OSDN Git Service

DO NOT MERGE: Fix CTS regression am: df17644db7 am: 057b548171 am: f645010092 -s...
[android-x86/frameworks-base.git] / core / java / android / content / pm / LauncherApps.java
1 /*
2  * Copyright (C) 2014 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.content.pm;
18
19 import android.content.ComponentName;
20 import android.content.Context;
21 import android.content.Intent;
22 import android.content.pm.ILauncherApps;
23 import android.content.pm.IOnAppsChangedListener;
24 import android.content.pm.PackageManager.NameNotFoundException;
25 import android.graphics.Rect;
26 import android.os.Bundle;
27 import android.os.Handler;
28 import android.os.Looper;
29 import android.os.Message;
30 import android.os.RemoteException;
31 import android.os.UserHandle;
32 import android.os.UserManager;
33 import android.util.Log;
34
35 import java.util.ArrayList;
36 import java.util.Collections;
37 import java.util.List;
38
39 /**
40  * Class for retrieving a list of launchable activities for the current user and any associated
41  * managed profiles. This is mainly for use by launchers. Apps can be queried for each user profile.
42  * Since the PackageManager will not deliver package broadcasts for other profiles, you can register
43  * for package changes here.
44  * <p>
45  * To watch for managed profiles being added or removed, register for the following broadcasts:
46  * {@link Intent#ACTION_MANAGED_PROFILE_ADDED} and {@link Intent#ACTION_MANAGED_PROFILE_REMOVED}.
47  * <p>
48  * You can retrieve the list of profiles associated with this user with
49  * {@link UserManager#getUserProfiles()}.
50  */
51 public class LauncherApps {
52
53     static final String TAG = "LauncherApps";
54     static final boolean DEBUG = false;
55
56     private Context mContext;
57     private ILauncherApps mService;
58     private PackageManager mPm;
59
60     private List<CallbackMessageHandler> mCallbacks
61             = new ArrayList<CallbackMessageHandler>();
62
63     /**
64      * Callbacks for package changes to this and related managed profiles.
65      */
66     public static abstract class Callback {
67         /**
68          * Indicates that a package was removed from the specified profile.
69          *
70          * If a package is removed while being updated onPackageChanged will be
71          * called instead.
72          *
73          * @param packageName The name of the package that was removed.
74          * @param user The UserHandle of the profile that generated the change.
75          */
76         abstract public void onPackageRemoved(String packageName, UserHandle user);
77
78         /**
79          * Indicates that a package was added to the specified profile.
80          *
81          * If a package is added while being updated then onPackageChanged will be
82          * called instead.
83          *
84          * @param packageName The name of the package that was added.
85          * @param user The UserHandle of the profile that generated the change.
86          */
87         abstract public void onPackageAdded(String packageName, UserHandle user);
88
89         /**
90          * Indicates that a package was modified in the specified profile.
91          * This can happen, for example, when the package is updated or when
92          * one or more components are enabled or disabled.
93          *
94          * @param packageName The name of the package that has changed.
95          * @param user The UserHandle of the profile that generated the change.
96          */
97         abstract public void onPackageChanged(String packageName, UserHandle user);
98
99         /**
100          * Indicates that one or more packages have become available. For
101          * example, this can happen when a removable storage card has
102          * reappeared.
103          *
104          * @param packageNames The names of the packages that have become
105          *            available.
106          * @param user The UserHandle of the profile that generated the change.
107          * @param replacing Indicates whether these packages are replacing
108          *            existing ones.
109          */
110         abstract public void onPackagesAvailable(String[] packageNames, UserHandle user,
111                 boolean replacing);
112
113         /**
114          * Indicates that one or more packages have become unavailable. For
115          * example, this can happen when a removable storage card has been
116          * removed.
117          *
118          * @param packageNames The names of the packages that have become
119          *            unavailable.
120          * @param user The UserHandle of the profile that generated the change.
121          * @param replacing Indicates whether the packages are about to be
122          *            replaced with new versions.
123          */
124         abstract public void onPackagesUnavailable(String[] packageNames, UserHandle user,
125                 boolean replacing);
126     }
127
128     /** @hide */
129     public LauncherApps(Context context, ILauncherApps service) {
130         mContext = context;
131         mService = service;
132         mPm = context.getPackageManager();
133     }
134
135     /**
136      * Retrieves a list of launchable activities that match {@link Intent#ACTION_MAIN} and
137      * {@link Intent#CATEGORY_LAUNCHER}, for a specified user.
138      *
139      * @param packageName The specific package to query. If null, it checks all installed packages
140      *            in the profile.
141      * @param user The UserHandle of the profile.
142      * @return List of launchable activities. Can be an empty list but will not be null.
143      */
144     public List<LauncherActivityInfo> getActivityList(String packageName, UserHandle user) {
145         List<ResolveInfo> activities = null;
146         try {
147             activities = mService.getLauncherActivities(packageName, user);
148         } catch (RemoteException re) {
149             throw new RuntimeException("Failed to call LauncherAppsService");
150         }
151         if (activities == null) {
152             return Collections.EMPTY_LIST;
153         }
154         ArrayList<LauncherActivityInfo> lais = new ArrayList<LauncherActivityInfo>();
155         final int count = activities.size();
156         for (int i = 0; i < count; i++) {
157             ResolveInfo ri = activities.get(i);
158             long firstInstallTime = 0;
159             try {
160                 firstInstallTime = mPm.getPackageInfo(ri.activityInfo.packageName,
161                     PackageManager.GET_UNINSTALLED_PACKAGES).firstInstallTime;
162             } catch (NameNotFoundException nnfe) {
163                 // Sorry, can't find package
164             }
165             LauncherActivityInfo lai = new LauncherActivityInfo(mContext, ri, user,
166                     firstInstallTime);
167             if (DEBUG) {
168                 Log.v(TAG, "Returning activity for profile " + user + " : "
169                         + lai.getComponentName());
170             }
171             lais.add(lai);
172         }
173         return lais;
174     }
175
176     static ComponentName getComponentName(ResolveInfo ri) {
177         return new ComponentName(ri.activityInfo.packageName, ri.activityInfo.name);
178     }
179
180     /**
181      * Returns the activity info for a given intent and user handle, if it resolves. Otherwise it
182      * returns null.
183      *
184      * @param intent The intent to find a match for.
185      * @param user The profile to look in for a match.
186      * @return An activity info object if there is a match.
187      */
188     public LauncherActivityInfo resolveActivity(Intent intent, UserHandle user) {
189         try {
190             ResolveInfo ri = mService.resolveActivity(intent, user);
191             if (ri != null) {
192                 long firstInstallTime = 0;
193                 try {
194                     firstInstallTime = mPm.getPackageInfo(ri.activityInfo.packageName,
195                             PackageManager.GET_UNINSTALLED_PACKAGES).firstInstallTime;
196                 } catch (NameNotFoundException nnfe) {
197                     // Sorry, can't find package
198                 }
199                 LauncherActivityInfo info = new LauncherActivityInfo(mContext, ri, user,
200                         firstInstallTime);
201                 return info;
202             }
203         } catch (RemoteException re) {
204             throw new RuntimeException("Failed to call LauncherAppsService");
205         }
206         return null;
207     }
208
209     /**
210      * Starts a Main activity in the specified profile.
211      *
212      * @param component The ComponentName of the activity to launch
213      * @param user The UserHandle of the profile
214      * @param sourceBounds The Rect containing the source bounds of the clicked icon
215      * @param opts Options to pass to startActivity
216      */
217     public void startMainActivity(ComponentName component, UserHandle user, Rect sourceBounds,
218             Bundle opts) {
219         if (DEBUG) {
220             Log.i(TAG, "StartMainActivity " + component + " " + user.getIdentifier());
221         }
222         try {
223             mService.startActivityAsUser(component, sourceBounds, opts, user);
224         } catch (RemoteException re) {
225             // Oops!
226         }
227     }
228
229     /**
230      * Starts the settings activity to show the application details for a
231      * package in the specified profile.
232      *
233      * @param component The ComponentName of the package to launch settings for.
234      * @param user The UserHandle of the profile
235      * @param sourceBounds The Rect containing the source bounds of the clicked icon
236      * @param opts Options to pass to startActivity
237      */
238     public void startAppDetailsActivity(ComponentName component, UserHandle user,
239             Rect sourceBounds, Bundle opts) {
240         try {
241             mService.showAppDetailsAsUser(component, sourceBounds, opts, user);
242         } catch (RemoteException re) {
243             // Oops!
244         }
245     }
246
247     /**
248      * Checks if the package is installed and enabled for a profile.
249      *
250      * @param packageName The package to check.
251      * @param user The UserHandle of the profile.
252      *
253      * @return true if the package exists and is enabled.
254      */
255     public boolean isPackageEnabled(String packageName, UserHandle user) {
256         try {
257             return mService.isPackageEnabled(packageName, user);
258         } catch (RemoteException re) {
259             throw new RuntimeException("Failed to call LauncherAppsService");
260         }
261     }
262
263     /**
264      * Checks if the activity exists and it enabled for a profile.
265      *
266      * @param component The activity to check.
267      * @param user The UserHandle of the profile.
268      *
269      * @return true if the activity exists and is enabled.
270      */
271     public boolean isActivityEnabled(ComponentName component, UserHandle user) {
272         try {
273             return mService.isActivityEnabled(component, user);
274         } catch (RemoteException re) {
275             throw new RuntimeException("Failed to call LauncherAppsService");
276         }
277     }
278
279
280     /**
281      * Registers a callback for changes to packages in current and managed profiles.
282      *
283      * @param callback The callback to register.
284      */
285     public void registerCallback(Callback callback) {
286         registerCallback(callback, null);
287     }
288
289     /**
290      * Registers a callback for changes to packages in current and managed profiles.
291      *
292      * @param callback The callback to register.
293      * @param handler that should be used to post callbacks on, may be null.
294      */
295     public void registerCallback(Callback callback, Handler handler) {
296         synchronized (this) {
297             if (callback != null && findCallbackLocked(callback) < 0) {
298                 boolean addedFirstCallback = mCallbacks.size() == 0;
299                 addCallbackLocked(callback, handler);
300                 if (addedFirstCallback) {
301                     try {
302                         mService.addOnAppsChangedListener(mAppsChangedListener);
303                     } catch (RemoteException re) {
304                     }
305                 }
306             }
307         }
308     }
309
310     /**
311      * Unregisters a callback that was previously registered.
312      *
313      * @param callback The callback to unregister.
314      * @see #registerCallback(Callback)
315      */
316     public void unregisterCallback(Callback callback) {
317         synchronized (this) {
318             removeCallbackLocked(callback);
319             if (mCallbacks.size() == 0) {
320                 try {
321                     mService.removeOnAppsChangedListener(mAppsChangedListener);
322                 } catch (RemoteException re) {
323                 }
324             }
325         }
326     }
327
328     /** @return position in mCallbacks for callback or -1 if not present. */
329     private int findCallbackLocked(Callback callback) {
330         if (callback == null) {
331             throw new IllegalArgumentException("Callback cannot be null");
332         }
333         final int size = mCallbacks.size();
334         for (int i = 0; i < size; ++i) {
335             if (mCallbacks.get(i).mCallback == callback) {
336                 return i;
337             }
338         }
339         return -1;
340     }
341
342     private void removeCallbackLocked(Callback callback) {
343         int pos = findCallbackLocked(callback);
344         if (pos >= 0) {
345             mCallbacks.remove(pos);
346         }
347     }
348
349     private void addCallbackLocked(Callback callback, Handler handler) {
350         // Remove if already present.
351         removeCallbackLocked(callback);
352         if (handler == null) {
353             handler = new Handler();
354         }
355         CallbackMessageHandler toAdd = new CallbackMessageHandler(handler.getLooper(), callback);
356         mCallbacks.add(toAdd);
357     }
358
359     private IOnAppsChangedListener.Stub mAppsChangedListener = new IOnAppsChangedListener.Stub() {
360
361         @Override
362         public void onPackageRemoved(UserHandle user, String packageName)
363                 throws RemoteException {
364             if (DEBUG) {
365                 Log.d(TAG, "onPackageRemoved " + user.getIdentifier() + "," + packageName);
366             }
367             synchronized (LauncherApps.this) {
368                 for (CallbackMessageHandler callback : mCallbacks) {
369                     callback.postOnPackageRemoved(packageName, user);
370                 }
371             }
372         }
373
374         @Override
375         public void onPackageChanged(UserHandle user, String packageName) throws RemoteException {
376             if (DEBUG) {
377                 Log.d(TAG, "onPackageChanged " + user.getIdentifier() + "," + packageName);
378             }
379             synchronized (LauncherApps.this) {
380                 for (CallbackMessageHandler callback : mCallbacks) {
381                     callback.postOnPackageChanged(packageName, user);
382                 }
383             }
384         }
385
386         @Override
387         public void onPackageAdded(UserHandle user, String packageName) throws RemoteException {
388             if (DEBUG) {
389                 Log.d(TAG, "onPackageAdded " + user.getIdentifier() + "," + packageName);
390             }
391             synchronized (LauncherApps.this) {
392                 for (CallbackMessageHandler callback : mCallbacks) {
393                     callback.postOnPackageAdded(packageName, user);
394                 }
395             }
396         }
397
398         @Override
399         public void onPackagesAvailable(UserHandle user, String[] packageNames, boolean replacing)
400                 throws RemoteException {
401             if (DEBUG) {
402                 Log.d(TAG, "onPackagesAvailable " + user.getIdentifier() + "," + packageNames);
403             }
404             synchronized (LauncherApps.this) {
405                 for (CallbackMessageHandler callback : mCallbacks) {
406                     callback.postOnPackagesAvailable(packageNames, user, replacing);
407                 }
408             }
409         }
410
411         @Override
412         public void onPackagesUnavailable(UserHandle user, String[] packageNames, boolean replacing)
413                 throws RemoteException {
414             if (DEBUG) {
415                 Log.d(TAG, "onPackagesUnavailable " + user.getIdentifier() + "," + packageNames);
416             }
417             synchronized (LauncherApps.this) {
418                 for (CallbackMessageHandler callback : mCallbacks) {
419                     callback.postOnPackagesUnavailable(packageNames, user, replacing);
420                 }
421            }
422         }
423     };
424
425     private static class CallbackMessageHandler extends Handler {
426         private static final int MSG_ADDED = 1;
427         private static final int MSG_REMOVED = 2;
428         private static final int MSG_CHANGED = 3;
429         private static final int MSG_AVAILABLE = 4;
430         private static final int MSG_UNAVAILABLE = 5;
431
432         private LauncherApps.Callback mCallback;
433
434         private static class CallbackInfo {
435             String[] packageNames;
436             String packageName;
437             boolean replacing;
438             UserHandle user;
439         }
440
441         public CallbackMessageHandler(Looper looper, LauncherApps.Callback callback) {
442             super(looper, null, true);
443             mCallback = callback;
444         }
445
446         @Override
447         public void handleMessage(Message msg) {
448             if (mCallback == null || !(msg.obj instanceof CallbackInfo)) {
449                 return;
450             }
451             CallbackInfo info = (CallbackInfo) msg.obj;
452             switch (msg.what) {
453                 case MSG_ADDED:
454                     mCallback.onPackageAdded(info.packageName, info.user);
455                     break;
456                 case MSG_REMOVED:
457                     mCallback.onPackageRemoved(info.packageName, info.user);
458                     break;
459                 case MSG_CHANGED:
460                     mCallback.onPackageChanged(info.packageName, info.user);
461                     break;
462                 case MSG_AVAILABLE:
463                     mCallback.onPackagesAvailable(info.packageNames, info.user, info.replacing);
464                     break;
465                 case MSG_UNAVAILABLE:
466                     mCallback.onPackagesUnavailable(info.packageNames, info.user, info.replacing);
467                     break;
468             }
469         }
470
471         public void postOnPackageAdded(String packageName, UserHandle user) {
472             CallbackInfo info = new CallbackInfo();
473             info.packageName = packageName;
474             info.user = user;
475             obtainMessage(MSG_ADDED, info).sendToTarget();
476         }
477
478         public void postOnPackageRemoved(String packageName, UserHandle user) {
479             CallbackInfo info = new CallbackInfo();
480             info.packageName = packageName;
481             info.user = user;
482             obtainMessage(MSG_REMOVED, info).sendToTarget();
483         }
484
485         public void postOnPackageChanged(String packageName, UserHandle user) {
486             CallbackInfo info = new CallbackInfo();
487             info.packageName = packageName;
488             info.user = user;
489             obtainMessage(MSG_CHANGED, info).sendToTarget();
490         }
491
492         public void postOnPackagesAvailable(String[] packageNames, UserHandle user,
493                 boolean replacing) {
494             CallbackInfo info = new CallbackInfo();
495             info.packageNames = packageNames;
496             info.replacing = replacing;
497             info.user = user;
498             obtainMessage(MSG_AVAILABLE, info).sendToTarget();
499         }
500
501         public void postOnPackagesUnavailable(String[] packageNames, UserHandle user,
502                 boolean replacing) {
503             CallbackInfo info = new CallbackInfo();
504             info.packageNames = packageNames;
505             info.replacing = replacing;
506             info.user = user;
507             obtainMessage(MSG_UNAVAILABLE, info).sendToTarget();
508         }
509     }
510 }