blob: 04b2f6087d481bdff69ed0f5545b8bde7bebab25 [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;
Dianne Hackbornfdf5b352014-10-08 17:43:48 -070020import android.app.ActivityManagerNative;
Amith Yamasanic1d07a42012-08-14 09:32:02 -070021import android.app.AppGlobals;
Dianne Hackbornfdf5b352014-10-08 17:43:48 -070022import android.app.IActivityManager;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080023import android.app.ISearchManager;
Bjorn Bringert8d17f3f2009-06-05 13:22:28 +010024import android.app.SearchManager;
Bjorn Bringert2126aac2009-12-03 15:48:19 +000025import android.app.SearchableInfo;
Bjorn Bringert2c7b1972010-05-04 20:44:16 +010026import android.content.BroadcastReceiver;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080027import android.content.ComponentName;
Narayan Kamathee69ff42011-06-28 12:07:18 +010028import android.content.ContentResolver;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080029import android.content.Context;
30import android.content.Intent;
Bjorn Bringert2c7b1972010-05-04 20:44:16 +010031import android.content.IntentFilter;
Amith Yamasanic1d07a42012-08-14 09:32:02 -070032import android.content.pm.IPackageManager;
33import android.content.pm.PackageManager;
Narayan Kamathee69ff42011-06-28 12:07:18 +010034import android.content.pm.ResolveInfo;
35import android.database.ContentObserver;
Amith Yamasani5bb87cd2012-06-14 11:32:13 -070036import android.os.Binder;
Tim Kilbourn0e5f1102015-06-05 16:18:09 -070037import android.os.Bundle;
Bjorn Bringert2c7b1972010-05-04 20:44:16 +010038import android.os.Process;
Amith Yamasanic1d07a42012-08-14 09:32:02 -070039import android.os.RemoteException;
Dianne Hackbornf02b60a2012-08-16 10:48:27 -070040import android.os.UserHandle;
Amith Yamasani258848d2012-08-10 17:06:33 -070041import android.os.UserManager;
Narayan Kamathee69ff42011-06-28 12:07:18 +010042import android.provider.Settings;
Bjorn Bringert8d17f3f2009-06-05 13:22:28 +010043import android.util.Log;
Amith Yamasani5bb87cd2012-06-14 11:32:13 -070044import android.util.SparseArray;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080045
Jeff Sharkey7a96c392012-11-15 14:01:46 -080046import com.android.internal.content.PackageMonitor;
47import com.android.internal.util.IndentingPrintWriter;
Jorim Jaggi165ce062015-07-06 16:18:11 -070048import com.android.server.LocalServices;
49import com.android.server.statusbar.StatusBarManagerInternal;
Jeff Sharkey7a96c392012-11-15 14:01:46 -080050
Amith Yamasani64442c12012-10-07 08:17:46 -070051import java.io.FileDescriptor;
52import java.io.PrintWriter;
Bjorn Bringert6d72e022009-04-29 14:56:12 +010053import java.util.List;
54
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080055/**
Bjorn Bringert444c7272009-07-06 21:32:50 +010056 * The search manager service handles the search UI, and maintains a registry of searchable
57 * activities.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080058 */
Bjorn Bringert444c7272009-07-06 21:32:50 +010059public class SearchManagerService extends ISearchManager.Stub {
60
61 // general debugging support
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080062 private static final String TAG = "SearchManagerService";
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080063
Bjorn Bringert444c7272009-07-06 21:32:50 +010064 // Context that the service is running in.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080065 private final Context mContext;
Bjorn Bringert8d17f3f2009-06-05 13:22:28 +010066
Bjorn Bringertab5d96c2010-02-23 22:48:46 +000067 // This field is initialized lazily in getSearchables(), and then never modified.
Amith Yamasani64442c12012-10-07 08:17:46 -070068 private final SparseArray<Searchables> mSearchables = new SparseArray<Searchables>();
Narayan Kamathee69ff42011-06-28 12:07:18 +010069
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080070 /**
Karl Rosaen875d50a2009-04-23 19:00:21 -070071 * Initializes the Search Manager service in the provided system context.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080072 * Only one instance of this object should be created!
73 *
74 * @param context to use for accessing DB, window manager, etc.
75 */
Satish Sampathf9acde22009-06-04 11:51:17 +010076 public SearchManagerService(Context context) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080077 mContext = context;
Dianne Hackbornd83a0962014-05-02 16:28:33 -070078 IntentFilter filter = new IntentFilter(Intent.ACTION_BOOT_COMPLETED);
79 filter.setPriority(IntentFilter.SYSTEM_HIGH_PRIORITY);
80 mContext.registerReceiver(new BootCompletedReceiver(), filter);
Amith Yamasanie6687942012-10-29 14:29:05 -070081 mContext.registerReceiver(new UserReceiver(),
Amith Yamasani64442c12012-10-07 08:17:46 -070082 new IntentFilter(Intent.ACTION_USER_REMOVED));
83 new MyPackageMonitor().register(context, null, UserHandle.ALL, true);
Bjorn Bringert444c7272009-07-06 21:32:50 +010084 }
85
Amith Yamasani64442c12012-10-07 08:17:46 -070086 private Searchables getSearchables(int userId) {
Amith Yamasani5bb87cd2012-06-14 11:32:13 -070087 long origId = Binder.clearCallingIdentity();
Amith Yamasani64442c12012-10-07 08:17:46 -070088 try {
89 boolean userExists = ((UserManager) mContext.getSystemService(Context.USER_SERVICE))
90 .getUserInfo(userId) != null;
91 if (!userExists) return null;
92 } finally {
93 Binder.restoreCallingIdentity(origId);
Amith Yamasani5bb87cd2012-06-14 11:32:13 -070094 }
Amith Yamasani64442c12012-10-07 08:17:46 -070095 synchronized (mSearchables) {
96 Searchables searchables = mSearchables.get(userId);
97
98 if (searchables == null) {
Dianne Hackborn40e9f292012-11-27 19:12:23 -080099 //Log.i(TAG, "Building list of searchable activities for userId=" + userId);
Amith Yamasani64442c12012-10-07 08:17:46 -0700100 searchables = new Searchables(mContext, userId);
101 searchables.buildSearchableList();
102 mSearchables.append(userId, searchables);
103 }
104 return searchables;
105 }
106 }
107
108 private void onUserRemoved(int userId) {
109 if (userId != UserHandle.USER_OWNER) {
110 synchronized (mSearchables) {
111 mSearchables.remove(userId);
112 }
113 }
Bjorn Bringert9bc75cb2009-07-13 13:17:27 +0100114 }
115
Bjorn Bringert444c7272009-07-06 21:32:50 +0100116 /**
Bjorn Bringert2c7b1972010-05-04 20:44:16 +0100117 * Creates the initial searchables list after boot.
118 */
119 private final class BootCompletedReceiver extends BroadcastReceiver {
120 @Override
121 public void onReceive(Context context, Intent intent) {
122 new Thread() {
123 @Override
124 public void run() {
125 Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
126 mContext.unregisterReceiver(BootCompletedReceiver.this);
Amith Yamasani5bb87cd2012-06-14 11:32:13 -0700127 getSearchables(0);
Bjorn Bringert2c7b1972010-05-04 20:44:16 +0100128 }
129 }.start();
130 }
131 }
132
Amith Yamasani64442c12012-10-07 08:17:46 -0700133 private final class UserReceiver extends BroadcastReceiver {
134 @Override
135 public void onReceive(Context context, Intent intent) {
136 onUserRemoved(intent.getIntExtra(Intent.EXTRA_USER_HANDLE, UserHandle.USER_OWNER));
137 }
138 }
139
Bjorn Bringert2c7b1972010-05-04 20:44:16 +0100140 /**
Bjorn Bringert444c7272009-07-06 21:32:50 +0100141 * Refreshes the "searchables" list when packages are added/removed.
142 */
Bjorn Bringertab5d96c2010-02-23 22:48:46 +0000143 class MyPackageMonitor extends PackageMonitor {
Amith Yamasani13bc6022011-08-23 12:11:35 -0700144
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800145 @Override
Bjorn Bringertab5d96c2010-02-23 22:48:46 +0000146 public void onSomePackagesChanged() {
Amith Yamasani13bc6022011-08-23 12:11:35 -0700147 updateSearchables();
148 }
149
150 @Override
151 public void onPackageModified(String pkg) {
152 updateSearchables();
153 }
154
155 private void updateSearchables() {
Amith Yamasani64442c12012-10-07 08:17:46 -0700156 final int changingUserId = getChangingUserId();
157 synchronized (mSearchables) {
Amith Yamasani5bb87cd2012-06-14 11:32:13 -0700158 // Update list of searchable activities
159 for (int i = 0; i < mSearchables.size(); i++) {
Amith Yamasani64442c12012-10-07 08:17:46 -0700160 if (changingUserId == mSearchables.keyAt(i)) {
161 getSearchables(mSearchables.keyAt(i)).buildSearchableList();
162 break;
163 }
Amith Yamasani5bb87cd2012-06-14 11:32:13 -0700164 }
165 }
Bjorn Bringertab5d96c2010-02-23 22:48:46 +0000166 // Inform all listeners that the list of searchables has been updated.
167 Intent intent = new Intent(SearchManager.INTENT_ACTION_SEARCHABLES_CHANGED);
Amith Yamasanie6687942012-10-29 14:29:05 -0700168 intent.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING
169 | Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
Amith Yamasani64442c12012-10-07 08:17:46 -0700170 mContext.sendBroadcastAsUser(intent, new UserHandle(changingUserId));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800171 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800172 }
173
Narayan Kamathee69ff42011-06-28 12:07:18 +0100174 class GlobalSearchProviderObserver extends ContentObserver {
175 private final ContentResolver mResolver;
176
177 public GlobalSearchProviderObserver(ContentResolver resolver) {
178 super(null);
179 mResolver = resolver;
180 mResolver.registerContentObserver(
181 Settings.Secure.getUriFor(Settings.Secure.SEARCH_GLOBAL_SEARCH_ACTIVITY),
182 false /* notifyDescendants */,
183 this);
184 }
185
186 @Override
187 public void onChange(boolean selfChange) {
Amith Yamasani64442c12012-10-07 08:17:46 -0700188 synchronized (mSearchables) {
Amith Yamasani5bb87cd2012-06-14 11:32:13 -0700189 for (int i = 0; i < mSearchables.size(); i++) {
190 getSearchables(mSearchables.keyAt(i)).buildSearchableList();
191 }
192 }
Narayan Kamathee69ff42011-06-28 12:07:18 +0100193 Intent intent = new Intent(SearchManager.INTENT_GLOBAL_SEARCH_ACTIVITY_CHANGED);
194 intent.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING);
Dianne Hackborn5ac72a22012-08-29 18:32:08 -0700195 mContext.sendBroadcastAsUser(intent, UserHandle.ALL);
Narayan Kamathee69ff42011-06-28 12:07:18 +0100196 }
197
198 }
199
Bjorn Bringert444c7272009-07-06 21:32:50 +0100200 //
201 // Searchable activities API
202 //
Bjorn Bringerta48a5af2009-05-20 17:58:39 +0100203
204 /**
Bjorn Bringert444c7272009-07-06 21:32:50 +0100205 * Returns the SearchableInfo for a given activity.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800206 *
207 * @param launchActivity The activity from which we're launching this search.
Karl Rosaen875d50a2009-04-23 19:00:21 -0700208 * @return Returns a SearchableInfo record describing the parameters of the search,
209 * or null if no searchable metadata was available.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800210 */
Bjorn Bringert6cf7a322010-02-23 13:17:06 +0000211 public SearchableInfo getSearchableInfo(final ComponentName launchActivity) {
212 if (launchActivity == null) {
213 Log.e(TAG, "getSearchableInfo(), activity == null");
214 return null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800215 }
Dianne Hackbornf02b60a2012-08-16 10:48:27 -0700216 return getSearchables(UserHandle.getCallingUserId()).getSearchableInfo(launchActivity);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800217 }
Satish Sampathf9acde22009-06-04 11:51:17 +0100218
Bjorn Bringert6d72e022009-04-29 14:56:12 +0100219 /**
220 * Returns a list of the searchable activities that can be included in global search.
221 */
222 public List<SearchableInfo> getSearchablesInGlobalSearch() {
Dianne Hackbornf02b60a2012-08-16 10:48:27 -0700223 return getSearchables(UserHandle.getCallingUserId()).getSearchablesInGlobalSearchList();
Bjorn Bringert6d72e022009-04-29 14:56:12 +0100224 }
Bjorn Bringert8d17f3f2009-06-05 13:22:28 +0100225
Narayan Kamathee69ff42011-06-28 12:07:18 +0100226 public List<ResolveInfo> getGlobalSearchActivities() {
Dianne Hackbornf02b60a2012-08-16 10:48:27 -0700227 return getSearchables(UserHandle.getCallingUserId()).getGlobalSearchActivities();
Narayan Kamathee69ff42011-06-28 12:07:18 +0100228 }
229
Bjorn Bringert8d17f3f2009-06-05 13:22:28 +0100230 /**
Bjorn Bringert6cf7a322010-02-23 13:17:06 +0000231 * Gets the name of the global search activity.
Bjorn Bringert8d17f3f2009-06-05 13:22:28 +0100232 */
Bjorn Bringert6cf7a322010-02-23 13:17:06 +0000233 public ComponentName getGlobalSearchActivity() {
Dianne Hackbornf02b60a2012-08-16 10:48:27 -0700234 return getSearchables(UserHandle.getCallingUserId()).getGlobalSearchActivity();
Bjorn Bringert444c7272009-07-06 21:32:50 +0100235 }
236
237 /**
Bjorn Bringert6cf7a322010-02-23 13:17:06 +0000238 * Gets the name of the web search activity.
Bjorn Bringert444c7272009-07-06 21:32:50 +0100239 */
Bjorn Bringert6cf7a322010-02-23 13:17:06 +0000240 public ComponentName getWebSearchActivity() {
Dianne Hackbornf02b60a2012-08-16 10:48:27 -0700241 return getSearchables(UserHandle.getCallingUserId()).getWebSearchActivity();
Bjorn Bringert444c7272009-07-06 21:32:50 +0100242 }
243
Amith Yamasanic1d07a42012-08-14 09:32:02 -0700244 @Override
Jorim Jaggi165ce062015-07-06 16:18:11 -0700245 public void launchAssist(Bundle args) {
246 StatusBarManagerInternal statusBarManager =
247 LocalServices.getService(StatusBarManagerInternal.class);
248 if (statusBarManager != null) {
249 statusBarManager.startAssist(args);
250 }
251 }
252
253 private ComponentName getLegacyAssistComponent(int userHandle) {
Amith Yamasanic1d07a42012-08-14 09:32:02 -0700254 try {
Ben Pietrzak05cb3632012-12-12 11:31:57 -0800255 userHandle = ActivityManager.handleIncomingUser(Binder.getCallingPid(),
Jorim Jaggi165ce062015-07-06 16:18:11 -0700256 Binder.getCallingUid(), userHandle, true, false, "getLegacyAssistComponent", null);
Amith Yamasanic1d07a42012-08-14 09:32:02 -0700257 IPackageManager pm = AppGlobals.getPackageManager();
258 Intent assistIntent = new Intent(Intent.ACTION_ASSIST);
259 ResolveInfo info =
260 pm.resolveIntent(assistIntent,
Jorim Jaggi165ce062015-07-06 16:18:11 -0700261 assistIntent.resolveTypeIfNeeded(mContext.getContentResolver()),
262 PackageManager.MATCH_DEFAULT_ONLY, userHandle);
Amith Yamasanic1d07a42012-08-14 09:32:02 -0700263 if (info != null) {
264 return new ComponentName(
265 info.activityInfo.applicationInfo.packageName,
266 info.activityInfo.name);
267 }
268 } catch (RemoteException re) {
269 // Local call
Jorim Jaggi165ce062015-07-06 16:18:11 -0700270 Log.e(TAG, "RemoteException in getLegacyAssistComponent: " + re);
Amith Yamasanic1d07a42012-08-14 09:32:02 -0700271 } catch (Exception e) {
Jorim Jaggi165ce062015-07-06 16:18:11 -0700272 Log.e(TAG, "Exception in getLegacyAssistComponent: " + e);
Amith Yamasanic1d07a42012-08-14 09:32:02 -0700273 }
274 return null;
275 }
Amith Yamasani64442c12012-10-07 08:17:46 -0700276
277 @Override
Jorim Jaggi165ce062015-07-06 16:18:11 -0700278 public boolean launchLegacyAssist(String hint, int userHandle, Bundle args) {
279 ComponentName comp = getLegacyAssistComponent(userHandle);
Dianne Hackbornfdf5b352014-10-08 17:43:48 -0700280 if (comp == null) {
281 return false;
282 }
283 long ident = Binder.clearCallingIdentity();
284 try {
285 Intent intent = new Intent(Intent.ACTION_ASSIST);
286 intent.setComponent(comp);
287 IActivityManager am = ActivityManagerNative.getDefault();
Dianne Hackborna83ce1d2015-03-11 15:16:13 -0700288 return am.launchAssistIntent(intent, ActivityManager.ASSIST_CONTEXT_BASIC, hint,
Tim Kilbourn0e5f1102015-06-05 16:18:09 -0700289 userHandle, args);
Dianne Hackbornfdf5b352014-10-08 17:43:48 -0700290 } catch (RemoteException e) {
291 } finally {
292 Binder.restoreCallingIdentity(ident);
293 }
294 return true;
295 }
296
297 @Override
Amith Yamasani64442c12012-10-07 08:17:46 -0700298 public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
Jeff Sharkey52801aa2012-10-12 16:06:16 -0700299 mContext.enforceCallingOrSelfPermission(android.Manifest.permission.DUMP, TAG);
300
Amith Yamasani64442c12012-10-07 08:17:46 -0700301 IndentingPrintWriter ipw = new IndentingPrintWriter(pw, " ");
302 synchronized (mSearchables) {
303 for (int i = 0; i < mSearchables.size(); i++) {
304 ipw.print("\nUser: "); ipw.println(mSearchables.keyAt(i));
305 ipw.increaseIndent();
306 mSearchables.valueAt(i).dump(fd, ipw, args);
307 ipw.decreaseIndent();
308 }
309 }
310 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800311}