| /* |
| * 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.ActivityManagerNative; |
| import android.app.IActivityWatcher; |
| import android.app.ISearchManager; |
| import android.app.ISearchManagerCallback; |
| import android.app.SearchManager; |
| import android.content.BroadcastReceiver; |
| import android.content.ComponentName; |
| import android.content.Context; |
| import android.content.Intent; |
| import android.content.IntentFilter; |
| import android.os.Bundle; |
| import android.os.Handler; |
| import android.os.RemoteException; |
| import android.util.Log; |
| |
| import java.util.List; |
| |
| /** |
| * The search manager service handles the search UI, and maintains a registry of searchable |
| * activities. |
| */ |
| public class SearchManagerService extends ISearchManager.Stub { |
| |
| // general debugging support |
| private static final String TAG = "SearchManagerService"; |
| private static final boolean DBG = false; |
| |
| // Context that the service is running in. |
| private final Context mContext; |
| |
| // This field is initialized in ensureSearchablesCreated(), and then never modified. |
| // 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! |
| * |
| * @param context to use for accessing DB, window manager, etc. |
| */ |
| 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() { |
| if (mSearchables != null) return; // already created |
| |
| mSearchables = new Searchables(mContext); |
| mSearchables.buildSearchableList(); |
| |
| IntentFilter packageFilter = new IntentFilter(); |
| packageFilter.addAction(Intent.ACTION_PACKAGE_ADDED); |
| packageFilter.addAction(Intent.ACTION_PACKAGE_REMOVED); |
| packageFilter.addAction(Intent.ACTION_PACKAGE_CHANGED); |
| packageFilter.addDataScheme("package"); |
| 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. |
| */ |
| private BroadcastReceiver mPackageChangedReceiver = new BroadcastReceiver() { |
| @Override |
| public void onReceive(Context context, Intent intent) { |
| String action = intent.getAction(); |
| |
| if (Intent.ACTION_PACKAGE_ADDED.equals(action) || |
| 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(); |
| } |
| } |
| }; |
| |
| 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. |
| */ |
| void broadcastSearchablesChanged() { |
| mContext.sendBroadcast( |
| new Intent(SearchManager.INTENT_ACTION_SEARCHABLES_CHANGED)); |
| } |
| |
| // |
| // Searchable activities API |
| // |
| |
| /** |
| * Returns the SearchableInfo for a given activity. |
| * |
| * @param launchActivity The activity from which we're launching this search. |
| * @param globalSearch If false, this will only launch the search that has been specifically |
| * defined by the application (which is usually defined as a local search). If no default |
| * search is defined in the current application or activity, no search will be launched. |
| * If true, this will always launch a platform-global (e.g. web-based) search instead. |
| * @return Returns a SearchableInfo record describing the parameters of the search, |
| * or null if no searchable metadata was available. |
| */ |
| public SearchableInfo getSearchableInfo(final ComponentName launchActivity, |
| final boolean globalSearch) { |
| if (globalSearch) { |
| return getSearchables().getDefaultSearchable(); |
| } else { |
| if (launchActivity == null) { |
| Log.e(TAG, "getSearchableInfo(), activity == null"); |
| return null; |
| } |
| return getSearchables().getSearchableInfo(launchActivity); |
| } |
| } |
| |
| /** |
| * Returns a list of the searchable activities that can be included in global search. |
| */ |
| public List<SearchableInfo> getSearchablesInGlobalSearch() { |
| return getSearchables().getSearchablesInGlobalSearchList(); |
| } |
| |
| /** |
| * Returns a list of the searchable activities that handle web searches. |
| * Can be called from any thread. |
| */ |
| public List<SearchableInfo> getSearchablesForWebSearch() { |
| return getSearchables().getSearchablesForWebSearchList(); |
| } |
| |
| /** |
| * Returns the default searchable activity for web searches. |
| * Can be called from any thread. |
| */ |
| public SearchableInfo getDefaultSearchableForWebSearch() { |
| return getSearchables().getDefaultSearchableForWebSearch(); |
| } |
| |
| /** |
| * Sets the default searchable activity for web searches. |
| * Can be called from any thread. |
| */ |
| public void setDefaultWebSearch(final ComponentName component) { |
| 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, |
| boolean globalSearch, |
| int ident) { |
| getSearchDialog().startSearch( |
| query, |
| false, |
| launchActivity, |
| appSearchData, |
| globalSearch, |
| 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(); |
| } |
| |
| } |