Loading core/java/android/app/Activity.java +2 −35 Original line number Original line Diff line number Diff line Loading @@ -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; Loading @@ -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; Loading Loading @@ -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); } } } /** /** Loading Loading @@ -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); } } } /** /** Loading Loading @@ -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; } } /** /** Loading @@ -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); Loading Loading @@ -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(); } } Loading core/java/android/app/ISearchManager.aidl +0 −4 Original line number Original line Diff line number Diff line Loading @@ -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); } } core/java/android/app/SearchDialog.java +16 −65 Original line number Original line Diff line number Diff line Loading @@ -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; Loading @@ -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; Loading Loading @@ -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; Loading Loading @@ -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); Loading Loading @@ -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. * * Loading @@ -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 Loading Loading @@ -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 Loading @@ -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); Loading @@ -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(); Loading Loading @@ -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() Loading core/java/android/app/SearchManager.java +0 −54 Original line number Original line Diff line number Diff line Loading @@ -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; Loading Loading @@ -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. Loading core/java/android/server/search/SearchDialogWrapper.java 0 → 100644 +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
core/java/android/app/Activity.java +2 −35 Original line number Original line Diff line number Diff line Loading @@ -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; Loading @@ -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; Loading Loading @@ -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); } } } /** /** Loading Loading @@ -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); } } } /** /** Loading Loading @@ -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; } } /** /** Loading @@ -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); Loading Loading @@ -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(); } } Loading
core/java/android/app/ISearchManager.aidl +0 −4 Original line number Original line Diff line number Diff line Loading @@ -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); } }
core/java/android/app/SearchDialog.java +16 −65 Original line number Original line Diff line number Diff line Loading @@ -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; Loading @@ -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; Loading Loading @@ -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; Loading Loading @@ -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); Loading Loading @@ -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. * * Loading @@ -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 Loading Loading @@ -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 Loading @@ -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); Loading @@ -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(); Loading Loading @@ -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() Loading
core/java/android/app/SearchManager.java +0 −54 Original line number Original line Diff line number Diff line Loading @@ -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; Loading Loading @@ -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. Loading
core/java/android/server/search/SearchDialogWrapper.java 0 → 100644 +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() + ")"); } }