Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 444c727e authored by Bjorn Bringert's avatar Bjorn Bringert
Browse files

Run search UI on its own thread.

Details:

- Add a new SearchDialogWrapper class that makes sure
  all access to the SearchDialog is run one a single thread
  other than the main ServerThread.
- Don't save/restore seach dialog state in Activity.
  This resulted in lots of calls to the SearchManager
  throughout the life cycle of all activities, for
  the questionable benefit of restoring the search dialog
  in a few cases.
- Remove search UI state save/restore, and the isVisible()
  method from SearchManagerService. They are no longer used,
  and were tricky to implement since they return values from
  the search UI thread to the service.
- Handle configuration changes in searchDialogWrapper instead
  of calling through from Activity.

Fixes http://b/issue?id=1938101

TODO:
- Activity.performPause() calls stopSearch(). This call may not happen
  until the new activity has been started. If the new activity starts a
  search immediately, this search could be cancelled by the old activity's
  call top stopSearch().
parent e9ac96f7
Loading
Loading
Loading
Loading
+2 −35
Original line number Original line Diff line number Diff line
@@ -606,7 +606,6 @@ public class Activity extends ContextThemeWrapper
    private static final String SAVED_DIALOG_IDS_KEY = "android:savedDialogIds";
    private static final String SAVED_DIALOG_IDS_KEY = "android:savedDialogIds";
    private static final String SAVED_DIALOGS_TAG = "android:savedDialogs";
    private static final String SAVED_DIALOGS_TAG = "android:savedDialogs";
    private static final String SAVED_DIALOG_KEY_PREFIX = "android:dialog_";
    private static final String SAVED_DIALOG_KEY_PREFIX = "android:dialog_";
    private static final String SAVED_SEARCH_DIALOG_KEY = "android:search_dialog";


    private SparseArray<Dialog> mManagedDialogs;
    private SparseArray<Dialog> mManagedDialogs;


@@ -630,7 +629,6 @@ public class Activity extends ContextThemeWrapper
    /*package*/ int mConfigChangeFlags;
    /*package*/ int mConfigChangeFlags;
    /*package*/ Configuration mCurrentConfig;
    /*package*/ Configuration mCurrentConfig;
    private SearchManager mSearchManager;
    private SearchManager mSearchManager;
    private Bundle mSearchDialogState = null;


    private Window mWindow;
    private Window mWindow;


@@ -808,13 +806,6 @@ public class Activity extends ContextThemeWrapper
    final void performRestoreInstanceState(Bundle savedInstanceState) {
    final void performRestoreInstanceState(Bundle savedInstanceState) {
        onRestoreInstanceState(savedInstanceState);
        onRestoreInstanceState(savedInstanceState);
        restoreManagedDialogs(savedInstanceState);
        restoreManagedDialogs(savedInstanceState);
        
        // Also restore the state of a search dialog (if any)
        // TODO more generic than just this manager
        Bundle searchState = savedInstanceState.getBundle(SAVED_SEARCH_DIALOG_KEY);
        if (searchState != null) {
            mSearchManager.restoreSearchDialog(searchState);
        }
    }
    }


    /**
    /**
@@ -1030,14 +1021,6 @@ public class Activity extends ContextThemeWrapper
    final void performSaveInstanceState(Bundle outState) {
    final void performSaveInstanceState(Bundle outState) {
        onSaveInstanceState(outState);
        onSaveInstanceState(outState);
        saveManagedDialogs(outState);
        saveManagedDialogs(outState);

        // Also save the state of a search dialog (if any)
        // TODO more generic than just this manager
        // onPause() should always be called before this method, so mSearchManagerState
        // should be up to date.
        if (mSearchDialogState != null) {
            outState.putBundle(SAVED_SEARCH_DIALOG_KEY, mSearchDialogState);
        }
    }
    }


    /**
    /**
@@ -1317,10 +1300,6 @@ public class Activity extends ContextThemeWrapper
                c.mCursor.close();
                c.mCursor.close();
            }
            }
        }
        }

        // Clear any search state saved in performPause(). If the state may be needed in the
        // future, it will have been saved by performSaveInstanceState()
        mSearchDialogState = null;
    }
    }


    /**
    /**
@@ -1342,10 +1321,6 @@ public class Activity extends ContextThemeWrapper
    public void onConfigurationChanged(Configuration newConfig) {
    public void onConfigurationChanged(Configuration newConfig) {
        mCalled = true;
        mCalled = true;


        // also update search dialog if showing
        // TODO more generic than just this manager
        mSearchManager.onConfigurationChanged(newConfig);
        
        if (mWindow != null) {
        if (mWindow != null) {
            // Pass the configuration changed event to the window
            // Pass the configuration changed event to the window
            mWindow.onConfigurationChanged(newConfig);
            mWindow.onConfigurationChanged(newConfig);
@@ -3575,20 +3550,12 @@ public class Activity extends ContextThemeWrapper
                "Activity " + mComponent.toShortString() +
                "Activity " + mComponent.toShortString() +
                " did not call through to super.onPostResume()");
                " did not call through to super.onPostResume()");
        }
        }

        // restore search dialog, if any
        if (mSearchDialogState != null) {
            mSearchManager.restoreSearchDialog(mSearchDialogState);
        }
        mSearchDialogState = null;
    }
    }


    final void performPause() {
    final void performPause() {
        onPause();
        onPause();


        // save search dialog state if the search dialog is open,
        // dismiss the search dialog if it is open
        // and then dismiss the search dialog
        mSearchDialogState = mSearchManager.saveSearchDialog();
        mSearchManager.stopSearch();
        mSearchManager.stopSearch();
    }
    }
    
    
+0 −4
Original line number Original line Diff line number Diff line
@@ -36,8 +36,4 @@ interface ISearchManager {
            boolean globalSearch,
            boolean globalSearch,
            ISearchManagerCallback searchManagerCallback);
            ISearchManagerCallback searchManagerCallback);
    void stopSearch();
    void stopSearch();
    boolean isVisible();
    Bundle onSaveInstanceState();
    void onRestoreInstanceState(in Bundle savedInstanceState);
    void onConfigurationChanged(in Configuration newConfig);
}
}
+16 −65
Original line number Original line Diff line number Diff line
@@ -19,13 +19,11 @@ package android.app;
import static android.app.SuggestionsAdapter.getColumnString;
import static android.app.SuggestionsAdapter.getColumnString;


import android.content.ActivityNotFoundException;
import android.content.ActivityNotFoundException;
import android.content.BroadcastReceiver;
import android.content.ComponentName;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.ContentResolver;
import android.content.ContentResolver;
import android.content.ContentValues;
import android.content.ContentValues;
import android.content.Context;
import android.content.Intent;
import android.content.pm.ActivityInfo;
import android.content.pm.ActivityInfo;
import android.content.pm.PackageManager;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.content.pm.ResolveInfo;
@@ -33,8 +31,8 @@ import android.content.pm.PackageManager.NameNotFoundException;
import android.content.res.Configuration;
import android.content.res.Configuration;
import android.content.res.Resources;
import android.content.res.Resources;
import android.database.Cursor;
import android.database.Cursor;
import android.graphics.drawable.Drawable;
import android.graphics.drawable.Animatable;
import android.graphics.drawable.Animatable;
import android.graphics.drawable.Drawable;
import android.net.Uri;
import android.net.Uri;
import android.os.Bundle;
import android.os.Bundle;
import android.os.SystemClock;
import android.os.SystemClock;
@@ -96,10 +94,6 @@ public class SearchDialog extends Dialog implements OnItemClickListener, OnItemS
    private static final int SEARCH_PLATE_LEFT_PADDING_GLOBAL = 12;
    private static final int SEARCH_PLATE_LEFT_PADDING_GLOBAL = 12;
    private static final int SEARCH_PLATE_LEFT_PADDING_NON_GLOBAL = 7;
    private static final int SEARCH_PLATE_LEFT_PADDING_NON_GLOBAL = 7;


    // interaction with runtime
    private IntentFilter mCloseDialogsFilter;
    private IntentFilter mPackageFilter;
    
    // views & widgets
    // views & widgets
    private TextView mBadgeLabel;
    private TextView mBadgeLabel;
    private ImageView mAppIcon;
    private ImageView mAppIcon;
@@ -211,14 +205,6 @@ public class SearchDialog extends Dialog implements OnItemClickListener, OnItemS
        // Touching outside of the search dialog will dismiss it 
        // Touching outside of the search dialog will dismiss it 
        setCanceledOnTouchOutside(true);
        setCanceledOnTouchOutside(true);


        // Set up broadcast filters
        mCloseDialogsFilter = new IntentFilter(Intent.ACTION_CLOSE_SYSTEM_DIALOGS);
        mPackageFilter = new IntentFilter();
        mPackageFilter.addAction(Intent.ACTION_PACKAGE_ADDED);
        mPackageFilter.addAction(Intent.ACTION_PACKAGE_REMOVED);
        mPackageFilter.addAction(Intent.ACTION_PACKAGE_CHANGED);
        mPackageFilter.addDataScheme("package");
        
        // Save voice intent for later queries/launching
        // Save voice intent for later queries/launching
        mVoiceWebSearchIntent = new Intent(RecognizerIntent.ACTION_WEB_SEARCH);
        mVoiceWebSearchIntent = new Intent(RecognizerIntent.ACTION_WEB_SEARCH);
        mVoiceWebSearchIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
        mVoiceWebSearchIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
@@ -383,15 +369,6 @@ public class SearchDialog extends Dialog implements OnItemClickListener, OnItemS
        return true;
        return true;
    }
    }


    @Override
    protected void onStart() {
        super.onStart();
        
        // receive broadcasts
        getContext().registerReceiver(mBroadcastReceiver, mCloseDialogsFilter);
        getContext().registerReceiver(mBroadcastReceiver, mPackageFilter);
    }

    /**
    /**
     * The search dialog is being dismissed, so handle all of the local shutdown operations.
     * The search dialog is being dismissed, so handle all of the local shutdown operations.
     * 
     * 
@@ -402,13 +379,6 @@ public class SearchDialog extends Dialog implements OnItemClickListener, OnItemS
    public void onStop() {
    public void onStop() {
        super.onStop();
        super.onStop();


        // stop receiving broadcasts (throws exception if none registered)
        try {
            getContext().unregisterReceiver(mBroadcastReceiver);
        } catch (RuntimeException e) {
            // This is OK - it just means we didn't have any registered
        }
        
        closeSuggestionsAdapter();
        closeSuggestionsAdapter();
        
        
        // dump extra memory we're hanging on to
        // dump extra memory we're hanging on to
@@ -455,10 +425,13 @@ public class SearchDialog extends Dialog implements OnItemClickListener, OnItemS
    /**
    /**
     * Save the minimal set of data necessary to recreate the search
     * Save the minimal set of data necessary to recreate the search
     * 
     * 
     * @return A bundle with the state of the dialog.
     * @return A bundle with the state of the dialog, or {@code null} if the search
     *         dialog is not showing.
     */
     */
    @Override
    @Override
    public Bundle onSaveInstanceState() {
    public Bundle onSaveInstanceState() {
        if (!isShowing()) return null;

        Bundle bundle = new Bundle();
        Bundle bundle = new Bundle();


        // setup info so I can recreate this particular search       
        // setup info so I can recreate this particular search       
@@ -483,6 +456,8 @@ public class SearchDialog extends Dialog implements OnItemClickListener, OnItemS
     */
     */
    @Override
    @Override
    public void onRestoreInstanceState(Bundle savedInstanceState) {
    public void onRestoreInstanceState(Bundle savedInstanceState) {
        if (savedInstanceState == null) return;

        ComponentName launchComponent = savedInstanceState.getParcelable(INSTANCE_KEY_COMPONENT);
        ComponentName launchComponent = savedInstanceState.getParcelable(INSTANCE_KEY_COMPONENT);
        Bundle appSearchData = savedInstanceState.getBundle(INSTANCE_KEY_APPDATA);
        Bundle appSearchData = savedInstanceState.getBundle(INSTANCE_KEY_APPDATA);
        boolean globalSearch = savedInstanceState.getBoolean(INSTANCE_KEY_GLOBALSEARCH);
        boolean globalSearch = savedInstanceState.getBoolean(INSTANCE_KEY_GLOBALSEARCH);
@@ -509,7 +484,7 @@ public class SearchDialog extends Dialog implements OnItemClickListener, OnItemS
    /**
    /**
     * Called after resources have changed, e.g. after screen rotation or locale change.
     * Called after resources have changed, e.g. after screen rotation or locale change.
     */
     */
    public void onConfigurationChanged(Configuration newConfig) {
    public void onConfigurationChanged() {
        if (isShowing()) {
        if (isShowing()) {
            // Redraw (resources may have changed)
            // Redraw (resources may have changed)
            updateSearchButton();
            updateSearchButton();
@@ -1015,34 +990,10 @@ public class SearchDialog extends Dialog implements OnItemClickListener, OnItemS
        }
        }
    };
    };


    /**
     * When the ACTION_CLOSE_SYSTEM_DIALOGS intent is received, we should close ourselves 
     * immediately, in order to allow a higher-priority UI to take over
     * (e.g. phone call received).
     * 
     * When a package is added, removed or changed, our current context
     * may no longer be valid.  This would only happen if a package is installed/removed exactly
     * when the search bar is open.  So for now we're just going to close the search
     * bar.  
     * Anything fancier would require some checks to see if the user's context was still valid.
     * Which would be messier.
     */
    private BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
        @Override
        public void onReceive(Context context, Intent intent) {
            String action = intent.getAction();
            if (Intent.ACTION_CLOSE_SYSTEM_DIALOGS.equals(action)) {
                cancel();
            } else if (Intent.ACTION_PACKAGE_ADDED.equals(action)
                    || Intent.ACTION_PACKAGE_REMOVED.equals(action)
                    || Intent.ACTION_PACKAGE_CHANGED.equals(action)) {
                cancel();
            }
        }
    };

    @Override
    @Override
    public void cancel() {
    public void cancel() {
        if (!isShowing()) return;

        // We made sure the IME was displayed, so also make sure it is closed
        // We made sure the IME was displayed, so also make sure it is closed
        // when we go away.
        // when we go away.
        InputMethodManager imm = (InputMethodManager)getContext()
        InputMethodManager imm = (InputMethodManager)getContext()
+0 −54
Original line number Original line Diff line number Diff line
@@ -20,7 +20,6 @@ import android.content.ComponentName;
import android.content.ContentResolver;
import android.content.ContentResolver;
import android.content.Context;
import android.content.Context;
import android.content.DialogInterface;
import android.content.DialogInterface;
import android.content.res.Configuration;
import android.database.Cursor;
import android.database.Cursor;
import android.net.Uri;
import android.net.Uri;
import android.os.Bundle;
import android.os.Bundle;
@@ -1729,59 +1728,6 @@ public class SearchManager
        throw new UnsupportedOperationException();
        throw new UnsupportedOperationException();
    }
    }


    /**
     * Saves the state of the search UI.
     *
     * @return A Bundle containing the state of the search dialog, or {@code null}
     *         if the search UI is not visible.
     *
     * @hide
     */
    public Bundle saveSearchDialog() {
        if (DBG) debug("saveSearchDialog(), mIsShowing=" + mIsShowing);
        if (!mIsShowing) return null;
        try {
            return mService.onSaveInstanceState();
        } catch (RemoteException ex) {
            Log.e(TAG, "onSaveInstanceState() failed: " + ex);
            return null;
        }
    }

    /**
     * Restores the state of the search dialog.
     *
     * @param searchDialogState Bundle to read the state from.
     *
     * @hide
     */
    public void restoreSearchDialog(Bundle searchDialogState) {
        if (DBG) debug("restoreSearchDialog(" + searchDialogState + ")");
        if (searchDialogState == null) return;
        try {
            mService.onRestoreInstanceState(searchDialogState);
        } catch (RemoteException ex) {
            Log.e(TAG, "onRestoreInstanceState() failed: " + ex);
        }
    }

    /**
     * Update the search dialog after a configuration change.
     *
     * @param newConfig The new configuration.
     *
     * @hide
     */
    public void onConfigurationChanged(Configuration newConfig) {
        if (DBG) debug("onConfigurationChanged(" + newConfig + "), mIsShowing=" + mIsShowing);
        if (!mIsShowing) return;
        try {
            mService.onConfigurationChanged(newConfig);
        } catch (RemoteException ex) {
            Log.e(TAG, "onConfigurationChanged() failed:" + ex);
        }
    }

    /**
    /**
     * Gets information about a searchable activity. This method is static so that it can
     * Gets information about a searchable activity. This method is static so that it can
     * be used from non-Activity contexts.
     * be used from non-Activity contexts.
+320 −0
Original line number Original line Diff line number Diff line
/*
 * Copyright (C) 2007 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package android.server.search;

import android.app.ISearchManagerCallback;
import android.app.SearchDialog;
import android.app.SearchManager;
import android.content.BroadcastReceiver;
import android.content.ComponentName;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.Bundle;
import android.os.DeadObjectException;
import android.os.Handler;
import android.os.HandlerThread;
import android.os.Looper;
import android.os.Message;
import android.os.RemoteException;
import android.os.SystemProperties;
import android.text.TextUtils;
import android.util.Log;

/**
 * Runs an instance of {@link SearchDialog} on its own thread.
 */
class SearchDialogWrapper
implements DialogInterface.OnCancelListener, DialogInterface.OnDismissListener {

    private static final String TAG = "SearchManagerService";
    private static final boolean DBG = false;

    private static final String DISABLE_SEARCH_PROPERTY = "dev.disablesearchdialog";

    private static final String SEARCH_UI_THREAD_NAME = "SearchDialog";
    private static final int SEARCH_UI_THREAD_PRIORITY =
        android.os.Process.THREAD_PRIORITY_FOREGROUND;

    // Takes no arguments
    private static final int MSG_INIT = 0;
    // Takes these arguments:
    // arg1: selectInitialQuery, 0 = false, 1 = true
    // arg2: globalSearch, 0 = false, 1 = true
    // obj: searchManagerCallback
    // data[KEY_INITIAL_QUERY]: initial query
    // data[KEY_LAUNCH_ACTIVITY]: launch activity
    // data[KEY_APP_SEARCH_DATA]: app search data
    private static final int MSG_START_SEARCH = 1;
    // Takes no arguments
    private static final int MSG_STOP_SEARCH = 2;
    // Takes no arguments
    private static final int MSG_ON_CONFIGURATION_CHANGED = 3;

    private static final String KEY_INITIAL_QUERY = "q";
    private static final String KEY_LAUNCH_ACTIVITY = "a";
    private static final String KEY_APP_SEARCH_DATA = "d";

    // Context used for getting search UI resources
    private final Context mContext;

    // Handles messages on the search UI thread.
    private final SearchDialogHandler mSearchUiThread;

    // The search UI
    SearchDialog mSearchDialog;

    // If the search UI is visible, this is the callback for the client that showed it.
    ISearchManagerCallback mCallback = null;

    // Allows disabling of search dialog for stress testing runs
    private final boolean mDisabledOnBoot;

    /**
     * Creates a new search dialog wrapper and a search UI thread. The search dialog itself will
     * be created some asynchronously on the search UI thread.
     *
     * @param context Context used for getting search UI resources.
     */
    public SearchDialogWrapper(Context context) {
        mContext = context;

        mDisabledOnBoot = !TextUtils.isEmpty(SystemProperties.get(DISABLE_SEARCH_PROPERTY));

        // Create the search UI thread
        HandlerThread t = new HandlerThread(SEARCH_UI_THREAD_NAME, SEARCH_UI_THREAD_PRIORITY);
        t.start();
        mSearchUiThread = new SearchDialogHandler(t.getLooper());

        // Create search UI on the search UI thread
        mSearchUiThread.sendEmptyMessage(MSG_INIT);
    }

    /**
     * Initializes the search UI.
     * Must be called from the search UI thread.
     */
    private void init() {
        mSearchDialog = new SearchDialog(mContext);
        mSearchDialog.setOnCancelListener(this);
        mSearchDialog.setOnDismissListener(this);
    }

    private void registerBroadcastReceiver() {
        IntentFilter closeDialogsFilter = new IntentFilter(Intent.ACTION_CLOSE_SYSTEM_DIALOGS);
        mContext.registerReceiver(mBroadcastReceiver, closeDialogsFilter);
        IntentFilter configurationChangedFilter =
                new IntentFilter(Intent.ACTION_CONFIGURATION_CHANGED);
        mContext.registerReceiver(mBroadcastReceiver, configurationChangedFilter);
    }

    private void unregisterBroadcastReceiver() {
        mContext.unregisterReceiver(mBroadcastReceiver);
    }

    /**
     * Closes the search dialog when requested by the system (e.g. when a phone call comes in).
     */
    private BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
        @Override
        public void onReceive(Context context, Intent intent) {
            String action = intent.getAction();
            if (Intent.ACTION_CLOSE_SYSTEM_DIALOGS.equals(action)) {
                if (DBG) debug(Intent.ACTION_CLOSE_SYSTEM_DIALOGS);
                stopSearch();
            } else if (Intent.ACTION_CONFIGURATION_CHANGED.equals(action)) {
                if (DBG) debug(Intent.ACTION_CONFIGURATION_CHANGED);
                onConfigurationChanged();
            }
        }
    };

    //
    // External API
    //

    /**
     * Launches the search UI.
     * Can be called from any thread.
     *
     * @see SearchManager#startSearch(String, boolean, ComponentName, Bundle, boolean)
     */
    public void startSearch(final String initialQuery,
            final boolean selectInitialQuery,
            final ComponentName launchActivity,
            final Bundle appSearchData,
            final boolean globalSearch,
            final ISearchManagerCallback searchManagerCallback) {
        if (DBG) debug("startSearch()");
        Message msg = Message.obtain();
        msg.what = MSG_START_SEARCH;
        msg.arg1 = selectInitialQuery ? 1 : 0;
        msg.arg2 = globalSearch ? 1 : 0;
        msg.obj = searchManagerCallback;
        Bundle msgData = msg.getData();
        msgData.putString(KEY_INITIAL_QUERY, initialQuery);
        msgData.putParcelable(KEY_LAUNCH_ACTIVITY, launchActivity);
        msgData.putBundle(KEY_APP_SEARCH_DATA, appSearchData);
        mSearchUiThread.sendMessage(msg);
    }

    /**
     * Cancels the search dialog.
     * Can be called from any thread.
     */
    public void stopSearch() {
        if (DBG) debug("stopSearch()");
        mSearchUiThread.sendEmptyMessage(MSG_STOP_SEARCH);
    }

    /**
     * Updates the search UI in response to a configuration change.
     * Can be called from any thread.
     */
    void onConfigurationChanged() {
        if (DBG) debug("onConfigurationChanged()");
        mSearchUiThread.sendEmptyMessage(MSG_ON_CONFIGURATION_CHANGED);
    }

    //
    // Implementation methods that run on the search UI thread
    //

    private class SearchDialogHandler extends Handler {

        public SearchDialogHandler(Looper looper) {
            super(looper);
        }

        @Override
        public void handleMessage(Message msg) {
            switch (msg.what) {
                case MSG_INIT:
                    init();
                    break;
                case MSG_START_SEARCH:
                    handleStartSearchMessage(msg);
                    break;
                case MSG_STOP_SEARCH:
                    performStopSearch();
                    break;
                case MSG_ON_CONFIGURATION_CHANGED:
                    performOnConfigurationChanged();
                    break;
            }
        }

        private void handleStartSearchMessage(Message msg) {
            Bundle msgData = msg.getData();
            String initialQuery = msgData.getString(KEY_INITIAL_QUERY);
            boolean selectInitialQuery = msg.arg1 != 0;
            ComponentName launchActivity =
                    (ComponentName) msgData.getParcelable(KEY_LAUNCH_ACTIVITY);
            Bundle appSearchData = msgData.getBundle(KEY_APP_SEARCH_DATA);
            boolean globalSearch = msg.arg2 != 0;
            ISearchManagerCallback searchManagerCallback = (ISearchManagerCallback) msg.obj;
            performStartSearch(initialQuery, selectInitialQuery, launchActivity,
                    appSearchData, globalSearch, searchManagerCallback);
        }

    }

    /**
     * Actually launches the search UI.
     * This must be called on the search UI thread.
     */
    void performStartSearch(String initialQuery,
            boolean selectInitialQuery,
            ComponentName launchActivity,
            Bundle appSearchData,
            boolean globalSearch,
            ISearchManagerCallback searchManagerCallback) {
        if (DBG) debug("performStartSearch()");

        if (mDisabledOnBoot) {
            Log.d(TAG, "ignoring start search request because " + DISABLE_SEARCH_PROPERTY
                    + " system property is set.");
            return;
        }

        registerBroadcastReceiver();
        mCallback = searchManagerCallback;
        mSearchDialog.show(initialQuery, selectInitialQuery, launchActivity, appSearchData,
                globalSearch);
    }

    /**
     * Actually cancels the search UI.
     * This must be called on the search UI thread.
     */
    void performStopSearch() {
        if (DBG) debug("performStopSearch()");
        mSearchDialog.cancel();
    }

    /**
     * Must be called from the search UI thread.
     */
    void performOnConfigurationChanged() {
        if (DBG) debug("performOnConfigurationChanged()");
        mSearchDialog.onConfigurationChanged();
    }

    /**
     * Called by {@link SearchDialog} when it goes away.
     */
    public void onDismiss(DialogInterface dialog) {
        if (DBG) debug("onDismiss()");
        if (mCallback != null) {
            try {
                // should be safe to do on the search UI thread, since it's a oneway interface
                mCallback.onDismiss();
            } catch (DeadObjectException ex) {
                // The process that hosted the callback has died, do nothing
            } catch (RemoteException ex) {
                Log.e(TAG, "onDismiss() failed: " + ex);
            }
            // we don't need the callback anymore, release it
            mCallback = null;
        }
        unregisterBroadcastReceiver();
    }

    /**
     * Called by {@link SearchDialog} when the user or activity cancels search.
     * Whenever this method is called, {@link #onDismiss} is always called afterwards.
     */
    public void onCancel(DialogInterface dialog) {
        if (DBG) debug("onCancel()");
        if (mCallback != null) {
            try {
                // should be safe to do on the search UI thread, since it's a oneway interface
                mCallback.onCancel();
            } catch (DeadObjectException ex) {
                // The process that hosted the callback has died, do nothing
            } catch (RemoteException ex) {
                Log.e(TAG, "onCancel() failed: " + ex);
            }
        }
    }

    private static void debug(String msg) {
        Thread thread = Thread.currentThread();
        Log.d(TAG, msg + " (" + thread.getName() + "-" + thread.getId() + ")");
    }
}
Loading