Searchables.java revision 5bb87cd9b81506b0c25d3f9184e406762a9e9d9c
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
195bb87cd9b81506b0c25d3f9184e406762a9e9d9cAmith Yamasaniimport android.app.AppGlobals;
2074708bbdf8d6f172b08343bdc578a20aa4b39148Bjorn Bringertimport android.app.SearchManager;
212126aac7f992b57fc52141a8bd09fa7a45ac2509Bjorn Bringertimport android.app.SearchableInfo;
22875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaenimport android.content.ComponentName;
23875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaenimport android.content.Context;
24875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaenimport android.content.Intent;
25875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaenimport android.content.pm.ActivityInfo;
26ee69ff4eaee9342843d5f25338288865dda2d36aNarayan Kamathimport android.content.pm.ApplicationInfo;
275bb87cd9b81506b0c25d3f9184e406762a9e9d9cAmith Yamasaniimport android.content.pm.IPackageManager;
28875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaenimport android.content.pm.PackageManager;
29875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaenimport android.content.pm.ResolveInfo;
30875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaenimport android.os.Bundle;
315bb87cd9b81506b0c25d3f9184e406762a9e9d9cAmith Yamasaniimport android.os.RemoteException;
32ee69ff4eaee9342843d5f25338288865dda2d36aNarayan Kamathimport android.provider.Settings;
33ee69ff4eaee9342843d5f25338288865dda2d36aNarayan Kamathimport android.text.TextUtils;
34cbd8a246f86704fb348247245904a9f114f11280Satish Sampathimport android.util.Log;
35875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen
36875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaenimport java.util.ArrayList;
37ee69ff4eaee9342843d5f25338288865dda2d36aNarayan Kamathimport java.util.Collections;
38ee69ff4eaee9342843d5f25338288865dda2d36aNarayan Kamathimport java.util.Comparator;
39875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaenimport java.util.HashMap;
40875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaenimport java.util.List;
41875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen
42875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen/**
43f9acde27486bcc6eea1092073f7b47c31749efd6Satish Sampath * This class maintains the information about all searchable activities.
445bb87cd9b81506b0c25d3f9184e406762a9e9d9cAmith Yamasani * This is a hidden class.
45875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen */
46875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaenpublic class Searchables {
47875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen
48cbd8a246f86704fb348247245904a9f114f11280Satish Sampath    private static final String LOG_TAG = "Searchables";
49cbd8a246f86704fb348247245904a9f114f11280Satish Sampath
50875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen    // static strings used for XML lookups, etc.
51f9acde27486bcc6eea1092073f7b47c31749efd6Satish Sampath    // TODO how should these be documented for the developer, in a more structured way than
52875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen    // the current long wordy javadoc in SearchManager.java ?
53875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen    private static final String MD_LABEL_DEFAULT_SEARCHABLE = "android.app.default_searchable";
54875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen    private static final String MD_SEARCHABLE_SYSTEM_SEARCH = "*";
55f9acde27486bcc6eea1092073f7b47c31749efd6Satish Sampath
56875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen    private Context mContext;
57f9acde27486bcc6eea1092073f7b47c31749efd6Satish Sampath
58875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen    private HashMap<ComponentName, SearchableInfo> mSearchablesMap = null;
59875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen    private ArrayList<SearchableInfo> mSearchablesList = null;
606d72e029cb6e5a9cf26aa3314c3dca83614fc91bBjorn Bringert    private ArrayList<SearchableInfo> mSearchablesInGlobalSearchList = null;
61ee69ff4eaee9342843d5f25338288865dda2d36aNarayan Kamath    // Contains all installed activities that handle the global search
62ee69ff4eaee9342843d5f25338288865dda2d36aNarayan Kamath    // intent.
63ee69ff4eaee9342843d5f25338288865dda2d36aNarayan Kamath    private List<ResolveInfo> mGlobalSearchActivities;
64ee69ff4eaee9342843d5f25338288865dda2d36aNarayan Kamath    private ComponentName mCurrentGlobalSearchActivity = null;
656cf7a325e6e9e70d9858e21fbb438341332ed254Bjorn Bringert    private ComponentName mWebSearchActivity = null;
66f9acde27486bcc6eea1092073f7b47c31749efd6Satish Sampath
6741282a35568b51270440450c46bb31aa00e52caaSatish Sampath    public static String GOOGLE_SEARCH_COMPONENT_NAME =
6841282a35568b51270440450c46bb31aa00e52caaSatish Sampath            "com.android.googlesearch/.GoogleSearch";
6941282a35568b51270440450c46bb31aa00e52caaSatish Sampath    public static String ENHANCED_GOOGLE_SEARCH_COMPONENT_NAME =
7041282a35568b51270440450c46bb31aa00e52caaSatish Sampath            "com.google.android.providers.enhancedgooglesearch/.Launcher";
7141282a35568b51270440450c46bb31aa00e52caaSatish Sampath
725bb87cd9b81506b0c25d3f9184e406762a9e9d9cAmith Yamasani    // Cache the package manager instance
735bb87cd9b81506b0c25d3f9184e406762a9e9d9cAmith Yamasani    private IPackageManager mPm;
745bb87cd9b81506b0c25d3f9184e406762a9e9d9cAmith Yamasani    // User for which this Searchables caches information
755bb87cd9b81506b0c25d3f9184e406762a9e9d9cAmith Yamasani    private int mUserId;
765bb87cd9b81506b0c25d3f9184e406762a9e9d9cAmith Yamasani
77875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen    /**
78f9acde27486bcc6eea1092073f7b47c31749efd6Satish Sampath     *
79875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen     * @param context Context to use for looking up activities etc.
80875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen     */
815bb87cd9b81506b0c25d3f9184e406762a9e9d9cAmith Yamasani    public Searchables (Context context, int userId) {
82875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen        mContext = context;
835bb87cd9b81506b0c25d3f9184e406762a9e9d9cAmith Yamasani        mUserId = userId;
84875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen    }
85f9acde27486bcc6eea1092073f7b47c31749efd6Satish Sampath
86875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen    /**
87875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen     * Look up, or construct, based on the activity.
88f9acde27486bcc6eea1092073f7b47c31749efd6Satish Sampath     *
89f9acde27486bcc6eea1092073f7b47c31749efd6Satish Sampath     * The activities fall into three cases, based on meta-data found in
90875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen     * the manifest entry:
91875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen     * <ol>
92875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen     * <li>The activity itself implements search.  This is indicated by the
93875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen     * presence of a "android.app.searchable" meta-data attribute.
94875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen     * The value is a reference to an XML file containing search information.</li>
95875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen     * <li>A related activity implements search.  This is indicated by the
96875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen     * presence of a "android.app.default_searchable" meta-data attribute.
97875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen     * The value is a string naming the activity implementing search.  In this
98875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen     * case the factory will "redirect" and return the searchable data.</li>
99875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen     * <li>No searchability data is provided.  We return null here and other
100875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen     * code will insert the "default" (e.g. contacts) search.
101f9acde27486bcc6eea1092073f7b47c31749efd6Satish Sampath     *
102875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen     * TODO: cache the result in the map, and check the map first.
103875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen     * TODO: it might make sense to implement the searchable reference as
104875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen     * an application meta-data entry.  This way we don't have to pepper each
105875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen     * and every activity.
106875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen     * TODO: can we skip the constructor step if it's a non-searchable?
107f9acde27486bcc6eea1092073f7b47c31749efd6Satish Sampath     * TODO: does it make sense to plug the default into a slot here for
108875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen     * automatic return?  Probably not, but it's one way to do it.
109875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen     *
110f9acde27486bcc6eea1092073f7b47c31749efd6Satish Sampath     * @param activity The name of the current activity, or null if the
111875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen     * activity does not define any explicit searchable metadata.
112875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen     */
113875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen    public SearchableInfo getSearchableInfo(ComponentName activity) {
114875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen        // Step 1.  Is the result already hashed?  (case 1)
115875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen        SearchableInfo result;
116875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen        synchronized (this) {
117875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen            result = mSearchablesMap.get(activity);
118875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen            if (result != null) return result;
119875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen        }
120f9acde27486bcc6eea1092073f7b47c31749efd6Satish Sampath
121875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen        // Step 2.  See if the current activity references a searchable.
122875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen        // Note:  Conceptually, this could be a while(true) loop, but there's
123f9acde27486bcc6eea1092073f7b47c31749efd6Satish Sampath        // no point in implementing reference chaining here and risking a loop.
124875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen        // References must point directly to searchable activities.
125f9acde27486bcc6eea1092073f7b47c31749efd6Satish Sampath
126875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen        ActivityInfo ai = null;
127875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen        try {
128875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen            ai = mContext.getPackageManager().
129875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen                       getActivityInfo(activity, PackageManager.GET_META_DATA );
130875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen            String refActivityName = null;
131f9acde27486bcc6eea1092073f7b47c31749efd6Satish Sampath
132875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen            // First look for activity-specific reference
133875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen            Bundle md = ai.metaData;
134875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen            if (md != null) {
135875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen                refActivityName = md.getString(MD_LABEL_DEFAULT_SEARCHABLE);
136875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen            }
137875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen            // If not found, try for app-wide reference
138875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen            if (refActivityName == null) {
139875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen                md = ai.applicationInfo.metaData;
140875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen                if (md != null) {
141875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen                    refActivityName = md.getString(MD_LABEL_DEFAULT_SEARCHABLE);
142875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen                }
143875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen            }
144f9acde27486bcc6eea1092073f7b47c31749efd6Satish Sampath
145875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen            // Irrespective of source, if a reference was found, follow it.
146875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen            if (refActivityName != null)
147875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen            {
1486cf7a325e6e9e70d9858e21fbb438341332ed254Bjorn Bringert                // This value is deprecated, return null
149875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen                if (refActivityName.equals(MD_SEARCHABLE_SYSTEM_SEARCH)) {
1506cf7a325e6e9e70d9858e21fbb438341332ed254Bjorn Bringert                    return null;
151875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen                }
152875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen                String pkg = activity.getPackageName();
153875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen                ComponentName referredActivity;
154875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen                if (refActivityName.charAt(0) == '.') {
155875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen                    referredActivity = new ComponentName(pkg, pkg + refActivityName);
156875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen                } else {
157875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen                    referredActivity = new ComponentName(pkg, refActivityName);
158875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen                }
159875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen
160875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen                // Now try the referred activity, and if found, cache
161875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen                // it against the original name so we can skip the check
162875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen                synchronized (this) {
163875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen                    result = mSearchablesMap.get(referredActivity);
164875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen                    if (result != null) {
165875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen                        mSearchablesMap.put(activity, result);
166875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen                        return result;
167875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen                    }
168875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen                }
169875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen            }
170875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen        } catch (PackageManager.NameNotFoundException e) {
171875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen            // case 3: no metadata
172875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen        }
173f9acde27486bcc6eea1092073f7b47c31749efd6Satish Sampath
174875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen        // Step 3.  None found. Return null.
175875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen        return null;
176f9acde27486bcc6eea1092073f7b47c31749efd6Satish Sampath
177875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen    }
178f9acde27486bcc6eea1092073f7b47c31749efd6Satish Sampath
179875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen    /**
180f9acde27486bcc6eea1092073f7b47c31749efd6Satish Sampath     * Builds an entire list (suitable for display) of
181f9acde27486bcc6eea1092073f7b47c31749efd6Satish Sampath     * activities that are searchable, by iterating the entire set of
182f9acde27486bcc6eea1092073f7b47c31749efd6Satish Sampath     * ACTION_SEARCH & ACTION_WEB_SEARCH intents.
183f9acde27486bcc6eea1092073f7b47c31749efd6Satish Sampath     *
184875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen     * Also clears the hash of all activities -> searches which will
185875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen     * refill as the user clicks "search".
186f9acde27486bcc6eea1092073f7b47c31749efd6Satish Sampath     *
187875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen     * This should only be done at startup and again if we know that the
188875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen     * list has changed.
189f9acde27486bcc6eea1092073f7b47c31749efd6Satish Sampath     *
190875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen     * TODO: every activity that provides a ACTION_SEARCH intent should
191875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen     * also provide searchability meta-data.  There are a bunch of checks here
192875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen     * that, if data is not found, silently skip to the next activity.  This
193875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen     * won't help a developer trying to figure out why their activity isn't
194875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen     * showing up in the list, but an exception here is too rough.  I would
195875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen     * like to find a better notification mechanism.
196f9acde27486bcc6eea1092073f7b47c31749efd6Satish Sampath     *
197875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen     * TODO: sort the list somehow?  UI choice.
198875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen     */
199875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen    public void buildSearchableList() {
20074708bbdf8d6f172b08343bdc578a20aa4b39148Bjorn Bringert        // These will become the new values at the end of the method
201f9acde27486bcc6eea1092073f7b47c31749efd6Satish Sampath        HashMap<ComponentName, SearchableInfo> newSearchablesMap
202875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen                                = new HashMap<ComponentName, SearchableInfo>();
203875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen        ArrayList<SearchableInfo> newSearchablesList
204875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen                                = new ArrayList<SearchableInfo>();
2056d72e029cb6e5a9cf26aa3314c3dca83614fc91bBjorn Bringert        ArrayList<SearchableInfo> newSearchablesInGlobalSearchList
2066d72e029cb6e5a9cf26aa3314c3dca83614fc91bBjorn Bringert                                = new ArrayList<SearchableInfo>();
207875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen
208f9acde27486bcc6eea1092073f7b47c31749efd6Satish Sampath        // Use intent resolver to generate list of ACTION_SEARCH & ACTION_WEB_SEARCH receivers.
209f9acde27486bcc6eea1092073f7b47c31749efd6Satish Sampath        List<ResolveInfo> searchList;
210875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen        final Intent intent = new Intent(Intent.ACTION_SEARCH);
2115bb87cd9b81506b0c25d3f9184e406762a9e9d9cAmith Yamasani        searchList = queryIntentActivities(intent, PackageManager.GET_META_DATA);
212f9acde27486bcc6eea1092073f7b47c31749efd6Satish Sampath
213f9acde27486bcc6eea1092073f7b47c31749efd6Satish Sampath        List<ResolveInfo> webSearchInfoList;
214f9acde27486bcc6eea1092073f7b47c31749efd6Satish Sampath        final Intent webSearchIntent = new Intent(Intent.ACTION_WEB_SEARCH);
2155bb87cd9b81506b0c25d3f9184e406762a9e9d9cAmith Yamasani        webSearchInfoList = queryIntentActivities(webSearchIntent, PackageManager.GET_META_DATA);
216f9acde27486bcc6eea1092073f7b47c31749efd6Satish Sampath
217875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen        // analyze each one, generate a Searchables record, and record
218f9acde27486bcc6eea1092073f7b47c31749efd6Satish Sampath        if (searchList != null || webSearchInfoList != null) {
219f9acde27486bcc6eea1092073f7b47c31749efd6Satish Sampath            int search_count = (searchList == null ? 0 : searchList.size());
220f9acde27486bcc6eea1092073f7b47c31749efd6Satish Sampath            int web_search_count = (webSearchInfoList == null ? 0 : webSearchInfoList.size());
221f9acde27486bcc6eea1092073f7b47c31749efd6Satish Sampath            int count = search_count + web_search_count;
222875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen            for (int ii = 0; ii < count; ii++) {
223875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen                // for each component, try to find metadata
224f9acde27486bcc6eea1092073f7b47c31749efd6Satish Sampath                ResolveInfo info = (ii < search_count)
225f9acde27486bcc6eea1092073f7b47c31749efd6Satish Sampath                        ? searchList.get(ii)
226f9acde27486bcc6eea1092073f7b47c31749efd6Satish Sampath                        : webSearchInfoList.get(ii - search_count);
227875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen                ActivityInfo ai = info.activityInfo;
228f9acde27486bcc6eea1092073f7b47c31749efd6Satish Sampath                // Check first to avoid duplicate entries.
229590f63433ce786722d263c7e913a88d3101e5cbcKarl Rosaen                if (newSearchablesMap.get(new ComponentName(ai.packageName, ai.name)) == null) {
230590f63433ce786722d263c7e913a88d3101e5cbcKarl Rosaen                    SearchableInfo searchable = SearchableInfo.getActivityMetaData(mContext, ai);
231590f63433ce786722d263c7e913a88d3101e5cbcKarl Rosaen                    if (searchable != null) {
232590f63433ce786722d263c7e913a88d3101e5cbcKarl Rosaen                        newSearchablesList.add(searchable);
233590f63433ce786722d263c7e913a88d3101e5cbcKarl Rosaen                        newSearchablesMap.put(searchable.getSearchActivity(), searchable);
234590f63433ce786722d263c7e913a88d3101e5cbcKarl Rosaen                        if (searchable.shouldIncludeInGlobalSearch()) {
235590f63433ce786722d263c7e913a88d3101e5cbcKarl Rosaen                            newSearchablesInGlobalSearchList.add(searchable);
236590f63433ce786722d263c7e913a88d3101e5cbcKarl Rosaen                        }
2376d72e029cb6e5a9cf26aa3314c3dca83614fc91bBjorn Bringert                    }
238875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen                }
239875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen            }
240875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen        }
241f9acde27486bcc6eea1092073f7b47c31749efd6Satish Sampath
242ee69ff4eaee9342843d5f25338288865dda2d36aNarayan Kamath        List<ResolveInfo> newGlobalSearchActivities = findGlobalSearchActivities();
243ee69ff4eaee9342843d5f25338288865dda2d36aNarayan Kamath
2446cf7a325e6e9e70d9858e21fbb438341332ed254Bjorn Bringert        // Find the global search activity
245ee69ff4eaee9342843d5f25338288865dda2d36aNarayan Kamath        ComponentName newGlobalSearchActivity = findGlobalSearchActivity(
246ee69ff4eaee9342843d5f25338288865dda2d36aNarayan Kamath                newGlobalSearchActivities);
247cbd8a246f86704fb348247245904a9f114f11280Satish Sampath
2486cf7a325e6e9e70d9858e21fbb438341332ed254Bjorn Bringert        // Find the web search activity
2496cf7a325e6e9e70d9858e21fbb438341332ed254Bjorn Bringert        ComponentName newWebSearchActivity = findWebSearchActivity(newGlobalSearchActivity);
250f9acde27486bcc6eea1092073f7b47c31749efd6Satish Sampath
25174708bbdf8d6f172b08343bdc578a20aa4b39148Bjorn Bringert        // Store a consistent set of new values
252875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen        synchronized (this) {
253875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen            mSearchablesMap = newSearchablesMap;
2546d72e029cb6e5a9cf26aa3314c3dca83614fc91bBjorn Bringert            mSearchablesList = newSearchablesList;
2556d72e029cb6e5a9cf26aa3314c3dca83614fc91bBjorn Bringert            mSearchablesInGlobalSearchList = newSearchablesInGlobalSearchList;
256ee69ff4eaee9342843d5f25338288865dda2d36aNarayan Kamath            mGlobalSearchActivities = newGlobalSearchActivities;
257ee69ff4eaee9342843d5f25338288865dda2d36aNarayan Kamath            mCurrentGlobalSearchActivity = newGlobalSearchActivity;
2586cf7a325e6e9e70d9858e21fbb438341332ed254Bjorn Bringert            mWebSearchActivity = newWebSearchActivity;
259875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen        }
260875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen    }
261ee69ff4eaee9342843d5f25338288865dda2d36aNarayan Kamath    /**
262ee69ff4eaee9342843d5f25338288865dda2d36aNarayan Kamath     * Returns a sorted list of installed search providers as per
263ee69ff4eaee9342843d5f25338288865dda2d36aNarayan Kamath     * the following heuristics:
264ee69ff4eaee9342843d5f25338288865dda2d36aNarayan Kamath     *
265ee69ff4eaee9342843d5f25338288865dda2d36aNarayan Kamath     * (a) System apps are given priority over non system apps.
266ee69ff4eaee9342843d5f25338288865dda2d36aNarayan Kamath     * (b) Among system apps and non system apps, the relative ordering
267ee69ff4eaee9342843d5f25338288865dda2d36aNarayan Kamath     * is defined by their declared priority.
268ee69ff4eaee9342843d5f25338288865dda2d36aNarayan Kamath     */
269ee69ff4eaee9342843d5f25338288865dda2d36aNarayan Kamath    private List<ResolveInfo> findGlobalSearchActivities() {
270ee69ff4eaee9342843d5f25338288865dda2d36aNarayan Kamath        // Step 1 : Query the package manager for a list
271ee69ff4eaee9342843d5f25338288865dda2d36aNarayan Kamath        // of activities that can handle the GLOBAL_SEARCH intent.
272ee69ff4eaee9342843d5f25338288865dda2d36aNarayan Kamath        Intent intent = new Intent(SearchManager.INTENT_ACTION_GLOBAL_SEARCH);
273ee69ff4eaee9342843d5f25338288865dda2d36aNarayan Kamath        List<ResolveInfo> activities =
2745bb87cd9b81506b0c25d3f9184e406762a9e9d9cAmith Yamasani                    queryIntentActivities(intent, PackageManager.MATCH_DEFAULT_ONLY);
275ee69ff4eaee9342843d5f25338288865dda2d36aNarayan Kamath        if (activities != null && !activities.isEmpty()) {
276ee69ff4eaee9342843d5f25338288865dda2d36aNarayan Kamath            // Step 2: Rank matching activities according to our heuristics.
277ee69ff4eaee9342843d5f25338288865dda2d36aNarayan Kamath            Collections.sort(activities, GLOBAL_SEARCH_RANKER);
278ee69ff4eaee9342843d5f25338288865dda2d36aNarayan Kamath        }
279ee69ff4eaee9342843d5f25338288865dda2d36aNarayan Kamath
280ee69ff4eaee9342843d5f25338288865dda2d36aNarayan Kamath        return activities;
281ee69ff4eaee9342843d5f25338288865dda2d36aNarayan Kamath    }
282f9acde27486bcc6eea1092073f7b47c31749efd6Satish Sampath
283f9acde27486bcc6eea1092073f7b47c31749efd6Satish Sampath    /**
2846cf7a325e6e9e70d9858e21fbb438341332ed254Bjorn Bringert     * Finds the global search activity.
285f9acde27486bcc6eea1092073f7b47c31749efd6Satish Sampath     */
286ee69ff4eaee9342843d5f25338288865dda2d36aNarayan Kamath    private ComponentName findGlobalSearchActivity(List<ResolveInfo> installed) {
287ee69ff4eaee9342843d5f25338288865dda2d36aNarayan Kamath        // Fetch the global search provider from the system settings,
288ee69ff4eaee9342843d5f25338288865dda2d36aNarayan Kamath        // and if it's still installed, return it.
289ee69ff4eaee9342843d5f25338288865dda2d36aNarayan Kamath        final String searchProviderSetting = getGlobalSearchProviderSetting();
290ee69ff4eaee9342843d5f25338288865dda2d36aNarayan Kamath        if (!TextUtils.isEmpty(searchProviderSetting)) {
291ee69ff4eaee9342843d5f25338288865dda2d36aNarayan Kamath            final ComponentName globalSearchComponent = ComponentName.unflattenFromString(
292ee69ff4eaee9342843d5f25338288865dda2d36aNarayan Kamath                    searchProviderSetting);
293ee69ff4eaee9342843d5f25338288865dda2d36aNarayan Kamath            if (globalSearchComponent != null && isInstalled(globalSearchComponent)) {
294ee69ff4eaee9342843d5f25338288865dda2d36aNarayan Kamath                return globalSearchComponent;
295ee69ff4eaee9342843d5f25338288865dda2d36aNarayan Kamath            }
296ee69ff4eaee9342843d5f25338288865dda2d36aNarayan Kamath        }
297ee69ff4eaee9342843d5f25338288865dda2d36aNarayan Kamath
298ee69ff4eaee9342843d5f25338288865dda2d36aNarayan Kamath        return getDefaultGlobalSearchProvider(installed);
299ee69ff4eaee9342843d5f25338288865dda2d36aNarayan Kamath    }
300ee69ff4eaee9342843d5f25338288865dda2d36aNarayan Kamath
301ee69ff4eaee9342843d5f25338288865dda2d36aNarayan Kamath    /**
302ee69ff4eaee9342843d5f25338288865dda2d36aNarayan Kamath     * Checks whether the global search provider with a given
303ee69ff4eaee9342843d5f25338288865dda2d36aNarayan Kamath     * component name is installed on the system or not. This deals with
304ee69ff4eaee9342843d5f25338288865dda2d36aNarayan Kamath     * cases such as the removal of an installed provider.
305ee69ff4eaee9342843d5f25338288865dda2d36aNarayan Kamath     */
306ee69ff4eaee9342843d5f25338288865dda2d36aNarayan Kamath    private boolean isInstalled(ComponentName globalSearch) {
3076cf7a325e6e9e70d9858e21fbb438341332ed254Bjorn Bringert        Intent intent = new Intent(SearchManager.INTENT_ACTION_GLOBAL_SEARCH);
308ee69ff4eaee9342843d5f25338288865dda2d36aNarayan Kamath        intent.setComponent(globalSearch);
309ee69ff4eaee9342843d5f25338288865dda2d36aNarayan Kamath
3105bb87cd9b81506b0c25d3f9184e406762a9e9d9cAmith Yamasani        List<ResolveInfo> activities = queryIntentActivities(intent,
3115bb87cd9b81506b0c25d3f9184e406762a9e9d9cAmith Yamasani                PackageManager.MATCH_DEFAULT_ONLY);
312ee69ff4eaee9342843d5f25338288865dda2d36aNarayan Kamath        if (activities != null && !activities.isEmpty()) {
313ee69ff4eaee9342843d5f25338288865dda2d36aNarayan Kamath            return true;
314ee69ff4eaee9342843d5f25338288865dda2d36aNarayan Kamath        }
315ee69ff4eaee9342843d5f25338288865dda2d36aNarayan Kamath
316ee69ff4eaee9342843d5f25338288865dda2d36aNarayan Kamath        return false;
317ee69ff4eaee9342843d5f25338288865dda2d36aNarayan Kamath    }
318ee69ff4eaee9342843d5f25338288865dda2d36aNarayan Kamath
319ee69ff4eaee9342843d5f25338288865dda2d36aNarayan Kamath    private static final Comparator<ResolveInfo> GLOBAL_SEARCH_RANKER =
320ee69ff4eaee9342843d5f25338288865dda2d36aNarayan Kamath            new Comparator<ResolveInfo>() {
321ee69ff4eaee9342843d5f25338288865dda2d36aNarayan Kamath        @Override
322ee69ff4eaee9342843d5f25338288865dda2d36aNarayan Kamath        public int compare(ResolveInfo lhs, ResolveInfo rhs) {
323ee69ff4eaee9342843d5f25338288865dda2d36aNarayan Kamath            if (lhs == rhs) {
324ee69ff4eaee9342843d5f25338288865dda2d36aNarayan Kamath                return 0;
325ee69ff4eaee9342843d5f25338288865dda2d36aNarayan Kamath            }
326ee69ff4eaee9342843d5f25338288865dda2d36aNarayan Kamath            boolean lhsSystem = isSystemApp(lhs);
327ee69ff4eaee9342843d5f25338288865dda2d36aNarayan Kamath            boolean rhsSystem = isSystemApp(rhs);
328ee69ff4eaee9342843d5f25338288865dda2d36aNarayan Kamath
329ee69ff4eaee9342843d5f25338288865dda2d36aNarayan Kamath            if (lhsSystem && !rhsSystem) {
330ee69ff4eaee9342843d5f25338288865dda2d36aNarayan Kamath                return -1;
331ee69ff4eaee9342843d5f25338288865dda2d36aNarayan Kamath            } else if (rhsSystem && !lhsSystem) {
332ee69ff4eaee9342843d5f25338288865dda2d36aNarayan Kamath                return 1;
3336cf7a325e6e9e70d9858e21fbb438341332ed254Bjorn Bringert            } else {
334ee69ff4eaee9342843d5f25338288865dda2d36aNarayan Kamath                // Either both system engines, or both non system
335ee69ff4eaee9342843d5f25338288865dda2d36aNarayan Kamath                // engines.
336ee69ff4eaee9342843d5f25338288865dda2d36aNarayan Kamath                //
337ee69ff4eaee9342843d5f25338288865dda2d36aNarayan Kamath                // Note, this isn't a typo. Higher priority numbers imply
338ee69ff4eaee9342843d5f25338288865dda2d36aNarayan Kamath                // higher priority, but are "lower" in the sort order.
339ee69ff4eaee9342843d5f25338288865dda2d36aNarayan Kamath                return rhs.priority - lhs.priority;
3406cf7a325e6e9e70d9858e21fbb438341332ed254Bjorn Bringert            }
341f9acde27486bcc6eea1092073f7b47c31749efd6Satish Sampath        }
342ee69ff4eaee9342843d5f25338288865dda2d36aNarayan Kamath    };
343ee69ff4eaee9342843d5f25338288865dda2d36aNarayan Kamath
344ee69ff4eaee9342843d5f25338288865dda2d36aNarayan Kamath    /**
345ee69ff4eaee9342843d5f25338288865dda2d36aNarayan Kamath     * @return true iff. the resolve info corresponds to a system application.
346ee69ff4eaee9342843d5f25338288865dda2d36aNarayan Kamath     */
347ee69ff4eaee9342843d5f25338288865dda2d36aNarayan Kamath    private static final boolean isSystemApp(ResolveInfo res) {
348ee69ff4eaee9342843d5f25338288865dda2d36aNarayan Kamath        return (res.activityInfo.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0;
349ee69ff4eaee9342843d5f25338288865dda2d36aNarayan Kamath    }
350ee69ff4eaee9342843d5f25338288865dda2d36aNarayan Kamath
351ee69ff4eaee9342843d5f25338288865dda2d36aNarayan Kamath    /**
352ee69ff4eaee9342843d5f25338288865dda2d36aNarayan Kamath     * Returns the highest ranked search provider as per the
353ee69ff4eaee9342843d5f25338288865dda2d36aNarayan Kamath     * ranking defined in {@link #getGlobalSearchActivities()}.
354ee69ff4eaee9342843d5f25338288865dda2d36aNarayan Kamath     */
355ee69ff4eaee9342843d5f25338288865dda2d36aNarayan Kamath    private ComponentName getDefaultGlobalSearchProvider(List<ResolveInfo> providerList) {
356ee69ff4eaee9342843d5f25338288865dda2d36aNarayan Kamath        if (providerList != null && !providerList.isEmpty()) {
357ee69ff4eaee9342843d5f25338288865dda2d36aNarayan Kamath            ActivityInfo ai = providerList.get(0).activityInfo;
358ee69ff4eaee9342843d5f25338288865dda2d36aNarayan Kamath            return new ComponentName(ai.packageName, ai.name);
359ee69ff4eaee9342843d5f25338288865dda2d36aNarayan Kamath        }
360ee69ff4eaee9342843d5f25338288865dda2d36aNarayan Kamath
3616cf7a325e6e9e70d9858e21fbb438341332ed254Bjorn Bringert        Log.w(LOG_TAG, "No global search activity found");
3626cf7a325e6e9e70d9858e21fbb438341332ed254Bjorn Bringert        return null;
363f9acde27486bcc6eea1092073f7b47c31749efd6Satish Sampath    }
364f9acde27486bcc6eea1092073f7b47c31749efd6Satish Sampath
365ee69ff4eaee9342843d5f25338288865dda2d36aNarayan Kamath    private String getGlobalSearchProviderSetting() {
366ee69ff4eaee9342843d5f25338288865dda2d36aNarayan Kamath        return Settings.Secure.getString(mContext.getContentResolver(),
367ee69ff4eaee9342843d5f25338288865dda2d36aNarayan Kamath                Settings.Secure.SEARCH_GLOBAL_SEARCH_ACTIVITY);
368ee69ff4eaee9342843d5f25338288865dda2d36aNarayan Kamath    }
369ee69ff4eaee9342843d5f25338288865dda2d36aNarayan Kamath
3706cf7a325e6e9e70d9858e21fbb438341332ed254Bjorn Bringert    /**
3716cf7a325e6e9e70d9858e21fbb438341332ed254Bjorn Bringert     * Finds the web search activity.
3726cf7a325e6e9e70d9858e21fbb438341332ed254Bjorn Bringert     *
3736cf7a325e6e9e70d9858e21fbb438341332ed254Bjorn Bringert     * Only looks in the package of the global search activity.
3746cf7a325e6e9e70d9858e21fbb438341332ed254Bjorn Bringert     */
3756cf7a325e6e9e70d9858e21fbb438341332ed254Bjorn Bringert    private ComponentName findWebSearchActivity(ComponentName globalSearchActivity) {
3766cf7a325e6e9e70d9858e21fbb438341332ed254Bjorn Bringert        if (globalSearchActivity == null) {
3776cf7a325e6e9e70d9858e21fbb438341332ed254Bjorn Bringert            return null;
3786cf7a325e6e9e70d9858e21fbb438341332ed254Bjorn Bringert        }
379f9acde27486bcc6eea1092073f7b47c31749efd6Satish Sampath        Intent intent = new Intent(Intent.ACTION_WEB_SEARCH);
3806cf7a325e6e9e70d9858e21fbb438341332ed254Bjorn Bringert        intent.setPackage(globalSearchActivity.getPackageName());
3816cf7a325e6e9e70d9858e21fbb438341332ed254Bjorn Bringert        List<ResolveInfo> activities =
3825bb87cd9b81506b0c25d3f9184e406762a9e9d9cAmith Yamasani                queryIntentActivities(intent, PackageManager.MATCH_DEFAULT_ONLY);
383ee69ff4eaee9342843d5f25338288865dda2d36aNarayan Kamath
384ee69ff4eaee9342843d5f25338288865dda2d36aNarayan Kamath        if (activities != null && !activities.isEmpty()) {
385ee69ff4eaee9342843d5f25338288865dda2d36aNarayan Kamath            ActivityInfo ai = activities.get(0).activityInfo;
3866cf7a325e6e9e70d9858e21fbb438341332ed254Bjorn Bringert            // TODO: do some sanity checks here?
3876cf7a325e6e9e70d9858e21fbb438341332ed254Bjorn Bringert            return new ComponentName(ai.packageName, ai.name);
388f9acde27486bcc6eea1092073f7b47c31749efd6Satish Sampath        }
3896cf7a325e6e9e70d9858e21fbb438341332ed254Bjorn Bringert        Log.w(LOG_TAG, "No web search activity found");
3906cf7a325e6e9e70d9858e21fbb438341332ed254Bjorn Bringert        return null;
391f9acde27486bcc6eea1092073f7b47c31749efd6Satish Sampath    }
392f9acde27486bcc6eea1092073f7b47c31749efd6Satish Sampath
3935bb87cd9b81506b0c25d3f9184e406762a9e9d9cAmith Yamasani    private List<ResolveInfo> queryIntentActivities(Intent intent, int flags) {
3945bb87cd9b81506b0c25d3f9184e406762a9e9d9cAmith Yamasani        if (mPm == null) {
3955bb87cd9b81506b0c25d3f9184e406762a9e9d9cAmith Yamasani            mPm = AppGlobals.getPackageManager();
3965bb87cd9b81506b0c25d3f9184e406762a9e9d9cAmith Yamasani        }
3975bb87cd9b81506b0c25d3f9184e406762a9e9d9cAmith Yamasani        List<ResolveInfo> activities = null;
3985bb87cd9b81506b0c25d3f9184e406762a9e9d9cAmith Yamasani        try {
3995bb87cd9b81506b0c25d3f9184e406762a9e9d9cAmith Yamasani            activities =
4005bb87cd9b81506b0c25d3f9184e406762a9e9d9cAmith Yamasani                    mPm.queryIntentActivities(intent,
4015bb87cd9b81506b0c25d3f9184e406762a9e9d9cAmith Yamasani                    intent.resolveTypeIfNeeded(mContext.getContentResolver()),
4025bb87cd9b81506b0c25d3f9184e406762a9e9d9cAmith Yamasani                    flags, mUserId);
4035bb87cd9b81506b0c25d3f9184e406762a9e9d9cAmith Yamasani        } catch (RemoteException re) {
4045bb87cd9b81506b0c25d3f9184e406762a9e9d9cAmith Yamasani            // Local call
4055bb87cd9b81506b0c25d3f9184e406762a9e9d9cAmith Yamasani        }
4065bb87cd9b81506b0c25d3f9184e406762a9e9d9cAmith Yamasani        return activities;
4075bb87cd9b81506b0c25d3f9184e406762a9e9d9cAmith Yamasani    }
4085bb87cd9b81506b0c25d3f9184e406762a9e9d9cAmith Yamasani
409875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen    /**
410875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen     * Returns the list of searchable activities.
411875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen     */
412875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen    public synchronized ArrayList<SearchableInfo> getSearchablesList() {
413875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen        ArrayList<SearchableInfo> result = new ArrayList<SearchableInfo>(mSearchablesList);
414875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen        return result;
415875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen    }
416f9acde27486bcc6eea1092073f7b47c31749efd6Satish Sampath
4176d72e029cb6e5a9cf26aa3314c3dca83614fc91bBjorn Bringert    /**
4186d72e029cb6e5a9cf26aa3314c3dca83614fc91bBjorn Bringert     * Returns a list of the searchable activities that can be included in global search.
4196d72e029cb6e5a9cf26aa3314c3dca83614fc91bBjorn Bringert     */
4206d72e029cb6e5a9cf26aa3314c3dca83614fc91bBjorn Bringert    public synchronized ArrayList<SearchableInfo> getSearchablesInGlobalSearchList() {
4216d72e029cb6e5a9cf26aa3314c3dca83614fc91bBjorn Bringert        return new ArrayList<SearchableInfo>(mSearchablesInGlobalSearchList);
4226d72e029cb6e5a9cf26aa3314c3dca83614fc91bBjorn Bringert    }
423f9acde27486bcc6eea1092073f7b47c31749efd6Satish Sampath
424f9acde27486bcc6eea1092073f7b47c31749efd6Satish Sampath    /**
425ee69ff4eaee9342843d5f25338288865dda2d36aNarayan Kamath     * Returns a list of activities that handle the global search intent.
426ee69ff4eaee9342843d5f25338288865dda2d36aNarayan Kamath     */
427ee69ff4eaee9342843d5f25338288865dda2d36aNarayan Kamath    public synchronized ArrayList<ResolveInfo> getGlobalSearchActivities() {
428ee69ff4eaee9342843d5f25338288865dda2d36aNarayan Kamath        return new ArrayList<ResolveInfo>(mGlobalSearchActivities);
429ee69ff4eaee9342843d5f25338288865dda2d36aNarayan Kamath    }
430ee69ff4eaee9342843d5f25338288865dda2d36aNarayan Kamath
431ee69ff4eaee9342843d5f25338288865dda2d36aNarayan Kamath    /**
4326cf7a325e6e9e70d9858e21fbb438341332ed254Bjorn Bringert     * Gets the name of the global search activity.
433f9acde27486bcc6eea1092073f7b47c31749efd6Satish Sampath     */
4346cf7a325e6e9e70d9858e21fbb438341332ed254Bjorn Bringert    public synchronized ComponentName getGlobalSearchActivity() {
435ee69ff4eaee9342843d5f25338288865dda2d36aNarayan Kamath        return mCurrentGlobalSearchActivity;
436f9acde27486bcc6eea1092073f7b47c31749efd6Satish Sampath    }
437f9acde27486bcc6eea1092073f7b47c31749efd6Satish Sampath
438f9acde27486bcc6eea1092073f7b47c31749efd6Satish Sampath    /**
4396cf7a325e6e9e70d9858e21fbb438341332ed254Bjorn Bringert     * Gets the name of the web search activity.
440f9acde27486bcc6eea1092073f7b47c31749efd6Satish Sampath     */
4416cf7a325e6e9e70d9858e21fbb438341332ed254Bjorn Bringert    public synchronized ComponentName getWebSearchActivity() {
4426cf7a325e6e9e70d9858e21fbb438341332ed254Bjorn Bringert        return mWebSearchActivity;
443f9acde27486bcc6eea1092073f7b47c31749efd6Satish Sampath    }
444875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen}
445