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
177a96c39c510923ef73bbb06ab20109f0168b8eb1Jeff Sharkeypackage com.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;
30f203aeef993b0f4ce65c9630d06bbd50a504e89fAmith Yamasaniimport android.os.Binder;
31875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaenimport android.os.Bundle;
325bb87cd9b81506b0c25d3f9184e406762a9e9d9cAmith Yamasaniimport android.os.RemoteException;
33ee69ff4eaee9342843d5f25338288865dda2d36aNarayan Kamathimport android.provider.Settings;
34ee69ff4eaee9342843d5f25338288865dda2d36aNarayan Kamathimport android.text.TextUtils;
35cbd8a246f86704fb348247245904a9f114f11280Satish Sampathimport android.util.Log;
36875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen
3764442c11555d828a41af0b8a58ab933357889061Amith Yamasaniimport java.io.FileDescriptor;
3864442c11555d828a41af0b8a58ab933357889061Amith Yamasaniimport java.io.PrintWriter;
39875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaenimport java.util.ArrayList;
40ee69ff4eaee9342843d5f25338288865dda2d36aNarayan Kamathimport java.util.Collections;
41ee69ff4eaee9342843d5f25338288865dda2d36aNarayan Kamathimport java.util.Comparator;
42875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaenimport java.util.HashMap;
43875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaenimport java.util.List;
44875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen
45875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen/**
46f9acde27486bcc6eea1092073f7b47c31749efd6Satish Sampath * This class maintains the information about all searchable activities.
475bb87cd9b81506b0c25d3f9184e406762a9e9d9cAmith Yamasani * This is a hidden class.
48875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen */
49875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaenpublic class Searchables {
50875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen
51cbd8a246f86704fb348247245904a9f114f11280Satish Sampath    private static final String LOG_TAG = "Searchables";
52cbd8a246f86704fb348247245904a9f114f11280Satish Sampath
53875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen    // static strings used for XML lookups, etc.
54f9acde27486bcc6eea1092073f7b47c31749efd6Satish Sampath    // TODO how should these be documented for the developer, in a more structured way than
55875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen    // the current long wordy javadoc in SearchManager.java ?
56875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen    private static final String MD_LABEL_DEFAULT_SEARCHABLE = "android.app.default_searchable";
57875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen    private static final String MD_SEARCHABLE_SYSTEM_SEARCH = "*";
58f9acde27486bcc6eea1092073f7b47c31749efd6Satish Sampath
59875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen    private Context mContext;
60f9acde27486bcc6eea1092073f7b47c31749efd6Satish Sampath
61875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen    private HashMap<ComponentName, SearchableInfo> mSearchablesMap = null;
62875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen    private ArrayList<SearchableInfo> mSearchablesList = null;
636d72e029cb6e5a9cf26aa3314c3dca83614fc91bBjorn Bringert    private ArrayList<SearchableInfo> mSearchablesInGlobalSearchList = null;
64ee69ff4eaee9342843d5f25338288865dda2d36aNarayan Kamath    // Contains all installed activities that handle the global search
65ee69ff4eaee9342843d5f25338288865dda2d36aNarayan Kamath    // intent.
66ee69ff4eaee9342843d5f25338288865dda2d36aNarayan Kamath    private List<ResolveInfo> mGlobalSearchActivities;
67ee69ff4eaee9342843d5f25338288865dda2d36aNarayan Kamath    private ComponentName mCurrentGlobalSearchActivity = null;
686cf7a325e6e9e70d9858e21fbb438341332ed254Bjorn Bringert    private ComponentName mWebSearchActivity = null;
69f9acde27486bcc6eea1092073f7b47c31749efd6Satish Sampath
7041282a35568b51270440450c46bb31aa00e52caaSatish Sampath    public static String GOOGLE_SEARCH_COMPONENT_NAME =
7141282a35568b51270440450c46bb31aa00e52caaSatish Sampath            "com.android.googlesearch/.GoogleSearch";
7241282a35568b51270440450c46bb31aa00e52caaSatish Sampath    public static String ENHANCED_GOOGLE_SEARCH_COMPONENT_NAME =
7341282a35568b51270440450c46bb31aa00e52caaSatish Sampath            "com.google.android.providers.enhancedgooglesearch/.Launcher";
7441282a35568b51270440450c46bb31aa00e52caaSatish Sampath
755bb87cd9b81506b0c25d3f9184e406762a9e9d9cAmith Yamasani    // Cache the package manager instance
76f203aeef993b0f4ce65c9630d06bbd50a504e89fAmith Yamasani    final private IPackageManager mPm;
775bb87cd9b81506b0c25d3f9184e406762a9e9d9cAmith Yamasani    // User for which this Searchables caches information
785bb87cd9b81506b0c25d3f9184e406762a9e9d9cAmith Yamasani    private int mUserId;
795bb87cd9b81506b0c25d3f9184e406762a9e9d9cAmith Yamasani
80875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen    /**
81f9acde27486bcc6eea1092073f7b47c31749efd6Satish Sampath     *
82875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen     * @param context Context to use for looking up activities etc.
83875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen     */
845bb87cd9b81506b0c25d3f9184e406762a9e9d9cAmith Yamasani    public Searchables (Context context, int userId) {
85875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen        mContext = context;
865bb87cd9b81506b0c25d3f9184e406762a9e9d9cAmith Yamasani        mUserId = userId;
87f203aeef993b0f4ce65c9630d06bbd50a504e89fAmith Yamasani        mPm = AppGlobals.getPackageManager();
88875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen    }
89f9acde27486bcc6eea1092073f7b47c31749efd6Satish Sampath
90875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen    /**
91875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen     * Look up, or construct, based on the activity.
92f9acde27486bcc6eea1092073f7b47c31749efd6Satish Sampath     *
93f9acde27486bcc6eea1092073f7b47c31749efd6Satish Sampath     * The activities fall into three cases, based on meta-data found in
94875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen     * the manifest entry:
95875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen     * <ol>
96875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen     * <li>The activity itself implements search.  This is indicated by the
97875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen     * presence of a "android.app.searchable" meta-data attribute.
98875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen     * The value is a reference to an XML file containing search information.</li>
99875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen     * <li>A related activity implements search.  This is indicated by the
100875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen     * presence of a "android.app.default_searchable" meta-data attribute.
101875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen     * The value is a string naming the activity implementing search.  In this
102875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen     * case the factory will "redirect" and return the searchable data.</li>
103875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen     * <li>No searchability data is provided.  We return null here and other
104875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen     * code will insert the "default" (e.g. contacts) search.
105f9acde27486bcc6eea1092073f7b47c31749efd6Satish Sampath     *
106875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen     * TODO: cache the result in the map, and check the map first.
107875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen     * TODO: it might make sense to implement the searchable reference as
108875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen     * an application meta-data entry.  This way we don't have to pepper each
109875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen     * and every activity.
110875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen     * TODO: can we skip the constructor step if it's a non-searchable?
111f9acde27486bcc6eea1092073f7b47c31749efd6Satish Sampath     * TODO: does it make sense to plug the default into a slot here for
112875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen     * automatic return?  Probably not, but it's one way to do it.
113875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen     *
114f9acde27486bcc6eea1092073f7b47c31749efd6Satish Sampath     * @param activity The name of the current activity, or null if the
115875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen     * activity does not define any explicit searchable metadata.
116875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen     */
117875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen    public SearchableInfo getSearchableInfo(ComponentName activity) {
118875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen        // Step 1.  Is the result already hashed?  (case 1)
119875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen        SearchableInfo result;
120875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen        synchronized (this) {
121875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen            result = mSearchablesMap.get(activity);
122875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen            if (result != null) return result;
123875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen        }
124f9acde27486bcc6eea1092073f7b47c31749efd6Satish Sampath
125875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen        // Step 2.  See if the current activity references a searchable.
126875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen        // Note:  Conceptually, this could be a while(true) loop, but there's
127f9acde27486bcc6eea1092073f7b47c31749efd6Satish Sampath        // no point in implementing reference chaining here and risking a loop.
128875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen        // References must point directly to searchable activities.
129f9acde27486bcc6eea1092073f7b47c31749efd6Satish Sampath
130875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen        ActivityInfo ai = null;
131875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen        try {
132f203aeef993b0f4ce65c9630d06bbd50a504e89fAmith Yamasani            ai = mPm.getActivityInfo(activity, PackageManager.GET_META_DATA, mUserId);
133f203aeef993b0f4ce65c9630d06bbd50a504e89fAmith Yamasani        } catch (RemoteException re) {
134f203aeef993b0f4ce65c9630d06bbd50a504e89fAmith Yamasani            Log.e(LOG_TAG, "Error getting activity info " + re);
135f203aeef993b0f4ce65c9630d06bbd50a504e89fAmith Yamasani            return null;
136f203aeef993b0f4ce65c9630d06bbd50a504e89fAmith Yamasani        }
137f203aeef993b0f4ce65c9630d06bbd50a504e89fAmith Yamasani        String refActivityName = null;
138f9acde27486bcc6eea1092073f7b47c31749efd6Satish Sampath
139f203aeef993b0f4ce65c9630d06bbd50a504e89fAmith Yamasani        // First look for activity-specific reference
140f203aeef993b0f4ce65c9630d06bbd50a504e89fAmith Yamasani        Bundle md = ai.metaData;
141f203aeef993b0f4ce65c9630d06bbd50a504e89fAmith Yamasani        if (md != null) {
142f203aeef993b0f4ce65c9630d06bbd50a504e89fAmith Yamasani            refActivityName = md.getString(MD_LABEL_DEFAULT_SEARCHABLE);
143f203aeef993b0f4ce65c9630d06bbd50a504e89fAmith Yamasani        }
144f203aeef993b0f4ce65c9630d06bbd50a504e89fAmith Yamasani        // If not found, try for app-wide reference
145f203aeef993b0f4ce65c9630d06bbd50a504e89fAmith Yamasani        if (refActivityName == null) {
146f203aeef993b0f4ce65c9630d06bbd50a504e89fAmith Yamasani            md = ai.applicationInfo.metaData;
147875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen            if (md != null) {
148875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen                refActivityName = md.getString(MD_LABEL_DEFAULT_SEARCHABLE);
149875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen            }
150f203aeef993b0f4ce65c9630d06bbd50a504e89fAmith Yamasani        }
151f9acde27486bcc6eea1092073f7b47c31749efd6Satish Sampath
152f203aeef993b0f4ce65c9630d06bbd50a504e89fAmith Yamasani        // Irrespective of source, if a reference was found, follow it.
153f203aeef993b0f4ce65c9630d06bbd50a504e89fAmith Yamasani        if (refActivityName != null)
154f203aeef993b0f4ce65c9630d06bbd50a504e89fAmith Yamasani        {
155f203aeef993b0f4ce65c9630d06bbd50a504e89fAmith Yamasani            // This value is deprecated, return null
156f203aeef993b0f4ce65c9630d06bbd50a504e89fAmith Yamasani            if (refActivityName.equals(MD_SEARCHABLE_SYSTEM_SEARCH)) {
157f203aeef993b0f4ce65c9630d06bbd50a504e89fAmith Yamasani                return null;
158f203aeef993b0f4ce65c9630d06bbd50a504e89fAmith Yamasani            }
159f203aeef993b0f4ce65c9630d06bbd50a504e89fAmith Yamasani            String pkg = activity.getPackageName();
160f203aeef993b0f4ce65c9630d06bbd50a504e89fAmith Yamasani            ComponentName referredActivity;
161f203aeef993b0f4ce65c9630d06bbd50a504e89fAmith Yamasani            if (refActivityName.charAt(0) == '.') {
162f203aeef993b0f4ce65c9630d06bbd50a504e89fAmith Yamasani                referredActivity = new ComponentName(pkg, pkg + refActivityName);
163f203aeef993b0f4ce65c9630d06bbd50a504e89fAmith Yamasani            } else {
164f203aeef993b0f4ce65c9630d06bbd50a504e89fAmith Yamasani                referredActivity = new ComponentName(pkg, refActivityName);
165f203aeef993b0f4ce65c9630d06bbd50a504e89fAmith Yamasani            }
166875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen
167f203aeef993b0f4ce65c9630d06bbd50a504e89fAmith Yamasani            // Now try the referred activity, and if found, cache
168f203aeef993b0f4ce65c9630d06bbd50a504e89fAmith Yamasani            // it against the original name so we can skip the check
169f203aeef993b0f4ce65c9630d06bbd50a504e89fAmith Yamasani            synchronized (this) {
170f203aeef993b0f4ce65c9630d06bbd50a504e89fAmith Yamasani                result = mSearchablesMap.get(referredActivity);
171f203aeef993b0f4ce65c9630d06bbd50a504e89fAmith Yamasani                if (result != null) {
172f203aeef993b0f4ce65c9630d06bbd50a504e89fAmith Yamasani                    mSearchablesMap.put(activity, result);
173f203aeef993b0f4ce65c9630d06bbd50a504e89fAmith Yamasani                    return result;
174875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen                }
175875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen            }
176875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen        }
177f9acde27486bcc6eea1092073f7b47c31749efd6Satish Sampath
178875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen        // Step 3.  None found. Return null.
179875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen        return null;
180f9acde27486bcc6eea1092073f7b47c31749efd6Satish Sampath
181875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen    }
182f9acde27486bcc6eea1092073f7b47c31749efd6Satish Sampath
183875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen    /**
184f9acde27486bcc6eea1092073f7b47c31749efd6Satish Sampath     * Builds an entire list (suitable for display) of
185f9acde27486bcc6eea1092073f7b47c31749efd6Satish Sampath     * activities that are searchable, by iterating the entire set of
186f9acde27486bcc6eea1092073f7b47c31749efd6Satish Sampath     * ACTION_SEARCH & ACTION_WEB_SEARCH intents.
187f9acde27486bcc6eea1092073f7b47c31749efd6Satish Sampath     *
188875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen     * Also clears the hash of all activities -> searches which will
189875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen     * refill as the user clicks "search".
190f9acde27486bcc6eea1092073f7b47c31749efd6Satish Sampath     *
191875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen     * This should only be done at startup and again if we know that the
192875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen     * list has changed.
193f9acde27486bcc6eea1092073f7b47c31749efd6Satish Sampath     *
194875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen     * TODO: every activity that provides a ACTION_SEARCH intent should
195875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen     * also provide searchability meta-data.  There are a bunch of checks here
196875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen     * that, if data is not found, silently skip to the next activity.  This
197875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen     * won't help a developer trying to figure out why their activity isn't
198875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen     * showing up in the list, but an exception here is too rough.  I would
199875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen     * like to find a better notification mechanism.
200f9acde27486bcc6eea1092073f7b47c31749efd6Satish Sampath     *
201875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen     * TODO: sort the list somehow?  UI choice.
202875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen     */
203875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen    public void buildSearchableList() {
20474708bbdf8d6f172b08343bdc578a20aa4b39148Bjorn Bringert        // These will become the new values at the end of the method
205f9acde27486bcc6eea1092073f7b47c31749efd6Satish Sampath        HashMap<ComponentName, SearchableInfo> newSearchablesMap
206875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen                                = new HashMap<ComponentName, SearchableInfo>();
207875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen        ArrayList<SearchableInfo> newSearchablesList
208875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen                                = new ArrayList<SearchableInfo>();
2096d72e029cb6e5a9cf26aa3314c3dca83614fc91bBjorn Bringert        ArrayList<SearchableInfo> newSearchablesInGlobalSearchList
2106d72e029cb6e5a9cf26aa3314c3dca83614fc91bBjorn Bringert                                = new ArrayList<SearchableInfo>();
211875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen
212f9acde27486bcc6eea1092073f7b47c31749efd6Satish Sampath        // Use intent resolver to generate list of ACTION_SEARCH & ACTION_WEB_SEARCH receivers.
213f9acde27486bcc6eea1092073f7b47c31749efd6Satish Sampath        List<ResolveInfo> searchList;
214875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen        final Intent intent = new Intent(Intent.ACTION_SEARCH);
21564442c11555d828a41af0b8a58ab933357889061Amith Yamasani
21664442c11555d828a41af0b8a58ab933357889061Amith Yamasani        long ident = Binder.clearCallingIdentity();
21764442c11555d828a41af0b8a58ab933357889061Amith Yamasani        try {
21864442c11555d828a41af0b8a58ab933357889061Amith Yamasani            searchList = queryIntentActivities(intent, PackageManager.GET_META_DATA);
21964442c11555d828a41af0b8a58ab933357889061Amith Yamasani
22064442c11555d828a41af0b8a58ab933357889061Amith Yamasani            List<ResolveInfo> webSearchInfoList;
22164442c11555d828a41af0b8a58ab933357889061Amith Yamasani            final Intent webSearchIntent = new Intent(Intent.ACTION_WEB_SEARCH);
22264442c11555d828a41af0b8a58ab933357889061Amith Yamasani            webSearchInfoList = queryIntentActivities(webSearchIntent, PackageManager.GET_META_DATA);
22364442c11555d828a41af0b8a58ab933357889061Amith Yamasani
22464442c11555d828a41af0b8a58ab933357889061Amith Yamasani            // analyze each one, generate a Searchables record, and record
22564442c11555d828a41af0b8a58ab933357889061Amith Yamasani            if (searchList != null || webSearchInfoList != null) {
22664442c11555d828a41af0b8a58ab933357889061Amith Yamasani                int search_count = (searchList == null ? 0 : searchList.size());
22764442c11555d828a41af0b8a58ab933357889061Amith Yamasani                int web_search_count = (webSearchInfoList == null ? 0 : webSearchInfoList.size());
22864442c11555d828a41af0b8a58ab933357889061Amith Yamasani                int count = search_count + web_search_count;
22964442c11555d828a41af0b8a58ab933357889061Amith Yamasani                for (int ii = 0; ii < count; ii++) {
23064442c11555d828a41af0b8a58ab933357889061Amith Yamasani                    // for each component, try to find metadata
23164442c11555d828a41af0b8a58ab933357889061Amith Yamasani                    ResolveInfo info = (ii < search_count)
23264442c11555d828a41af0b8a58ab933357889061Amith Yamasani                            ? searchList.get(ii)
23364442c11555d828a41af0b8a58ab933357889061Amith Yamasani                            : webSearchInfoList.get(ii - search_count);
23464442c11555d828a41af0b8a58ab933357889061Amith Yamasani                    ActivityInfo ai = info.activityInfo;
23564442c11555d828a41af0b8a58ab933357889061Amith Yamasani                    // Check first to avoid duplicate entries.
23664442c11555d828a41af0b8a58ab933357889061Amith Yamasani                    if (newSearchablesMap.get(new ComponentName(ai.packageName, ai.name)) == null) {
23764442c11555d828a41af0b8a58ab933357889061Amith Yamasani                        SearchableInfo searchable = SearchableInfo.getActivityMetaData(mContext, ai,
23864442c11555d828a41af0b8a58ab933357889061Amith Yamasani                                mUserId);
23964442c11555d828a41af0b8a58ab933357889061Amith Yamasani                        if (searchable != null) {
24064442c11555d828a41af0b8a58ab933357889061Amith Yamasani                            newSearchablesList.add(searchable);
24164442c11555d828a41af0b8a58ab933357889061Amith Yamasani                            newSearchablesMap.put(searchable.getSearchActivity(), searchable);
24264442c11555d828a41af0b8a58ab933357889061Amith Yamasani                            if (searchable.shouldIncludeInGlobalSearch()) {
24364442c11555d828a41af0b8a58ab933357889061Amith Yamasani                                newSearchablesInGlobalSearchList.add(searchable);
24464442c11555d828a41af0b8a58ab933357889061Amith Yamasani                            }
245590f63433ce786722d263c7e913a88d3101e5cbcKarl Rosaen                        }
2466d72e029cb6e5a9cf26aa3314c3dca83614fc91bBjorn Bringert                    }
247875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen                }
248875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen            }
249f9acde27486bcc6eea1092073f7b47c31749efd6Satish Sampath
25064442c11555d828a41af0b8a58ab933357889061Amith Yamasani            List<ResolveInfo> newGlobalSearchActivities = findGlobalSearchActivities();
251ee69ff4eaee9342843d5f25338288865dda2d36aNarayan Kamath
25264442c11555d828a41af0b8a58ab933357889061Amith Yamasani            // Find the global search activity
25364442c11555d828a41af0b8a58ab933357889061Amith Yamasani            ComponentName newGlobalSearchActivity = findGlobalSearchActivity(
25464442c11555d828a41af0b8a58ab933357889061Amith Yamasani                    newGlobalSearchActivities);
255cbd8a246f86704fb348247245904a9f114f11280Satish Sampath
25664442c11555d828a41af0b8a58ab933357889061Amith Yamasani            // Find the web search activity
25764442c11555d828a41af0b8a58ab933357889061Amith Yamasani            ComponentName newWebSearchActivity = findWebSearchActivity(newGlobalSearchActivity);
258f9acde27486bcc6eea1092073f7b47c31749efd6Satish Sampath
25964442c11555d828a41af0b8a58ab933357889061Amith Yamasani            // Store a consistent set of new values
26064442c11555d828a41af0b8a58ab933357889061Amith Yamasani            synchronized (this) {
26164442c11555d828a41af0b8a58ab933357889061Amith Yamasani                mSearchablesMap = newSearchablesMap;
26264442c11555d828a41af0b8a58ab933357889061Amith Yamasani                mSearchablesList = newSearchablesList;
26364442c11555d828a41af0b8a58ab933357889061Amith Yamasani                mSearchablesInGlobalSearchList = newSearchablesInGlobalSearchList;
26464442c11555d828a41af0b8a58ab933357889061Amith Yamasani                mGlobalSearchActivities = newGlobalSearchActivities;
26564442c11555d828a41af0b8a58ab933357889061Amith Yamasani                mCurrentGlobalSearchActivity = newGlobalSearchActivity;
26664442c11555d828a41af0b8a58ab933357889061Amith Yamasani                mWebSearchActivity = newWebSearchActivity;
26764442c11555d828a41af0b8a58ab933357889061Amith Yamasani            }
26864442c11555d828a41af0b8a58ab933357889061Amith Yamasani        } finally {
26964442c11555d828a41af0b8a58ab933357889061Amith Yamasani            Binder.restoreCallingIdentity(ident);
270875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen        }
271875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen    }
27264442c11555d828a41af0b8a58ab933357889061Amith Yamasani
273ee69ff4eaee9342843d5f25338288865dda2d36aNarayan Kamath    /**
274ee69ff4eaee9342843d5f25338288865dda2d36aNarayan Kamath     * Returns a sorted list of installed search providers as per
275ee69ff4eaee9342843d5f25338288865dda2d36aNarayan Kamath     * the following heuristics:
276ee69ff4eaee9342843d5f25338288865dda2d36aNarayan Kamath     *
277ee69ff4eaee9342843d5f25338288865dda2d36aNarayan Kamath     * (a) System apps are given priority over non system apps.
278ee69ff4eaee9342843d5f25338288865dda2d36aNarayan Kamath     * (b) Among system apps and non system apps, the relative ordering
279ee69ff4eaee9342843d5f25338288865dda2d36aNarayan Kamath     * is defined by their declared priority.
280ee69ff4eaee9342843d5f25338288865dda2d36aNarayan Kamath     */
281ee69ff4eaee9342843d5f25338288865dda2d36aNarayan Kamath    private List<ResolveInfo> findGlobalSearchActivities() {
282ee69ff4eaee9342843d5f25338288865dda2d36aNarayan Kamath        // Step 1 : Query the package manager for a list
283ee69ff4eaee9342843d5f25338288865dda2d36aNarayan Kamath        // of activities that can handle the GLOBAL_SEARCH intent.
284ee69ff4eaee9342843d5f25338288865dda2d36aNarayan Kamath        Intent intent = new Intent(SearchManager.INTENT_ACTION_GLOBAL_SEARCH);
285ee69ff4eaee9342843d5f25338288865dda2d36aNarayan Kamath        List<ResolveInfo> activities =
2865bb87cd9b81506b0c25d3f9184e406762a9e9d9cAmith Yamasani                    queryIntentActivities(intent, PackageManager.MATCH_DEFAULT_ONLY);
287ee69ff4eaee9342843d5f25338288865dda2d36aNarayan Kamath        if (activities != null && !activities.isEmpty()) {
288ee69ff4eaee9342843d5f25338288865dda2d36aNarayan Kamath            // Step 2: Rank matching activities according to our heuristics.
289ee69ff4eaee9342843d5f25338288865dda2d36aNarayan Kamath            Collections.sort(activities, GLOBAL_SEARCH_RANKER);
290ee69ff4eaee9342843d5f25338288865dda2d36aNarayan Kamath        }
291ee69ff4eaee9342843d5f25338288865dda2d36aNarayan Kamath
292ee69ff4eaee9342843d5f25338288865dda2d36aNarayan Kamath        return activities;
293ee69ff4eaee9342843d5f25338288865dda2d36aNarayan Kamath    }
294f9acde27486bcc6eea1092073f7b47c31749efd6Satish Sampath
295f9acde27486bcc6eea1092073f7b47c31749efd6Satish Sampath    /**
2966cf7a325e6e9e70d9858e21fbb438341332ed254Bjorn Bringert     * Finds the global search activity.
297f9acde27486bcc6eea1092073f7b47c31749efd6Satish Sampath     */
298ee69ff4eaee9342843d5f25338288865dda2d36aNarayan Kamath    private ComponentName findGlobalSearchActivity(List<ResolveInfo> installed) {
299ee69ff4eaee9342843d5f25338288865dda2d36aNarayan Kamath        // Fetch the global search provider from the system settings,
300ee69ff4eaee9342843d5f25338288865dda2d36aNarayan Kamath        // and if it's still installed, return it.
301ee69ff4eaee9342843d5f25338288865dda2d36aNarayan Kamath        final String searchProviderSetting = getGlobalSearchProviderSetting();
302ee69ff4eaee9342843d5f25338288865dda2d36aNarayan Kamath        if (!TextUtils.isEmpty(searchProviderSetting)) {
303ee69ff4eaee9342843d5f25338288865dda2d36aNarayan Kamath            final ComponentName globalSearchComponent = ComponentName.unflattenFromString(
304ee69ff4eaee9342843d5f25338288865dda2d36aNarayan Kamath                    searchProviderSetting);
305ee69ff4eaee9342843d5f25338288865dda2d36aNarayan Kamath            if (globalSearchComponent != null && isInstalled(globalSearchComponent)) {
306ee69ff4eaee9342843d5f25338288865dda2d36aNarayan Kamath                return globalSearchComponent;
307ee69ff4eaee9342843d5f25338288865dda2d36aNarayan Kamath            }
308ee69ff4eaee9342843d5f25338288865dda2d36aNarayan Kamath        }
309ee69ff4eaee9342843d5f25338288865dda2d36aNarayan Kamath
310ee69ff4eaee9342843d5f25338288865dda2d36aNarayan Kamath        return getDefaultGlobalSearchProvider(installed);
311ee69ff4eaee9342843d5f25338288865dda2d36aNarayan Kamath    }
312ee69ff4eaee9342843d5f25338288865dda2d36aNarayan Kamath
313ee69ff4eaee9342843d5f25338288865dda2d36aNarayan Kamath    /**
314ee69ff4eaee9342843d5f25338288865dda2d36aNarayan Kamath     * Checks whether the global search provider with a given
315ee69ff4eaee9342843d5f25338288865dda2d36aNarayan Kamath     * component name is installed on the system or not. This deals with
316ee69ff4eaee9342843d5f25338288865dda2d36aNarayan Kamath     * cases such as the removal of an installed provider.
317ee69ff4eaee9342843d5f25338288865dda2d36aNarayan Kamath     */
318ee69ff4eaee9342843d5f25338288865dda2d36aNarayan Kamath    private boolean isInstalled(ComponentName globalSearch) {
3196cf7a325e6e9e70d9858e21fbb438341332ed254Bjorn Bringert        Intent intent = new Intent(SearchManager.INTENT_ACTION_GLOBAL_SEARCH);
320ee69ff4eaee9342843d5f25338288865dda2d36aNarayan Kamath        intent.setComponent(globalSearch);
321ee69ff4eaee9342843d5f25338288865dda2d36aNarayan Kamath
3225bb87cd9b81506b0c25d3f9184e406762a9e9d9cAmith Yamasani        List<ResolveInfo> activities = queryIntentActivities(intent,
3235bb87cd9b81506b0c25d3f9184e406762a9e9d9cAmith Yamasani                PackageManager.MATCH_DEFAULT_ONLY);
324ee69ff4eaee9342843d5f25338288865dda2d36aNarayan Kamath        if (activities != null && !activities.isEmpty()) {
325ee69ff4eaee9342843d5f25338288865dda2d36aNarayan Kamath            return true;
326ee69ff4eaee9342843d5f25338288865dda2d36aNarayan Kamath        }
327ee69ff4eaee9342843d5f25338288865dda2d36aNarayan Kamath
328ee69ff4eaee9342843d5f25338288865dda2d36aNarayan Kamath        return false;
329ee69ff4eaee9342843d5f25338288865dda2d36aNarayan Kamath    }
330ee69ff4eaee9342843d5f25338288865dda2d36aNarayan Kamath
331ee69ff4eaee9342843d5f25338288865dda2d36aNarayan Kamath    private static final Comparator<ResolveInfo> GLOBAL_SEARCH_RANKER =
332ee69ff4eaee9342843d5f25338288865dda2d36aNarayan Kamath            new Comparator<ResolveInfo>() {
333ee69ff4eaee9342843d5f25338288865dda2d36aNarayan Kamath        @Override
334ee69ff4eaee9342843d5f25338288865dda2d36aNarayan Kamath        public int compare(ResolveInfo lhs, ResolveInfo rhs) {
335ee69ff4eaee9342843d5f25338288865dda2d36aNarayan Kamath            if (lhs == rhs) {
336ee69ff4eaee9342843d5f25338288865dda2d36aNarayan Kamath                return 0;
337ee69ff4eaee9342843d5f25338288865dda2d36aNarayan Kamath            }
338ee69ff4eaee9342843d5f25338288865dda2d36aNarayan Kamath            boolean lhsSystem = isSystemApp(lhs);
339ee69ff4eaee9342843d5f25338288865dda2d36aNarayan Kamath            boolean rhsSystem = isSystemApp(rhs);
340ee69ff4eaee9342843d5f25338288865dda2d36aNarayan Kamath
341ee69ff4eaee9342843d5f25338288865dda2d36aNarayan Kamath            if (lhsSystem && !rhsSystem) {
342ee69ff4eaee9342843d5f25338288865dda2d36aNarayan Kamath                return -1;
343ee69ff4eaee9342843d5f25338288865dda2d36aNarayan Kamath            } else if (rhsSystem && !lhsSystem) {
344ee69ff4eaee9342843d5f25338288865dda2d36aNarayan Kamath                return 1;
3456cf7a325e6e9e70d9858e21fbb438341332ed254Bjorn Bringert            } else {
346ee69ff4eaee9342843d5f25338288865dda2d36aNarayan Kamath                // Either both system engines, or both non system
347ee69ff4eaee9342843d5f25338288865dda2d36aNarayan Kamath                // engines.
348ee69ff4eaee9342843d5f25338288865dda2d36aNarayan Kamath                //
349ee69ff4eaee9342843d5f25338288865dda2d36aNarayan Kamath                // Note, this isn't a typo. Higher priority numbers imply
350ee69ff4eaee9342843d5f25338288865dda2d36aNarayan Kamath                // higher priority, but are "lower" in the sort order.
351ee69ff4eaee9342843d5f25338288865dda2d36aNarayan Kamath                return rhs.priority - lhs.priority;
3526cf7a325e6e9e70d9858e21fbb438341332ed254Bjorn Bringert            }
353f9acde27486bcc6eea1092073f7b47c31749efd6Satish Sampath        }
354ee69ff4eaee9342843d5f25338288865dda2d36aNarayan Kamath    };
355ee69ff4eaee9342843d5f25338288865dda2d36aNarayan Kamath
356ee69ff4eaee9342843d5f25338288865dda2d36aNarayan Kamath    /**
357ee69ff4eaee9342843d5f25338288865dda2d36aNarayan Kamath     * @return true iff. the resolve info corresponds to a system application.
358ee69ff4eaee9342843d5f25338288865dda2d36aNarayan Kamath     */
359ee69ff4eaee9342843d5f25338288865dda2d36aNarayan Kamath    private static final boolean isSystemApp(ResolveInfo res) {
360ee69ff4eaee9342843d5f25338288865dda2d36aNarayan Kamath        return (res.activityInfo.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0;
361ee69ff4eaee9342843d5f25338288865dda2d36aNarayan Kamath    }
362ee69ff4eaee9342843d5f25338288865dda2d36aNarayan Kamath
363ee69ff4eaee9342843d5f25338288865dda2d36aNarayan Kamath    /**
364ee69ff4eaee9342843d5f25338288865dda2d36aNarayan Kamath     * Returns the highest ranked search provider as per the
365ee69ff4eaee9342843d5f25338288865dda2d36aNarayan Kamath     * ranking defined in {@link #getGlobalSearchActivities()}.
366ee69ff4eaee9342843d5f25338288865dda2d36aNarayan Kamath     */
367ee69ff4eaee9342843d5f25338288865dda2d36aNarayan Kamath    private ComponentName getDefaultGlobalSearchProvider(List<ResolveInfo> providerList) {
368ee69ff4eaee9342843d5f25338288865dda2d36aNarayan Kamath        if (providerList != null && !providerList.isEmpty()) {
369ee69ff4eaee9342843d5f25338288865dda2d36aNarayan Kamath            ActivityInfo ai = providerList.get(0).activityInfo;
370ee69ff4eaee9342843d5f25338288865dda2d36aNarayan Kamath            return new ComponentName(ai.packageName, ai.name);
371ee69ff4eaee9342843d5f25338288865dda2d36aNarayan Kamath        }
372ee69ff4eaee9342843d5f25338288865dda2d36aNarayan Kamath
3736cf7a325e6e9e70d9858e21fbb438341332ed254Bjorn Bringert        Log.w(LOG_TAG, "No global search activity found");
3746cf7a325e6e9e70d9858e21fbb438341332ed254Bjorn Bringert        return null;
375f9acde27486bcc6eea1092073f7b47c31749efd6Satish Sampath    }
376f9acde27486bcc6eea1092073f7b47c31749efd6Satish Sampath
377ee69ff4eaee9342843d5f25338288865dda2d36aNarayan Kamath    private String getGlobalSearchProviderSetting() {
378ee69ff4eaee9342843d5f25338288865dda2d36aNarayan Kamath        return Settings.Secure.getString(mContext.getContentResolver(),
379ee69ff4eaee9342843d5f25338288865dda2d36aNarayan Kamath                Settings.Secure.SEARCH_GLOBAL_SEARCH_ACTIVITY);
380ee69ff4eaee9342843d5f25338288865dda2d36aNarayan Kamath    }
381ee69ff4eaee9342843d5f25338288865dda2d36aNarayan Kamath
3826cf7a325e6e9e70d9858e21fbb438341332ed254Bjorn Bringert    /**
3836cf7a325e6e9e70d9858e21fbb438341332ed254Bjorn Bringert     * Finds the web search activity.
3846cf7a325e6e9e70d9858e21fbb438341332ed254Bjorn Bringert     *
3856cf7a325e6e9e70d9858e21fbb438341332ed254Bjorn Bringert     * Only looks in the package of the global search activity.
3866cf7a325e6e9e70d9858e21fbb438341332ed254Bjorn Bringert     */
3876cf7a325e6e9e70d9858e21fbb438341332ed254Bjorn Bringert    private ComponentName findWebSearchActivity(ComponentName globalSearchActivity) {
3886cf7a325e6e9e70d9858e21fbb438341332ed254Bjorn Bringert        if (globalSearchActivity == null) {
3896cf7a325e6e9e70d9858e21fbb438341332ed254Bjorn Bringert            return null;
3906cf7a325e6e9e70d9858e21fbb438341332ed254Bjorn Bringert        }
391f9acde27486bcc6eea1092073f7b47c31749efd6Satish Sampath        Intent intent = new Intent(Intent.ACTION_WEB_SEARCH);
3926cf7a325e6e9e70d9858e21fbb438341332ed254Bjorn Bringert        intent.setPackage(globalSearchActivity.getPackageName());
3936cf7a325e6e9e70d9858e21fbb438341332ed254Bjorn Bringert        List<ResolveInfo> activities =
3945bb87cd9b81506b0c25d3f9184e406762a9e9d9cAmith Yamasani                queryIntentActivities(intent, PackageManager.MATCH_DEFAULT_ONLY);
395ee69ff4eaee9342843d5f25338288865dda2d36aNarayan Kamath
396ee69ff4eaee9342843d5f25338288865dda2d36aNarayan Kamath        if (activities != null && !activities.isEmpty()) {
397ee69ff4eaee9342843d5f25338288865dda2d36aNarayan Kamath            ActivityInfo ai = activities.get(0).activityInfo;
3986cf7a325e6e9e70d9858e21fbb438341332ed254Bjorn Bringert            // TODO: do some sanity checks here?
3996cf7a325e6e9e70d9858e21fbb438341332ed254Bjorn Bringert            return new ComponentName(ai.packageName, ai.name);
400f9acde27486bcc6eea1092073f7b47c31749efd6Satish Sampath        }
4016cf7a325e6e9e70d9858e21fbb438341332ed254Bjorn Bringert        Log.w(LOG_TAG, "No web search activity found");
4026cf7a325e6e9e70d9858e21fbb438341332ed254Bjorn Bringert        return null;
403f9acde27486bcc6eea1092073f7b47c31749efd6Satish Sampath    }
404f9acde27486bcc6eea1092073f7b47c31749efd6Satish Sampath
4055bb87cd9b81506b0c25d3f9184e406762a9e9d9cAmith Yamasani    private List<ResolveInfo> queryIntentActivities(Intent intent, int flags) {
4065bb87cd9b81506b0c25d3f9184e406762a9e9d9cAmith Yamasani        List<ResolveInfo> activities = null;
4075bb87cd9b81506b0c25d3f9184e406762a9e9d9cAmith Yamasani        try {
4085bb87cd9b81506b0c25d3f9184e406762a9e9d9cAmith Yamasani            activities =
4095bb87cd9b81506b0c25d3f9184e406762a9e9d9cAmith Yamasani                    mPm.queryIntentActivities(intent,
4105bb87cd9b81506b0c25d3f9184e406762a9e9d9cAmith Yamasani                    intent.resolveTypeIfNeeded(mContext.getContentResolver()),
4115bb87cd9b81506b0c25d3f9184e406762a9e9d9cAmith Yamasani                    flags, mUserId);
4125bb87cd9b81506b0c25d3f9184e406762a9e9d9cAmith Yamasani        } catch (RemoteException re) {
4135bb87cd9b81506b0c25d3f9184e406762a9e9d9cAmith Yamasani            // Local call
4145bb87cd9b81506b0c25d3f9184e406762a9e9d9cAmith Yamasani        }
4155bb87cd9b81506b0c25d3f9184e406762a9e9d9cAmith Yamasani        return activities;
4165bb87cd9b81506b0c25d3f9184e406762a9e9d9cAmith Yamasani    }
4175bb87cd9b81506b0c25d3f9184e406762a9e9d9cAmith Yamasani
418875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen    /**
419875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen     * Returns the list of searchable activities.
420875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen     */
421875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen    public synchronized ArrayList<SearchableInfo> getSearchablesList() {
422875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen        ArrayList<SearchableInfo> result = new ArrayList<SearchableInfo>(mSearchablesList);
423875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen        return result;
424875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen    }
425f9acde27486bcc6eea1092073f7b47c31749efd6Satish Sampath
4266d72e029cb6e5a9cf26aa3314c3dca83614fc91bBjorn Bringert    /**
4276d72e029cb6e5a9cf26aa3314c3dca83614fc91bBjorn Bringert     * Returns a list of the searchable activities that can be included in global search.
4286d72e029cb6e5a9cf26aa3314c3dca83614fc91bBjorn Bringert     */
4296d72e029cb6e5a9cf26aa3314c3dca83614fc91bBjorn Bringert    public synchronized ArrayList<SearchableInfo> getSearchablesInGlobalSearchList() {
4306d72e029cb6e5a9cf26aa3314c3dca83614fc91bBjorn Bringert        return new ArrayList<SearchableInfo>(mSearchablesInGlobalSearchList);
4316d72e029cb6e5a9cf26aa3314c3dca83614fc91bBjorn Bringert    }
432f9acde27486bcc6eea1092073f7b47c31749efd6Satish Sampath
433f9acde27486bcc6eea1092073f7b47c31749efd6Satish Sampath    /**
434ee69ff4eaee9342843d5f25338288865dda2d36aNarayan Kamath     * Returns a list of activities that handle the global search intent.
435ee69ff4eaee9342843d5f25338288865dda2d36aNarayan Kamath     */
436ee69ff4eaee9342843d5f25338288865dda2d36aNarayan Kamath    public synchronized ArrayList<ResolveInfo> getGlobalSearchActivities() {
437ee69ff4eaee9342843d5f25338288865dda2d36aNarayan Kamath        return new ArrayList<ResolveInfo>(mGlobalSearchActivities);
438ee69ff4eaee9342843d5f25338288865dda2d36aNarayan Kamath    }
439ee69ff4eaee9342843d5f25338288865dda2d36aNarayan Kamath
440ee69ff4eaee9342843d5f25338288865dda2d36aNarayan Kamath    /**
4416cf7a325e6e9e70d9858e21fbb438341332ed254Bjorn Bringert     * Gets the name of the global search activity.
442f9acde27486bcc6eea1092073f7b47c31749efd6Satish Sampath     */
4436cf7a325e6e9e70d9858e21fbb438341332ed254Bjorn Bringert    public synchronized ComponentName getGlobalSearchActivity() {
444ee69ff4eaee9342843d5f25338288865dda2d36aNarayan Kamath        return mCurrentGlobalSearchActivity;
445f9acde27486bcc6eea1092073f7b47c31749efd6Satish Sampath    }
446f9acde27486bcc6eea1092073f7b47c31749efd6Satish Sampath
447f9acde27486bcc6eea1092073f7b47c31749efd6Satish Sampath    /**
4486cf7a325e6e9e70d9858e21fbb438341332ed254Bjorn Bringert     * Gets the name of the web search activity.
449f9acde27486bcc6eea1092073f7b47c31749efd6Satish Sampath     */
4506cf7a325e6e9e70d9858e21fbb438341332ed254Bjorn Bringert    public synchronized ComponentName getWebSearchActivity() {
4516cf7a325e6e9e70d9858e21fbb438341332ed254Bjorn Bringert        return mWebSearchActivity;
452f9acde27486bcc6eea1092073f7b47c31749efd6Satish Sampath    }
45364442c11555d828a41af0b8a58ab933357889061Amith Yamasani
45464442c11555d828a41af0b8a58ab933357889061Amith Yamasani    void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
45564442c11555d828a41af0b8a58ab933357889061Amith Yamasani        pw.println("Searchable authorities:");
45664442c11555d828a41af0b8a58ab933357889061Amith Yamasani        synchronized (this) {
45764442c11555d828a41af0b8a58ab933357889061Amith Yamasani            if (mSearchablesList != null) {
45864442c11555d828a41af0b8a58ab933357889061Amith Yamasani                for (SearchableInfo info: mSearchablesList) {
45964442c11555d828a41af0b8a58ab933357889061Amith Yamasani                    pw.print("  "); pw.println(info.getSuggestAuthority());
46064442c11555d828a41af0b8a58ab933357889061Amith Yamasani                }
46164442c11555d828a41af0b8a58ab933357889061Amith Yamasani            }
46264442c11555d828a41af0b8a58ab933357889061Amith Yamasani        }
46364442c11555d828a41af0b8a58ab933357889061Amith Yamasani    }
464875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen}
465