OSDN Git Service

Merge "add Toshiba usb driver link delete Fujitsu-Toshiba bug: 9755017" into jb-mr1...
[android-x86/frameworks-base.git] / core / java / android / server / search / SearchManagerService.java
1 /*
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
17 package android.server.search;
18
19 import com.android.internal.content.PackageMonitor;
20 import com.android.internal.util.IndentingPrintWriter;
21
22 import android.app.ActivityManager;
23 import android.app.ActivityManagerNative;
24 import android.app.AppGlobals;
25 import android.app.ISearchManager;
26 import android.app.SearchManager;
27 import android.app.SearchableInfo;
28 import android.content.BroadcastReceiver;
29 import android.content.ComponentName;
30 import android.content.ContentResolver;
31 import android.content.Context;
32 import android.content.Intent;
33 import android.content.IntentFilter;
34 import android.content.pm.IPackageManager;
35 import android.content.pm.PackageManager;
36 import android.content.pm.ResolveInfo;
37 import android.database.ContentObserver;
38 import android.os.Binder;
39 import android.os.Process;
40 import android.os.RemoteException;
41 import android.os.UserHandle;
42 import android.os.UserManager;
43 import android.provider.Settings;
44 import android.util.Log;
45 import android.util.Slog;
46 import android.util.SparseArray;
47
48 import java.io.FileDescriptor;
49 import java.io.PrintWriter;
50 import java.util.List;
51
52 /**
53  * The search manager service handles the search UI, and maintains a registry of searchable
54  * activities.
55  */
56 public class SearchManagerService extends ISearchManager.Stub {
57
58     // general debugging support
59     private static final String TAG = "SearchManagerService";
60
61     // Context that the service is running in.
62     private final Context mContext;
63
64     // This field is initialized lazily in getSearchables(), and then never modified.
65     private final SparseArray<Searchables> mSearchables = new SparseArray<Searchables>();
66
67     /**
68      * Initializes the Search Manager service in the provided system context.
69      * Only one instance of this object should be created!
70      *
71      * @param context to use for accessing DB, window manager, etc.
72      */
73     public SearchManagerService(Context context)  {
74         mContext = context;
75         mContext.registerReceiver(new BootCompletedReceiver(),
76                 new IntentFilter(Intent.ACTION_BOOT_COMPLETED));
77         mContext.registerReceiver(new UserReceiver(),
78                 new IntentFilter(Intent.ACTION_USER_REMOVED));
79         new MyPackageMonitor().register(context, null, UserHandle.ALL, true);
80     }
81
82     private Searchables getSearchables(int userId) {
83         long origId = Binder.clearCallingIdentity();
84         try {
85             boolean userExists = ((UserManager) mContext.getSystemService(Context.USER_SERVICE))
86                     .getUserInfo(userId) != null;
87             if (!userExists) return null;
88         } finally {
89             Binder.restoreCallingIdentity(origId);
90         }
91         synchronized (mSearchables) {
92             Searchables searchables = mSearchables.get(userId);
93
94             if (searchables == null) {
95                 //Log.i(TAG, "Building list of searchable activities for userId=" + userId);
96                 searchables = new Searchables(mContext, userId);
97                 searchables.buildSearchableList();
98                 mSearchables.append(userId, searchables);
99             }
100             return searchables;
101         }
102     }
103
104     private void onUserRemoved(int userId) {
105         if (userId != UserHandle.USER_OWNER) {
106             synchronized (mSearchables) {
107                 mSearchables.remove(userId);
108             }
109         }
110     }
111
112     /**
113      * Creates the initial searchables list after boot.
114      */
115     private final class BootCompletedReceiver extends BroadcastReceiver {
116         @Override
117         public void onReceive(Context context, Intent intent) {
118             new Thread() {
119                 @Override
120                 public void run() {
121                     Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
122                     mContext.unregisterReceiver(BootCompletedReceiver.this);
123                     getSearchables(0);
124                 }
125             }.start();
126         }
127     }
128
129     private final class UserReceiver extends BroadcastReceiver {
130         @Override
131         public void onReceive(Context context, Intent intent) {
132             onUserRemoved(intent.getIntExtra(Intent.EXTRA_USER_HANDLE, UserHandle.USER_OWNER));
133         }
134     }
135
136     /**
137      * Refreshes the "searchables" list when packages are added/removed.
138      */
139     class MyPackageMonitor extends PackageMonitor {
140
141         @Override
142         public void onSomePackagesChanged() {
143             updateSearchables();
144         }
145
146         @Override
147         public void onPackageModified(String pkg) {
148             updateSearchables();
149         }
150
151         private void updateSearchables() {
152             final int changingUserId = getChangingUserId();
153             synchronized (mSearchables) {
154                 // Update list of searchable activities
155                 for (int i = 0; i < mSearchables.size(); i++) {
156                     if (changingUserId == mSearchables.keyAt(i)) {
157                         getSearchables(mSearchables.keyAt(i)).buildSearchableList();
158                         break;
159                     }
160                 }
161             }
162             // Inform all listeners that the list of searchables has been updated.
163             Intent intent = new Intent(SearchManager.INTENT_ACTION_SEARCHABLES_CHANGED);
164             intent.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING
165                     | Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
166             mContext.sendBroadcastAsUser(intent, new UserHandle(changingUserId));
167         }
168     }
169
170     class GlobalSearchProviderObserver extends ContentObserver {
171         private final ContentResolver mResolver;
172
173         public GlobalSearchProviderObserver(ContentResolver resolver) {
174             super(null);
175             mResolver = resolver;
176             mResolver.registerContentObserver(
177                     Settings.Secure.getUriFor(Settings.Secure.SEARCH_GLOBAL_SEARCH_ACTIVITY),
178                     false /* notifyDescendants */,
179                     this);
180         }
181
182         @Override
183         public void onChange(boolean selfChange) {
184             synchronized (mSearchables) {
185                 for (int i = 0; i < mSearchables.size(); i++) {
186                     getSearchables(mSearchables.keyAt(i)).buildSearchableList();
187                 }
188             }
189             Intent intent = new Intent(SearchManager.INTENT_GLOBAL_SEARCH_ACTIVITY_CHANGED);
190             intent.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING);
191             mContext.sendBroadcastAsUser(intent, UserHandle.ALL);
192         }
193
194     }
195
196     //
197     // Searchable activities API
198     //
199
200     /**
201      * Returns the SearchableInfo for a given activity.
202      *
203      * @param launchActivity The activity from which we're launching this search.
204      * @return Returns a SearchableInfo record describing the parameters of the search,
205      * or null if no searchable metadata was available.
206      */
207     public SearchableInfo getSearchableInfo(final ComponentName launchActivity) {
208         if (launchActivity == null) {
209             Log.e(TAG, "getSearchableInfo(), activity == null");
210             return null;
211         }
212         return getSearchables(UserHandle.getCallingUserId()).getSearchableInfo(launchActivity);
213     }
214
215     /**
216      * Returns a list of the searchable activities that can be included in global search.
217      */
218     public List<SearchableInfo> getSearchablesInGlobalSearch() {
219         return getSearchables(UserHandle.getCallingUserId()).getSearchablesInGlobalSearchList();
220     }
221
222     public List<ResolveInfo> getGlobalSearchActivities() {
223         return getSearchables(UserHandle.getCallingUserId()).getGlobalSearchActivities();
224     }
225
226     /**
227      * Gets the name of the global search activity.
228      */
229     public ComponentName getGlobalSearchActivity() {
230         return getSearchables(UserHandle.getCallingUserId()).getGlobalSearchActivity();
231     }
232
233     /**
234      * Gets the name of the web search activity.
235      */
236     public ComponentName getWebSearchActivity() {
237         return getSearchables(UserHandle.getCallingUserId()).getWebSearchActivity();
238     }
239
240     @Override
241     public ComponentName getAssistIntent(int userHandle) {
242         try {
243             if (userHandle != UserHandle.getCallingUserId()) {
244                 // Requesting a different user, make sure that they have the permission
245                 if (ActivityManager.checkComponentPermission(
246                         android.Manifest.permission.INTERACT_ACROSS_USERS_FULL,
247                         Binder.getCallingUid(), -1, true)
248                         == PackageManager.PERMISSION_GRANTED) {
249                     // Translate to the current user id, if caller wasn't aware
250                     if (userHandle == UserHandle.USER_CURRENT) {
251                         long identity = Binder.clearCallingIdentity();
252                         userHandle = ActivityManagerNative.getDefault().getCurrentUser().id;
253                         Binder.restoreCallingIdentity(identity);
254                     }
255                 } else {
256                     String msg = "Permission Denial: "
257                             + "Request to getAssistIntent for " + userHandle
258                             + " but is calling from user " + UserHandle.getCallingUserId()
259                             + "; this requires "
260                             + android.Manifest.permission.INTERACT_ACROSS_USERS_FULL;
261                     Slog.w(TAG, msg);
262                     return null;
263                 }
264             }
265             IPackageManager pm = AppGlobals.getPackageManager();
266             Intent assistIntent = new Intent(Intent.ACTION_ASSIST);
267             ResolveInfo info =
268                     pm.resolveIntent(assistIntent,
269                     assistIntent.resolveTypeIfNeeded(mContext.getContentResolver()),
270                     PackageManager.MATCH_DEFAULT_ONLY, userHandle);
271             if (info != null) {
272                 return new ComponentName(
273                         info.activityInfo.applicationInfo.packageName,
274                         info.activityInfo.name);
275             }
276         } catch (RemoteException re) {
277             // Local call
278             Log.e(TAG, "RemoteException in getAssistIntent: " + re);
279         } catch (Exception e) {
280             Log.e(TAG, "Exception in getAssistIntent: " + e);
281         }
282         return null;
283     }
284
285     @Override
286     public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
287         mContext.enforceCallingOrSelfPermission(android.Manifest.permission.DUMP, TAG);
288
289         IndentingPrintWriter ipw = new IndentingPrintWriter(pw, "  ");
290         synchronized (mSearchables) {
291             for (int i = 0; i < mSearchables.size(); i++) {
292                 ipw.print("\nUser: "); ipw.println(mSearchables.keyAt(i));
293                 ipw.increaseIndent();
294                 mSearchables.valueAt(i).dump(fd, ipw, args);
295                 ipw.decreaseIndent();
296             }
297         }
298     }
299 }