2 * Copyright (C) 2014 The Android Open Source Project
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
17 package android.content.pm;
19 import android.annotation.IntDef;
20 import android.annotation.NonNull;
21 import android.annotation.Nullable;
22 import android.annotation.TestApi;
23 import android.content.ComponentName;
24 import android.content.Context;
25 import android.content.Intent;
26 import android.content.pm.PackageManager.ApplicationInfoFlags;
27 import android.content.pm.PackageManager.NameNotFoundException;
28 import android.content.res.Resources;
29 import android.graphics.Bitmap;
30 import android.graphics.BitmapFactory;
31 import android.graphics.Rect;
32 import android.graphics.drawable.BitmapDrawable;
33 import android.graphics.drawable.Drawable;
34 import android.os.Bundle;
35 import android.os.Handler;
36 import android.os.Looper;
37 import android.os.Message;
38 import android.os.ParcelFileDescriptor;
39 import android.os.RemoteException;
40 import android.os.ServiceManager;
41 import android.os.UserHandle;
42 import android.os.UserManager;
43 import android.util.DisplayMetrics;
44 import android.util.Log;
46 import java.io.IOException;
47 import java.lang.annotation.Retention;
48 import java.lang.annotation.RetentionPolicy;
49 import java.util.ArrayList;
50 import java.util.Arrays;
51 import java.util.Collections;
52 import java.util.List;
55 * Class for retrieving a list of launchable activities for the current user and any associated
56 * managed profiles. This is mainly for use by launchers. Apps can be queried for each user profile.
57 * Since the PackageManager will not deliver package broadcasts for other profiles, you can register
58 * for package changes here.
60 * To watch for managed profiles being added or removed, register for the following broadcasts:
61 * {@link Intent#ACTION_MANAGED_PROFILE_ADDED} and {@link Intent#ACTION_MANAGED_PROFILE_REMOVED}.
63 * You can retrieve the list of profiles associated with this user with
64 * {@link UserManager#getUserProfiles()}.
66 public class LauncherApps {
68 static final String TAG = "LauncherApps";
69 static final boolean DEBUG = false;
71 private Context mContext;
72 private ILauncherApps mService;
73 private PackageManager mPm;
75 private List<CallbackMessageHandler> mCallbacks
76 = new ArrayList<CallbackMessageHandler>();
79 * Callbacks for package changes to this and related managed profiles.
81 public static abstract class Callback {
83 * Indicates that a package was removed from the specified profile.
85 * If a package is removed while being updated onPackageChanged will be
88 * @param packageName The name of the package that was removed.
89 * @param user The UserHandle of the profile that generated the change.
91 abstract public void onPackageRemoved(String packageName, UserHandle user);
94 * Indicates that a package was added to the specified profile.
96 * If a package is added while being updated then onPackageChanged will be
99 * @param packageName The name of the package that was added.
100 * @param user The UserHandle of the profile that generated the change.
102 abstract public void onPackageAdded(String packageName, UserHandle user);
105 * Indicates that a package was modified in the specified profile.
106 * This can happen, for example, when the package is updated or when
107 * one or more components are enabled or disabled.
109 * @param packageName The name of the package that has changed.
110 * @param user The UserHandle of the profile that generated the change.
112 abstract public void onPackageChanged(String packageName, UserHandle user);
115 * Indicates that one or more packages have become available. For
116 * example, this can happen when a removable storage card has
119 * @param packageNames The names of the packages that have become
121 * @param user The UserHandle of the profile that generated the change.
122 * @param replacing Indicates whether these packages are replacing
125 abstract public void onPackagesAvailable(String[] packageNames, UserHandle user,
129 * Indicates that one or more packages have become unavailable. For
130 * example, this can happen when a removable storage card has been
133 * @param packageNames The names of the packages that have become
135 * @param user The UserHandle of the profile that generated the change.
136 * @param replacing Indicates whether the packages are about to be
137 * replaced with new versions.
139 abstract public void onPackagesUnavailable(String[] packageNames, UserHandle user,
143 * Indicates that one or more packages have been suspended. For
144 * example, this can happen when a Device Administrator suspends
147 * @param packageNames The names of the packages that have just been
149 * @param user The UserHandle of the profile that generated the change.
151 public void onPackagesSuspended(String[] packageNames, UserHandle user) {
155 * Indicates that one or more packages have been unsuspended. For
156 * example, this can happen when a Device Administrator unsuspends
159 * @param packageNames The names of the packages that have just been
161 * @param user The UserHandle of the profile that generated the change.
163 public void onPackagesUnsuspended(String[] packageNames, UserHandle user) {
167 * Indicates that one or more shortcuts of any kinds (dynamic, pinned, or manifest)
168 * have been added, updated or removed.
170 * <p>Only the applications that are allowed to access the shortcut information,
171 * as defined in {@link #hasShortcutHostPermission()}, will receive it.
173 * @param packageName The name of the package that has the shortcuts.
174 * @param shortcuts all shortcuts from the package (dynamic, manifest and/or pinned) will
175 * be passed. Only "key" information will be provided, as defined in
176 * {@link ShortcutInfo#hasKeyFieldsOnly()}.
177 * @param user The UserHandle of the profile that generated the change.
179 * @see ShortcutManager
181 public void onShortcutsChanged(@NonNull String packageName,
182 @NonNull List<ShortcutInfo> shortcuts, @NonNull UserHandle user) {
187 * Represents a query passed to {@link #getShortcuts(ShortcutQuery, UserHandle)}.
189 public static class ShortcutQuery {
191 * Include dynamic shortcuts in the result.
193 public static final int FLAG_MATCH_DYNAMIC = 1 << 0;
195 /** @hide kept for unit tests */
197 public static final int FLAG_GET_DYNAMIC = FLAG_MATCH_DYNAMIC;
200 * Include pinned shortcuts in the result.
202 public static final int FLAG_MATCH_PINNED = 1 << 1;
204 /** @hide kept for unit tests */
206 public static final int FLAG_GET_PINNED = FLAG_MATCH_PINNED;
209 * Include manifest shortcuts in the result.
211 public static final int FLAG_MATCH_MANIFEST = 1 << 3;
213 /** @hide kept for unit tests */
215 public static final int FLAG_GET_MANIFEST = FLAG_MATCH_MANIFEST;
218 public static final int FLAG_MATCH_ALL_KINDS =
219 FLAG_GET_DYNAMIC | FLAG_GET_PINNED | FLAG_GET_MANIFEST;
221 /** @hide kept for unit tests */
223 public static final int FLAG_GET_ALL_KINDS = FLAG_MATCH_ALL_KINDS;
226 * Requests "key" fields only. See {@link ShortcutInfo#hasKeyFieldsOnly()} for which
227 * fields are available. This allows quicker access to shortcut information in order to
228 * determine in-memory cache in the caller needs to be updated.
230 * <p>Typically, launcher applications cache all or most shortcuts' information
231 * in memory in order to show shortcuts without a delay. When they want to update their
232 * cache (e.g. when their process restart), they can fetch all shortcuts' information with
233 * with this flag, then check {@link ShortcutInfo#getLastChangedTimestamp()} for each
234 * shortcut and issue a second call to fetch the non-key information of only updated
237 * @see ShortcutManager
239 public static final int FLAG_GET_KEY_FIELDS_ONLY = 1 << 2;
247 FLAG_GET_KEY_FIELDS_ONLY,
249 @Retention(RetentionPolicy.SOURCE)
250 public @interface QueryFlags {}
258 List<String> mShortcutIds;
261 ComponentName mActivity;
266 public ShortcutQuery() {
270 * If non-zero, returns only shortcuts that have been added or updated since the timestamp.
271 * Units are as per {@link System#currentTimeMillis()}.
273 public ShortcutQuery setChangedSince(long changedSince) {
274 mChangedSince = changedSince;
279 * If non-null, returns only shortcuts from the package.
281 public ShortcutQuery setPackage(@Nullable String packageName) {
282 mPackage = packageName;
287 * If non-null, return only the specified shortcuts by ID. When setting this field,
288 * a package name must also be set with {@link #setPackage}.
290 public ShortcutQuery setShortcutIds(@Nullable List<String> shortcutIds) {
291 mShortcutIds = shortcutIds;
296 * If non-null, returns only shortcuts associated with the activity; i.e.
297 * {@link ShortcutInfo}s whose {@link ShortcutInfo#getActivity()} are equal
298 * to {@code activity}.
300 public ShortcutQuery setActivity(@Nullable ComponentName activity) {
301 mActivity = activity;
306 * Set query options. At least one of the {@code MATCH} flags should be set. (Otherwise
307 * no shortcuts will be returned.)
309 * @see {@link #FLAG_MATCH_DYNAMIC}
310 * @see {@link #FLAG_MATCH_PINNED}
311 * @see {@link #FLAG_MATCH_MANIFEST}
312 * @see {@link #FLAG_GET_KEY_FIELDS_ONLY}
314 public ShortcutQuery setQueryFlags(@QueryFlags int queryFlags) {
315 mQueryFlags = queryFlags;
321 public LauncherApps(Context context, ILauncherApps service) {
324 mPm = context.getPackageManager();
329 public LauncherApps(Context context) {
330 this(context, ILauncherApps.Stub.asInterface(
331 ServiceManager.getService(Context.LAUNCHER_APPS_SERVICE)));
335 * Retrieves a list of launchable activities that match {@link Intent#ACTION_MAIN} and
336 * {@link Intent#CATEGORY_LAUNCHER}, for a specified user.
338 * @param packageName The specific package to query. If null, it checks all installed packages
340 * @param user The UserHandle of the profile.
341 * @return List of launchable activities. Can be an empty list but will not be null.
343 public List<LauncherActivityInfo> getActivityList(String packageName, UserHandle user) {
344 ParceledListSlice<ResolveInfo> activities = null;
346 activities = mService.getLauncherActivities(packageName, user);
347 } catch (RemoteException re) {
348 throw re.rethrowFromSystemServer();
350 if (activities == null) {
351 return Collections.EMPTY_LIST;
353 ArrayList<LauncherActivityInfo> lais = new ArrayList<LauncherActivityInfo>();
354 for (ResolveInfo ri : activities.getList()) {
355 LauncherActivityInfo lai = new LauncherActivityInfo(mContext, ri.activityInfo, user);
357 Log.v(TAG, "Returning activity for profile " + user + " : "
358 + lai.getComponentName());
366 * Returns the activity info for a given intent and user handle, if it resolves. Otherwise it
369 * @param intent The intent to find a match for.
370 * @param user The profile to look in for a match.
371 * @return An activity info object if there is a match.
373 public LauncherActivityInfo resolveActivity(Intent intent, UserHandle user) {
375 ActivityInfo ai = mService.resolveActivity(intent.getComponent(), user);
377 LauncherActivityInfo info = new LauncherActivityInfo(mContext, ai, user);
380 } catch (RemoteException re) {
381 throw re.rethrowFromSystemServer();
387 * Starts a Main activity in the specified profile.
389 * @param component The ComponentName of the activity to launch
390 * @param user The UserHandle of the profile
391 * @param sourceBounds The Rect containing the source bounds of the clicked icon
392 * @param opts Options to pass to startActivity
394 public void startMainActivity(ComponentName component, UserHandle user, Rect sourceBounds,
397 Log.i(TAG, "StartMainActivity " + component + " " + user.getIdentifier());
400 mService.startActivityAsUser(component, sourceBounds, opts, user);
401 } catch (RemoteException re) {
402 throw re.rethrowFromSystemServer();
407 * Starts the settings activity to show the application details for a
408 * package in the specified profile.
410 * @param component The ComponentName of the package to launch settings for.
411 * @param user The UserHandle of the profile
412 * @param sourceBounds The Rect containing the source bounds of the clicked icon
413 * @param opts Options to pass to startActivity
415 public void startAppDetailsActivity(ComponentName component, UserHandle user,
416 Rect sourceBounds, Bundle opts) {
418 mService.showAppDetailsAsUser(component, sourceBounds, opts, user);
419 } catch (RemoteException re) {
420 throw re.rethrowFromSystemServer();
425 * Checks if the package is installed and enabled for a profile.
427 * @param packageName The package to check.
428 * @param user The UserHandle of the profile.
430 * @return true if the package exists and is enabled.
432 public boolean isPackageEnabled(String packageName, UserHandle user) {
434 return mService.isPackageEnabled(packageName, user);
435 } catch (RemoteException re) {
436 throw re.rethrowFromSystemServer();
441 * Retrieve all of the information we know about a particular package / application.
443 * @param packageName The package of the application
444 * @param flags Additional option flags {@link PackageManager#getApplicationInfo}
445 * @param user The UserHandle of the profile.
447 * @return An {@link ApplicationInfo} containing information about the package or
448 * null of the package isn't found.
451 public ApplicationInfo getApplicationInfo(String packageName, @ApplicationInfoFlags int flags,
454 return mService.getApplicationInfo(packageName, flags, user);
455 } catch (RemoteException re) {
456 throw re.rethrowFromSystemServer();
461 * Checks if the activity exists and it enabled for a profile.
463 * @param component The activity to check.
464 * @param user The UserHandle of the profile.
466 * @return true if the activity exists and is enabled.
468 public boolean isActivityEnabled(ComponentName component, UserHandle user) {
470 return mService.isActivityEnabled(component, user);
471 } catch (RemoteException re) {
472 throw re.rethrowFromSystemServer();
477 * Returns whether the caller can access the shortcut information.
479 * <p>Only the default launcher can access the shortcut information.
481 * <p>Note when this method returns {@code false}, it may be a temporary situation because
482 * the user is trying a new launcher application. The user may decide to change the default
483 * launcher back to the calling application again, so even if a launcher application loses
484 * this permission, it does <b>not</b> have to purge pinned shortcut information.
485 * Also in this situation, pinned shortcuts can still be started, even though the caller
486 * no longer has the shortcut host permission.
488 * @see ShortcutManager
490 public boolean hasShortcutHostPermission() {
492 return mService.hasShortcutHostPermission(mContext.getPackageName());
493 } catch (RemoteException re) {
494 throw re.rethrowFromSystemServer();
499 * Returns {@link ShortcutInfo}s that match {@code query}.
501 * <p>Callers must be allowed to access the shortcut information, as defined in {@link
502 * #hasShortcutHostPermission()}.
504 * @param query result includes shortcuts matching this query.
505 * @param user The UserHandle of the profile.
507 * @return the IDs of {@link ShortcutInfo}s that match the query.
509 * @see ShortcutManager
512 public List<ShortcutInfo> getShortcuts(@NonNull ShortcutQuery query,
513 @NonNull UserHandle user) {
515 return mService.getShortcuts(mContext.getPackageName(),
516 query.mChangedSince, query.mPackage, query.mShortcutIds, query.mActivity,
517 query.mQueryFlags, user)
519 } catch (RemoteException e) {
520 throw e.rethrowFromSystemServer();
525 * @hide // No longer used. Use getShortcuts() instead. Kept for unit tests.
529 public List<ShortcutInfo> getShortcutInfo(@NonNull String packageName,
530 @NonNull List<String> ids, @NonNull UserHandle user) {
531 final ShortcutQuery q = new ShortcutQuery();
532 q.setPackage(packageName);
533 q.setShortcutIds(ids);
534 q.setQueryFlags(ShortcutQuery.FLAG_GET_ALL_KINDS);
535 return getShortcuts(q, user);
539 * Pin shortcuts on a package.
541 * <p>This API is <b>NOT</b> cumulative; this will replace all pinned shortcuts for the package.
542 * However, different launchers may have different set of pinned shortcuts.
544 * <p>Callers must be allowed to access the shortcut information, as defined in {@link
545 * #hasShortcutHostPermission()}.
547 * @param packageName The target package name.
548 * @param shortcutIds The IDs of the shortcut to be pinned.
549 * @param user The UserHandle of the profile.
551 * @see ShortcutManager
553 public void pinShortcuts(@NonNull String packageName, @NonNull List<String> shortcutIds,
554 @NonNull UserHandle user) {
556 mService.pinShortcuts(mContext.getPackageName(), packageName, shortcutIds, user);
557 } catch (RemoteException e) {
558 throw e.rethrowFromSystemServer();
563 * @hide kept for testing.
566 public int getShortcutIconResId(@NonNull ShortcutInfo shortcut) {
567 return shortcut.getIconResourceId();
571 * @hide kept for testing.
574 public int getShortcutIconResId(@NonNull String packageName, @NonNull String shortcutId,
575 @NonNull UserHandle user) {
576 final ShortcutQuery q = new ShortcutQuery();
577 q.setPackage(packageName);
578 q.setShortcutIds(Arrays.asList(shortcutId));
579 q.setQueryFlags(ShortcutQuery.FLAG_GET_ALL_KINDS);
580 final List<ShortcutInfo> shortcuts = getShortcuts(q, user);
582 return shortcuts.size() > 0 ? shortcuts.get(0).getIconResourceId() : 0;
586 * @hide internal/unit tests only
588 public ParcelFileDescriptor getShortcutIconFd(
589 @NonNull ShortcutInfo shortcut) {
590 return getShortcutIconFd(shortcut.getPackage(), shortcut.getId(),
591 shortcut.getUserId());
595 * @hide internal/unit tests only
597 public ParcelFileDescriptor getShortcutIconFd(
598 @NonNull String packageName, @NonNull String shortcutId, @NonNull UserHandle user) {
599 return getShortcutIconFd(packageName, shortcutId, user.getIdentifier());
602 private ParcelFileDescriptor getShortcutIconFd(
603 @NonNull String packageName, @NonNull String shortcutId, int userId) {
605 return mService.getShortcutIconFd(mContext.getPackageName(),
606 packageName, shortcutId, userId);
607 } catch (RemoteException e) {
608 throw e.rethrowFromSystemServer();
613 * Returns the icon for this shortcut, without any badging for the profile.
615 * <p>Callers must be allowed to access the shortcut information, as defined in {@link
616 * #hasShortcutHostPermission()}.
618 * @param density The preferred density of the icon, zero for default density. Use
619 * density DPI values from {@link DisplayMetrics}.
621 * @return The drawable associated with the shortcut.
623 * @see ShortcutManager
624 * @see #getShortcutBadgedIconDrawable(ShortcutInfo, int)
625 * @see DisplayMetrics
627 public Drawable getShortcutIconDrawable(@NonNull ShortcutInfo shortcut, int density) {
628 if (shortcut.hasIconFile()) {
629 final ParcelFileDescriptor pfd = getShortcutIconFd(shortcut);
634 final Bitmap bmp = BitmapFactory.decodeFileDescriptor(pfd.getFileDescriptor());
635 return (bmp == null) ? null : new BitmapDrawable(mContext.getResources(), bmp);
639 } catch (IOException ignore) {
642 } else if (shortcut.hasIconResource()) {
644 final int resId = shortcut.getIconResourceId();
646 return null; // Shouldn't happen but just in case.
648 final ApplicationInfo ai = getApplicationInfo(shortcut.getPackage(),
649 /* flags =*/ 0, shortcut.getUserHandle());
650 final Resources res = mContext.getPackageManager().getResourcesForApplication(ai);
651 return res.getDrawableForDensity(resId, density);
652 } catch (NameNotFoundException | Resources.NotFoundException e) {
656 return null; // Has no icon.
661 * Returns the shortcut icon with badging appropriate for the profile.
663 * <p>Callers must be allowed to access the shortcut information, as defined in {@link
664 * #hasShortcutHostPermission()}.
666 * @param density Optional density for the icon, or 0 to use the default density. Use
667 * @return A badged icon for the shortcut.
669 * @see ShortcutManager
670 * @see #getShortcutBadgedIconDrawable(ShortcutInfo, int)
671 * @see DisplayMetrics
673 public Drawable getShortcutBadgedIconDrawable(ShortcutInfo shortcut, int density) {
674 final Drawable originalIcon = getShortcutIconDrawable(shortcut, density);
676 return (originalIcon == null) ? null : mContext.getPackageManager().getUserBadgedIcon(
677 originalIcon, shortcut.getUserHandle());
683 * <p>Callers must be allowed to access the shortcut information, as defined in {@link
684 * #hasShortcutHostPermission()}.
686 * @param packageName The target shortcut package name.
687 * @param shortcutId The target shortcut ID.
688 * @param sourceBounds The Rect containing the source bounds of the clicked icon.
689 * @param startActivityOptions Options to pass to startActivity.
690 * @param user The UserHandle of the profile.
692 public void startShortcut(@NonNull String packageName, @NonNull String shortcutId,
693 @Nullable Rect sourceBounds, @Nullable Bundle startActivityOptions,
694 @NonNull UserHandle user) {
695 startShortcut(packageName, shortcutId, sourceBounds, startActivityOptions,
696 user.getIdentifier());
700 * Launches a shortcut.
702 * <p>Callers must be allowed to access the shortcut information, as defined in {@link
703 * #hasShortcutHostPermission()}.
705 * @param shortcut The target shortcut.
706 * @param sourceBounds The Rect containing the source bounds of the clicked icon.
707 * @param startActivityOptions Options to pass to startActivity.
709 public void startShortcut(@NonNull ShortcutInfo shortcut,
710 @Nullable Rect sourceBounds, @Nullable Bundle startActivityOptions) {
711 startShortcut(shortcut.getPackage(), shortcut.getId(),
712 sourceBounds, startActivityOptions,
713 shortcut.getUserId());
716 private void startShortcut(@NonNull String packageName, @NonNull String shortcutId,
717 @Nullable Rect sourceBounds, @Nullable Bundle startActivityOptions,
720 mService.startShortcut(mContext.getPackageName(), packageName, shortcutId,
721 sourceBounds, startActivityOptions, userId);
722 } catch (RemoteException e) {
723 throw e.rethrowFromSystemServer();
728 * Registers a callback for changes to packages in current and managed profiles.
730 * @param callback The callback to register.
732 public void registerCallback(Callback callback) {
733 registerCallback(callback, null);
737 * Registers a callback for changes to packages in current and managed profiles.
739 * @param callback The callback to register.
740 * @param handler that should be used to post callbacks on, may be null.
742 public void registerCallback(Callback callback, Handler handler) {
743 synchronized (this) {
744 if (callback != null && findCallbackLocked(callback) < 0) {
745 boolean addedFirstCallback = mCallbacks.size() == 0;
746 addCallbackLocked(callback, handler);
747 if (addedFirstCallback) {
749 mService.addOnAppsChangedListener(mContext.getPackageName(),
750 mAppsChangedListener);
751 } catch (RemoteException re) {
752 throw re.rethrowFromSystemServer();
760 * Unregisters a callback that was previously registered.
762 * @param callback The callback to unregister.
763 * @see #registerCallback(Callback)
765 public void unregisterCallback(Callback callback) {
766 synchronized (this) {
767 removeCallbackLocked(callback);
768 if (mCallbacks.size() == 0) {
770 mService.removeOnAppsChangedListener(mAppsChangedListener);
771 } catch (RemoteException re) {
772 throw re.rethrowFromSystemServer();
778 /** @return position in mCallbacks for callback or -1 if not present. */
779 private int findCallbackLocked(Callback callback) {
780 if (callback == null) {
781 throw new IllegalArgumentException("Callback cannot be null");
783 final int size = mCallbacks.size();
784 for (int i = 0; i < size; ++i) {
785 if (mCallbacks.get(i).mCallback == callback) {
792 private void removeCallbackLocked(Callback callback) {
793 int pos = findCallbackLocked(callback);
795 mCallbacks.remove(pos);
799 private void addCallbackLocked(Callback callback, Handler handler) {
800 // Remove if already present.
801 removeCallbackLocked(callback);
802 if (handler == null) {
803 handler = new Handler();
805 CallbackMessageHandler toAdd = new CallbackMessageHandler(handler.getLooper(), callback);
806 mCallbacks.add(toAdd);
809 private IOnAppsChangedListener.Stub mAppsChangedListener = new IOnAppsChangedListener.Stub() {
812 public void onPackageRemoved(UserHandle user, String packageName)
813 throws RemoteException {
815 Log.d(TAG, "onPackageRemoved " + user.getIdentifier() + "," + packageName);
817 synchronized (LauncherApps.this) {
818 for (CallbackMessageHandler callback : mCallbacks) {
819 callback.postOnPackageRemoved(packageName, user);
825 public void onPackageChanged(UserHandle user, String packageName) throws RemoteException {
827 Log.d(TAG, "onPackageChanged " + user.getIdentifier() + "," + packageName);
829 synchronized (LauncherApps.this) {
830 for (CallbackMessageHandler callback : mCallbacks) {
831 callback.postOnPackageChanged(packageName, user);
837 public void onPackageAdded(UserHandle user, String packageName) throws RemoteException {
839 Log.d(TAG, "onPackageAdded " + user.getIdentifier() + "," + packageName);
841 synchronized (LauncherApps.this) {
842 for (CallbackMessageHandler callback : mCallbacks) {
843 callback.postOnPackageAdded(packageName, user);
849 public void onPackagesAvailable(UserHandle user, String[] packageNames, boolean replacing)
850 throws RemoteException {
852 Log.d(TAG, "onPackagesAvailable " + user.getIdentifier() + "," + packageNames);
854 synchronized (LauncherApps.this) {
855 for (CallbackMessageHandler callback : mCallbacks) {
856 callback.postOnPackagesAvailable(packageNames, user, replacing);
862 public void onPackagesUnavailable(UserHandle user, String[] packageNames, boolean replacing)
863 throws RemoteException {
865 Log.d(TAG, "onPackagesUnavailable " + user.getIdentifier() + "," + packageNames);
867 synchronized (LauncherApps.this) {
868 for (CallbackMessageHandler callback : mCallbacks) {
869 callback.postOnPackagesUnavailable(packageNames, user, replacing);
875 public void onPackagesSuspended(UserHandle user, String[] packageNames)
876 throws RemoteException {
878 Log.d(TAG, "onPackagesSuspended " + user.getIdentifier() + "," + packageNames);
880 synchronized (LauncherApps.this) {
881 for (CallbackMessageHandler callback : mCallbacks) {
882 callback.postOnPackagesSuspended(packageNames, user);
888 public void onPackagesUnsuspended(UserHandle user, String[] packageNames)
889 throws RemoteException {
891 Log.d(TAG, "onPackagesUnsuspended " + user.getIdentifier() + "," + packageNames);
893 synchronized (LauncherApps.this) {
894 for (CallbackMessageHandler callback : mCallbacks) {
895 callback.postOnPackagesUnsuspended(packageNames, user);
901 public void onShortcutChanged(UserHandle user, String packageName,
902 ParceledListSlice shortcuts) {
904 Log.d(TAG, "onShortcutChanged " + user.getIdentifier() + "," + packageName);
906 final List<ShortcutInfo> list = shortcuts.getList();
907 synchronized (LauncherApps.this) {
908 for (CallbackMessageHandler callback : mCallbacks) {
909 callback.postOnShortcutChanged(packageName, user, list);
915 private static class CallbackMessageHandler extends Handler {
916 private static final int MSG_ADDED = 1;
917 private static final int MSG_REMOVED = 2;
918 private static final int MSG_CHANGED = 3;
919 private static final int MSG_AVAILABLE = 4;
920 private static final int MSG_UNAVAILABLE = 5;
921 private static final int MSG_SUSPENDED = 6;
922 private static final int MSG_UNSUSPENDED = 7;
923 private static final int MSG_SHORTCUT_CHANGED = 8;
925 private LauncherApps.Callback mCallback;
927 private static class CallbackInfo {
928 String[] packageNames;
932 List<ShortcutInfo> shortcuts;
935 public CallbackMessageHandler(Looper looper, LauncherApps.Callback callback) {
936 super(looper, null, true);
937 mCallback = callback;
941 public void handleMessage(Message msg) {
942 if (mCallback == null || !(msg.obj instanceof CallbackInfo)) {
945 CallbackInfo info = (CallbackInfo) msg.obj;
948 mCallback.onPackageAdded(info.packageName, info.user);
951 mCallback.onPackageRemoved(info.packageName, info.user);
954 mCallback.onPackageChanged(info.packageName, info.user);
957 mCallback.onPackagesAvailable(info.packageNames, info.user, info.replacing);
959 case MSG_UNAVAILABLE:
960 mCallback.onPackagesUnavailable(info.packageNames, info.user, info.replacing);
963 mCallback.onPackagesSuspended(info.packageNames, info.user);
965 case MSG_UNSUSPENDED:
966 mCallback.onPackagesUnsuspended(info.packageNames, info.user);
968 case MSG_SHORTCUT_CHANGED:
969 mCallback.onShortcutsChanged(info.packageName, info.shortcuts, info.user);
974 public void postOnPackageAdded(String packageName, UserHandle user) {
975 CallbackInfo info = new CallbackInfo();
976 info.packageName = packageName;
978 obtainMessage(MSG_ADDED, info).sendToTarget();
981 public void postOnPackageRemoved(String packageName, UserHandle user) {
982 CallbackInfo info = new CallbackInfo();
983 info.packageName = packageName;
985 obtainMessage(MSG_REMOVED, info).sendToTarget();
988 public void postOnPackageChanged(String packageName, UserHandle user) {
989 CallbackInfo info = new CallbackInfo();
990 info.packageName = packageName;
992 obtainMessage(MSG_CHANGED, info).sendToTarget();
995 public void postOnPackagesAvailable(String[] packageNames, UserHandle user,
997 CallbackInfo info = new CallbackInfo();
998 info.packageNames = packageNames;
999 info.replacing = replacing;
1001 obtainMessage(MSG_AVAILABLE, info).sendToTarget();
1004 public void postOnPackagesUnavailable(String[] packageNames, UserHandle user,
1005 boolean replacing) {
1006 CallbackInfo info = new CallbackInfo();
1007 info.packageNames = packageNames;
1008 info.replacing = replacing;
1010 obtainMessage(MSG_UNAVAILABLE, info).sendToTarget();
1013 public void postOnPackagesSuspended(String[] packageNames, UserHandle user) {
1014 CallbackInfo info = new CallbackInfo();
1015 info.packageNames = packageNames;
1017 obtainMessage(MSG_SUSPENDED, info).sendToTarget();
1020 public void postOnPackagesUnsuspended(String[] packageNames, UserHandle user) {
1021 CallbackInfo info = new CallbackInfo();
1022 info.packageNames = packageNames;
1024 obtainMessage(MSG_UNSUSPENDED, info).sendToTarget();
1027 public void postOnShortcutChanged(String packageName, UserHandle user,
1028 List<ShortcutInfo> shortcuts) {
1029 CallbackInfo info = new CallbackInfo();
1030 info.packageName = packageName;
1032 info.shortcuts = shortcuts;
1033 obtainMessage(MSG_SHORTCUT_CHANGED, info).sendToTarget();