Merge "Move Search dialog out of system process into current activity."
This commit is contained in:
committed by
Android (Google) Code Review
commit
a3b95a995f
@@ -39,6 +39,7 @@ import android.os.Build;
|
||||
import android.os.Bundle;
|
||||
import android.os.Handler;
|
||||
import android.os.IBinder;
|
||||
import android.os.Looper;
|
||||
import android.os.RemoteException;
|
||||
import android.text.Selection;
|
||||
import android.text.SpannableStringBuilder;
|
||||
@@ -3449,17 +3450,7 @@ public class Activity extends ContextThemeWrapper
|
||||
return;
|
||||
}
|
||||
|
||||
// uses super.getSystemService() since this.getSystemService() looks at the
|
||||
// mSearchManager field.
|
||||
mSearchManager = (SearchManager) super.getSystemService(Context.SEARCH_SERVICE);
|
||||
int ident = mIdent;
|
||||
if (ident == 0) {
|
||||
if (mParent != null) ident = mParent.mIdent;
|
||||
if (ident == 0) {
|
||||
throw new IllegalArgumentException("no ident");
|
||||
}
|
||||
}
|
||||
mSearchManager.setIdent(ident, getComponentName());
|
||||
mSearchManager = new SearchManager(this, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -29,23 +29,4 @@ interface ISearchManager {
|
||||
List<SearchableInfo> getSearchablesForWebSearch();
|
||||
SearchableInfo getDefaultSearchableForWebSearch();
|
||||
void setDefaultWebSearch(in ComponentName component);
|
||||
void startSearch(in String initialQuery,
|
||||
boolean selectInitialQuery,
|
||||
in ComponentName launchActivity,
|
||||
in Bundle appSearchData,
|
||||
boolean globalSearch,
|
||||
ISearchManagerCallback searchManagerCallback,
|
||||
int ident);
|
||||
|
||||
void triggerSearch(in String query,
|
||||
in ComponentName launchActivity,
|
||||
in Bundle appSearchData,
|
||||
ISearchManagerCallback searchManagerCallback,
|
||||
int ident);
|
||||
|
||||
void stopSearch();
|
||||
|
||||
|
||||
boolean isVisible();
|
||||
|
||||
}
|
||||
|
||||
@@ -73,8 +73,8 @@ import java.util.WeakHashMap;
|
||||
import java.util.concurrent.atomic.AtomicLong;
|
||||
|
||||
/**
|
||||
* System search dialog. This is controlled by the
|
||||
* SearchManagerService and runs in the system process.
|
||||
* Search dialog. This is controlled by the
|
||||
* SearchManager and runs in the current foreground process.
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
@@ -118,6 +118,7 @@ public class SearchDialog extends Dialog implements OnItemClickListener, OnItemS
|
||||
private Bundle mAppSearchData;
|
||||
private boolean mGlobalSearchMode;
|
||||
private Context mActivityContext;
|
||||
private SearchManager mSearchManager;
|
||||
|
||||
// Values we store to allow user to toggle between in-app search and global search.
|
||||
private ComponentName mStoredComponentName;
|
||||
@@ -157,7 +158,7 @@ public class SearchDialog extends Dialog implements OnItemClickListener, OnItemS
|
||||
*
|
||||
* @param context Application Context we can use for system acess
|
||||
*/
|
||||
public SearchDialog(Context context) {
|
||||
public SearchDialog(Context context, SearchManager searchManager) {
|
||||
super(context, com.android.internal.R.style.Theme_GlobalSearchBar);
|
||||
|
||||
// Save voice intent for later queries/launching
|
||||
@@ -168,6 +169,7 @@ public class SearchDialog extends Dialog implements OnItemClickListener, OnItemS
|
||||
|
||||
mVoiceAppSearchIntent = new Intent(RecognizerIntent.ACTION_RECOGNIZE_SPEECH);
|
||||
mVoiceAppSearchIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
|
||||
mSearchManager = searchManager;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -180,7 +182,6 @@ public class SearchDialog extends Dialog implements OnItemClickListener, OnItemS
|
||||
|
||||
Window theWindow = getWindow();
|
||||
WindowManager.LayoutParams lp = theWindow.getAttributes();
|
||||
lp.type = WindowManager.LayoutParams.TYPE_SEARCH_BAR;
|
||||
lp.width = ViewGroup.LayoutParams.MATCH_PARENT;
|
||||
// taking up the whole window (even when transparent) is less than ideal,
|
||||
// but necessary to show the popup window until the window manager supports
|
||||
@@ -291,8 +292,10 @@ public class SearchDialog extends Dialog implements OnItemClickListener, OnItemS
|
||||
//
|
||||
// TODO: When the browser icon issue is reconciled in Eclair, remove this special case.
|
||||
if (isBrowserSearch()) currentSearchText = "";
|
||||
|
||||
return doShow(currentSearchText, false, null, mAppSearchData, true);
|
||||
|
||||
cancel();
|
||||
mSearchManager.startGlobalSearch(currentSearchText, false, mStoredAppSearchData);
|
||||
return true;
|
||||
} else {
|
||||
if (mStoredComponentName != null) {
|
||||
// This means we should toggle *back* to an in-app search context from
|
||||
@@ -1314,8 +1317,7 @@ public class SearchDialog extends Dialog implements OnItemClickListener, OnItemS
|
||||
}
|
||||
|
||||
/**
|
||||
* Launches an intent, including any special intent handling. Doesn't dismiss the dialog
|
||||
* since that will be handled in {@link SearchDialogWrapper#performActivityResuming}
|
||||
* Launches an intent, including any special intent handling.
|
||||
*/
|
||||
private void launchIntent(Intent intent) {
|
||||
if (intent == null) {
|
||||
|
||||
@@ -1709,7 +1709,7 @@ public class SearchManager
|
||||
/* package */ OnDismissListener mDismissListener = null;
|
||||
/* package */ OnCancelListener mCancelListener = null;
|
||||
|
||||
private final SearchManagerCallback mSearchManagerCallback = new SearchManagerCallback();
|
||||
private SearchDialog mSearchDialog;
|
||||
|
||||
/*package*/ SearchManager(Context context, Handler handler) {
|
||||
mContext = context;
|
||||
@@ -1778,31 +1778,29 @@ public class SearchManager
|
||||
ComponentName launchActivity,
|
||||
Bundle appSearchData,
|
||||
boolean globalSearch) {
|
||||
if (mIdent == 0) throw new IllegalArgumentException(
|
||||
"Called from outside of an Activity context");
|
||||
ensureSearchDialog();
|
||||
|
||||
if (globalSearch) {
|
||||
startGlobalSearch(initialQuery, selectInitialQuery, appSearchData);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!mAssociatedPackage.equals(launchActivity.getPackageName())) {
|
||||
Log.w(TAG, "invoking app search on a different package " +
|
||||
"not associated with this search manager");
|
||||
}
|
||||
try {
|
||||
// activate the search manager and start it up!
|
||||
mService.startSearch(initialQuery, selectInitialQuery, launchActivity, appSearchData,
|
||||
globalSearch, mSearchManagerCallback, mIdent);
|
||||
} catch (RemoteException ex) {
|
||||
Log.e(TAG, "startSearch() failed.", ex);
|
||||
mSearchDialog.show(initialQuery, selectInitialQuery, launchActivity, appSearchData,
|
||||
globalSearch);
|
||||
}
|
||||
|
||||
private void ensureSearchDialog() {
|
||||
if (mSearchDialog == null) {
|
||||
mSearchDialog = new SearchDialog(mContext, this);
|
||||
mSearchDialog.setOnCancelListener(this);
|
||||
mSearchDialog.setOnDismissListener(this);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Starts the global search activity.
|
||||
*/
|
||||
private void startGlobalSearch(String initialQuery, boolean selectInitialQuery,
|
||||
/* package */ void startGlobalSearch(String initialQuery, boolean selectInitialQuery,
|
||||
Bundle appSearchData) {
|
||||
ComponentName globalSearchActivity = getGlobalSearchActivity();
|
||||
if (globalSearchActivity == null) {
|
||||
@@ -1876,8 +1874,6 @@ public class SearchManager
|
||||
public void triggerSearch(String query,
|
||||
ComponentName launchActivity,
|
||||
Bundle appSearchData) {
|
||||
if (mIdent == 0) throw new IllegalArgumentException(
|
||||
"Called from outside of an Activity context");
|
||||
if (!mAssociatedPackage.equals(launchActivity.getPackageName())) {
|
||||
throw new IllegalArgumentException("invoking app search on a different package " +
|
||||
"not associated with this search manager");
|
||||
@@ -1886,12 +1882,8 @@ public class SearchManager
|
||||
Log.w(TAG, "triggerSearch called with empty query, ignoring.");
|
||||
return;
|
||||
}
|
||||
try {
|
||||
mService.triggerSearch(query, launchActivity, appSearchData, mSearchManagerCallback,
|
||||
mIdent);
|
||||
} catch (RemoteException ex) {
|
||||
Log.e(TAG, "triggerSearch() failed.", ex);
|
||||
}
|
||||
startSearch(query, false, launchActivity, appSearchData, false);
|
||||
mSearchDialog.launchQuerySearch();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1906,10 +1898,8 @@ public class SearchManager
|
||||
* @see #startSearch
|
||||
*/
|
||||
public void stopSearch() {
|
||||
if (DBG) debug("stopSearch()");
|
||||
try {
|
||||
mService.stopSearch();
|
||||
} catch (RemoteException ex) {
|
||||
if (mSearchDialog != null) {
|
||||
mSearchDialog.cancel();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1923,13 +1913,7 @@ public class SearchManager
|
||||
* @hide
|
||||
*/
|
||||
public boolean isVisible() {
|
||||
if (DBG) debug("isVisible()");
|
||||
try {
|
||||
return mService.isVisible();
|
||||
} catch (RemoteException e) {
|
||||
Log.e(TAG, "isVisible() failed: " + e);
|
||||
return false;
|
||||
}
|
||||
return mSearchDialog == null? false : mSearchDialog.isShowing();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1976,44 +1960,14 @@ public class SearchManager
|
||||
mCancelListener = listener;
|
||||
}
|
||||
|
||||
private class SearchManagerCallback extends ISearchManagerCallback.Stub {
|
||||
|
||||
private final Runnable mFireOnDismiss = new Runnable() {
|
||||
public void run() {
|
||||
if (DBG) debug("mFireOnDismiss");
|
||||
if (mDismissListener != null) {
|
||||
mDismissListener.onDismiss();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
private final Runnable mFireOnCancel = new Runnable() {
|
||||
public void run() {
|
||||
if (DBG) debug("mFireOnCancel");
|
||||
if (mCancelListener != null) {
|
||||
mCancelListener.onCancel();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
public void onDismiss() {
|
||||
if (DBG) debug("onDismiss()");
|
||||
mHandler.post(mFireOnDismiss);
|
||||
}
|
||||
|
||||
public void onCancel() {
|
||||
if (DBG) debug("onCancel()");
|
||||
mHandler.post(mFireOnCancel);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated This method is an obsolete internal implementation detail. Do not use.
|
||||
*/
|
||||
@Deprecated
|
||||
public void onCancel(DialogInterface dialog) {
|
||||
throw new UnsupportedOperationException();
|
||||
if (mCancelListener != null) {
|
||||
mCancelListener.onCancel();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -2021,7 +1975,9 @@ public class SearchManager
|
||||
*/
|
||||
@Deprecated
|
||||
public void onDismiss(DialogInterface dialog) {
|
||||
throw new UnsupportedOperationException();
|
||||
if (mDismissListener != null) {
|
||||
mDismissListener.onDismiss();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -2208,4 +2164,4 @@ public class SearchManager
|
||||
Thread thread = Thread.currentThread();
|
||||
Log.d(TAG, msg + " (" + thread.getName() + "-" + thread.getId() + ")");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,426 +0,0 @@
|
||||
/*
|
||||
* 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 SEARCH_UI_THREAD_NAME = "SearchDialog";
|
||||
private static final int SEARCH_UI_THREAD_PRIORITY =
|
||||
android.os.Process.THREAD_PRIORITY_DEFAULT;
|
||||
|
||||
// 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
|
||||
// data[KEY_TRIGGER]: 0 = false, 1 = true
|
||||
private static final int MSG_START_SEARCH = 1;
|
||||
// Takes no arguments
|
||||
private static final int MSG_STOP_SEARCH = 2;
|
||||
// arg1 is activity id
|
||||
private static final int MSG_ACTIVITY_RESUMING = 3;
|
||||
// obj is the reason
|
||||
private static final int MSG_CLOSING_SYSTEM_DIALOGS = 4;
|
||||
|
||||
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";
|
||||
private static final String KEY_IDENT = "i";
|
||||
private static final String KEY_TRIGGER = "t";
|
||||
|
||||
// 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;
|
||||
|
||||
// Identity of last activity that started search.
|
||||
private int mStartedIdent = 0;
|
||||
|
||||
// Identity of currently resumed activity.
|
||||
private int mResumedIdent = 0;
|
||||
|
||||
// True if we have registered our receivers.
|
||||
private boolean mReceiverRegistered;
|
||||
|
||||
private volatile boolean mVisible = false;
|
||||
|
||||
/**
|
||||
* 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;
|
||||
|
||||
// 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);
|
||||
}
|
||||
|
||||
public boolean isVisible() {
|
||||
return mVisible;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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() {
|
||||
if (!mReceiverRegistered) {
|
||||
IntentFilter filter = new IntentFilter(
|
||||
Intent.ACTION_CONFIGURATION_CHANGED);
|
||||
mContext.registerReceiver(mBroadcastReceiver, filter, null,
|
||||
mSearchUiThread);
|
||||
mReceiverRegistered = true;
|
||||
}
|
||||
}
|
||||
|
||||
private void unregisterBroadcastReceiver() {
|
||||
if (mReceiverRegistered) {
|
||||
mContext.unregisterReceiver(mBroadcastReceiver);
|
||||
mReceiverRegistered = false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 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_CONFIGURATION_CHANGED.equals(action)) {
|
||||
if (DBG) debug(Intent.ACTION_CONFIGURATION_CHANGED);
|
||||
performOnConfigurationChanged();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
//
|
||||
// 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,
|
||||
int ident,
|
||||
boolean trigger) {
|
||||
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);
|
||||
msgData.putInt(KEY_IDENT, ident);
|
||||
msgData.putInt(KEY_TRIGGER, trigger ? 1 : 0);
|
||||
mSearchUiThread.sendMessage(msg);
|
||||
// be a little more eager in setting this so isVisible will return the correct value if
|
||||
// called immediately after startSearch
|
||||
mVisible = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Cancels the search dialog.
|
||||
* Can be called from any thread.
|
||||
*/
|
||||
public void stopSearch() {
|
||||
if (DBG) debug("stopSearch()");
|
||||
mSearchUiThread.sendEmptyMessage(MSG_STOP_SEARCH);
|
||||
// be a little more eager in setting this so isVisible will return the correct value if
|
||||
// called immediately after stopSearch
|
||||
mVisible = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the currently resumed activity.
|
||||
* Can be called from any thread.
|
||||
*/
|
||||
public void activityResuming(int ident) {
|
||||
if (DBG) debug("activityResuming(ident=" + ident + ")");
|
||||
Message msg = Message.obtain();
|
||||
msg.what = MSG_ACTIVITY_RESUMING;
|
||||
msg.arg1 = ident;
|
||||
mSearchUiThread.sendMessage(msg);
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles closing of system windows/dialogs
|
||||
* Can be called from any thread.
|
||||
*/
|
||||
public void closingSystemDialogs(String reason) {
|
||||
if (DBG) debug("closingSystemDialogs(reason=" + reason + ")");
|
||||
Message msg = Message.obtain();
|
||||
msg.what = MSG_CLOSING_SYSTEM_DIALOGS;
|
||||
msg.obj = reason;
|
||||
mSearchUiThread.sendMessage(msg);
|
||||
}
|
||||
|
||||
//
|
||||
// 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_ACTIVITY_RESUMING:
|
||||
performActivityResuming(msg.arg1);
|
||||
break;
|
||||
case MSG_CLOSING_SYSTEM_DIALOGS:
|
||||
performClosingSystemDialogs((String)msg.obj);
|
||||
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;
|
||||
int ident = msgData.getInt(KEY_IDENT);
|
||||
boolean trigger = msgData.getInt(KEY_TRIGGER) != 0;
|
||||
performStartSearch(initialQuery, selectInitialQuery, launchActivity,
|
||||
appSearchData, globalSearch, searchManagerCallback, ident, trigger);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* 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,
|
||||
int ident,
|
||||
boolean trigger) {
|
||||
if (DBG) debug("performStartSearch()");
|
||||
|
||||
registerBroadcastReceiver();
|
||||
mCallback = searchManagerCallback;
|
||||
|
||||
// clean up any hidden dialog that we were waiting to resume
|
||||
if (mStartedIdent != 0) {
|
||||
mSearchDialog.dismiss();
|
||||
}
|
||||
|
||||
mStartedIdent = ident;
|
||||
if (DBG) Log.v(TAG, "******************* DIALOG: start");
|
||||
|
||||
mSearchDialog.show(initialQuery, selectInitialQuery, launchActivity, appSearchData,
|
||||
globalSearch);
|
||||
mVisible = true;
|
||||
if (trigger) {
|
||||
mSearchDialog.launchQuerySearch();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Actually cancels the search UI.
|
||||
* This must be called on the search UI thread.
|
||||
*/
|
||||
void performStopSearch() {
|
||||
if (DBG) debug("performStopSearch()");
|
||||
if (DBG) Log.v(TAG, "******************* DIALOG: cancel");
|
||||
mSearchDialog.cancel();
|
||||
mVisible = false;
|
||||
mStartedIdent = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the resumed activity
|
||||
* This must be called on the search UI thread.
|
||||
*/
|
||||
void performActivityResuming(int ident) {
|
||||
if (DBG) debug("performResumingActivity(): mStartedIdent="
|
||||
+ mStartedIdent + ", resuming: " + ident);
|
||||
this.mResumedIdent = ident;
|
||||
if (mStartedIdent != 0) {
|
||||
if (mStartedIdent == mResumedIdent) {
|
||||
// we are resuming into the activity where we previously hid the dialog, bring it
|
||||
// back
|
||||
if (DBG) Log.v(TAG, "******************* DIALOG: show");
|
||||
mSearchDialog.show();
|
||||
mVisible = true;
|
||||
} else {
|
||||
// resuming into some other activity; hide ourselves in case we ever come back
|
||||
// so we can show ourselves quickly again
|
||||
if (DBG) Log.v(TAG, "******************* DIALOG: hide");
|
||||
mSearchDialog.hide();
|
||||
mVisible = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates due to system dialogs being closed
|
||||
* This must be called on the search UI thread.
|
||||
*/
|
||||
void performClosingSystemDialogs(String reason) {
|
||||
if (DBG) debug("performClosingSystemDialogs(): mStartedIdent="
|
||||
+ mStartedIdent + ", reason: " + reason);
|
||||
if (!"search".equals(reason)) {
|
||||
if (DBG) debug(Intent.ACTION_CLOSE_SYSTEM_DIALOGS);
|
||||
performStopSearch();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 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()");
|
||||
mStartedIdent = 0;
|
||||
mVisible = false;
|
||||
callOnDismiss();
|
||||
|
||||
// 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()");
|
||||
callOnCancel();
|
||||
}
|
||||
|
||||
private void callOnDismiss() {
|
||||
if (mCallback == null) return;
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
private void callOnCancel() {
|
||||
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() + ")");
|
||||
}
|
||||
}
|
||||
@@ -51,10 +51,6 @@ public class SearchManagerService extends ISearchManager.Stub {
|
||||
// Only accessed by ensureSearchablesCreated() and getSearchables()
|
||||
private Searchables mSearchables;
|
||||
|
||||
// This field is initialized in ensureSearchDialogCreated(), and then never modified.
|
||||
// Only accessed by ensureSearchDialogCreated() and getSearchDialog()
|
||||
private SearchDialogWrapper mSearchDialog;
|
||||
|
||||
/**
|
||||
* Initializes the Search Manager service in the provided system context.
|
||||
* Only one instance of this object should be created!
|
||||
@@ -63,23 +59,6 @@ public class SearchManagerService extends ISearchManager.Stub {
|
||||
*/
|
||||
public SearchManagerService(Context context) {
|
||||
mContext = context;
|
||||
// call initialize() after all pending actions on the main system thread have finished
|
||||
new Handler().post(new Runnable() {
|
||||
public void run() {
|
||||
initialize();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes the list of searchable activities and the search UI.
|
||||
*/
|
||||
void initialize() {
|
||||
try {
|
||||
ActivityManagerNative.getDefault().registerActivityWatcher(
|
||||
mActivityWatcher);
|
||||
} catch (RemoteException e) {
|
||||
}
|
||||
}
|
||||
|
||||
private synchronized void ensureSearchablesCreated() {
|
||||
@@ -96,22 +75,11 @@ public class SearchManagerService extends ISearchManager.Stub {
|
||||
mContext.registerReceiver(mPackageChangedReceiver, packageFilter);
|
||||
}
|
||||
|
||||
private synchronized void ensureSearchDialogCreated() {
|
||||
if (mSearchDialog != null) return;
|
||||
|
||||
mSearchDialog = new SearchDialogWrapper(mContext);
|
||||
}
|
||||
|
||||
private synchronized Searchables getSearchables() {
|
||||
ensureSearchablesCreated();
|
||||
return mSearchables;
|
||||
}
|
||||
|
||||
private synchronized SearchDialogWrapper getSearchDialog() {
|
||||
ensureSearchDialogCreated();
|
||||
return mSearchDialog;
|
||||
}
|
||||
|
||||
/**
|
||||
* Refreshes the "searchables" list when packages are added/removed.
|
||||
*/
|
||||
@@ -124,8 +92,6 @@ public class SearchManagerService extends ISearchManager.Stub {
|
||||
Intent.ACTION_PACKAGE_REMOVED.equals(action) ||
|
||||
Intent.ACTION_PACKAGE_CHANGED.equals(action)) {
|
||||
if (DBG) Log.d(TAG, "Got " + action);
|
||||
// Dismiss search dialog, since the search context may no longer be valid
|
||||
getSearchDialog().stopSearch();
|
||||
// Update list of searchable activities
|
||||
getSearchables().buildSearchableList();
|
||||
broadcastSearchablesChanged();
|
||||
@@ -133,19 +99,6 @@ public class SearchManagerService extends ISearchManager.Stub {
|
||||
}
|
||||
};
|
||||
|
||||
private IActivityWatcher.Stub mActivityWatcher = new IActivityWatcher.Stub() {
|
||||
public void activityResuming(int activityId) throws RemoteException {
|
||||
if (DBG) Log.i("foo", "********************** resuming: " + activityId);
|
||||
if (mSearchDialog == null) return;
|
||||
mSearchDialog.activityResuming(activityId);
|
||||
}
|
||||
public void closingSystemDialogs(String reason) {
|
||||
if (DBG) Log.i("foo", "********************** closing dialogs: " + reason);
|
||||
if (mSearchDialog == null) return;
|
||||
mSearchDialog.closingSystemDialogs(reason);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Informs all listeners that the list of searchables has been updated.
|
||||
*/
|
||||
@@ -214,62 +167,4 @@ public class SearchManagerService extends ISearchManager.Stub {
|
||||
getSearchables().setDefaultWebSearch(component);
|
||||
broadcastSearchablesChanged();
|
||||
}
|
||||
|
||||
// Search UI API
|
||||
|
||||
/**
|
||||
* Launches the search UI. Can be called from any thread.
|
||||
*
|
||||
* @see SearchManager#startSearch(String, boolean, ComponentName, Bundle, boolean)
|
||||
*/
|
||||
public void startSearch(String initialQuery,
|
||||
boolean selectInitialQuery,
|
||||
ComponentName launchActivity,
|
||||
Bundle appSearchData,
|
||||
boolean globalSearch,
|
||||
ISearchManagerCallback searchManagerCallback,
|
||||
int ident) {
|
||||
getSearchDialog().startSearch(initialQuery,
|
||||
selectInitialQuery,
|
||||
launchActivity,
|
||||
appSearchData,
|
||||
globalSearch,
|
||||
searchManagerCallback,
|
||||
ident,
|
||||
false); // don't trigger
|
||||
}
|
||||
|
||||
/**
|
||||
* Launches the search UI and triggers the search, as if the user had clicked on the
|
||||
* search button within the dialog.
|
||||
*
|
||||
* @see SearchManager#triggerSearch(String, android.content.ComponentName, android.os.Bundle)
|
||||
*/
|
||||
public void triggerSearch(String query,
|
||||
ComponentName launchActivity,
|
||||
Bundle appSearchData,
|
||||
ISearchManagerCallback searchManagerCallback,
|
||||
int ident) {
|
||||
getSearchDialog().startSearch(
|
||||
query,
|
||||
false,
|
||||
launchActivity,
|
||||
appSearchData,
|
||||
false,
|
||||
searchManagerCallback,
|
||||
ident,
|
||||
true); // triger search after launching
|
||||
}
|
||||
|
||||
/**
|
||||
* Cancels the search dialog. Can be called from any thread.
|
||||
*/
|
||||
public void stopSearch() {
|
||||
getSearchDialog().stopSearch();
|
||||
}
|
||||
|
||||
public boolean isVisible() {
|
||||
return mSearchDialog != null && mSearchDialog.isVisible();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user