blob: 6bacdfdafbda1472addcaa3cada4072a8c5ecd0a [file] [log] [blame]
Karl Rosaen875d50a2009-04-23 19:00:21 -07001/*
2 * Copyright (C) 2009 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
Jeff Sharkey7a96c392012-11-15 14:01:46 -080017package com.android.server.search;
Karl Rosaen875d50a2009-04-23 19:00:21 -070018
Amith Yamasani5bb87cd2012-06-14 11:32:13 -070019import android.app.AppGlobals;
Bjorn Bringert74708bb2009-04-28 11:26:52 +010020import android.app.SearchManager;
Bjorn Bringert2126aac2009-12-03 15:48:19 +000021import android.app.SearchableInfo;
Karl Rosaen875d50a2009-04-23 19:00:21 -070022import android.content.ComponentName;
23import android.content.Context;
24import android.content.Intent;
25import android.content.pm.ActivityInfo;
Narayan Kamathee69ff42011-06-28 12:07:18 +010026import android.content.pm.ApplicationInfo;
Amith Yamasani5bb87cd2012-06-14 11:32:13 -070027import android.content.pm.IPackageManager;
Karl Rosaen875d50a2009-04-23 19:00:21 -070028import android.content.pm.PackageManager;
29import android.content.pm.ResolveInfo;
Amith Yamasanif203aee2012-08-29 18:41:53 -070030import android.os.Binder;
Karl Rosaen875d50a2009-04-23 19:00:21 -070031import android.os.Bundle;
Amith Yamasani5bb87cd2012-06-14 11:32:13 -070032import android.os.RemoteException;
Narayan Kamathee69ff42011-06-28 12:07:18 +010033import android.provider.Settings;
34import android.text.TextUtils;
Satish Sampathcbd8a242009-05-15 21:47:07 +010035import android.util.Log;
Karl Rosaen875d50a2009-04-23 19:00:21 -070036
Amith Yamasani64442c12012-10-07 08:17:46 -070037import java.io.FileDescriptor;
38import java.io.PrintWriter;
Karl Rosaen875d50a2009-04-23 19:00:21 -070039import java.util.ArrayList;
Narayan Kamathee69ff42011-06-28 12:07:18 +010040import java.util.Collections;
41import java.util.Comparator;
Karl Rosaen875d50a2009-04-23 19:00:21 -070042import java.util.HashMap;
43import java.util.List;
44
45/**
Satish Sampathf9acde22009-06-04 11:51:17 +010046 * This class maintains the information about all searchable activities.
Amith Yamasani5bb87cd2012-06-14 11:32:13 -070047 * This is a hidden class.
Karl Rosaen875d50a2009-04-23 19:00:21 -070048 */
49public class Searchables {
50
Satish Sampathcbd8a242009-05-15 21:47:07 +010051 private static final String LOG_TAG = "Searchables";
52
Karl Rosaen875d50a2009-04-23 19:00:21 -070053 // static strings used for XML lookups, etc.
Satish Sampathf9acde22009-06-04 11:51:17 +010054 // TODO how should these be documented for the developer, in a more structured way than
Karl Rosaen875d50a2009-04-23 19:00:21 -070055 // the current long wordy javadoc in SearchManager.java ?
56 private static final String MD_LABEL_DEFAULT_SEARCHABLE = "android.app.default_searchable";
57 private static final String MD_SEARCHABLE_SYSTEM_SEARCH = "*";
Satish Sampathf9acde22009-06-04 11:51:17 +010058
Karl Rosaen875d50a2009-04-23 19:00:21 -070059 private Context mContext;
Satish Sampathf9acde22009-06-04 11:51:17 +010060
Karl Rosaen875d50a2009-04-23 19:00:21 -070061 private HashMap<ComponentName, SearchableInfo> mSearchablesMap = null;
62 private ArrayList<SearchableInfo> mSearchablesList = null;
Bjorn Bringert6d72e022009-04-29 14:56:12 +010063 private ArrayList<SearchableInfo> mSearchablesInGlobalSearchList = null;
Narayan Kamathee69ff42011-06-28 12:07:18 +010064 // Contains all installed activities that handle the global search
65 // intent.
66 private List<ResolveInfo> mGlobalSearchActivities;
67 private ComponentName mCurrentGlobalSearchActivity = null;
Bjorn Bringert6cf7a322010-02-23 13:17:06 +000068 private ComponentName mWebSearchActivity = null;
Satish Sampathf9acde22009-06-04 11:51:17 +010069
Satish Sampath41282a32009-06-23 17:05:35 +010070 public static String GOOGLE_SEARCH_COMPONENT_NAME =
71 "com.android.googlesearch/.GoogleSearch";
72 public static String ENHANCED_GOOGLE_SEARCH_COMPONENT_NAME =
73 "com.google.android.providers.enhancedgooglesearch/.Launcher";
74
Amith Yamasani5bb87cd2012-06-14 11:32:13 -070075 // Cache the package manager instance
Amith Yamasanif203aee2012-08-29 18:41:53 -070076 final private IPackageManager mPm;
Amith Yamasani5bb87cd2012-06-14 11:32:13 -070077 // User for which this Searchables caches information
78 private int mUserId;
79
Karl Rosaen875d50a2009-04-23 19:00:21 -070080 /**
Satish Sampathf9acde22009-06-04 11:51:17 +010081 *
Karl Rosaen875d50a2009-04-23 19:00:21 -070082 * @param context Context to use for looking up activities etc.
83 */
Amith Yamasani5bb87cd2012-06-14 11:32:13 -070084 public Searchables (Context context, int userId) {
Karl Rosaen875d50a2009-04-23 19:00:21 -070085 mContext = context;
Amith Yamasani5bb87cd2012-06-14 11:32:13 -070086 mUserId = userId;
Amith Yamasanif203aee2012-08-29 18:41:53 -070087 mPm = AppGlobals.getPackageManager();
Karl Rosaen875d50a2009-04-23 19:00:21 -070088 }
Satish Sampathf9acde22009-06-04 11:51:17 +010089
Karl Rosaen875d50a2009-04-23 19:00:21 -070090 /**
91 * Look up, or construct, based on the activity.
Satish Sampathf9acde22009-06-04 11:51:17 +010092 *
93 * The activities fall into three cases, based on meta-data found in
Karl Rosaen875d50a2009-04-23 19:00:21 -070094 * the manifest entry:
95 * <ol>
96 * <li>The activity itself implements search. This is indicated by the
97 * presence of a "android.app.searchable" meta-data attribute.
98 * The value is a reference to an XML file containing search information.</li>
99 * <li>A related activity implements search. This is indicated by the
100 * presence of a "android.app.default_searchable" meta-data attribute.
101 * The value is a string naming the activity implementing search. In this
102 * case the factory will "redirect" and return the searchable data.</li>
103 * <li>No searchability data is provided. We return null here and other
104 * code will insert the "default" (e.g. contacts) search.
Satish Sampathf9acde22009-06-04 11:51:17 +0100105 *
Karl Rosaen875d50a2009-04-23 19:00:21 -0700106 * TODO: cache the result in the map, and check the map first.
107 * TODO: it might make sense to implement the searchable reference as
108 * an application meta-data entry. This way we don't have to pepper each
109 * and every activity.
110 * TODO: can we skip the constructor step if it's a non-searchable?
Satish Sampathf9acde22009-06-04 11:51:17 +0100111 * TODO: does it make sense to plug the default into a slot here for
Karl Rosaen875d50a2009-04-23 19:00:21 -0700112 * automatic return? Probably not, but it's one way to do it.
113 *
Satish Sampathf9acde22009-06-04 11:51:17 +0100114 * @param activity The name of the current activity, or null if the
Karl Rosaen875d50a2009-04-23 19:00:21 -0700115 * activity does not define any explicit searchable metadata.
116 */
117 public SearchableInfo getSearchableInfo(ComponentName activity) {
118 // Step 1. Is the result already hashed? (case 1)
119 SearchableInfo result;
120 synchronized (this) {
121 result = mSearchablesMap.get(activity);
122 if (result != null) return result;
123 }
Satish Sampathf9acde22009-06-04 11:51:17 +0100124
Karl Rosaen875d50a2009-04-23 19:00:21 -0700125 // Step 2. See if the current activity references a searchable.
126 // Note: Conceptually, this could be a while(true) loop, but there's
Satish Sampathf9acde22009-06-04 11:51:17 +0100127 // no point in implementing reference chaining here and risking a loop.
Karl Rosaen875d50a2009-04-23 19:00:21 -0700128 // References must point directly to searchable activities.
Satish Sampathf9acde22009-06-04 11:51:17 +0100129
Karl Rosaen875d50a2009-04-23 19:00:21 -0700130 ActivityInfo ai = null;
131 try {
Amith Yamasanif203aee2012-08-29 18:41:53 -0700132 ai = mPm.getActivityInfo(activity, PackageManager.GET_META_DATA, mUserId);
133 } catch (RemoteException re) {
134 Log.e(LOG_TAG, "Error getting activity info " + re);
135 return null;
136 }
137 String refActivityName = null;
Satish Sampathf9acde22009-06-04 11:51:17 +0100138
Amith Yamasanif203aee2012-08-29 18:41:53 -0700139 // First look for activity-specific reference
140 Bundle md = ai.metaData;
141 if (md != null) {
142 refActivityName = md.getString(MD_LABEL_DEFAULT_SEARCHABLE);
143 }
144 // If not found, try for app-wide reference
145 if (refActivityName == null) {
146 md = ai.applicationInfo.metaData;
Karl Rosaen875d50a2009-04-23 19:00:21 -0700147 if (md != null) {
148 refActivityName = md.getString(MD_LABEL_DEFAULT_SEARCHABLE);
149 }
Amith Yamasanif203aee2012-08-29 18:41:53 -0700150 }
151
152 // Irrespective of source, if a reference was found, follow it.
153 if (refActivityName != null)
154 {
155 // This value is deprecated, return null
156 if (refActivityName.equals(MD_SEARCHABLE_SYSTEM_SEARCH)) {
157 return null;
158 }
159 String pkg = activity.getPackageName();
160 ComponentName referredActivity;
161 if (refActivityName.charAt(0) == '.') {
162 referredActivity = new ComponentName(pkg, pkg + refActivityName);
163 } else {
164 referredActivity = new ComponentName(pkg, refActivityName);
Karl Rosaen875d50a2009-04-23 19:00:21 -0700165 }
Satish Sampathf9acde22009-06-04 11:51:17 +0100166
Amith Yamasanif203aee2012-08-29 18:41:53 -0700167 // Now try the referred activity, and if found, cache
168 // it against the original name so we can skip the check
169 synchronized (this) {
170 result = mSearchablesMap.get(referredActivity);
171 if (result != null) {
172 mSearchablesMap.put(activity, result);
173 return result;
Karl Rosaen875d50a2009-04-23 19:00:21 -0700174 }
175 }
Karl Rosaen875d50a2009-04-23 19:00:21 -0700176 }
Satish Sampathf9acde22009-06-04 11:51:17 +0100177
Karl Rosaen875d50a2009-04-23 19:00:21 -0700178 // Step 3. None found. Return null.
179 return null;
Satish Sampathf9acde22009-06-04 11:51:17 +0100180
Karl Rosaen875d50a2009-04-23 19:00:21 -0700181 }
Satish Sampathf9acde22009-06-04 11:51:17 +0100182
Karl Rosaen875d50a2009-04-23 19:00:21 -0700183 /**
Satish Sampathf9acde22009-06-04 11:51:17 +0100184 * Builds an entire list (suitable for display) of
185 * activities that are searchable, by iterating the entire set of
186 * ACTION_SEARCH & ACTION_WEB_SEARCH intents.
187 *
Karl Rosaen875d50a2009-04-23 19:00:21 -0700188 * Also clears the hash of all activities -> searches which will
189 * refill as the user clicks "search".
Satish Sampathf9acde22009-06-04 11:51:17 +0100190 *
Karl Rosaen875d50a2009-04-23 19:00:21 -0700191 * This should only be done at startup and again if we know that the
192 * list has changed.
Satish Sampathf9acde22009-06-04 11:51:17 +0100193 *
Karl Rosaen875d50a2009-04-23 19:00:21 -0700194 * TODO: every activity that provides a ACTION_SEARCH intent should
195 * also provide searchability meta-data. There are a bunch of checks here
196 * that, if data is not found, silently skip to the next activity. This
197 * won't help a developer trying to figure out why their activity isn't
198 * showing up in the list, but an exception here is too rough. I would
199 * like to find a better notification mechanism.
Satish Sampathf9acde22009-06-04 11:51:17 +0100200 *
Karl Rosaen875d50a2009-04-23 19:00:21 -0700201 * TODO: sort the list somehow? UI choice.
202 */
Jeff Sharkey4175be22016-01-09 14:57:45 -0700203 public void updateSearchableList() {
Bjorn Bringert74708bb2009-04-28 11:26:52 +0100204 // These will become the new values at the end of the method
Satish Sampathf9acde22009-06-04 11:51:17 +0100205 HashMap<ComponentName, SearchableInfo> newSearchablesMap
Karl Rosaen875d50a2009-04-23 19:00:21 -0700206 = new HashMap<ComponentName, SearchableInfo>();
207 ArrayList<SearchableInfo> newSearchablesList
208 = new ArrayList<SearchableInfo>();
Bjorn Bringert6d72e022009-04-29 14:56:12 +0100209 ArrayList<SearchableInfo> newSearchablesInGlobalSearchList
210 = new ArrayList<SearchableInfo>();
Karl Rosaen875d50a2009-04-23 19:00:21 -0700211
Satish Sampathf9acde22009-06-04 11:51:17 +0100212 // Use intent resolver to generate list of ACTION_SEARCH & ACTION_WEB_SEARCH receivers.
213 List<ResolveInfo> searchList;
Karl Rosaen875d50a2009-04-23 19:00:21 -0700214 final Intent intent = new Intent(Intent.ACTION_SEARCH);
Satish Sampathf9acde22009-06-04 11:51:17 +0100215
Amith Yamasani64442c12012-10-07 08:17:46 -0700216 long ident = Binder.clearCallingIdentity();
217 try {
Jeff Sharkey4175be22016-01-09 14:57:45 -0700218 searchList = queryIntentActivities(intent,
219 PackageManager.GET_META_DATA | PackageManager.MATCH_DEBUG_TRIAGED_MISSING);
Satish Sampathf9acde22009-06-04 11:51:17 +0100220
Amith Yamasani64442c12012-10-07 08:17:46 -0700221 List<ResolveInfo> webSearchInfoList;
222 final Intent webSearchIntent = new Intent(Intent.ACTION_WEB_SEARCH);
Jeff Sharkey4175be22016-01-09 14:57:45 -0700223 webSearchInfoList = queryIntentActivities(webSearchIntent,
224 PackageManager.GET_META_DATA | PackageManager.MATCH_DEBUG_TRIAGED_MISSING);
Amith Yamasani64442c12012-10-07 08:17:46 -0700225
226 // analyze each one, generate a Searchables record, and record
227 if (searchList != null || webSearchInfoList != null) {
228 int search_count = (searchList == null ? 0 : searchList.size());
229 int web_search_count = (webSearchInfoList == null ? 0 : webSearchInfoList.size());
230 int count = search_count + web_search_count;
231 for (int ii = 0; ii < count; ii++) {
232 // for each component, try to find metadata
233 ResolveInfo info = (ii < search_count)
234 ? searchList.get(ii)
235 : webSearchInfoList.get(ii - search_count);
236 ActivityInfo ai = info.activityInfo;
237 // Check first to avoid duplicate entries.
238 if (newSearchablesMap.get(new ComponentName(ai.packageName, ai.name)) == null) {
239 SearchableInfo searchable = SearchableInfo.getActivityMetaData(mContext, ai,
240 mUserId);
241 if (searchable != null) {
242 newSearchablesList.add(searchable);
243 newSearchablesMap.put(searchable.getSearchActivity(), searchable);
244 if (searchable.shouldIncludeInGlobalSearch()) {
245 newSearchablesInGlobalSearchList.add(searchable);
246 }
Karl Rosaen590f6342009-08-27 17:42:48 -0700247 }
Bjorn Bringert6d72e022009-04-29 14:56:12 +0100248 }
Karl Rosaen875d50a2009-04-23 19:00:21 -0700249 }
250 }
Satish Sampathf9acde22009-06-04 11:51:17 +0100251
Amith Yamasani64442c12012-10-07 08:17:46 -0700252 List<ResolveInfo> newGlobalSearchActivities = findGlobalSearchActivities();
Narayan Kamathee69ff42011-06-28 12:07:18 +0100253
Amith Yamasani64442c12012-10-07 08:17:46 -0700254 // Find the global search activity
255 ComponentName newGlobalSearchActivity = findGlobalSearchActivity(
256 newGlobalSearchActivities);
Satish Sampathf9acde22009-06-04 11:51:17 +0100257
Amith Yamasani64442c12012-10-07 08:17:46 -0700258 // Find the web search activity
259 ComponentName newWebSearchActivity = findWebSearchActivity(newGlobalSearchActivity);
Satish Sampathf9acde22009-06-04 11:51:17 +0100260
Amith Yamasani64442c12012-10-07 08:17:46 -0700261 // Store a consistent set of new values
262 synchronized (this) {
263 mSearchablesMap = newSearchablesMap;
264 mSearchablesList = newSearchablesList;
265 mSearchablesInGlobalSearchList = newSearchablesInGlobalSearchList;
266 mGlobalSearchActivities = newGlobalSearchActivities;
267 mCurrentGlobalSearchActivity = newGlobalSearchActivity;
268 mWebSearchActivity = newWebSearchActivity;
269 }
270 } finally {
271 Binder.restoreCallingIdentity(ident);
Karl Rosaen875d50a2009-04-23 19:00:21 -0700272 }
273 }
Amith Yamasani64442c12012-10-07 08:17:46 -0700274
Satish Sampathf9acde22009-06-04 11:51:17 +0100275 /**
Narayan Kamathee69ff42011-06-28 12:07:18 +0100276 * Returns a sorted list of installed search providers as per
277 * the following heuristics:
Bjorn Bringert6cf7a322010-02-23 13:17:06 +0000278 *
Narayan Kamathee69ff42011-06-28 12:07:18 +0100279 * (a) System apps are given priority over non system apps.
280 * (b) Among system apps and non system apps, the relative ordering
281 * is defined by their declared priority.
Satish Sampathf9acde22009-06-04 11:51:17 +0100282 */
Narayan Kamathee69ff42011-06-28 12:07:18 +0100283 private List<ResolveInfo> findGlobalSearchActivities() {
284 // Step 1 : Query the package manager for a list
285 // of activities that can handle the GLOBAL_SEARCH intent.
Bjorn Bringert6cf7a322010-02-23 13:17:06 +0000286 Intent intent = new Intent(SearchManager.INTENT_ACTION_GLOBAL_SEARCH);
Jeff Sharkey4175be22016-01-09 14:57:45 -0700287 List<ResolveInfo> activities = queryIntentActivities(intent,
288 PackageManager.MATCH_DEFAULT_ONLY | PackageManager.MATCH_DEBUG_TRIAGED_MISSING);
Narayan Kamathee69ff42011-06-28 12:07:18 +0100289 if (activities != null && !activities.isEmpty()) {
290 // Step 2: Rank matching activities according to our heuristics.
291 Collections.sort(activities, GLOBAL_SEARCH_RANKER);
292 }
293
294 return activities;
295 }
296
297 /**
298 * Finds the global search activity.
299 */
300 private ComponentName findGlobalSearchActivity(List<ResolveInfo> installed) {
301 // Fetch the global search provider from the system settings,
302 // and if it's still installed, return it.
303 final String searchProviderSetting = getGlobalSearchProviderSetting();
304 if (!TextUtils.isEmpty(searchProviderSetting)) {
305 final ComponentName globalSearchComponent = ComponentName.unflattenFromString(
306 searchProviderSetting);
307 if (globalSearchComponent != null && isInstalled(globalSearchComponent)) {
308 return globalSearchComponent;
Bjorn Bringert6cf7a322010-02-23 13:17:06 +0000309 }
Satish Sampathf9acde22009-06-04 11:51:17 +0100310 }
Narayan Kamathee69ff42011-06-28 12:07:18 +0100311
312 return getDefaultGlobalSearchProvider(installed);
313 }
314
315 /**
316 * Checks whether the global search provider with a given
317 * component name is installed on the system or not. This deals with
318 * cases such as the removal of an installed provider.
319 */
320 private boolean isInstalled(ComponentName globalSearch) {
321 Intent intent = new Intent(SearchManager.INTENT_ACTION_GLOBAL_SEARCH);
322 intent.setComponent(globalSearch);
323
Amith Yamasani5bb87cd2012-06-14 11:32:13 -0700324 List<ResolveInfo> activities = queryIntentActivities(intent,
325 PackageManager.MATCH_DEFAULT_ONLY);
Narayan Kamathee69ff42011-06-28 12:07:18 +0100326 if (activities != null && !activities.isEmpty()) {
327 return true;
328 }
329
330 return false;
331 }
332
333 private static final Comparator<ResolveInfo> GLOBAL_SEARCH_RANKER =
334 new Comparator<ResolveInfo>() {
335 @Override
336 public int compare(ResolveInfo lhs, ResolveInfo rhs) {
337 if (lhs == rhs) {
338 return 0;
339 }
340 boolean lhsSystem = isSystemApp(lhs);
341 boolean rhsSystem = isSystemApp(rhs);
342
343 if (lhsSystem && !rhsSystem) {
344 return -1;
345 } else if (rhsSystem && !lhsSystem) {
346 return 1;
347 } else {
348 // Either both system engines, or both non system
349 // engines.
350 //
351 // Note, this isn't a typo. Higher priority numbers imply
352 // higher priority, but are "lower" in the sort order.
353 return rhs.priority - lhs.priority;
354 }
355 }
356 };
357
358 /**
359 * @return true iff. the resolve info corresponds to a system application.
360 */
361 private static final boolean isSystemApp(ResolveInfo res) {
362 return (res.activityInfo.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0;
363 }
364
365 /**
366 * Returns the highest ranked search provider as per the
367 * ranking defined in {@link #getGlobalSearchActivities()}.
368 */
369 private ComponentName getDefaultGlobalSearchProvider(List<ResolveInfo> providerList) {
370 if (providerList != null && !providerList.isEmpty()) {
371 ActivityInfo ai = providerList.get(0).activityInfo;
372 return new ComponentName(ai.packageName, ai.name);
373 }
374
Bjorn Bringert6cf7a322010-02-23 13:17:06 +0000375 Log.w(LOG_TAG, "No global search activity found");
376 return null;
Satish Sampathf9acde22009-06-04 11:51:17 +0100377 }
378
Narayan Kamathee69ff42011-06-28 12:07:18 +0100379 private String getGlobalSearchProviderSetting() {
380 return Settings.Secure.getString(mContext.getContentResolver(),
381 Settings.Secure.SEARCH_GLOBAL_SEARCH_ACTIVITY);
382 }
383
Bjorn Bringert6cf7a322010-02-23 13:17:06 +0000384 /**
385 * Finds the web search activity.
386 *
387 * Only looks in the package of the global search activity.
388 */
389 private ComponentName findWebSearchActivity(ComponentName globalSearchActivity) {
390 if (globalSearchActivity == null) {
391 return null;
Satish Sampathf9acde22009-06-04 11:51:17 +0100392 }
Bjorn Bringert6cf7a322010-02-23 13:17:06 +0000393 Intent intent = new Intent(Intent.ACTION_WEB_SEARCH);
394 intent.setPackage(globalSearchActivity.getPackageName());
Bjorn Bringert6cf7a322010-02-23 13:17:06 +0000395 List<ResolveInfo> activities =
Amith Yamasani5bb87cd2012-06-14 11:32:13 -0700396 queryIntentActivities(intent, PackageManager.MATCH_DEFAULT_ONLY);
Narayan Kamathee69ff42011-06-28 12:07:18 +0100397
398 if (activities != null && !activities.isEmpty()) {
399 ActivityInfo ai = activities.get(0).activityInfo;
Bjorn Bringert6cf7a322010-02-23 13:17:06 +0000400 // TODO: do some sanity checks here?
401 return new ComponentName(ai.packageName, ai.name);
402 }
403 Log.w(LOG_TAG, "No web search activity found");
404 return null;
Satish Sampathf9acde22009-06-04 11:51:17 +0100405 }
406
Amith Yamasani5bb87cd2012-06-14 11:32:13 -0700407 private List<ResolveInfo> queryIntentActivities(Intent intent, int flags) {
Amith Yamasani5bb87cd2012-06-14 11:32:13 -0700408 List<ResolveInfo> activities = null;
409 try {
410 activities =
411 mPm.queryIntentActivities(intent,
412 intent.resolveTypeIfNeeded(mContext.getContentResolver()),
Jeff Sharkeyd5896632016-03-04 16:16:00 -0700413 flags, mUserId).getList();
Amith Yamasani5bb87cd2012-06-14 11:32:13 -0700414 } catch (RemoteException re) {
415 // Local call
416 }
417 return activities;
418 }
419
Karl Rosaen875d50a2009-04-23 19:00:21 -0700420 /**
421 * Returns the list of searchable activities.
422 */
423 public synchronized ArrayList<SearchableInfo> getSearchablesList() {
424 ArrayList<SearchableInfo> result = new ArrayList<SearchableInfo>(mSearchablesList);
425 return result;
426 }
Satish Sampathf9acde22009-06-04 11:51:17 +0100427
Bjorn Bringert6d72e022009-04-29 14:56:12 +0100428 /**
429 * Returns a list of the searchable activities that can be included in global search.
430 */
431 public synchronized ArrayList<SearchableInfo> getSearchablesInGlobalSearchList() {
432 return new ArrayList<SearchableInfo>(mSearchablesInGlobalSearchList);
433 }
Satish Sampathf9acde22009-06-04 11:51:17 +0100434
435 /**
Narayan Kamathee69ff42011-06-28 12:07:18 +0100436 * Returns a list of activities that handle the global search intent.
437 */
438 public synchronized ArrayList<ResolveInfo> getGlobalSearchActivities() {
439 return new ArrayList<ResolveInfo>(mGlobalSearchActivities);
440 }
441
442 /**
Bjorn Bringert6cf7a322010-02-23 13:17:06 +0000443 * Gets the name of the global search activity.
Satish Sampathf9acde22009-06-04 11:51:17 +0100444 */
Bjorn Bringert6cf7a322010-02-23 13:17:06 +0000445 public synchronized ComponentName getGlobalSearchActivity() {
Narayan Kamathee69ff42011-06-28 12:07:18 +0100446 return mCurrentGlobalSearchActivity;
Satish Sampathf9acde22009-06-04 11:51:17 +0100447 }
448
449 /**
Bjorn Bringert6cf7a322010-02-23 13:17:06 +0000450 * Gets the name of the web search activity.
Satish Sampathf9acde22009-06-04 11:51:17 +0100451 */
Bjorn Bringert6cf7a322010-02-23 13:17:06 +0000452 public synchronized ComponentName getWebSearchActivity() {
453 return mWebSearchActivity;
Satish Sampathf9acde22009-06-04 11:51:17 +0100454 }
Amith Yamasani64442c12012-10-07 08:17:46 -0700455
456 void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
457 pw.println("Searchable authorities:");
458 synchronized (this) {
459 if (mSearchablesList != null) {
460 for (SearchableInfo info: mSearchablesList) {
461 pw.print(" "); pw.println(info.getSuggestAuthority());
462 }
463 }
464 }
465 }
Karl Rosaen875d50a2009-04-23 19:00:21 -0700466}