/* * 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.ISearchManager; import android.content.BroadcastReceiver; import android.content.ComponentName; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; import android.os.Handler; import android.util.Config; /** * This is a simplified version of the Search Manager service. It no longer handles * presentation (UI). Its function is to maintain the map & list of "searchable" * items, which provides a mapping from individual activities (where a user might have * invoked search) to specific searchable activities (where the search will be dispatched). */ public class SearchManagerService extends ISearchManager.Stub { // general debugging support private static final String TAG = "SearchManagerService"; private static final boolean DEBUG = false; private static final boolean localLOGV = DEBUG ? Config.LOGD : Config.LOGV; // configuration choices private static final boolean IMMEDIATE_SEARCHABLES_UPDATE = true; // class maintenance and general shared data private final Context mContext; private final Handler mHandler; private boolean mSearchablesDirty; /** * Initialize 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; mHandler = new Handler(); // Setup the infrastructure for updating and maintaining the list // of searchable activities. IntentFilter filter = new IntentFilter(); filter.addAction(Intent.ACTION_PACKAGE_ADDED); filter.addAction(Intent.ACTION_PACKAGE_REMOVED); filter.addAction(Intent.ACTION_PACKAGE_CHANGED); filter.addDataScheme("package"); mContext.registerReceiver(mIntentReceiver, filter, null, mHandler); mSearchablesDirty = true; // After startup settles down, preload the searchables list, // which will reduce the delay when the search UI is invoked. if (IMMEDIATE_SEARCHABLES_UPDATE) { mHandler.post(mRunUpdateSearchable); } } /** * Listens for intent broadcasts. * * The primary purpose here is to refresh the "searchables" list * if packages are added/removed. */ private BroadcastReceiver mIntentReceiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { String action = intent.getAction(); // First, test for intents that matter at any time if (action.equals(Intent.ACTION_PACKAGE_ADDED) || action.equals(Intent.ACTION_PACKAGE_REMOVED) || action.equals(Intent.ACTION_PACKAGE_CHANGED)) { mSearchablesDirty = true; if (IMMEDIATE_SEARCHABLES_UPDATE) { mHandler.post(mRunUpdateSearchable); } return; } } }; /** * This runnable (for the main handler / UI thread) will update the searchables list. */ private Runnable mRunUpdateSearchable = new Runnable() { public void run() { if (mSearchablesDirty) { updateSearchables(); } } }; /** * Update the list of searchables, either at startup or in response to * a package add/remove broadcast message. */ private void updateSearchables() { SearchableInfo.buildSearchableList(mContext); mSearchablesDirty = false; // TODO This is a hack. This shouldn't be hardcoded here, it's probably // a policy. // ComponentName defaultSearch = new ComponentName( // "com.android.contacts", // "com.android.contacts.ContactsListActivity" ); ComponentName defaultSearch = new ComponentName( "com.android.googlesearch", "com.android.googlesearch.GoogleSearch" ); SearchableInfo.setDefaultSearchable(mContext, defaultSearch); } /** * Return the searchableinfo for a given activity * * @param launchActivity The activity from which we're launching this search. * @return Returns a SearchableInfo record describing the parameters of the search, * or null if no searchable metadata was available. * @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. */ public SearchableInfo getSearchableInfo(ComponentName launchActivity, boolean globalSearch) { // final check. however we should try to avoid this, because // it slows down the entry into the UI. if (mSearchablesDirty) { updateSearchables(); } SearchableInfo si = null; if (globalSearch) { si = SearchableInfo.getDefaultSearchable(); } else { si = SearchableInfo.getSearchableInfo(mContext, launchActivity); } return si; } }