Searchables.java revision 6d72e029cb6e5a9cf26aa3314c3dca83614fc91b
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; 20875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaenimport android.content.ComponentName; 21875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaenimport android.content.Context; 22875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaenimport android.content.Intent; 23875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaenimport android.content.pm.ActivityInfo; 24875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaenimport android.content.pm.PackageManager; 25875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaenimport android.content.pm.ResolveInfo; 26875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaenimport android.os.Bundle; 27875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen 28875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaenimport java.util.ArrayList; 29875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaenimport java.util.HashMap; 30875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaenimport java.util.List; 31875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen 32875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen/** 33875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen * This class maintains the information about all searchable activities. 34875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen */ 35875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaenpublic class Searchables { 36875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen 37875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen // static strings used for XML lookups, etc. 38875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen // TODO how should these be documented for the developer, in a more structured way than 39875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen // the current long wordy javadoc in SearchManager.java ? 40875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen private static final String MD_LABEL_DEFAULT_SEARCHABLE = "android.app.default_searchable"; 41875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen private static final String MD_SEARCHABLE_SYSTEM_SEARCH = "*"; 42875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen 43875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen private Context mContext; 44875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen 45875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen private HashMap<ComponentName, SearchableInfo> mSearchablesMap = null; 46875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen private ArrayList<SearchableInfo> mSearchablesList = null; 476d72e029cb6e5a9cf26aa3314c3dca83614fc91bBjorn Bringert private ArrayList<SearchableInfo> mSearchablesInGlobalSearchList = null; 48875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen private SearchableInfo mDefaultSearchable = null; 49875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen 50875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen /** 51875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen * 52875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen * @param context Context to use for looking up activities etc. 53875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen */ 54875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen public Searchables (Context context) { 55875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen mContext = context; 56875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen } 57875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen 58875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen /** 59875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen * Look up, or construct, based on the activity. 60875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen * 61875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen * The activities fall into three cases, based on meta-data found in 62875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen * the manifest entry: 63875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen * <ol> 64875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen * <li>The activity itself implements search. This is indicated by the 65875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen * presence of a "android.app.searchable" meta-data attribute. 66875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen * The value is a reference to an XML file containing search information.</li> 67875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen * <li>A related activity implements search. This is indicated by the 68875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen * presence of a "android.app.default_searchable" meta-data attribute. 69875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen * The value is a string naming the activity implementing search. In this 70875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen * case the factory will "redirect" and return the searchable data.</li> 71875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen * <li>No searchability data is provided. We return null here and other 72875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen * code will insert the "default" (e.g. contacts) search. 73875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen * 74875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen * TODO: cache the result in the map, and check the map first. 75875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen * TODO: it might make sense to implement the searchable reference as 76875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen * an application meta-data entry. This way we don't have to pepper each 77875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen * and every activity. 78875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen * TODO: can we skip the constructor step if it's a non-searchable? 79875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen * TODO: does it make sense to plug the default into a slot here for 80875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen * automatic return? Probably not, but it's one way to do it. 81875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen * 82875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen * @param activity The name of the current activity, or null if the 83875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen * activity does not define any explicit searchable metadata. 84875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen */ 85875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen public SearchableInfo getSearchableInfo(ComponentName activity) { 86875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen // Step 1. Is the result already hashed? (case 1) 87875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen SearchableInfo result; 88875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen synchronized (this) { 89875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen result = mSearchablesMap.get(activity); 90875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen if (result != null) return result; 91875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen } 92875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen 93875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen // Step 2. See if the current activity references a searchable. 94875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen // Note: Conceptually, this could be a while(true) loop, but there's 95875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen // no point in implementing reference chaining here and risking a loop. 96875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen // References must point directly to searchable activities. 97875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen 98875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen ActivityInfo ai = null; 99875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen try { 100875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen ai = mContext.getPackageManager(). 101875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen getActivityInfo(activity, PackageManager.GET_META_DATA ); 102875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen String refActivityName = null; 103875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen 104875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen // First look for activity-specific reference 105875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen Bundle md = ai.metaData; 106875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen if (md != null) { 107875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen refActivityName = md.getString(MD_LABEL_DEFAULT_SEARCHABLE); 108875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen } 109875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen // If not found, try for app-wide reference 110875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen if (refActivityName == null) { 111875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen md = ai.applicationInfo.metaData; 112875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen if (md != null) { 113875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen refActivityName = md.getString(MD_LABEL_DEFAULT_SEARCHABLE); 114875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen } 115875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen } 116875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen 117875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen // Irrespective of source, if a reference was found, follow it. 118875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen if (refActivityName != null) 119875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen { 120875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen // An app or activity can declare that we should simply launch 121875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen // "system default search" if search is invoked. 122875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen if (refActivityName.equals(MD_SEARCHABLE_SYSTEM_SEARCH)) { 123875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen return getDefaultSearchable(); 124875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen } 125875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen String pkg = activity.getPackageName(); 126875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen ComponentName referredActivity; 127875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen if (refActivityName.charAt(0) == '.') { 128875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen referredActivity = new ComponentName(pkg, pkg + refActivityName); 129875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen } else { 130875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen referredActivity = new ComponentName(pkg, refActivityName); 131875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen } 132875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen 133875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen // Now try the referred activity, and if found, cache 134875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen // it against the original name so we can skip the check 135875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen synchronized (this) { 136875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen result = mSearchablesMap.get(referredActivity); 137875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen if (result != null) { 138875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen mSearchablesMap.put(activity, result); 139875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen return result; 140875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen } 141875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen } 142875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen } 143875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen } catch (PackageManager.NameNotFoundException e) { 144875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen // case 3: no metadata 145875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen } 146875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen 147875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen // Step 3. None found. Return null. 148875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen return null; 149875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen 150875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen } 151875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen 152875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen /** 153875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen * Provides the system-default search activity, which you can use 154875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen * whenever getSearchableInfo() returns null; 155875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen * 156875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen * @return Returns the system-default search activity, null if never defined 157875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen */ 158875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen public synchronized SearchableInfo getDefaultSearchable() { 159875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen return mDefaultSearchable; 160875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen } 161875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen 162875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen public synchronized boolean isDefaultSearchable(SearchableInfo searchable) { 163875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen return searchable == mDefaultSearchable; 164875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen } 165875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen 166875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen /** 167875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen * Builds an entire list (suitable for display) of 168875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen * activities that are searchable, by iterating the entire set of 169875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen * ACTION_SEARCH intents. 170875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen * 171875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen * Also clears the hash of all activities -> searches which will 172875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen * refill as the user clicks "search". 173875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen * 174875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen * This should only be done at startup and again if we know that the 175875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen * list has changed. 176875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen * 177875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen * TODO: every activity that provides a ACTION_SEARCH intent should 178875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen * also provide searchability meta-data. There are a bunch of checks here 179875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen * that, if data is not found, silently skip to the next activity. This 180875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen * won't help a developer trying to figure out why their activity isn't 181875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen * showing up in the list, but an exception here is too rough. I would 182875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen * like to find a better notification mechanism. 183875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen * 184875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen * TODO: sort the list somehow? UI choice. 185875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen */ 186875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen public void buildSearchableList() { 187875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen 18874708bbdf8d6f172b08343bdc578a20aa4b39148Bjorn Bringert // These will become the new values at the end of the method 189875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen HashMap<ComponentName, SearchableInfo> newSearchablesMap 190875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen = new HashMap<ComponentName, SearchableInfo>(); 191875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen ArrayList<SearchableInfo> newSearchablesList 192875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen = new ArrayList<SearchableInfo>(); 1936d72e029cb6e5a9cf26aa3314c3dca83614fc91bBjorn Bringert ArrayList<SearchableInfo> newSearchablesInGlobalSearchList 1946d72e029cb6e5a9cf26aa3314c3dca83614fc91bBjorn Bringert = new ArrayList<SearchableInfo>(); 195875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen 196875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen final PackageManager pm = mContext.getPackageManager(); 19774708bbdf8d6f172b08343bdc578a20aa4b39148Bjorn Bringert 19874708bbdf8d6f172b08343bdc578a20aa4b39148Bjorn Bringert // use intent resolver to generate list of ACTION_SEARCH receivers 199875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen List<ResolveInfo> infoList; 200875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen final Intent intent = new Intent(Intent.ACTION_SEARCH); 201875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen infoList = pm.queryIntentActivities(intent, PackageManager.GET_META_DATA); 202875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen 203875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen // analyze each one, generate a Searchables record, and record 204875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen if (infoList != null) { 205875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen int count = infoList.size(); 206875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen for (int ii = 0; ii < count; ii++) { 207875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen // for each component, try to find metadata 208875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen ResolveInfo info = infoList.get(ii); 209875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen ActivityInfo ai = info.activityInfo; 210875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen SearchableInfo searchable = SearchableInfo.getActivityMetaData(mContext, ai); 211875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen if (searchable != null) { 212875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen newSearchablesList.add(searchable); 213875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen newSearchablesMap.put(searchable.mSearchActivity, searchable); 2146d72e029cb6e5a9cf26aa3314c3dca83614fc91bBjorn Bringert if (searchable.shouldIncludeInGlobalSearch()) { 2156d72e029cb6e5a9cf26aa3314c3dca83614fc91bBjorn Bringert newSearchablesInGlobalSearchList.add(searchable); 2166d72e029cb6e5a9cf26aa3314c3dca83614fc91bBjorn Bringert } 217875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen } 218875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen } 219875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen } 220875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen 22174708bbdf8d6f172b08343bdc578a20aa4b39148Bjorn Bringert // Find the global search provider 22274708bbdf8d6f172b08343bdc578a20aa4b39148Bjorn Bringert Intent globalSearchIntent = new Intent(SearchManager.INTENT_ACTION_GLOBAL_SEARCH); 22374708bbdf8d6f172b08343bdc578a20aa4b39148Bjorn Bringert ComponentName globalSearchActivity = globalSearchIntent.resolveActivity(pm); 22474708bbdf8d6f172b08343bdc578a20aa4b39148Bjorn Bringert SearchableInfo newDefaultSearchable = newSearchablesMap.get(globalSearchActivity); 22574708bbdf8d6f172b08343bdc578a20aa4b39148Bjorn Bringert 22674708bbdf8d6f172b08343bdc578a20aa4b39148Bjorn Bringert // Store a consistent set of new values 227875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen synchronized (this) { 228875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen mSearchablesMap = newSearchablesMap; 2296d72e029cb6e5a9cf26aa3314c3dca83614fc91bBjorn Bringert mSearchablesList = newSearchablesList; 2306d72e029cb6e5a9cf26aa3314c3dca83614fc91bBjorn Bringert mSearchablesInGlobalSearchList = newSearchablesInGlobalSearchList; 23174708bbdf8d6f172b08343bdc578a20aa4b39148Bjorn Bringert mDefaultSearchable = newDefaultSearchable; 232875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen } 233875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen } 234875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen 235875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen /** 236875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen * Returns the list of searchable activities. 237875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen */ 238875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen public synchronized ArrayList<SearchableInfo> getSearchablesList() { 239875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen ArrayList<SearchableInfo> result = new ArrayList<SearchableInfo>(mSearchablesList); 240875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen return result; 241875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen } 2426d72e029cb6e5a9cf26aa3314c3dca83614fc91bBjorn Bringert 2436d72e029cb6e5a9cf26aa3314c3dca83614fc91bBjorn Bringert /** 2446d72e029cb6e5a9cf26aa3314c3dca83614fc91bBjorn Bringert * Returns a list of the searchable activities that can be included in global search. 2456d72e029cb6e5a9cf26aa3314c3dca83614fc91bBjorn Bringert */ 2466d72e029cb6e5a9cf26aa3314c3dca83614fc91bBjorn Bringert public synchronized ArrayList<SearchableInfo> getSearchablesInGlobalSearchList() { 2476d72e029cb6e5a9cf26aa3314c3dca83614fc91bBjorn Bringert return new ArrayList<SearchableInfo>(mSearchablesInGlobalSearchList); 2486d72e029cb6e5a9cf26aa3314c3dca83614fc91bBjorn Bringert } 249875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen} 250