1875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen/*
2875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen * Copyright (C) 2009 The Android Open Source Project
3875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen *
4875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen * Licensed under the Apache License, Version 2.0 (the "License");
5875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen * you may not use this file except in compliance with the License.
6875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen * You may obtain a copy of the License at
7875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen *
8875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen *      http://www.apache.org/licenses/LICENSE-2.0
9875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen *
10875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen * Unless required by applicable law or agreed to in writing, software
11875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen * distributed under the License is distributed on an "AS IS" BASIS,
12875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen * See the License for the specific language governing permissions and
14875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen * limitations under the License.
15875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen */
16875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen
17875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaenpackage android.server.search;
18875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen
1974708bbdf8d6f172b08343bdc578a20aa4b39148Bjorn Bringertimport android.app.SearchManager;
202126aac7f992b57fc52141a8bd09fa7a45ac2509Bjorn Bringertimport android.app.SearchableInfo;
21875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaenimport android.content.ComponentName;
22875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaenimport android.content.Context;
23875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaenimport android.content.Intent;
24875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaenimport android.content.pm.ActivityInfo;
25ee69ff4eaee9342843d5f25338288865dda2d36aNarayan Kamathimport android.content.pm.ApplicationInfo;
26875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaenimport android.content.pm.PackageManager;
27875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaenimport android.content.pm.ResolveInfo;
28875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaenimport android.os.Bundle;
29ee69ff4eaee9342843d5f25338288865dda2d36aNarayan Kamathimport android.provider.Settings;
30ee69ff4eaee9342843d5f25338288865dda2d36aNarayan Kamathimport android.text.TextUtils;
31cbd8a246f86704fb348247245904a9f114f11280Satish Sampathimport android.util.Log;
32875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen
33875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaenimport java.util.ArrayList;
34ee69ff4eaee9342843d5f25338288865dda2d36aNarayan Kamathimport java.util.Collections;
35ee69ff4eaee9342843d5f25338288865dda2d36aNarayan Kamathimport java.util.Comparator;
36875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaenimport java.util.HashMap;
37875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaenimport java.util.List;
38875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen
39875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen/**
40f9acde27486bcc6eea1092073f7b47c31749efd6Satish Sampath * This class maintains the information about all searchable activities.
41875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen */
42875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaenpublic class Searchables {
43875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen
44cbd8a246f86704fb348247245904a9f114f11280Satish Sampath    private static final String LOG_TAG = "Searchables";
45cbd8a246f86704fb348247245904a9f114f11280Satish Sampath
46875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen    // static strings used for XML lookups, etc.
47f9acde27486bcc6eea1092073f7b47c31749efd6Satish Sampath    // TODO how should these be documented for the developer, in a more structured way than
48875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen    // the current long wordy javadoc in SearchManager.java ?
49875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen    private static final String MD_LABEL_DEFAULT_SEARCHABLE = "android.app.default_searchable";
50875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen    private static final String MD_SEARCHABLE_SYSTEM_SEARCH = "*";
51f9acde27486bcc6eea1092073f7b47c31749efd6Satish Sampath
52875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen    private Context mContext;
53f9acde27486bcc6eea1092073f7b47c31749efd6Satish Sampath
54875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen    private HashMap<ComponentName, SearchableInfo> mSearchablesMap = null;
55875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen    private ArrayList<SearchableInfo> mSearchablesList = null;
566d72e029cb6e5a9cf26aa3314c3dca83614fc91bBjorn Bringert    private ArrayList<SearchableInfo> mSearchablesInGlobalSearchList = null;
57ee69ff4eaee9342843d5f25338288865dda2d36aNarayan Kamath    // Contains all installed activities that handle the global search
58ee69ff4eaee9342843d5f25338288865dda2d36aNarayan Kamath    // intent.
59ee69ff4eaee9342843d5f25338288865dda2d36aNarayan Kamath    private List<ResolveInfo> mGlobalSearchActivities;
60ee69ff4eaee9342843d5f25338288865dda2d36aNarayan Kamath    private ComponentName mCurrentGlobalSearchActivity = null;
616cf7a325e6e9e70d9858e21fbb438341332ed254Bjorn Bringert    private ComponentName mWebSearchActivity = null;
62f9acde27486bcc6eea1092073f7b47c31749efd6Satish Sampath
6341282a35568b51270440450c46bb31aa00e52caaSatish Sampath    public static String GOOGLE_SEARCH_COMPONENT_NAME =
6441282a35568b51270440450c46bb31aa00e52caaSatish Sampath            "com.android.googlesearch/.GoogleSearch";
6541282a35568b51270440450c46bb31aa00e52caaSatish Sampath    public static String ENHANCED_GOOGLE_SEARCH_COMPONENT_NAME =
6641282a35568b51270440450c46bb31aa00e52caaSatish Sampath            "com.google.android.providers.enhancedgooglesearch/.Launcher";
6741282a35568b51270440450c46bb31aa00e52caaSatish Sampath
68875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen    /**
69f9acde27486bcc6eea1092073f7b47c31749efd6Satish Sampath     *
70875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen     * @param context Context to use for looking up activities etc.
71875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen     */
72875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen    public Searchables (Context context) {
73875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen        mContext = context;
74875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen    }
75f9acde27486bcc6eea1092073f7b47c31749efd6Satish Sampath
76875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen    /**
77875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen     * Look up, or construct, based on the activity.
78f9acde27486bcc6eea1092073f7b47c31749efd6Satish Sampath     *
79f9acde27486bcc6eea1092073f7b47c31749efd6Satish Sampath     * The activities fall into three cases, based on meta-data found in
80875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen     * the manifest entry:
81875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen     * <ol>
82875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen     * <li>The activity itself implements search.  This is indicated by the
83875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen     * presence of a "android.app.searchable" meta-data attribute.
84875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen     * The value is a reference to an XML file containing search information.</li>
85875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen     * <li>A related activity implements search.  This is indicated by the
86875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen     * presence of a "android.app.default_searchable" meta-data attribute.
87875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen     * The value is a string naming the activity implementing search.  In this
88875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen     * case the factory will "redirect" and return the searchable data.</li>
89875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen     * <li>No searchability data is provided.  We return null here and other
90875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen     * code will insert the "default" (e.g. contacts) search.
91f9acde27486bcc6eea1092073f7b47c31749efd6Satish Sampath     *
92875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen     * TODO: cache the result in the map, and check the map first.
93875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen     * TODO: it might make sense to implement the searchable reference as
94875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen     * an application meta-data entry.  This way we don't have to pepper each
95875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen     * and every activity.
96875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen     * TODO: can we skip the constructor step if it's a non-searchable?
97f9acde27486bcc6eea1092073f7b47c31749efd6Satish Sampath     * TODO: does it make sense to plug the default into a slot here for
98875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen     * automatic return?  Probably not, but it's one way to do it.
99875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen     *
100f9acde27486bcc6eea1092073f7b47c31749efd6Satish Sampath     * @param activity The name of the current activity, or null if the
101875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen     * activity does not define any explicit searchable metadata.
102875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen     */
103875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen    public SearchableInfo getSearchableInfo(ComponentName activity) {
104875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen        // Step 1.  Is the result already hashed?  (case 1)
105875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen        SearchableInfo result;
106875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen        synchronized (this) {
107875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen            result = mSearchablesMap.get(activity);
108875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen            if (result != null) return result;
109875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen        }
110f9acde27486bcc6eea1092073f7b47c31749efd6Satish Sampath
111875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen        // Step 2.  See if the current activity references a searchable.
112875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen        // Note:  Conceptually, this could be a while(true) loop, but there's
113f9acde27486bcc6eea1092073f7b47c31749efd6Satish Sampath        // no point in implementing reference chaining here and risking a loop.
114875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen        // References must point directly to searchable activities.
115f9acde27486bcc6eea1092073f7b47c31749efd6Satish Sampath
116875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen        ActivityInfo ai = null;
117875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen        try {
118875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen            ai = mContext.getPackageManager().
119875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen                       getActivityInfo(activity, PackageManager.GET_META_DATA );
120875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen            String refActivityName = null;
121f9acde27486bcc6eea1092073f7b47c31749efd6Satish Sampath
122875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen            // First look for activity-specific reference
123875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen            Bundle md = ai.metaData;
124875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen            if (md != null) {
125875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen                refActivityName = md.getString(MD_LABEL_DEFAULT_SEARCHABLE);
126875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen            }
127875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen            // If not found, try for app-wide reference
128875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen            if (refActivityName == null) {
129875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen                md = ai.applicationInfo.metaData;
130875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen                if (md != null) {
131875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen                    refActivityName = md.getString(MD_LABEL_DEFAULT_SEARCHABLE);
132875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen                }
133875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen            }
134f9acde27486bcc6eea1092073f7b47c31749efd6Satish Sampath
135875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen            // Irrespective of source, if a reference was found, follow it.
136875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen            if (refActivityName != null)
137875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen            {
1386cf7a325e6e9e70d9858e21fbb438341332ed254Bjorn Bringert                // This value is deprecated, return null
139875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen                if (refActivityName.equals(MD_SEARCHABLE_SYSTEM_SEARCH)) {
1406cf7a325e6e9e70d9858e21fbb438341332ed254Bjorn Bringert                    return null;
141875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen                }
142875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen                String pkg = activity.getPackageName();
143875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen                ComponentName referredActivity;
144875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen                if (refActivityName.charAt(0) == '.') {
145875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen                    referredActivity = new ComponentName(pkg, pkg + refActivityName);
146875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen                } else {
147875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen                    referredActivity = new ComponentName(pkg, refActivityName);
148875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen                }
149875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen
150875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen                // Now try the referred activity, and if found, cache
151875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen                // it against the original name so we can skip the check
152875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen                synchronized (this) {
153875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen                    result = mSearchablesMap.get(referredActivity);
154875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen                    if (result != null) {
155875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen                        mSearchablesMap.put(activity, result);
156875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen                        return result;
157875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen                    }
158875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen                }
159875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen            }
160875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen        } catch (PackageManager.NameNotFoundException e) {
161875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen            // case 3: no metadata
162875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen        }
163f9acde27486bcc6eea1092073f7b47c31749efd6Satish Sampath
164875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen        // Step 3.  None found. Return null.
165875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen        return null;
166f9acde27486bcc6eea1092073f7b47c31749efd6Satish Sampath
167875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen    }
168f9acde27486bcc6eea1092073f7b47c31749efd6Satish Sampath
169875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen    /**
170f9acde27486bcc6eea1092073f7b47c31749efd6Satish Sampath     * Builds an entire list (suitable for display) of
171f9acde27486bcc6eea1092073f7b47c31749efd6Satish Sampath     * activities that are searchable, by iterating the entire set of
172f9acde27486bcc6eea1092073f7b47c31749efd6Satish Sampath     * ACTION_SEARCH & ACTION_WEB_SEARCH intents.
173f9acde27486bcc6eea1092073f7b47c31749efd6Satish Sampath     *
174875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen     * Also clears the hash of all activities -> searches which will
175875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen     * refill as the user clicks "search".
176f9acde27486bcc6eea1092073f7b47c31749efd6Satish Sampath     *
177875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen     * This should only be done at startup and again if we know that the
178875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen     * list has changed.
179f9acde27486bcc6eea1092073f7b47c31749efd6Satish Sampath     *
180875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen     * TODO: every activity that provides a ACTION_SEARCH intent should
181875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen     * also provide searchability meta-data.  There are a bunch of checks here
182875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen     * that, if data is not found, silently skip to the next activity.  This
183875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen     * won't help a developer trying to figure out why their activity isn't
184875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen     * showing up in the list, but an exception here is too rough.  I would
185875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen     * like to find a better notification mechanism.
186f9acde27486bcc6eea1092073f7b47c31749efd6Satish Sampath     *
187875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen     * TODO: sort the list somehow?  UI choice.
188875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen     */
189875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen    public void buildSearchableList() {
19074708bbdf8d6f172b08343bdc578a20aa4b39148Bjorn Bringert        // These will become the new values at the end of the method
191f9acde27486bcc6eea1092073f7b47c31749efd6Satish Sampath        HashMap<ComponentName, SearchableInfo> newSearchablesMap
192875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen                                = new HashMap<ComponentName, SearchableInfo>();
193875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen        ArrayList<SearchableInfo> newSearchablesList
194875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen                                = new ArrayList<SearchableInfo>();
1956d72e029cb6e5a9cf26aa3314c3dca83614fc91bBjorn Bringert        ArrayList<SearchableInfo> newSearchablesInGlobalSearchList
1966d72e029cb6e5a9cf26aa3314c3dca83614fc91bBjorn Bringert                                = new ArrayList<SearchableInfo>();
197875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen
198875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen        final PackageManager pm = mContext.getPackageManager();
199f9acde27486bcc6eea1092073f7b47c31749efd6Satish Sampath
200f9acde27486bcc6eea1092073f7b47c31749efd6Satish Sampath        // Use intent resolver to generate list of ACTION_SEARCH & ACTION_WEB_SEARCH receivers.
201f9acde27486bcc6eea1092073f7b47c31749efd6Satish Sampath        List<ResolveInfo> searchList;
202875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen        final Intent intent = new Intent(Intent.ACTION_SEARCH);
203f9acde27486bcc6eea1092073f7b47c31749efd6Satish Sampath        searchList = pm.queryIntentActivities(intent, PackageManager.GET_META_DATA);
204f9acde27486bcc6eea1092073f7b47c31749efd6Satish Sampath
205f9acde27486bcc6eea1092073f7b47c31749efd6Satish Sampath        List<ResolveInfo> webSearchInfoList;
206f9acde27486bcc6eea1092073f7b47c31749efd6Satish Sampath        final Intent webSearchIntent = new Intent(Intent.ACTION_WEB_SEARCH);
207f9acde27486bcc6eea1092073f7b47c31749efd6Satish Sampath        webSearchInfoList = pm.queryIntentActivities(webSearchIntent, PackageManager.GET_META_DATA);
208f9acde27486bcc6eea1092073f7b47c31749efd6Satish Sampath
209875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen        // analyze each one, generate a Searchables record, and record
210f9acde27486bcc6eea1092073f7b47c31749efd6Satish Sampath        if (searchList != null || webSearchInfoList != null) {
211f9acde27486bcc6eea1092073f7b47c31749efd6Satish Sampath            int search_count = (searchList == null ? 0 : searchList.size());
212f9acde27486bcc6eea1092073f7b47c31749efd6Satish Sampath            int web_search_count = (webSearchInfoList == null ? 0 : webSearchInfoList.size());
213f9acde27486bcc6eea1092073f7b47c31749efd6Satish Sampath            int count = search_count + web_search_count;
214875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen            for (int ii = 0; ii < count; ii++) {
215875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen                // for each component, try to find metadata
216f9acde27486bcc6eea1092073f7b47c31749efd6Satish Sampath                ResolveInfo info = (ii < search_count)
217f9acde27486bcc6eea1092073f7b47c31749efd6Satish Sampath                        ? searchList.get(ii)
218f9acde27486bcc6eea1092073f7b47c31749efd6Satish Sampath                        : webSearchInfoList.get(ii - search_count);
219875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen                ActivityInfo ai = info.activityInfo;
220f9acde27486bcc6eea1092073f7b47c31749efd6Satish Sampath                // Check first to avoid duplicate entries.
221590f63433ce786722d263c7e913a88d3101e5cbcKarl Rosaen                if (newSearchablesMap.get(new ComponentName(ai.packageName, ai.name)) == null) {
222590f63433ce786722d263c7e913a88d3101e5cbcKarl Rosaen                    SearchableInfo searchable = SearchableInfo.getActivityMetaData(mContext, ai);
223590f63433ce786722d263c7e913a88d3101e5cbcKarl Rosaen                    if (searchable != null) {
224590f63433ce786722d263c7e913a88d3101e5cbcKarl Rosaen                        newSearchablesList.add(searchable);
225590f63433ce786722d263c7e913a88d3101e5cbcKarl Rosaen                        newSearchablesMap.put(searchable.getSearchActivity(), searchable);
226590f63433ce786722d263c7e913a88d3101e5cbcKarl Rosaen                        if (searchable.shouldIncludeInGlobalSearch()) {
227590f63433ce786722d263c7e913a88d3101e5cbcKarl Rosaen                            newSearchablesInGlobalSearchList.add(searchable);
228590f63433ce786722d263c7e913a88d3101e5cbcKarl Rosaen                        }
2296d72e029cb6e5a9cf26aa3314c3dca83614fc91bBjorn Bringert                    }
230875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen                }
231875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen            }
232875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen        }
233f9acde27486bcc6eea1092073f7b47c31749efd6Satish Sampath
234ee69ff4eaee9342843d5f25338288865dda2d36aNarayan Kamath        List<ResolveInfo> newGlobalSearchActivities = findGlobalSearchActivities();
235ee69ff4eaee9342843d5f25338288865dda2d36aNarayan Kamath
2366cf7a325e6e9e70d9858e21fbb438341332ed254Bjorn Bringert        // Find the global search activity
237ee69ff4eaee9342843d5f25338288865dda2d36aNarayan Kamath        ComponentName newGlobalSearchActivity = findGlobalSearchActivity(
238ee69ff4eaee9342843d5f25338288865dda2d36aNarayan Kamath                newGlobalSearchActivities);
239cbd8a246f86704fb348247245904a9f114f11280Satish Sampath
2406cf7a325e6e9e70d9858e21fbb438341332ed254Bjorn Bringert        // Find the web search activity
2416cf7a325e6e9e70d9858e21fbb438341332ed254Bjorn Bringert        ComponentName newWebSearchActivity = findWebSearchActivity(newGlobalSearchActivity);
242f9acde27486bcc6eea1092073f7b47c31749efd6Satish Sampath
24374708bbdf8d6f172b08343bdc578a20aa4b39148Bjorn Bringert        // Store a consistent set of new values
244875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen        synchronized (this) {
245875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen            mSearchablesMap = newSearchablesMap;
2466d72e029cb6e5a9cf26aa3314c3dca83614fc91bBjorn Bringert            mSearchablesList = newSearchablesList;
2476d72e029cb6e5a9cf26aa3314c3dca83614fc91bBjorn Bringert            mSearchablesInGlobalSearchList = newSearchablesInGlobalSearchList;
248ee69ff4eaee9342843d5f25338288865dda2d36aNarayan Kamath            mGlobalSearchActivities = newGlobalSearchActivities;
249ee69ff4eaee9342843d5f25338288865dda2d36aNarayan Kamath            mCurrentGlobalSearchActivity = newGlobalSearchActivity;
2506cf7a325e6e9e70d9858e21fbb438341332ed254Bjorn Bringert            mWebSearchActivity = newWebSearchActivity;
251875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen        }
252875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen    }
253ee69ff4eaee9342843d5f25338288865dda2d36aNarayan Kamath    /**
254ee69ff4eaee9342843d5f25338288865dda2d36aNarayan Kamath     * Returns a sorted list of installed search providers as per
255ee69ff4eaee9342843d5f25338288865dda2d36aNarayan Kamath     * the following heuristics:
256ee69ff4eaee9342843d5f25338288865dda2d36aNarayan Kamath     *
257ee69ff4eaee9342843d5f25338288865dda2d36aNarayan Kamath     * (a) System apps are given priority over non system apps.
258ee69ff4eaee9342843d5f25338288865dda2d36aNarayan Kamath     * (b) Among system apps and non system apps, the relative ordering
259ee69ff4eaee9342843d5f25338288865dda2d36aNarayan Kamath     * is defined by their declared priority.
260ee69ff4eaee9342843d5f25338288865dda2d36aNarayan Kamath     */
261ee69ff4eaee9342843d5f25338288865dda2d36aNarayan Kamath    private List<ResolveInfo> findGlobalSearchActivities() {
262ee69ff4eaee9342843d5f25338288865dda2d36aNarayan Kamath        // Step 1 : Query the package manager for a list
263ee69ff4eaee9342843d5f25338288865dda2d36aNarayan Kamath        // of activities that can handle the GLOBAL_SEARCH intent.
264ee69ff4eaee9342843d5f25338288865dda2d36aNarayan Kamath        Intent intent = new Intent(SearchManager.INTENT_ACTION_GLOBAL_SEARCH);
265ee69ff4eaee9342843d5f25338288865dda2d36aNarayan Kamath        PackageManager pm = mContext.getPackageManager();
266ee69ff4eaee9342843d5f25338288865dda2d36aNarayan Kamath        List<ResolveInfo> activities =
267ee69ff4eaee9342843d5f25338288865dda2d36aNarayan Kamath                pm.queryIntentActivities(intent, PackageManager.MATCH_DEFAULT_ONLY);
268ee69ff4eaee9342843d5f25338288865dda2d36aNarayan Kamath
269ee69ff4eaee9342843d5f25338288865dda2d36aNarayan Kamath        if (activities != null && !activities.isEmpty()) {
270ee69ff4eaee9342843d5f25338288865dda2d36aNarayan Kamath            // Step 2: Rank matching activities according to our heuristics.
271ee69ff4eaee9342843d5f25338288865dda2d36aNarayan Kamath            Collections.sort(activities, GLOBAL_SEARCH_RANKER);
272ee69ff4eaee9342843d5f25338288865dda2d36aNarayan Kamath        }
273ee69ff4eaee9342843d5f25338288865dda2d36aNarayan Kamath
274ee69ff4eaee9342843d5f25338288865dda2d36aNarayan Kamath        return activities;
275ee69ff4eaee9342843d5f25338288865dda2d36aNarayan Kamath    }
276f9acde27486bcc6eea1092073f7b47c31749efd6Satish Sampath
277f9acde27486bcc6eea1092073f7b47c31749efd6Satish Sampath    /**
2786cf7a325e6e9e70d9858e21fbb438341332ed254Bjorn Bringert     * Finds the global search activity.
279f9acde27486bcc6eea1092073f7b47c31749efd6Satish Sampath     */
280ee69ff4eaee9342843d5f25338288865dda2d36aNarayan Kamath    private ComponentName findGlobalSearchActivity(List<ResolveInfo> installed) {
281ee69ff4eaee9342843d5f25338288865dda2d36aNarayan Kamath        // Fetch the global search provider from the system settings,
282ee69ff4eaee9342843d5f25338288865dda2d36aNarayan Kamath        // and if it's still installed, return it.
283ee69ff4eaee9342843d5f25338288865dda2d36aNarayan Kamath        final String searchProviderSetting = getGlobalSearchProviderSetting();
284ee69ff4eaee9342843d5f25338288865dda2d36aNarayan Kamath        if (!TextUtils.isEmpty(searchProviderSetting)) {
285ee69ff4eaee9342843d5f25338288865dda2d36aNarayan Kamath            final ComponentName globalSearchComponent = ComponentName.unflattenFromString(
286ee69ff4eaee9342843d5f25338288865dda2d36aNarayan Kamath                    searchProviderSetting);
287ee69ff4eaee9342843d5f25338288865dda2d36aNarayan Kamath            if (globalSearchComponent != null && isInstalled(globalSearchComponent)) {
288ee69ff4eaee9342843d5f25338288865dda2d36aNarayan Kamath                return globalSearchComponent;
289ee69ff4eaee9342843d5f25338288865dda2d36aNarayan Kamath            }
290ee69ff4eaee9342843d5f25338288865dda2d36aNarayan Kamath        }
291ee69ff4eaee9342843d5f25338288865dda2d36aNarayan Kamath
292ee69ff4eaee9342843d5f25338288865dda2d36aNarayan Kamath        return getDefaultGlobalSearchProvider(installed);
293ee69ff4eaee9342843d5f25338288865dda2d36aNarayan Kamath    }
294ee69ff4eaee9342843d5f25338288865dda2d36aNarayan Kamath
295ee69ff4eaee9342843d5f25338288865dda2d36aNarayan Kamath    /**
296ee69ff4eaee9342843d5f25338288865dda2d36aNarayan Kamath     * Checks whether the global search provider with a given
297ee69ff4eaee9342843d5f25338288865dda2d36aNarayan Kamath     * component name is installed on the system or not. This deals with
298ee69ff4eaee9342843d5f25338288865dda2d36aNarayan Kamath     * cases such as the removal of an installed provider.
299ee69ff4eaee9342843d5f25338288865dda2d36aNarayan Kamath     */
300ee69ff4eaee9342843d5f25338288865dda2d36aNarayan Kamath    private boolean isInstalled(ComponentName globalSearch) {
3016cf7a325e6e9e70d9858e21fbb438341332ed254Bjorn Bringert        Intent intent = new Intent(SearchManager.INTENT_ACTION_GLOBAL_SEARCH);
302ee69ff4eaee9342843d5f25338288865dda2d36aNarayan Kamath        intent.setComponent(globalSearch);
303ee69ff4eaee9342843d5f25338288865dda2d36aNarayan Kamath
3046cf7a325e6e9e70d9858e21fbb438341332ed254Bjorn Bringert        PackageManager pm = mContext.getPackageManager();
3056cf7a325e6e9e70d9858e21fbb438341332ed254Bjorn Bringert        List<ResolveInfo> activities =
3066cf7a325e6e9e70d9858e21fbb438341332ed254Bjorn Bringert                pm.queryIntentActivities(intent, PackageManager.MATCH_DEFAULT_ONLY);
307ee69ff4eaee9342843d5f25338288865dda2d36aNarayan Kamath
308ee69ff4eaee9342843d5f25338288865dda2d36aNarayan Kamath        if (activities != null && !activities.isEmpty()) {
309ee69ff4eaee9342843d5f25338288865dda2d36aNarayan Kamath            return true;
310ee69ff4eaee9342843d5f25338288865dda2d36aNarayan Kamath        }
311ee69ff4eaee9342843d5f25338288865dda2d36aNarayan Kamath
312ee69ff4eaee9342843d5f25338288865dda2d36aNarayan Kamath        return false;
313ee69ff4eaee9342843d5f25338288865dda2d36aNarayan Kamath    }
314ee69ff4eaee9342843d5f25338288865dda2d36aNarayan Kamath
315ee69ff4eaee9342843d5f25338288865dda2d36aNarayan Kamath    private static final Comparator<ResolveInfo> GLOBAL_SEARCH_RANKER =
316ee69ff4eaee9342843d5f25338288865dda2d36aNarayan Kamath            new Comparator<ResolveInfo>() {
317ee69ff4eaee9342843d5f25338288865dda2d36aNarayan Kamath        @Override
318ee69ff4eaee9342843d5f25338288865dda2d36aNarayan Kamath        public int compare(ResolveInfo lhs, ResolveInfo rhs) {
319ee69ff4eaee9342843d5f25338288865dda2d36aNarayan Kamath            if (lhs == rhs) {
320ee69ff4eaee9342843d5f25338288865dda2d36aNarayan Kamath                return 0;
321ee69ff4eaee9342843d5f25338288865dda2d36aNarayan Kamath            }
322ee69ff4eaee9342843d5f25338288865dda2d36aNarayan Kamath            boolean lhsSystem = isSystemApp(lhs);
323ee69ff4eaee9342843d5f25338288865dda2d36aNarayan Kamath            boolean rhsSystem = isSystemApp(rhs);
324ee69ff4eaee9342843d5f25338288865dda2d36aNarayan Kamath
325ee69ff4eaee9342843d5f25338288865dda2d36aNarayan Kamath            if (lhsSystem && !rhsSystem) {
326ee69ff4eaee9342843d5f25338288865dda2d36aNarayan Kamath                return -1;
327ee69ff4eaee9342843d5f25338288865dda2d36aNarayan Kamath            } else if (rhsSystem && !lhsSystem) {
328ee69ff4eaee9342843d5f25338288865dda2d36aNarayan Kamath                return 1;
3296cf7a325e6e9e70d9858e21fbb438341332ed254Bjorn Bringert            } else {
330ee69ff4eaee9342843d5f25338288865dda2d36aNarayan Kamath                // Either both system engines, or both non system
331ee69ff4eaee9342843d5f25338288865dda2d36aNarayan Kamath                // engines.
332ee69ff4eaee9342843d5f25338288865dda2d36aNarayan Kamath                //
333ee69ff4eaee9342843d5f25338288865dda2d36aNarayan Kamath                // Note, this isn't a typo. Higher priority numbers imply
334ee69ff4eaee9342843d5f25338288865dda2d36aNarayan Kamath                // higher priority, but are "lower" in the sort order.
335ee69ff4eaee9342843d5f25338288865dda2d36aNarayan Kamath                return rhs.priority - lhs.priority;
3366cf7a325e6e9e70d9858e21fbb438341332ed254Bjorn Bringert            }
337f9acde27486bcc6eea1092073f7b47c31749efd6Satish Sampath        }
338ee69ff4eaee9342843d5f25338288865dda2d36aNarayan Kamath    };
339ee69ff4eaee9342843d5f25338288865dda2d36aNarayan Kamath
340ee69ff4eaee9342843d5f25338288865dda2d36aNarayan Kamath    /**
341ee69ff4eaee9342843d5f25338288865dda2d36aNarayan Kamath     * @return true iff. the resolve info corresponds to a system application.
342ee69ff4eaee9342843d5f25338288865dda2d36aNarayan Kamath     */
343ee69ff4eaee9342843d5f25338288865dda2d36aNarayan Kamath    private static final boolean isSystemApp(ResolveInfo res) {
344ee69ff4eaee9342843d5f25338288865dda2d36aNarayan Kamath        return (res.activityInfo.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0;
345ee69ff4eaee9342843d5f25338288865dda2d36aNarayan Kamath    }
346ee69ff4eaee9342843d5f25338288865dda2d36aNarayan Kamath
347ee69ff4eaee9342843d5f25338288865dda2d36aNarayan Kamath    /**
348ee69ff4eaee9342843d5f25338288865dda2d36aNarayan Kamath     * Returns the highest ranked search provider as per the
349ee69ff4eaee9342843d5f25338288865dda2d36aNarayan Kamath     * ranking defined in {@link #getGlobalSearchActivities()}.
350ee69ff4eaee9342843d5f25338288865dda2d36aNarayan Kamath     */
351ee69ff4eaee9342843d5f25338288865dda2d36aNarayan Kamath    private ComponentName getDefaultGlobalSearchProvider(List<ResolveInfo> providerList) {
352ee69ff4eaee9342843d5f25338288865dda2d36aNarayan Kamath        if (providerList != null && !providerList.isEmpty()) {
353ee69ff4eaee9342843d5f25338288865dda2d36aNarayan Kamath            ActivityInfo ai = providerList.get(0).activityInfo;
354ee69ff4eaee9342843d5f25338288865dda2d36aNarayan Kamath            return new ComponentName(ai.packageName, ai.name);
355ee69ff4eaee9342843d5f25338288865dda2d36aNarayan Kamath        }
356ee69ff4eaee9342843d5f25338288865dda2d36aNarayan Kamath
3576cf7a325e6e9e70d9858e21fbb438341332ed254Bjorn Bringert        Log.w(LOG_TAG, "No global search activity found");
3586cf7a325e6e9e70d9858e21fbb438341332ed254Bjorn Bringert        return null;
359f9acde27486bcc6eea1092073f7b47c31749efd6Satish Sampath    }
360f9acde27486bcc6eea1092073f7b47c31749efd6Satish Sampath
361ee69ff4eaee9342843d5f25338288865dda2d36aNarayan Kamath    private String getGlobalSearchProviderSetting() {
362ee69ff4eaee9342843d5f25338288865dda2d36aNarayan Kamath        return Settings.Secure.getString(mContext.getContentResolver(),
363ee69ff4eaee9342843d5f25338288865dda2d36aNarayan Kamath                Settings.Secure.SEARCH_GLOBAL_SEARCH_ACTIVITY);
364ee69ff4eaee9342843d5f25338288865dda2d36aNarayan Kamath    }
365ee69ff4eaee9342843d5f25338288865dda2d36aNarayan Kamath
3666cf7a325e6e9e70d9858e21fbb438341332ed254Bjorn Bringert    /**
3676cf7a325e6e9e70d9858e21fbb438341332ed254Bjorn Bringert     * Finds the web search activity.
3686cf7a325e6e9e70d9858e21fbb438341332ed254Bjorn Bringert     *
3696cf7a325e6e9e70d9858e21fbb438341332ed254Bjorn Bringert     * Only looks in the package of the global search activity.
3706cf7a325e6e9e70d9858e21fbb438341332ed254Bjorn Bringert     */
3716cf7a325e6e9e70d9858e21fbb438341332ed254Bjorn Bringert    private ComponentName findWebSearchActivity(ComponentName globalSearchActivity) {
3726cf7a325e6e9e70d9858e21fbb438341332ed254Bjorn Bringert        if (globalSearchActivity == null) {
3736cf7a325e6e9e70d9858e21fbb438341332ed254Bjorn Bringert            return null;
3746cf7a325e6e9e70d9858e21fbb438341332ed254Bjorn Bringert        }
375f9acde27486bcc6eea1092073f7b47c31749efd6Satish Sampath        Intent intent = new Intent(Intent.ACTION_WEB_SEARCH);
3766cf7a325e6e9e70d9858e21fbb438341332ed254Bjorn Bringert        intent.setPackage(globalSearchActivity.getPackageName());
3776cf7a325e6e9e70d9858e21fbb438341332ed254Bjorn Bringert        PackageManager pm = mContext.getPackageManager();
3786cf7a325e6e9e70d9858e21fbb438341332ed254Bjorn Bringert        List<ResolveInfo> activities =
3796cf7a325e6e9e70d9858e21fbb438341332ed254Bjorn Bringert                pm.queryIntentActivities(intent, PackageManager.MATCH_DEFAULT_ONLY);
380ee69ff4eaee9342843d5f25338288865dda2d36aNarayan Kamath
381ee69ff4eaee9342843d5f25338288865dda2d36aNarayan Kamath        if (activities != null && !activities.isEmpty()) {
382ee69ff4eaee9342843d5f25338288865dda2d36aNarayan Kamath            ActivityInfo ai = activities.get(0).activityInfo;
3836cf7a325e6e9e70d9858e21fbb438341332ed254Bjorn Bringert            // TODO: do some sanity checks here?
3846cf7a325e6e9e70d9858e21fbb438341332ed254Bjorn Bringert            return new ComponentName(ai.packageName, ai.name);
385f9acde27486bcc6eea1092073f7b47c31749efd6Satish Sampath        }
3866cf7a325e6e9e70d9858e21fbb438341332ed254Bjorn Bringert        Log.w(LOG_TAG, "No web search activity found");
3876cf7a325e6e9e70d9858e21fbb438341332ed254Bjorn Bringert        return null;
388f9acde27486bcc6eea1092073f7b47c31749efd6Satish Sampath    }
389f9acde27486bcc6eea1092073f7b47c31749efd6Satish Sampath
390875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen    /**
391875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen     * Returns the list of searchable activities.
392875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen     */
393875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen    public synchronized ArrayList<SearchableInfo> getSearchablesList() {
394875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen        ArrayList<SearchableInfo> result = new ArrayList<SearchableInfo>(mSearchablesList);
395875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen        return result;
396875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen    }
397f9acde27486bcc6eea1092073f7b47c31749efd6Satish Sampath
3986d72e029cb6e5a9cf26aa3314c3dca83614fc91bBjorn Bringert    /**
3996d72e029cb6e5a9cf26aa3314c3dca83614fc91bBjorn Bringert     * Returns a list of the searchable activities that can be included in global search.
4006d72e029cb6e5a9cf26aa3314c3dca83614fc91bBjorn Bringert     */
4016d72e029cb6e5a9cf26aa3314c3dca83614fc91bBjorn Bringert    public synchronized ArrayList<SearchableInfo> getSearchablesInGlobalSearchList() {
4026d72e029cb6e5a9cf26aa3314c3dca83614fc91bBjorn Bringert        return new ArrayList<SearchableInfo>(mSearchablesInGlobalSearchList);
4036d72e029cb6e5a9cf26aa3314c3dca83614fc91bBjorn Bringert    }
404f9acde27486bcc6eea1092073f7b47c31749efd6Satish Sampath
405f9acde27486bcc6eea1092073f7b47c31749efd6Satish Sampath    /**
406ee69ff4eaee9342843d5f25338288865dda2d36aNarayan Kamath     * Returns a list of activities that handle the global search intent.
407ee69ff4eaee9342843d5f25338288865dda2d36aNarayan Kamath     */
408ee69ff4eaee9342843d5f25338288865dda2d36aNarayan Kamath    public synchronized ArrayList<ResolveInfo> getGlobalSearchActivities() {
409ee69ff4eaee9342843d5f25338288865dda2d36aNarayan Kamath        return new ArrayList<ResolveInfo>(mGlobalSearchActivities);
410ee69ff4eaee9342843d5f25338288865dda2d36aNarayan Kamath    }
411ee69ff4eaee9342843d5f25338288865dda2d36aNarayan Kamath
412ee69ff4eaee9342843d5f25338288865dda2d36aNarayan Kamath    /**
4136cf7a325e6e9e70d9858e21fbb438341332ed254Bjorn Bringert     * Gets the name of the global search activity.
414f9acde27486bcc6eea1092073f7b47c31749efd6Satish Sampath     */
4156cf7a325e6e9e70d9858e21fbb438341332ed254Bjorn Bringert    public synchronized ComponentName getGlobalSearchActivity() {
416ee69ff4eaee9342843d5f25338288865dda2d36aNarayan Kamath        return mCurrentGlobalSearchActivity;
417f9acde27486bcc6eea1092073f7b47c31749efd6Satish Sampath    }
418f9acde27486bcc6eea1092073f7b47c31749efd6Satish Sampath
419f9acde27486bcc6eea1092073f7b47c31749efd6Satish Sampath    /**
4206cf7a325e6e9e70d9858e21fbb438341332ed254Bjorn Bringert     * Gets the name of the web search activity.
421f9acde27486bcc6eea1092073f7b47c31749efd6Satish Sampath     */
4226cf7a325e6e9e70d9858e21fbb438341332ed254Bjorn Bringert    public synchronized ComponentName getWebSearchActivity() {
4236cf7a325e6e9e70d9858e21fbb438341332ed254Bjorn Bringert        return mWebSearchActivity;
424f9acde27486bcc6eea1092073f7b47c31749efd6Satish Sampath    }
425875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen}
426