blob: 486477a544a462441ce96010483870911c337cf3 [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;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080021import android.app.ISearchManager;
Bjorn Bringert8d17f3f2009-06-05 13:22:28 +010022import android.app.SearchManager;
Bjorn Bringert2126aac2009-12-03 15:48:19 +000023import android.app.SearchableInfo;
Bjorn Bringert2c7b1972010-05-04 20:44:16 +010024import android.content.BroadcastReceiver;
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;
Bjorn Bringert2c7b1972010-05-04 20:44:16 +010029import android.content.IntentFilter;
Amith Yamasanic1d07a42012-08-14 09:32:02 -070030import android.content.pm.IPackageManager;
31import android.content.pm.PackageManager;
Narayan Kamathee69ff42011-06-28 12:07:18 +010032import android.content.pm.ResolveInfo;
33import android.database.ContentObserver;
Amith Yamasani5bb87cd2012-06-14 11:32:13 -070034import android.os.Binder;
Bjorn Bringert2c7b1972010-05-04 20:44:16 +010035import android.os.Process;
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 Sharkey7a96c392012-11-15 14:01:46 -080043import com.android.internal.content.PackageMonitor;
44import com.android.internal.util.IndentingPrintWriter;
45
Amith Yamasani64442c12012-10-07 08:17:46 -070046import java.io.FileDescriptor;
47import java.io.PrintWriter;
Bjorn Bringert6d72e022009-04-29 14:56:12 +010048import java.util.List;
49
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080050/**
Bjorn Bringert444c7272009-07-06 21:32:50 +010051 * The search manager service handles the search UI, and maintains a registry of searchable
52 * activities.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080053 */
Bjorn Bringert444c7272009-07-06 21:32:50 +010054public class SearchManagerService extends ISearchManager.Stub {
55
56 // general debugging support
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080057 private static final String TAG = "SearchManagerService";
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080058
Bjorn Bringert444c7272009-07-06 21:32:50 +010059 // Context that the service is running in.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080060 private final Context mContext;
Bjorn Bringert8d17f3f2009-06-05 13:22:28 +010061
Bjorn Bringertab5d96c2010-02-23 22:48:46 +000062 // This field is initialized lazily in getSearchables(), and then never modified.
Amith Yamasani64442c12012-10-07 08:17:46 -070063 private final SparseArray<Searchables> mSearchables = new SparseArray<Searchables>();
Narayan Kamathee69ff42011-06-28 12:07:18 +010064
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080065 /**
Karl Rosaen875d50a2009-04-23 19:00:21 -070066 * Initializes the Search Manager service in the provided system context.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080067 * Only one instance of this object should be created!
68 *
69 * @param context to use for accessing DB, window manager, etc.
70 */
Satish Sampathf9acde22009-06-04 11:51:17 +010071 public SearchManagerService(Context context) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080072 mContext = context;
Bjorn Bringert2c7b1972010-05-04 20:44:16 +010073 mContext.registerReceiver(new BootCompletedReceiver(),
74 new IntentFilter(Intent.ACTION_BOOT_COMPLETED));
Amith Yamasanie6687942012-10-29 14:29:05 -070075 mContext.registerReceiver(new UserReceiver(),
Amith Yamasani64442c12012-10-07 08:17:46 -070076 new IntentFilter(Intent.ACTION_USER_REMOVED));
77 new MyPackageMonitor().register(context, null, UserHandle.ALL, true);
Bjorn Bringert444c7272009-07-06 21:32:50 +010078 }
79
Amith Yamasani64442c12012-10-07 08:17:46 -070080 private Searchables getSearchables(int userId) {
Amith Yamasani5bb87cd2012-06-14 11:32:13 -070081 long origId = Binder.clearCallingIdentity();
Amith Yamasani64442c12012-10-07 08:17:46 -070082 try {
83 boolean userExists = ((UserManager) mContext.getSystemService(Context.USER_SERVICE))
84 .getUserInfo(userId) != null;
85 if (!userExists) return null;
86 } finally {
87 Binder.restoreCallingIdentity(origId);
Amith Yamasani5bb87cd2012-06-14 11:32:13 -070088 }
Amith Yamasani64442c12012-10-07 08:17:46 -070089 synchronized (mSearchables) {
90 Searchables searchables = mSearchables.get(userId);
91
92 if (searchables == null) {
Dianne Hackborn40e9f292012-11-27 19:12:23 -080093 //Log.i(TAG, "Building list of searchable activities for userId=" + userId);
Amith Yamasani64442c12012-10-07 08:17:46 -070094 searchables = new Searchables(mContext, userId);
95 searchables.buildSearchableList();
96 mSearchables.append(userId, searchables);
97 }
98 return searchables;
99 }
100 }
101
102 private void onUserRemoved(int userId) {
103 if (userId != UserHandle.USER_OWNER) {
104 synchronized (mSearchables) {
105 mSearchables.remove(userId);
106 }
107 }
Bjorn Bringert9bc75cb2009-07-13 13:17:27 +0100108 }
109
Bjorn Bringert444c7272009-07-06 21:32:50 +0100110 /**
Bjorn Bringert2c7b1972010-05-04 20:44:16 +0100111 * Creates the initial searchables list after boot.
112 */
113 private final class BootCompletedReceiver extends BroadcastReceiver {
114 @Override
115 public void onReceive(Context context, Intent intent) {
116 new Thread() {
117 @Override
118 public void run() {
119 Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
120 mContext.unregisterReceiver(BootCompletedReceiver.this);
Amith Yamasani5bb87cd2012-06-14 11:32:13 -0700121 getSearchables(0);
Bjorn Bringert2c7b1972010-05-04 20:44:16 +0100122 }
123 }.start();
124 }
125 }
126
Amith Yamasani64442c12012-10-07 08:17:46 -0700127 private final class UserReceiver extends BroadcastReceiver {
128 @Override
129 public void onReceive(Context context, Intent intent) {
130 onUserRemoved(intent.getIntExtra(Intent.EXTRA_USER_HANDLE, UserHandle.USER_OWNER));
131 }
132 }
133
Bjorn Bringert2c7b1972010-05-04 20:44:16 +0100134 /**
Bjorn Bringert444c7272009-07-06 21:32:50 +0100135 * Refreshes the "searchables" list when packages are added/removed.
136 */
Bjorn Bringertab5d96c2010-02-23 22:48:46 +0000137 class MyPackageMonitor extends PackageMonitor {
Amith Yamasani13bc6022011-08-23 12:11:35 -0700138
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800139 @Override
Bjorn Bringertab5d96c2010-02-23 22:48:46 +0000140 public void onSomePackagesChanged() {
Amith Yamasani13bc6022011-08-23 12:11:35 -0700141 updateSearchables();
142 }
143
144 @Override
145 public void onPackageModified(String pkg) {
146 updateSearchables();
147 }
148
149 private void updateSearchables() {
Amith Yamasani64442c12012-10-07 08:17:46 -0700150 final int changingUserId = getChangingUserId();
151 synchronized (mSearchables) {
Amith Yamasani5bb87cd2012-06-14 11:32:13 -0700152 // Update list of searchable activities
153 for (int i = 0; i < mSearchables.size(); i++) {
Amith Yamasani64442c12012-10-07 08:17:46 -0700154 if (changingUserId == mSearchables.keyAt(i)) {
155 getSearchables(mSearchables.keyAt(i)).buildSearchableList();
156 break;
157 }
Amith Yamasani5bb87cd2012-06-14 11:32:13 -0700158 }
159 }
Bjorn Bringertab5d96c2010-02-23 22:48:46 +0000160 // Inform all listeners that the list of searchables has been updated.
161 Intent intent = new Intent(SearchManager.INTENT_ACTION_SEARCHABLES_CHANGED);
Amith Yamasanie6687942012-10-29 14:29:05 -0700162 intent.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING
163 | Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
Amith Yamasani64442c12012-10-07 08:17:46 -0700164 mContext.sendBroadcastAsUser(intent, new UserHandle(changingUserId));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800165 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800166 }
167
Narayan Kamathee69ff42011-06-28 12:07:18 +0100168 class GlobalSearchProviderObserver extends ContentObserver {
169 private final ContentResolver mResolver;
170
171 public GlobalSearchProviderObserver(ContentResolver resolver) {
172 super(null);
173 mResolver = resolver;
174 mResolver.registerContentObserver(
175 Settings.Secure.getUriFor(Settings.Secure.SEARCH_GLOBAL_SEARCH_ACTIVITY),
176 false /* notifyDescendants */,
177 this);
178 }
179
180 @Override
181 public void onChange(boolean selfChange) {
Amith Yamasani64442c12012-10-07 08:17:46 -0700182 synchronized (mSearchables) {
Amith Yamasani5bb87cd2012-06-14 11:32:13 -0700183 for (int i = 0; i < mSearchables.size(); i++) {
184 getSearchables(mSearchables.keyAt(i)).buildSearchableList();
185 }
186 }
Narayan Kamathee69ff42011-06-28 12:07:18 +0100187 Intent intent = new Intent(SearchManager.INTENT_GLOBAL_SEARCH_ACTIVITY_CHANGED);
188 intent.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING);
Dianne Hackborn5ac72a22012-08-29 18:32:08 -0700189 mContext.sendBroadcastAsUser(intent, UserHandle.ALL);
Narayan Kamathee69ff42011-06-28 12:07:18 +0100190 }
191
192 }
193
Bjorn Bringert444c7272009-07-06 21:32:50 +0100194 //
195 // Searchable activities API
196 //
Bjorn Bringerta48a5af2009-05-20 17:58:39 +0100197
198 /**
Bjorn Bringert444c7272009-07-06 21:32:50 +0100199 * Returns the SearchableInfo for a given activity.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800200 *
201 * @param launchActivity The activity from which we're launching this search.
Karl Rosaen875d50a2009-04-23 19:00:21 -0700202 * @return Returns a SearchableInfo record describing the parameters of the search,
203 * or null if no searchable metadata was available.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800204 */
Bjorn Bringert6cf7a322010-02-23 13:17:06 +0000205 public SearchableInfo getSearchableInfo(final ComponentName launchActivity) {
206 if (launchActivity == null) {
207 Log.e(TAG, "getSearchableInfo(), activity == null");
208 return null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800209 }
Dianne Hackbornf02b60a2012-08-16 10:48:27 -0700210 return getSearchables(UserHandle.getCallingUserId()).getSearchableInfo(launchActivity);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800211 }
Satish Sampathf9acde22009-06-04 11:51:17 +0100212
Bjorn Bringert6d72e022009-04-29 14:56:12 +0100213 /**
214 * Returns a list of the searchable activities that can be included in global search.
215 */
216 public List<SearchableInfo> getSearchablesInGlobalSearch() {
Dianne Hackbornf02b60a2012-08-16 10:48:27 -0700217 return getSearchables(UserHandle.getCallingUserId()).getSearchablesInGlobalSearchList();
Bjorn Bringert6d72e022009-04-29 14:56:12 +0100218 }
Bjorn Bringert8d17f3f2009-06-05 13:22:28 +0100219
Narayan Kamathee69ff42011-06-28 12:07:18 +0100220 public List<ResolveInfo> getGlobalSearchActivities() {
Dianne Hackbornf02b60a2012-08-16 10:48:27 -0700221 return getSearchables(UserHandle.getCallingUserId()).getGlobalSearchActivities();
Narayan Kamathee69ff42011-06-28 12:07:18 +0100222 }
223
Bjorn Bringert8d17f3f2009-06-05 13:22:28 +0100224 /**
Bjorn Bringert6cf7a322010-02-23 13:17:06 +0000225 * Gets the name of the global search activity.
Bjorn Bringert8d17f3f2009-06-05 13:22:28 +0100226 */
Bjorn Bringert6cf7a322010-02-23 13:17:06 +0000227 public ComponentName getGlobalSearchActivity() {
Dianne Hackbornf02b60a2012-08-16 10:48:27 -0700228 return getSearchables(UserHandle.getCallingUserId()).getGlobalSearchActivity();
Bjorn Bringert444c7272009-07-06 21:32:50 +0100229 }
230
231 /**
Bjorn Bringert6cf7a322010-02-23 13:17:06 +0000232 * Gets the name of the web search activity.
Bjorn Bringert444c7272009-07-06 21:32:50 +0100233 */
Bjorn Bringert6cf7a322010-02-23 13:17:06 +0000234 public ComponentName getWebSearchActivity() {
Dianne Hackbornf02b60a2012-08-16 10:48:27 -0700235 return getSearchables(UserHandle.getCallingUserId()).getWebSearchActivity();
Bjorn Bringert444c7272009-07-06 21:32:50 +0100236 }
237
Amith Yamasanic1d07a42012-08-14 09:32:02 -0700238 @Override
239 public ComponentName getAssistIntent(int userHandle) {
240 try {
Ben Pietrzak05cb3632012-12-12 11:31:57 -0800241 userHandle = ActivityManager.handleIncomingUser(Binder.getCallingPid(),
242 Binder.getCallingUid(), userHandle, true, false, "getAssistIntent", null);
Amith Yamasanic1d07a42012-08-14 09:32:02 -0700243 IPackageManager pm = AppGlobals.getPackageManager();
244 Intent assistIntent = new Intent(Intent.ACTION_ASSIST);
245 ResolveInfo info =
246 pm.resolveIntent(assistIntent,
247 assistIntent.resolveTypeIfNeeded(mContext.getContentResolver()),
248 PackageManager.MATCH_DEFAULT_ONLY, userHandle);
249 if (info != null) {
250 return new ComponentName(
251 info.activityInfo.applicationInfo.packageName,
252 info.activityInfo.name);
253 }
254 } catch (RemoteException re) {
255 // Local call
256 Log.e(TAG, "RemoteException in getAssistIntent: " + re);
257 } catch (Exception e) {
258 Log.e(TAG, "Exception in getAssistIntent: " + e);
259 }
260 return null;
261 }
Amith Yamasani64442c12012-10-07 08:17:46 -0700262
263 @Override
264 public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
Jeff Sharkey52801aa2012-10-12 16:06:16 -0700265 mContext.enforceCallingOrSelfPermission(android.Manifest.permission.DUMP, TAG);
266
Amith Yamasani64442c12012-10-07 08:17:46 -0700267 IndentingPrintWriter ipw = new IndentingPrintWriter(pw, " ");
268 synchronized (mSearchables) {
269 for (int i = 0; i < mSearchables.size(); i++) {
270 ipw.print("\nUser: "); ipw.println(mSearchables.keyAt(i));
271 ipw.increaseIndent();
272 mSearchables.valueAt(i).dump(fd, ipw, args);
273 ipw.decreaseIndent();
274 }
275 }
276 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800277}