OSDN Git Service

DO NOT MERGE: Fix CTS regression am: df17644db7 am: 057b548171
[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.app.AppGlobals;
20 import android.content.ComponentName;
21 import android.content.Context;
22 import android.content.Intent;
23 import android.content.pm.ILauncherApps;
24 import android.content.pm.IOnAppsChangedListener;
25 import android.content.pm.PackageManager.NameNotFoundException;
26 import android.graphics.Rect;
27 import android.os.Bundle;
28 import android.os.Handler;
29 import android.os.Looper;
30 import android.os.Message;
31 import android.os.RemoteException;
32 import android.os.UserHandle;
33 import android.os.UserManager;
34 import android.util.Log;
35
36 import java.util.ArrayList;
37 import java.util.Collections;
38 import java.util.List;
39
40 /**
41  * Class for retrieving a list of launchable activities for the current user and any associated
42  * managed profiles. This is mainly for use by launchers. Apps can be queried for each user profile.
43  * Since the PackageManager will not deliver package broadcasts for other profiles, you can register
44  * for package changes here.
45  * <p>
46  * To watch for managed profiles being added or removed, register for the following broadcasts:
47  * {@link Intent#ACTION_MANAGED_PROFILE_ADDED} and {@link Intent#ACTION_MANAGED_PROFILE_REMOVED}.
48  * <p>
49  * You can retrieve the list of profiles associated with this user with
50  * {@link UserManager#getUserProfiles()}.
51  */
52 public class LauncherApps {
53
54     static final String TAG = "LauncherApps";
55     static final boolean DEBUG = false;
56
57     private Context mContext;
58     private ILauncherApps mService;
59     private PackageManager mPm;
60
61     private List<CallbackMessageHandler> mCallbacks
62             = new ArrayList<CallbackMessageHandler>();
63
64     /**
65      * Callbacks for package changes to this and related managed profiles.
66      */
67     public static abstract class Callback {
68         /**
69          * Indicates that a package was removed from the specified profile.
70          *
71          * If a package is removed while being updated onPackageChanged will be
72          * called instead.
73          *
74          * @param packageName The name of the package that was removed.
75          * @param user The UserHandle of the profile that generated the change.
76          */
77         abstract public void onPackageRemoved(String packageName, UserHandle user);
78
79         /**
80          * Indicates that a package was added to the specified profile.
81          *
82          * If a package is added while being updated then onPackageChanged will be
83          * called instead.
84          *
85          * @param packageName The name of the package that was added.
86          * @param user The UserHandle of the profile that generated the change.
87          */
88         abstract public void onPackageAdded(String packageName, UserHandle user);
89
90         /**
91          * Indicates that a package was modified in the specified profile.
92          * This can happen, for example, when the package is updated or when
93          * one or more components are enabled or disabled.
94          *
95          * @param packageName The name of the package that has changed.
96          * @param user The UserHandle of the profile that generated the change.
97          */
98         abstract public void onPackageChanged(String packageName, UserHandle user);
99
100         /**
101          * Indicates that one or more packages have become available. For
102          * example, this can happen when a removable storage card has
103          * reappeared.
104          *
105          * @param packageNames The names of the packages that have become
106          *            available.
107          * @param user The UserHandle of the profile that generated the change.
108          * @param replacing Indicates whether these packages are replacing
109          *            existing ones.
110          */
111         abstract public void onPackagesAvailable(String[] packageNames, UserHandle user,
112                 boolean replacing);
113
114         /**
115          * Indicates that one or more packages have become unavailable. For
116          * example, this can happen when a removable storage card has been
117          * removed.
118          *
119          * @param packageNames The names of the packages that have become
120          *            unavailable.
121          * @param user The UserHandle of the profile that generated the change.
122          * @param replacing Indicates whether the packages are about to be
123          *            replaced with new versions.
124          */
125         abstract public void onPackagesUnavailable(String[] packageNames, UserHandle user,
126                 boolean replacing);
127     }
128
129     /** @hide */
130     public LauncherApps(Context context, ILauncherApps service) {
131         mContext = context;
132         mService = service;
133         mPm = context.getPackageManager();
134     }
135
136     /**
137      * Retrieves a list of launchable activities that match {@link Intent#ACTION_MAIN} and
138      * {@link Intent#CATEGORY_LAUNCHER}, for a specified user.
139      *
140      * @param packageName The specific package to query. If null, it checks all installed packages
141      *            in the profile.
142      * @param user The UserHandle of the profile.
143      * @return List of launchable activities. Can be an empty list but will not be null.
144      */
145     public List<LauncherActivityInfo> getActivityList(String packageName, UserHandle user) {
146         List<ResolveInfo> activities = null;
147         try {
148             activities = mService.getLauncherActivities(packageName, user);
149         } catch (RemoteException re) {
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 && !mCallbacks.contains(callback)) {
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     private void removeCallbackLocked(Callback callback) {
329         if (callback == null) {
330             throw new IllegalArgumentException("Callback cannot be null");
331         }
332         final int size = mCallbacks.size();
333         for (int i = 0; i < size; ++i) {
334             if (mCallbacks.get(i).mCallback == callback) {
335                 mCallbacks.remove(i);
336                 return;
337             }
338         }
339     }
340
341     private void addCallbackLocked(Callback callback, Handler handler) {
342         // Remove if already present.
343         removeCallbackLocked(callback);
344         if (handler == null) {
345             handler = new Handler();
346         }
347         CallbackMessageHandler toAdd = new CallbackMessageHandler(handler.getLooper(), callback);
348         mCallbacks.add(toAdd);
349     }
350
351     private IOnAppsChangedListener.Stub mAppsChangedListener = new IOnAppsChangedListener.Stub() {
352
353         @Override
354         public void onPackageRemoved(UserHandle user, String packageName)
355                 throws RemoteException {
356             if (DEBUG) {
357                 Log.d(TAG, "onPackageRemoved " + user.getIdentifier() + "," + packageName);
358             }
359             synchronized (LauncherApps.this) {
360                 for (CallbackMessageHandler callback : mCallbacks) {
361                     callback.postOnPackageRemoved(packageName, user);
362                 }
363             }
364         }
365
366         @Override
367         public void onPackageChanged(UserHandle user, String packageName) throws RemoteException {
368             if (DEBUG) {
369                 Log.d(TAG, "onPackageChanged " + user.getIdentifier() + "," + packageName);
370             }
371             synchronized (LauncherApps.this) {
372                 for (CallbackMessageHandler callback : mCallbacks) {
373                     callback.postOnPackageChanged(packageName, user);
374                 }
375             }
376         }
377
378         @Override
379         public void onPackageAdded(UserHandle user, String packageName) throws RemoteException {
380             if (DEBUG) {
381                 Log.d(TAG, "onPackageAdded " + user.getIdentifier() + "," + packageName);
382             }
383             synchronized (LauncherApps.this) {
384                 for (CallbackMessageHandler callback : mCallbacks) {
385                     callback.postOnPackageAdded(packageName, user);
386                 }
387             }
388         }
389
390         @Override
391         public void onPackagesAvailable(UserHandle user, String[] packageNames, boolean replacing)
392                 throws RemoteException {
393             if (DEBUG) {
394                 Log.d(TAG, "onPackagesAvailable " + user.getIdentifier() + "," + packageNames);
395             }
396             synchronized (LauncherApps.this) {
397                 for (CallbackMessageHandler callback : mCallbacks) {
398                     callback.postOnPackagesAvailable(packageNames, user, replacing);
399                 }
400             }
401         }
402
403         @Override
404         public void onPackagesUnavailable(UserHandle user, String[] packageNames, boolean replacing)
405                 throws RemoteException {
406             if (DEBUG) {
407                 Log.d(TAG, "onPackagesUnavailable " + user.getIdentifier() + "," + packageNames);
408             }
409             synchronized (LauncherApps.this) {
410                 for (CallbackMessageHandler callback : mCallbacks) {
411                     callback.postOnPackagesUnavailable(packageNames, user, replacing);
412                 }
413            }
414         }
415     };
416
417     private static class CallbackMessageHandler extends Handler {
418         private static final int MSG_ADDED = 1;
419         private static final int MSG_REMOVED = 2;
420         private static final int MSG_CHANGED = 3;
421         private static final int MSG_AVAILABLE = 4;
422         private static final int MSG_UNAVAILABLE = 5;
423
424         private LauncherApps.Callback mCallback;
425
426         private static class CallbackInfo {
427             String[] packageNames;
428             String packageName;
429             boolean replacing;
430             UserHandle user;
431         }
432
433         public CallbackMessageHandler(Looper looper, LauncherApps.Callback callback) {
434             super(looper, null, true);
435             mCallback = callback;
436         }
437
438         @Override
439         public void handleMessage(Message msg) {
440             if (mCallback == null || !(msg.obj instanceof CallbackInfo)) {
441                 return;
442             }
443             CallbackInfo info = (CallbackInfo) msg.obj;
444             switch (msg.what) {
445                 case MSG_ADDED:
446                     mCallback.onPackageAdded(info.packageName, info.user);
447                     break;
448                 case MSG_REMOVED:
449                     mCallback.onPackageRemoved(info.packageName, info.user);
450                     break;
451                 case MSG_CHANGED:
452                     mCallback.onPackageChanged(info.packageName, info.user);
453                     break;
454                 case MSG_AVAILABLE:
455                     mCallback.onPackagesAvailable(info.packageNames, info.user, info.replacing);
456                     break;
457                 case MSG_UNAVAILABLE:
458                     mCallback.onPackagesUnavailable(info.packageNames, info.user, info.replacing);
459                     break;
460             }
461         }
462
463         public void postOnPackageAdded(String packageName, UserHandle user) {
464             CallbackInfo info = new CallbackInfo();
465             info.packageName = packageName;
466             info.user = user;
467             obtainMessage(MSG_ADDED, info).sendToTarget();
468         }
469
470         public void postOnPackageRemoved(String packageName, UserHandle user) {
471             CallbackInfo info = new CallbackInfo();
472             info.packageName = packageName;
473             info.user = user;
474             obtainMessage(MSG_REMOVED, info).sendToTarget();
475         }
476
477         public void postOnPackageChanged(String packageName, UserHandle user) {
478             CallbackInfo info = new CallbackInfo();
479             info.packageName = packageName;
480             info.user = user;
481             obtainMessage(MSG_CHANGED, info).sendToTarget();
482         }
483
484         public void postOnPackagesAvailable(String[] packageNames, UserHandle user,
485                 boolean replacing) {
486             CallbackInfo info = new CallbackInfo();
487             info.packageNames = packageNames;
488             info.replacing = replacing;
489             info.user = user;
490             obtainMessage(MSG_AVAILABLE, info).sendToTarget();
491         }
492
493         public void postOnPackagesUnavailable(String[] packageNames, UserHandle user,
494                 boolean replacing) {
495             CallbackInfo info = new CallbackInfo();
496             info.packageNames = packageNames;
497             info.replacing = replacing;
498             info.user = user;
499             obtainMessage(MSG_UNAVAILABLE, info).sendToTarget();
500         }
501     }
502
503     /**
504      * TODO Remove after 2014-09-22
505      * @hide
506      */
507     public void addCallback(Callback callback) {
508         registerCallback(callback);
509     }
510
511     /**
512      * TODO Remove after 2014-09-22
513      * @hide
514      */
515     public void removeCallback(Callback callback) {
516         unregisterCallback(callback);
517     }
518 }