blob: 896977141702bd11db7eed792852fdb19e2dc9d4 [file] [log] [blame]
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001/*
2 * Copyright (C) 2007 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;
Bjorn Bringertab5d96c2010-02-23 22:48:46 +000018
Amith Yamasanic1d07a42012-08-14 09:32:02 -070019import android.app.ActivityManager;
Amith Yamasanic1d07a42012-08-14 09:32:02 -070020import android.app.AppGlobals;
Dianne Hackbornfdf5b352014-10-08 17:43:48 -070021import android.app.IActivityManager;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080022import android.app.ISearchManager;
Bjorn Bringert8d17f3f2009-06-05 13:22:28 +010023import android.app.SearchManager;
Bjorn Bringert2126aac2009-12-03 15:48:19 +000024import android.app.SearchableInfo;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080025import android.content.ComponentName;
Narayan Kamathee69ff42011-06-28 12:07:18 +010026import android.content.ContentResolver;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080027import android.content.Context;
28import android.content.Intent;
Amith Yamasanic1d07a42012-08-14 09:32:02 -070029import android.content.pm.IPackageManager;
30import android.content.pm.PackageManager;
Narayan Kamathee69ff42011-06-28 12:07:18 +010031import android.content.pm.ResolveInfo;
32import android.database.ContentObserver;
Amith Yamasani5bb87cd2012-06-14 11:32:13 -070033import android.os.Binder;
Tim Kilbourn0e5f1102015-06-05 16:18:09 -070034import android.os.Bundle;
Fyodor Kupolov7877b8a2016-06-29 14:39:19 -070035import android.os.Handler;
Amith Yamasanic1d07a42012-08-14 09:32:02 -070036import android.os.RemoteException;
Dianne Hackbornf02b60a2012-08-16 10:48:27 -070037import android.os.UserHandle;
Amith Yamasani258848d2012-08-10 17:06:33 -070038import android.os.UserManager;
Narayan Kamathee69ff42011-06-28 12:07:18 +010039import android.provider.Settings;
Bjorn Bringert8d17f3f2009-06-05 13:22:28 +010040import android.util.Log;
Amith Yamasani5bb87cd2012-06-14 11:32:13 -070041import android.util.SparseArray;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080042
Jeff Sharkey4175be22016-01-09 14:57:45 -070043import com.android.internal.annotations.GuardedBy;
Jeff Sharkey7a96c392012-11-15 14:01:46 -080044import com.android.internal.content.PackageMonitor;
Fyodor Kupolov7877b8a2016-06-29 14:39:19 -070045import com.android.internal.os.BackgroundThread;
Jeff Sharkeyfe9a53b2017-03-31 14:08:23 -060046import com.android.internal.util.DumpUtils;
Jeff Sharkey7a96c392012-11-15 14:01:46 -080047import com.android.internal.util.IndentingPrintWriter;
Jorim Jaggi165ce062015-07-06 16:18:11 -070048import com.android.server.LocalServices;
Jeff Sharkey4175be22016-01-09 14:57:45 -070049import com.android.server.SystemService;
Jorim Jaggi165ce062015-07-06 16:18:11 -070050import com.android.server.statusbar.StatusBarManagerInternal;
Jeff Sharkey7a96c392012-11-15 14:01:46 -080051
Amith Yamasani64442c12012-10-07 08:17:46 -070052import java.io.FileDescriptor;
53import java.io.PrintWriter;
Bjorn Bringert6d72e022009-04-29 14:56:12 +010054import java.util.List;
55
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080056/**
Jeff Sharkey4175be22016-01-09 14:57:45 -070057 * The search manager service handles the search UI, and maintains a registry of
58 * searchable activities.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080059 */
Bjorn Bringert444c7272009-07-06 21:32:50 +010060public class SearchManagerService extends ISearchManager.Stub {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080061 private static final String TAG = "SearchManagerService";
Fyodor Kupolov7877b8a2016-06-29 14:39:19 -070062 final Handler mHandler;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080063
Jeff Sharkey4175be22016-01-09 14:57:45 -070064 public static class Lifecycle extends SystemService {
65 private SearchManagerService mService;
66
67 public Lifecycle(Context context) {
68 super(context);
69 }
70
71 @Override
72 public void onStart() {
73 mService = new SearchManagerService(getContext());
74 publishBinderService(Context.SEARCH_SERVICE, mService);
75 }
76
77 @Override
Fyodor Kupolov7877b8a2016-06-29 14:39:19 -070078 public void onUnlockUser(final int userId) {
79 mService.mHandler.post(new Runnable() {
80 @Override
81 public void run() {
82 mService.onUnlockUser(userId);
83 }
84 });
Jeff Sharkey4175be22016-01-09 14:57:45 -070085 }
86
87 @Override
88 public void onCleanupUser(int userHandle) {
89 mService.onCleanupUser(userHandle);
90 }
91 }
92
Bjorn Bringert444c7272009-07-06 21:32:50 +010093 // Context that the service is running in.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080094 private final Context mContext;
Bjorn Bringert8d17f3f2009-06-05 13:22:28 +010095
Bjorn Bringertab5d96c2010-02-23 22:48:46 +000096 // This field is initialized lazily in getSearchables(), and then never modified.
Jeff Sharkey4175be22016-01-09 14:57:45 -070097 @GuardedBy("mSearchables")
98 private final SparseArray<Searchables> mSearchables = new SparseArray<>();
Narayan Kamathee69ff42011-06-28 12:07:18 +010099
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800100 /**
Karl Rosaen875d50a2009-04-23 19:00:21 -0700101 * Initializes the Search Manager service in the provided system context.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800102 * Only one instance of this object should be created!
103 *
104 * @param context to use for accessing DB, window manager, etc.
105 */
Satish Sampathf9acde22009-06-04 11:51:17 +0100106 public SearchManagerService(Context context) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800107 mContext = context;
Amith Yamasani64442c12012-10-07 08:17:46 -0700108 new MyPackageMonitor().register(context, null, UserHandle.ALL, true);
Jeff Sharkey4175be22016-01-09 14:57:45 -0700109 new GlobalSearchProviderObserver(context.getContentResolver());
Fyodor Kupolov7877b8a2016-06-29 14:39:19 -0700110 mHandler = BackgroundThread.getHandler();
Bjorn Bringert444c7272009-07-06 21:32:50 +0100111 }
112
Amith Yamasani64442c12012-10-07 08:17:46 -0700113 private Searchables getSearchables(int userId) {
Jeff Sharkey4175be22016-01-09 14:57:45 -0700114 return getSearchables(userId, false);
115 }
116
117 private Searchables getSearchables(int userId, boolean forceUpdate) {
118 final long token = Binder.clearCallingIdentity();
Amith Yamasani64442c12012-10-07 08:17:46 -0700119 try {
Jeff Sharkey4175be22016-01-09 14:57:45 -0700120 final UserManager um = mContext.getSystemService(UserManager.class);
121 if (um.getUserInfo(userId) == null) {
122 throw new IllegalStateException("User " + userId + " doesn't exist");
123 }
Jeff Sharkeyce18c812016-04-27 16:00:41 -0600124 if (!um.isUserUnlockingOrUnlocked(userId)) {
Jeff Sharkey4175be22016-01-09 14:57:45 -0700125 throw new IllegalStateException("User " + userId + " isn't unlocked");
126 }
Amith Yamasani64442c12012-10-07 08:17:46 -0700127 } finally {
Jeff Sharkey4175be22016-01-09 14:57:45 -0700128 Binder.restoreCallingIdentity(token);
Amith Yamasani5bb87cd2012-06-14 11:32:13 -0700129 }
Amith Yamasani64442c12012-10-07 08:17:46 -0700130 synchronized (mSearchables) {
131 Searchables searchables = mSearchables.get(userId);
Amith Yamasani64442c12012-10-07 08:17:46 -0700132 if (searchables == null) {
Amith Yamasani64442c12012-10-07 08:17:46 -0700133 searchables = new Searchables(mContext, userId);
Jeff Sharkey4175be22016-01-09 14:57:45 -0700134 searchables.updateSearchableList();
Amith Yamasani64442c12012-10-07 08:17:46 -0700135 mSearchables.append(userId, searchables);
Jeff Sharkey4175be22016-01-09 14:57:45 -0700136 } else if (forceUpdate) {
137 searchables.updateSearchableList();
Amith Yamasani64442c12012-10-07 08:17:46 -0700138 }
139 return searchables;
140 }
141 }
142
Jeff Sharkey4175be22016-01-09 14:57:45 -0700143 private void onUnlockUser(int userId) {
Jeff Sharkey38e0d0f52016-07-26 09:47:04 -0600144 try {
145 getSearchables(userId, true);
146 } catch (IllegalStateException ignored) {
147 // We're just trying to warm a cache, so we don't mind if the user
148 // was stopped or destroyed before we got here.
149 }
Bjorn Bringert9bc75cb2009-07-13 13:17:27 +0100150 }
151
Jeff Sharkey4175be22016-01-09 14:57:45 -0700152 private void onCleanupUser(int userId) {
153 synchronized (mSearchables) {
154 mSearchables.remove(userId);
Amith Yamasani64442c12012-10-07 08:17:46 -0700155 }
156 }
157
Bjorn Bringert2c7b1972010-05-04 20:44:16 +0100158 /**
Bjorn Bringert444c7272009-07-06 21:32:50 +0100159 * Refreshes the "searchables" list when packages are added/removed.
160 */
Bjorn Bringertab5d96c2010-02-23 22:48:46 +0000161 class MyPackageMonitor extends PackageMonitor {
Amith Yamasani13bc6022011-08-23 12:11:35 -0700162
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800163 @Override
Bjorn Bringertab5d96c2010-02-23 22:48:46 +0000164 public void onSomePackagesChanged() {
Amith Yamasani13bc6022011-08-23 12:11:35 -0700165 updateSearchables();
166 }
167
168 @Override
169 public void onPackageModified(String pkg) {
170 updateSearchables();
171 }
172
173 private void updateSearchables() {
Amith Yamasani64442c12012-10-07 08:17:46 -0700174 final int changingUserId = getChangingUserId();
175 synchronized (mSearchables) {
Amith Yamasani5bb87cd2012-06-14 11:32:13 -0700176 // Update list of searchable activities
177 for (int i = 0; i < mSearchables.size(); i++) {
Amith Yamasani64442c12012-10-07 08:17:46 -0700178 if (changingUserId == mSearchables.keyAt(i)) {
Jeff Sharkey4175be22016-01-09 14:57:45 -0700179 mSearchables.valueAt(i).updateSearchableList();
Amith Yamasani64442c12012-10-07 08:17:46 -0700180 break;
181 }
Amith Yamasani5bb87cd2012-06-14 11:32:13 -0700182 }
183 }
Bjorn Bringertab5d96c2010-02-23 22:48:46 +0000184 // Inform all listeners that the list of searchables has been updated.
185 Intent intent = new Intent(SearchManager.INTENT_ACTION_SEARCHABLES_CHANGED);
Amith Yamasanie6687942012-10-29 14:29:05 -0700186 intent.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING
187 | Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
Amith Yamasani64442c12012-10-07 08:17:46 -0700188 mContext.sendBroadcastAsUser(intent, new UserHandle(changingUserId));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800189 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800190 }
191
Narayan Kamathee69ff42011-06-28 12:07:18 +0100192 class GlobalSearchProviderObserver extends ContentObserver {
193 private final ContentResolver mResolver;
194
195 public GlobalSearchProviderObserver(ContentResolver resolver) {
196 super(null);
197 mResolver = resolver;
198 mResolver.registerContentObserver(
199 Settings.Secure.getUriFor(Settings.Secure.SEARCH_GLOBAL_SEARCH_ACTIVITY),
200 false /* notifyDescendants */,
201 this);
202 }
203
204 @Override
205 public void onChange(boolean selfChange) {
Amith Yamasani64442c12012-10-07 08:17:46 -0700206 synchronized (mSearchables) {
Amith Yamasani5bb87cd2012-06-14 11:32:13 -0700207 for (int i = 0; i < mSearchables.size(); i++) {
Jeff Sharkey4175be22016-01-09 14:57:45 -0700208 mSearchables.valueAt(i).updateSearchableList();
Amith Yamasani5bb87cd2012-06-14 11:32:13 -0700209 }
210 }
Narayan Kamathee69ff42011-06-28 12:07:18 +0100211 Intent intent = new Intent(SearchManager.INTENT_GLOBAL_SEARCH_ACTIVITY_CHANGED);
212 intent.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING);
Dianne Hackborn5ac72a22012-08-29 18:32:08 -0700213 mContext.sendBroadcastAsUser(intent, UserHandle.ALL);
Narayan Kamathee69ff42011-06-28 12:07:18 +0100214 }
Narayan Kamathee69ff42011-06-28 12:07:18 +0100215 }
216
Bjorn Bringert444c7272009-07-06 21:32:50 +0100217 //
218 // Searchable activities API
219 //
Bjorn Bringerta48a5af2009-05-20 17:58:39 +0100220
221 /**
Bjorn Bringert444c7272009-07-06 21:32:50 +0100222 * Returns the SearchableInfo for a given activity.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800223 *
224 * @param launchActivity The activity from which we're launching this search.
Karl Rosaen875d50a2009-04-23 19:00:21 -0700225 * @return Returns a SearchableInfo record describing the parameters of the search,
226 * or null if no searchable metadata was available.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800227 */
Jeff Sharkey4175be22016-01-09 14:57:45 -0700228 @Override
Bjorn Bringert6cf7a322010-02-23 13:17:06 +0000229 public SearchableInfo getSearchableInfo(final ComponentName launchActivity) {
230 if (launchActivity == null) {
231 Log.e(TAG, "getSearchableInfo(), activity == null");
232 return null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800233 }
Dianne Hackbornf02b60a2012-08-16 10:48:27 -0700234 return getSearchables(UserHandle.getCallingUserId()).getSearchableInfo(launchActivity);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800235 }
Satish Sampathf9acde22009-06-04 11:51:17 +0100236
Bjorn Bringert6d72e022009-04-29 14:56:12 +0100237 /**
238 * Returns a list of the searchable activities that can be included in global search.
239 */
Jeff Sharkey4175be22016-01-09 14:57:45 -0700240 @Override
Bjorn Bringert6d72e022009-04-29 14:56:12 +0100241 public List<SearchableInfo> getSearchablesInGlobalSearch() {
Dianne Hackbornf02b60a2012-08-16 10:48:27 -0700242 return getSearchables(UserHandle.getCallingUserId()).getSearchablesInGlobalSearchList();
Bjorn Bringert6d72e022009-04-29 14:56:12 +0100243 }
Bjorn Bringert8d17f3f2009-06-05 13:22:28 +0100244
Jeff Sharkey4175be22016-01-09 14:57:45 -0700245 @Override
Narayan Kamathee69ff42011-06-28 12:07:18 +0100246 public List<ResolveInfo> getGlobalSearchActivities() {
Dianne Hackbornf02b60a2012-08-16 10:48:27 -0700247 return getSearchables(UserHandle.getCallingUserId()).getGlobalSearchActivities();
Narayan Kamathee69ff42011-06-28 12:07:18 +0100248 }
249
Bjorn Bringert8d17f3f2009-06-05 13:22:28 +0100250 /**
Bjorn Bringert6cf7a322010-02-23 13:17:06 +0000251 * Gets the name of the global search activity.
Bjorn Bringert8d17f3f2009-06-05 13:22:28 +0100252 */
Jeff Sharkey4175be22016-01-09 14:57:45 -0700253 @Override
Bjorn Bringert6cf7a322010-02-23 13:17:06 +0000254 public ComponentName getGlobalSearchActivity() {
Dianne Hackbornf02b60a2012-08-16 10:48:27 -0700255 return getSearchables(UserHandle.getCallingUserId()).getGlobalSearchActivity();
Bjorn Bringert444c7272009-07-06 21:32:50 +0100256 }
257
258 /**
Bjorn Bringert6cf7a322010-02-23 13:17:06 +0000259 * Gets the name of the web search activity.
Bjorn Bringert444c7272009-07-06 21:32:50 +0100260 */
Jeff Sharkey4175be22016-01-09 14:57:45 -0700261 @Override
Bjorn Bringert6cf7a322010-02-23 13:17:06 +0000262 public ComponentName getWebSearchActivity() {
Dianne Hackbornf02b60a2012-08-16 10:48:27 -0700263 return getSearchables(UserHandle.getCallingUserId()).getWebSearchActivity();
Bjorn Bringert444c7272009-07-06 21:32:50 +0100264 }
265
Amith Yamasanic1d07a42012-08-14 09:32:02 -0700266 @Override
Jorim Jaggi165ce062015-07-06 16:18:11 -0700267 public void launchAssist(Bundle args) {
268 StatusBarManagerInternal statusBarManager =
269 LocalServices.getService(StatusBarManagerInternal.class);
270 if (statusBarManager != null) {
271 statusBarManager.startAssist(args);
272 }
273 }
274
275 private ComponentName getLegacyAssistComponent(int userHandle) {
Amith Yamasanic1d07a42012-08-14 09:32:02 -0700276 try {
Ben Pietrzak05cb3632012-12-12 11:31:57 -0800277 userHandle = ActivityManager.handleIncomingUser(Binder.getCallingPid(),
Jorim Jaggi165ce062015-07-06 16:18:11 -0700278 Binder.getCallingUid(), userHandle, true, false, "getLegacyAssistComponent", null);
Amith Yamasanic1d07a42012-08-14 09:32:02 -0700279 IPackageManager pm = AppGlobals.getPackageManager();
280 Intent assistIntent = new Intent(Intent.ACTION_ASSIST);
281 ResolveInfo info =
282 pm.resolveIntent(assistIntent,
Jorim Jaggi165ce062015-07-06 16:18:11 -0700283 assistIntent.resolveTypeIfNeeded(mContext.getContentResolver()),
284 PackageManager.MATCH_DEFAULT_ONLY, userHandle);
Amith Yamasanic1d07a42012-08-14 09:32:02 -0700285 if (info != null) {
286 return new ComponentName(
287 info.activityInfo.applicationInfo.packageName,
288 info.activityInfo.name);
289 }
290 } catch (RemoteException re) {
291 // Local call
Jorim Jaggi165ce062015-07-06 16:18:11 -0700292 Log.e(TAG, "RemoteException in getLegacyAssistComponent: " + re);
Amith Yamasanic1d07a42012-08-14 09:32:02 -0700293 } catch (Exception e) {
Jorim Jaggi165ce062015-07-06 16:18:11 -0700294 Log.e(TAG, "Exception in getLegacyAssistComponent: " + e);
Amith Yamasanic1d07a42012-08-14 09:32:02 -0700295 }
296 return null;
297 }
Amith Yamasani64442c12012-10-07 08:17:46 -0700298
299 @Override
Jorim Jaggi165ce062015-07-06 16:18:11 -0700300 public boolean launchLegacyAssist(String hint, int userHandle, Bundle args) {
Powei Feng719e70c2017-04-11 23:00:45 +0000301 ComponentName comp = getLegacyAssistComponent(userHandle);
Dianne Hackbornfdf5b352014-10-08 17:43:48 -0700302 if (comp == null) {
303 return false;
304 }
305 long ident = Binder.clearCallingIdentity();
306 try {
307 Intent intent = new Intent(Intent.ACTION_ASSIST);
308 intent.setComponent(comp);
Sudheer Shankadc589ac2016-11-10 15:30:17 -0800309 IActivityManager am = ActivityManager.getService();
Powei Feng719e70c2017-04-11 23:00:45 +0000310 return am.launchAssistIntent(intent, ActivityManager.ASSIST_CONTEXT_BASIC, hint,
311 userHandle, args);
Dianne Hackbornfdf5b352014-10-08 17:43:48 -0700312 } catch (RemoteException e) {
313 } finally {
314 Binder.restoreCallingIdentity(ident);
315 }
316 return true;
317 }
318
319 @Override
Amith Yamasani64442c12012-10-07 08:17:46 -0700320 public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
Jeff Sharkeyfe9a53b2017-03-31 14:08:23 -0600321 if (!DumpUtils.checkDumpPermission(mContext, TAG, pw)) return;
Jeff Sharkey52801aa2012-10-12 16:06:16 -0700322
Amith Yamasani64442c12012-10-07 08:17:46 -0700323 IndentingPrintWriter ipw = new IndentingPrintWriter(pw, " ");
324 synchronized (mSearchables) {
325 for (int i = 0; i < mSearchables.size(); i++) {
326 ipw.print("\nUser: "); ipw.println(mSearchables.keyAt(i));
327 ipw.increaseIndent();
328 mSearchables.valueAt(i).dump(fd, ipw, args);
329 ipw.decreaseIndent();
330 }
331 }
332 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800333}