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