Loading core/java/android/app/Activity.java +2 −11 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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 Loading core/java/android/app/ISearchManager.aidl +0 −19 Original line number Diff line number Diff line Loading @@ -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(); } core/java/android/app/SearchDialog.java +10 −8 Original line number Diff line number Diff line Loading @@ -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 */ Loading Loading @@ -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; Loading Loading @@ -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 Loading @@ -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; } /** Loading @@ -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 Loading Loading @@ -292,7 +293,9 @@ 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 Loading Loading @@ -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) { Loading core/java/android/app/SearchManager.java +24 −68 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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"); mSearchDialog.show(initialQuery, selectInitialQuery, launchActivity, appSearchData, globalSearch); } 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); 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) { Loading Loading @@ -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"); Loading @@ -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(); } /** Loading @@ -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(); } } Loading @@ -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(); } /** Loading Loading @@ -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(); } } /** Loading @@ -2021,7 +1975,9 @@ public class SearchManager */ @Deprecated public void onDismiss(DialogInterface dialog) { throw new UnsupportedOperationException(); if (mDismissListener != null) { mDismissListener.onDismiss(); } } /** Loading core/java/android/server/search/SearchDialogWrapper.javadeleted 100644 → 0 +0 −426 Original line number 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 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() + ")"); } } Loading
core/java/android/app/Activity.java +2 −11 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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 Loading
core/java/android/app/ISearchManager.aidl +0 −19 Original line number Diff line number Diff line Loading @@ -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(); }
core/java/android/app/SearchDialog.java +10 −8 Original line number Diff line number Diff line Loading @@ -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 */ Loading Loading @@ -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; Loading Loading @@ -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 Loading @@ -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; } /** Loading @@ -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 Loading Loading @@ -292,7 +293,9 @@ 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 Loading Loading @@ -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) { Loading
core/java/android/app/SearchManager.java +24 −68 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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"); mSearchDialog.show(initialQuery, selectInitialQuery, launchActivity, appSearchData, globalSearch); } 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); 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) { Loading Loading @@ -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"); Loading @@ -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(); } /** Loading @@ -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(); } } Loading @@ -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(); } /** Loading Loading @@ -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(); } } /** Loading @@ -2021,7 +1975,9 @@ public class SearchManager */ @Deprecated public void onDismiss(DialogInterface dialog) { throw new UnsupportedOperationException(); if (mDismissListener != null) { mDismissListener.onDismiss(); } } /** Loading
core/java/android/server/search/SearchDialogWrapper.javadeleted 100644 → 0 +0 −426 Original line number 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 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() + ")"); } }