Home | History | Annotate | Download | only in pm
      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.annotation.IntDef;
     20 import android.annotation.NonNull;
     21 import android.annotation.Nullable;
     22 import android.annotation.SdkConstant;
     23 import android.annotation.SystemService;
     24 import android.annotation.SdkConstant.SdkConstantType;
     25 import android.annotation.TestApi;
     26 import android.app.PendingIntent;
     27 import android.appwidget.AppWidgetManager;
     28 import android.appwidget.AppWidgetProviderInfo;
     29 import android.content.ActivityNotFoundException;
     30 import android.content.ComponentName;
     31 import android.content.Context;
     32 import android.content.Intent;
     33 import android.content.IntentSender;
     34 import android.content.pm.PackageManager.ApplicationInfoFlags;
     35 import android.content.pm.PackageManager.NameNotFoundException;
     36 import android.content.res.Resources;
     37 import android.graphics.Bitmap;
     38 import android.graphics.BitmapFactory;
     39 import android.graphics.Rect;
     40 import android.graphics.drawable.BitmapDrawable;
     41 import android.graphics.drawable.Drawable;
     42 import android.graphics.drawable.Icon;
     43 import android.graphics.drawable.AdaptiveIconDrawable;
     44 import android.os.Bundle;
     45 import android.os.Handler;
     46 import android.os.Looper;
     47 import android.os.Message;
     48 import android.os.Parcel;
     49 import android.os.ParcelFileDescriptor;
     50 import android.os.Parcelable;
     51 import android.os.RemoteException;
     52 import android.os.ServiceManager;
     53 import android.os.UserHandle;
     54 import android.os.UserManager;
     55 import android.util.DisplayMetrics;
     56 import android.util.Log;
     57 
     58 import com.android.internal.util.Preconditions;
     59 
     60 import java.io.IOException;
     61 import java.lang.annotation.Retention;
     62 import java.lang.annotation.RetentionPolicy;
     63 import java.util.ArrayList;
     64 import java.util.Arrays;
     65 import java.util.Collections;
     66 import java.util.List;
     67 
     68 /**
     69  * Class for retrieving a list of launchable activities for the current user and any associated
     70  * managed profiles that are visible to the current user, which can be retrieved with
     71  * {@link #getProfiles}. This is mainly for use by launchers.
     72  *
     73  * Apps can be queried for each user profile.
     74  * Since the PackageManager will not deliver package broadcasts for other profiles, you can register
     75  * for package changes here.
     76  * <p>
     77  * To watch for managed profiles being added or removed, register for the following broadcasts:
     78  * {@link Intent#ACTION_MANAGED_PROFILE_ADDED} and {@link Intent#ACTION_MANAGED_PROFILE_REMOVED}.
     79  * <p>
     80  * Note as of Android O, apps on a managed profile are no longer allowed to access apps on the
     81  * main profile.  Apps can only access profiles returned by {@link #getProfiles()}.
     82  */
     83 @SystemService(Context.LAUNCHER_APPS_SERVICE)
     84 public class LauncherApps {
     85 
     86     static final String TAG = "LauncherApps";
     87     static final boolean DEBUG = false;
     88 
     89     /**
     90      * Activity Action: For the default launcher to show the confirmation dialog to create
     91      * a pinned shortcut.
     92      *
     93      * <p>See the {@link ShortcutManager} javadoc for details.
     94      *
     95      * <p>
     96      * Use {@link #getPinItemRequest(Intent)} to get a {@link PinItemRequest} object,
     97      * and call {@link PinItemRequest#accept(Bundle)}
     98      * if the user accepts.  If the user doesn't accept, no further action is required.
     99      *
    100      * @see #EXTRA_PIN_ITEM_REQUEST
    101      */
    102     @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
    103     public static final String ACTION_CONFIRM_PIN_SHORTCUT =
    104             "android.content.pm.action.CONFIRM_PIN_SHORTCUT";
    105 
    106     /**
    107      * Activity Action: For the default launcher to show the confirmation dialog to create
    108      * a pinned app widget.
    109      *
    110      * <p>See the {@link android.appwidget.AppWidgetManager#requestPinAppWidget} javadoc for
    111      * details.
    112      *
    113      * <p>
    114      * Use {@link #getPinItemRequest(Intent)} to get a {@link PinItemRequest} object,
    115      * and call {@link PinItemRequest#accept(Bundle)}
    116      * if the user accepts.  If the user doesn't accept, no further action is required.
    117      *
    118      * @see #EXTRA_PIN_ITEM_REQUEST
    119      */
    120     @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
    121     public static final String ACTION_CONFIRM_PIN_APPWIDGET =
    122             "android.content.pm.action.CONFIRM_PIN_APPWIDGET";
    123 
    124     /**
    125      * An extra for {@link #ACTION_CONFIRM_PIN_SHORTCUT} &amp; {@link #ACTION_CONFIRM_PIN_APPWIDGET}
    126      * containing a {@link PinItemRequest} of appropriate type asked to pin.
    127      *
    128      * <p>A helper function {@link #getPinItemRequest(Intent)} can be used
    129      * instead of using this constant directly.
    130      *
    131      * @see #ACTION_CONFIRM_PIN_SHORTCUT
    132      * @see #ACTION_CONFIRM_PIN_APPWIDGET
    133      */
    134     public static final String EXTRA_PIN_ITEM_REQUEST =
    135             "android.content.pm.extra.PIN_ITEM_REQUEST";
    136 
    137     private final Context mContext;
    138     private final ILauncherApps mService;
    139     private final PackageManager mPm;
    140     private final UserManager mUserManager;
    141 
    142     private List<CallbackMessageHandler> mCallbacks
    143             = new ArrayList<CallbackMessageHandler>();
    144 
    145     /**
    146      * Callbacks for package changes to this and related managed profiles.
    147      */
    148     public static abstract class Callback {
    149         /**
    150          * Indicates that a package was removed from the specified profile.
    151          *
    152          * If a package is removed while being updated onPackageChanged will be
    153          * called instead.
    154          *
    155          * @param packageName The name of the package that was removed.
    156          * @param user The UserHandle of the profile that generated the change.
    157          */
    158         abstract public void onPackageRemoved(String packageName, UserHandle user);
    159 
    160         /**
    161          * Indicates that a package was added to the specified profile.
    162          *
    163          * If a package is added while being updated then onPackageChanged will be
    164          * called instead.
    165          *
    166          * @param packageName The name of the package that was added.
    167          * @param user The UserHandle of the profile that generated the change.
    168          */
    169         abstract public void onPackageAdded(String packageName, UserHandle user);
    170 
    171         /**
    172          * Indicates that a package was modified in the specified profile.
    173          * This can happen, for example, when the package is updated or when
    174          * one or more components are enabled or disabled.
    175          *
    176          * @param packageName The name of the package that has changed.
    177          * @param user The UserHandle of the profile that generated the change.
    178          */
    179         abstract public void onPackageChanged(String packageName, UserHandle user);
    180 
    181         /**
    182          * Indicates that one or more packages have become available. For
    183          * example, this can happen when a removable storage card has
    184          * reappeared.
    185          *
    186          * @param packageNames The names of the packages that have become
    187          *            available.
    188          * @param user The UserHandle of the profile that generated the change.
    189          * @param replacing Indicates whether these packages are replacing
    190          *            existing ones.
    191          */
    192         abstract public void onPackagesAvailable(String[] packageNames, UserHandle user,
    193                 boolean replacing);
    194 
    195         /**
    196          * Indicates that one or more packages have become unavailable. For
    197          * example, this can happen when a removable storage card has been
    198          * removed.
    199          *
    200          * @param packageNames The names of the packages that have become
    201          *            unavailable.
    202          * @param user The UserHandle of the profile that generated the change.
    203          * @param replacing Indicates whether the packages are about to be
    204          *            replaced with new versions.
    205          */
    206         abstract public void onPackagesUnavailable(String[] packageNames, UserHandle user,
    207                 boolean replacing);
    208 
    209         /**
    210          * Indicates that one or more packages have been suspended. For
    211          * example, this can happen when a Device Administrator suspends
    212          * an applicaton.
    213          *
    214          * @param packageNames The names of the packages that have just been
    215          *            suspended.
    216          * @param user The UserHandle of the profile that generated the change.
    217          */
    218         public void onPackagesSuspended(String[] packageNames, UserHandle user) {
    219         }
    220 
    221         /**
    222          * Indicates that one or more packages have been unsuspended. For
    223          * example, this can happen when a Device Administrator unsuspends
    224          * an applicaton.
    225          *
    226          * @param packageNames The names of the packages that have just been
    227          *            unsuspended.
    228          * @param user The UserHandle of the profile that generated the change.
    229          */
    230         public void onPackagesUnsuspended(String[] packageNames, UserHandle user) {
    231         }
    232 
    233         /**
    234          * Indicates that one or more shortcuts of any kind (dynamic, pinned, or manifest)
    235          * have been added, updated or removed.
    236          *
    237          * <p>Only the applications that are allowed to access the shortcut information,
    238          * as defined in {@link #hasShortcutHostPermission()}, will receive it.
    239          *
    240          * @param packageName The name of the package that has the shortcuts.
    241          * @param shortcuts All shortcuts from the package (dynamic, manifest and/or pinned).
    242          *    Only "key" information will be provided, as defined in
    243          *    {@link ShortcutInfo#hasKeyFieldsOnly()}.
    244          * @param user The UserHandle of the profile that generated the change.
    245          *
    246          * @see ShortcutManager
    247          */
    248         public void onShortcutsChanged(@NonNull String packageName,
    249                 @NonNull List<ShortcutInfo> shortcuts, @NonNull UserHandle user) {
    250         }
    251     }
    252 
    253     /**
    254      * Represents a query passed to {@link #getShortcuts(ShortcutQuery, UserHandle)}.
    255      */
    256     public static class ShortcutQuery {
    257         /**
    258          * Include dynamic shortcuts in the result.
    259          */
    260         public static final int FLAG_MATCH_DYNAMIC = 1 << 0;
    261 
    262         /** @hide kept for unit tests */
    263         @Deprecated
    264         public static final int FLAG_GET_DYNAMIC = FLAG_MATCH_DYNAMIC;
    265 
    266         /**
    267          * Include pinned shortcuts in the result.
    268          */
    269         public static final int FLAG_MATCH_PINNED = 1 << 1;
    270 
    271         /** @hide kept for unit tests */
    272         @Deprecated
    273         public static final int FLAG_GET_PINNED = FLAG_MATCH_PINNED;
    274 
    275         /**
    276          * Include manifest shortcuts in the result.
    277          */
    278         public static final int FLAG_MATCH_MANIFEST = 1 << 3;
    279 
    280         /** @hide kept for unit tests */
    281         @Deprecated
    282         public static final int FLAG_GET_MANIFEST = FLAG_MATCH_MANIFEST;
    283 
    284         /**
    285          * Does not retrieve CHOOSER only shortcuts.
    286          * TODO: Add another flag for MATCH_ALL_PINNED
    287          * @hide
    288          */
    289         public static final int FLAG_MATCH_ALL_KINDS =
    290                 FLAG_GET_DYNAMIC | FLAG_GET_PINNED | FLAG_GET_MANIFEST;
    291 
    292         /** @hide kept for unit tests */
    293         @Deprecated
    294         public static final int FLAG_GET_ALL_KINDS = FLAG_MATCH_ALL_KINDS;
    295 
    296         /**
    297          * Requests "key" fields only.  See {@link ShortcutInfo#hasKeyFieldsOnly()}'s javadoc to
    298          * see which fields fields "key".
    299          * This allows quicker access to shortcut information in order to
    300          * determine whether the caller's in-memory cache needs to be updated.
    301          *
    302          * <p>Typically, launcher applications cache all or most shortcut information
    303          * in memory in order to show shortcuts without a delay.
    304          *
    305          * When a given launcher application wants to update its cache, such as when its process
    306          * restarts, it can fetch shortcut information with this flag.
    307          * The application can then check {@link ShortcutInfo#getLastChangedTimestamp()} for each
    308          * shortcut, fetching a shortcut's non-key information only if that shortcut has been
    309          * updated.
    310          *
    311          * @see ShortcutManager
    312          */
    313         public static final int FLAG_GET_KEY_FIELDS_ONLY = 1 << 2;
    314 
    315         /** @hide */
    316         @IntDef(flag = true,
    317                 value = {
    318                         FLAG_MATCH_DYNAMIC,
    319                         FLAG_MATCH_PINNED,
    320                         FLAG_MATCH_MANIFEST,
    321                         FLAG_GET_KEY_FIELDS_ONLY,
    322                 })
    323         @Retention(RetentionPolicy.SOURCE)
    324         public @interface QueryFlags {}
    325 
    326         long mChangedSince;
    327 
    328         @Nullable
    329         String mPackage;
    330 
    331         @Nullable
    332         List<String> mShortcutIds;
    333 
    334         @Nullable
    335         ComponentName mActivity;
    336 
    337         @QueryFlags
    338         int mQueryFlags;
    339 
    340         public ShortcutQuery() {
    341         }
    342 
    343         /**
    344          * If non-zero, returns only shortcuts that have been added or updated
    345          * since the given timestamp, expressed in milliseconds since the Epoch&mdash;see
    346          * {@link System#currentTimeMillis()}.
    347          */
    348         public ShortcutQuery setChangedSince(long changedSince) {
    349             mChangedSince = changedSince;
    350             return this;
    351         }
    352 
    353         /**
    354          * If non-null, returns only shortcuts from the package.
    355          */
    356         public ShortcutQuery setPackage(@Nullable String packageName) {
    357             mPackage = packageName;
    358             return this;
    359         }
    360 
    361         /**
    362          * If non-null, return only the specified shortcuts by ID.  When setting this field,
    363          * a package name must also be set with {@link #setPackage}.
    364          */
    365         public ShortcutQuery setShortcutIds(@Nullable List<String> shortcutIds) {
    366             mShortcutIds = shortcutIds;
    367             return this;
    368         }
    369 
    370         /**
    371          * If non-null, returns only shortcuts associated with the activity; i.e.
    372          * {@link ShortcutInfo}s whose {@link ShortcutInfo#getActivity()} are equal
    373          * to {@code activity}.
    374          */
    375         public ShortcutQuery setActivity(@Nullable ComponentName activity) {
    376             mActivity = activity;
    377             return this;
    378         }
    379 
    380         /**
    381          * Set query options.  At least one of the {@code MATCH} flags should be set.  Otherwise,
    382          * no shortcuts will be returned.
    383          *
    384          * <ul>
    385          *     <li>{@link #FLAG_MATCH_DYNAMIC}
    386          *     <li>{@link #FLAG_MATCH_PINNED}
    387          *     <li>{@link #FLAG_MATCH_MANIFEST}
    388          *     <li>{@link #FLAG_GET_KEY_FIELDS_ONLY}
    389          * </ul>
    390          */
    391         public ShortcutQuery setQueryFlags(@QueryFlags int queryFlags) {
    392             mQueryFlags = queryFlags;
    393             return this;
    394         }
    395     }
    396 
    397     /** @hide */
    398     public LauncherApps(Context context, ILauncherApps service) {
    399         mContext = context;
    400         mService = service;
    401         mPm = context.getPackageManager();
    402         mUserManager = context.getSystemService(UserManager.class);
    403     }
    404 
    405     /** @hide */
    406     @TestApi
    407     public LauncherApps(Context context) {
    408         this(context, ILauncherApps.Stub.asInterface(
    409                 ServiceManager.getService(Context.LAUNCHER_APPS_SERVICE)));
    410     }
    411 
    412     /**
    413      * Show an error log on logcat, when the calling user is a managed profile, and the target
    414      * user is different from the calling user, in order to help developers to detect it.
    415      */
    416     private void logErrorForInvalidProfileAccess(@NonNull UserHandle target) {
    417         if (UserHandle.myUserId() != target.getIdentifier() && mUserManager.isManagedProfile()) {
    418             Log.w(TAG, "Accessing other profiles/users from managed profile is no longer allowed.");
    419         }
    420     }
    421 
    422     /**
    423      * Return a list of profiles that the caller can access via the {@link LauncherApps} APIs.
    424      *
    425      * <p>If the caller is running on a managed profile, it'll return only the current profile.
    426      * Otherwise it'll return the same list as {@link UserManager#getUserProfiles()} would.
    427      */
    428     public List<UserHandle> getProfiles() {
    429         if (mUserManager.isManagedProfile()) {
    430             // If it's a managed profile, only return the current profile.
    431             final List result =  new ArrayList(1);
    432             result.add(android.os.Process.myUserHandle());
    433             return result;
    434         } else {
    435             return mUserManager.getUserProfiles();
    436         }
    437     }
    438 
    439     /**
    440      * Retrieves a list of launchable activities that match {@link Intent#ACTION_MAIN} and
    441      * {@link Intent#CATEGORY_LAUNCHER}, for a specified user.
    442      *
    443      * @param packageName The specific package to query. If null, it checks all installed packages
    444      *            in the profile.
    445      * @param user The UserHandle of the profile.
    446      * @return List of launchable activities. Can be an empty list but will not be null.
    447      */
    448     public List<LauncherActivityInfo> getActivityList(String packageName, UserHandle user) {
    449         logErrorForInvalidProfileAccess(user);
    450         try {
    451             return convertToActivityList(mService.getLauncherActivities(mContext.getPackageName(),
    452                     packageName, user), user);
    453         } catch (RemoteException re) {
    454             throw re.rethrowFromSystemServer();
    455         }
    456     }
    457 
    458     /**
    459      * Returns the activity info for a given intent and user handle, if it resolves. Otherwise it
    460      * returns null.
    461      *
    462      * @param intent The intent to find a match for.
    463      * @param user The profile to look in for a match.
    464      * @return An activity info object if there is a match.
    465      */
    466     public LauncherActivityInfo resolveActivity(Intent intent, UserHandle user) {
    467         logErrorForInvalidProfileAccess(user);
    468         try {
    469             ActivityInfo ai = mService.resolveActivity(mContext.getPackageName(),
    470                     intent.getComponent(), user);
    471             if (ai != null) {
    472                 LauncherActivityInfo info = new LauncherActivityInfo(mContext, ai, user);
    473                 return info;
    474             }
    475         } catch (RemoteException re) {
    476             throw re.rethrowFromSystemServer();
    477         }
    478         return null;
    479     }
    480 
    481     /**
    482      * Starts a Main activity in the specified profile.
    483      *
    484      * @param component The ComponentName of the activity to launch
    485      * @param user The UserHandle of the profile
    486      * @param sourceBounds The Rect containing the source bounds of the clicked icon
    487      * @param opts Options to pass to startActivity
    488      */
    489     public void startMainActivity(ComponentName component, UserHandle user, Rect sourceBounds,
    490             Bundle opts) {
    491         logErrorForInvalidProfileAccess(user);
    492         if (DEBUG) {
    493             Log.i(TAG, "StartMainActivity " + component + " " + user.getIdentifier());
    494         }
    495         try {
    496             mService.startActivityAsUser(mContext.getPackageName(),
    497                     component, sourceBounds, opts, user);
    498         } catch (RemoteException re) {
    499             throw re.rethrowFromSystemServer();
    500         }
    501     }
    502 
    503     /**
    504      * Starts the settings activity to show the application details for a
    505      * package in the specified profile.
    506      *
    507      * @param component The ComponentName of the package to launch settings for.
    508      * @param user The UserHandle of the profile
    509      * @param sourceBounds The Rect containing the source bounds of the clicked icon
    510      * @param opts Options to pass to startActivity
    511      */
    512     public void startAppDetailsActivity(ComponentName component, UserHandle user,
    513             Rect sourceBounds, Bundle opts) {
    514         logErrorForInvalidProfileAccess(user);
    515         try {
    516             mService.showAppDetailsAsUser(mContext.getPackageName(),
    517                     component, sourceBounds, opts, user);
    518         } catch (RemoteException re) {
    519             throw re.rethrowFromSystemServer();
    520         }
    521     }
    522 
    523     /**
    524      * Retrieves a list of config activities for creating {@link ShortcutInfo}.
    525      *
    526      * @param packageName The specific package to query. If null, it checks all installed packages
    527      *            in the profile.
    528      * @param user The UserHandle of the profile.
    529      * @return List of config activities. Can be an empty list but will not be null.
    530      *
    531      * @see Intent#ACTION_CREATE_SHORTCUT
    532      * @see #getShortcutConfigActivityIntent(LauncherActivityInfo)
    533      */
    534     public List<LauncherActivityInfo> getShortcutConfigActivityList(@Nullable String packageName,
    535             @NonNull UserHandle user) {
    536         logErrorForInvalidProfileAccess(user);
    537         try {
    538             return convertToActivityList(mService.getShortcutConfigActivities(
    539                     mContext.getPackageName(), packageName, user),
    540                     user);
    541         } catch (RemoteException re) {
    542             throw re.rethrowFromSystemServer();
    543         }
    544     }
    545 
    546     private List<LauncherActivityInfo> convertToActivityList(
    547             @Nullable ParceledListSlice<ResolveInfo> activities, UserHandle user) {
    548         if (activities == null) {
    549             return Collections.EMPTY_LIST;
    550         }
    551         ArrayList<LauncherActivityInfo> lais = new ArrayList<>();
    552         for (ResolveInfo ri : activities.getList()) {
    553             LauncherActivityInfo lai = new LauncherActivityInfo(mContext, ri.activityInfo, user);
    554             if (DEBUG) {
    555                 Log.v(TAG, "Returning activity for profile " + user + " : "
    556                         + lai.getComponentName());
    557             }
    558             lais.add(lai);
    559         }
    560         return lais;
    561     }
    562 
    563     /**
    564      * Returns an intent sender which can be used to start the configure activity for creating
    565      * custom shortcuts. Use this method if the provider is in another profile as you are not
    566      * allowed to start an activity in another profile.
    567      *
    568      * <p>The caller should receive {@link PinItemRequest} in onActivityResult on
    569      * {@link android.app.Activity#RESULT_OK}.
    570      *
    571      * <p>Callers must be allowed to access the shortcut information, as defined in {@link
    572      * #hasShortcutHostPermission()}.
    573      *
    574      * @param info a configuration activity returned by {@link #getShortcutConfigActivityList}
    575      *
    576      * @throws IllegalStateException when the user is locked or not running.
    577      * @throws SecurityException if {@link #hasShortcutHostPermission()} is false.
    578      *
    579      * @see #getPinItemRequest(Intent)
    580      * @see Intent#ACTION_CREATE_SHORTCUT
    581      * @see android.app.Activity#startIntentSenderForResult
    582      */
    583     @Nullable
    584     public IntentSender getShortcutConfigActivityIntent(@NonNull LauncherActivityInfo info) {
    585         try {
    586             return mService.getShortcutConfigActivityIntent(
    587                     mContext.getPackageName(), info.getComponentName(), info.getUser());
    588         } catch (RemoteException re) {
    589             throw re.rethrowFromSystemServer();
    590         }
    591     }
    592 
    593     /**
    594      * Checks if the package is installed and enabled for a profile.
    595      *
    596      * @param packageName The package to check.
    597      * @param user The UserHandle of the profile.
    598      *
    599      * @return true if the package exists and is enabled.
    600      */
    601     public boolean isPackageEnabled(String packageName, UserHandle user) {
    602         logErrorForInvalidProfileAccess(user);
    603         try {
    604             return mService.isPackageEnabled(mContext.getPackageName(), packageName, user);
    605         } catch (RemoteException re) {
    606             throw re.rethrowFromSystemServer();
    607         }
    608     }
    609 
    610     /**
    611      * Get {@link ApplicationInfo} for a profile
    612      *
    613      * @param packageName The package name of the application
    614      * @param flags Additional option flags {@link PackageManager#getApplicationInfo}
    615      * @param user The UserHandle of the profile.
    616      *
    617      * @return An {@link ApplicationInfo} containing information about the package or
    618      *         null if the package isn't installed for the given user, or the target user
    619      *         is not enabled.
    620      */
    621     public ApplicationInfo getApplicationInfo(@NonNull String packageName,
    622             @ApplicationInfoFlags int flags, @NonNull UserHandle user)
    623             throws PackageManager.NameNotFoundException {
    624         Preconditions.checkNotNull(packageName, "packageName");
    625         Preconditions.checkNotNull(packageName, "user");
    626         logErrorForInvalidProfileAccess(user);
    627         try {
    628             final ApplicationInfo ai = mService
    629                     .getApplicationInfo(mContext.getPackageName(), packageName, flags, user);
    630             if (ai == null) {
    631                 throw new NameNotFoundException("Package " + packageName + " not found for user "
    632                         + user.getIdentifier());
    633             }
    634             return ai;
    635         } catch (RemoteException re) {
    636             throw re.rethrowFromSystemServer();
    637         }
    638     }
    639 
    640     /**
    641      * Checks if the activity exists and it enabled for a profile.
    642      *
    643      * @param component The activity to check.
    644      * @param user The UserHandle of the profile.
    645      *
    646      * @return true if the activity exists and is enabled.
    647      */
    648     public boolean isActivityEnabled(ComponentName component, UserHandle user) {
    649         logErrorForInvalidProfileAccess(user);
    650         try {
    651             return mService.isActivityEnabled(mContext.getPackageName(), component, user);
    652         } catch (RemoteException re) {
    653             throw re.rethrowFromSystemServer();
    654         }
    655     }
    656 
    657     /**
    658      * Returns whether the caller can access the shortcut information.
    659      *
    660      * <p>Only the default launcher can access the shortcut information.
    661      *
    662      * <p>Note when this method returns {@code false}, it may be a temporary situation because
    663      * the user is trying a new launcher application.  The user may decide to change the default
    664      * launcher back to the calling application again, so even if a launcher application loses
    665      * this permission, it does <b>not</b> have to purge pinned shortcut information.
    666      * If the calling launcher application contains pinned shortcuts, they will still work,
    667      * even though the caller no longer has the shortcut host permission.
    668      *
    669      * @throws IllegalStateException when the user is locked.
    670      *
    671      * @see ShortcutManager
    672      */
    673     public boolean hasShortcutHostPermission() {
    674         try {
    675             return mService.hasShortcutHostPermission(mContext.getPackageName());
    676         } catch (RemoteException re) {
    677             throw re.rethrowFromSystemServer();
    678         }
    679     }
    680 
    681     /**
    682      * Returns {@link ShortcutInfo}s that match {@code query}.
    683      *
    684      * <p>Callers must be allowed to access the shortcut information, as defined in {@link
    685      * #hasShortcutHostPermission()}.
    686      *
    687      * @param query result includes shortcuts matching this query.
    688      * @param user The UserHandle of the profile.
    689      *
    690      * @return the IDs of {@link ShortcutInfo}s that match the query.
    691      * @throws IllegalStateException when the user is locked, or when the {@code user} user
    692      * is locked or not running.
    693      *
    694      * @see ShortcutManager
    695      */
    696     @Nullable
    697     public List<ShortcutInfo> getShortcuts(@NonNull ShortcutQuery query,
    698             @NonNull UserHandle user) {
    699         logErrorForInvalidProfileAccess(user);
    700         try {
    701             return mService.getShortcuts(mContext.getPackageName(),
    702                     query.mChangedSince, query.mPackage, query.mShortcutIds, query.mActivity,
    703                     query.mQueryFlags, user)
    704                     .getList();
    705         } catch (RemoteException e) {
    706             throw e.rethrowFromSystemServer();
    707         }
    708     }
    709 
    710     /**
    711      * @hide // No longer used.  Use getShortcuts() instead.  Kept for unit tests.
    712      */
    713     @Nullable
    714     @Deprecated
    715     public List<ShortcutInfo> getShortcutInfo(@NonNull String packageName,
    716             @NonNull List<String> ids, @NonNull UserHandle user) {
    717         final ShortcutQuery q = new ShortcutQuery();
    718         q.setPackage(packageName);
    719         q.setShortcutIds(ids);
    720         q.setQueryFlags(ShortcutQuery.FLAG_GET_ALL_KINDS);
    721         return getShortcuts(q, user);
    722     }
    723 
    724     /**
    725      * Pin shortcuts on a package.
    726      *
    727      * <p>This API is <b>NOT</b> cumulative; this will replace all pinned shortcuts for the package.
    728      * However, different launchers may have different set of pinned shortcuts.
    729      *
    730      * <p>The calling launcher application must be allowed to access the shortcut information,
    731      * as defined in {@link #hasShortcutHostPermission()}.
    732      *
    733      * @param packageName The target package name.
    734      * @param shortcutIds The IDs of the shortcut to be pinned.
    735      * @param user The UserHandle of the profile.
    736      * @throws IllegalStateException when the user is locked, or when the {@code user} user
    737      * is locked or not running.
    738      *
    739      * @see ShortcutManager
    740      */
    741     public void pinShortcuts(@NonNull String packageName, @NonNull List<String> shortcutIds,
    742             @NonNull UserHandle user) {
    743         logErrorForInvalidProfileAccess(user);
    744         try {
    745             mService.pinShortcuts(mContext.getPackageName(), packageName, shortcutIds, user);
    746         } catch (RemoteException e) {
    747             throw e.rethrowFromSystemServer();
    748         }
    749     }
    750 
    751     /**
    752      * @hide kept for testing.
    753      */
    754     @Deprecated
    755     public int getShortcutIconResId(@NonNull ShortcutInfo shortcut) {
    756         return shortcut.getIconResourceId();
    757     }
    758 
    759     /**
    760      * @hide kept for testing.
    761      */
    762     @Deprecated
    763     public int getShortcutIconResId(@NonNull String packageName, @NonNull String shortcutId,
    764             @NonNull UserHandle user) {
    765         final ShortcutQuery q = new ShortcutQuery();
    766         q.setPackage(packageName);
    767         q.setShortcutIds(Arrays.asList(shortcutId));
    768         q.setQueryFlags(ShortcutQuery.FLAG_GET_ALL_KINDS);
    769         final List<ShortcutInfo> shortcuts = getShortcuts(q, user);
    770 
    771         return shortcuts.size() > 0 ? shortcuts.get(0).getIconResourceId() : 0;
    772     }
    773 
    774     /**
    775      * @hide internal/unit tests only
    776      */
    777     public ParcelFileDescriptor getShortcutIconFd(
    778             @NonNull ShortcutInfo shortcut) {
    779         return getShortcutIconFd(shortcut.getPackage(), shortcut.getId(),
    780                 shortcut.getUserId());
    781     }
    782 
    783     /**
    784      * @hide internal/unit tests only
    785      */
    786     public ParcelFileDescriptor getShortcutIconFd(
    787             @NonNull String packageName, @NonNull String shortcutId, @NonNull UserHandle user) {
    788         return getShortcutIconFd(packageName, shortcutId, user.getIdentifier());
    789     }
    790 
    791     private ParcelFileDescriptor getShortcutIconFd(
    792             @NonNull String packageName, @NonNull String shortcutId, int userId) {
    793         try {
    794             return mService.getShortcutIconFd(mContext.getPackageName(),
    795                     packageName, shortcutId, userId);
    796         } catch (RemoteException e) {
    797             throw e.rethrowFromSystemServer();
    798         }
    799     }
    800 
    801     /**
    802      * Returns the icon for this shortcut, without any badging for the profile.
    803      *
    804      * <p>The calling launcher application must be allowed to access the shortcut information,
    805      * as defined in {@link #hasShortcutHostPermission()}.
    806      *
    807      * @param density The preferred density of the icon, zero for default density. Use
    808      * density DPI values from {@link DisplayMetrics}.
    809      *
    810      * @return The drawable associated with the shortcut.
    811      * @throws IllegalStateException when the user is locked, or when the {@code user} user
    812      * is locked or not running.
    813      *
    814      * @see ShortcutManager
    815      * @see #getShortcutBadgedIconDrawable(ShortcutInfo, int)
    816      * @see DisplayMetrics
    817      */
    818     public Drawable getShortcutIconDrawable(@NonNull ShortcutInfo shortcut, int density) {
    819         if (shortcut.hasIconFile()) {
    820             final ParcelFileDescriptor pfd = getShortcutIconFd(shortcut);
    821             if (pfd == null) {
    822                 return null;
    823             }
    824             try {
    825                 final Bitmap bmp = BitmapFactory.decodeFileDescriptor(pfd.getFileDescriptor());
    826                 if (bmp != null) {
    827                     BitmapDrawable dr = new BitmapDrawable(mContext.getResources(), bmp);
    828                     if (shortcut.hasAdaptiveBitmap()) {
    829                         return new AdaptiveIconDrawable(null, dr);
    830                     } else {
    831                         return dr;
    832                     }
    833                 }
    834                 return null;
    835             } finally {
    836                 try {
    837                     pfd.close();
    838                 } catch (IOException ignore) {
    839                 }
    840             }
    841         } else if (shortcut.hasIconResource()) {
    842             return loadDrawableResourceFromPackage(shortcut.getPackage(),
    843                     shortcut.getIconResourceId(), shortcut.getUserHandle(), density);
    844         } else if (shortcut.getIcon() != null) {
    845             // This happens if a shortcut is pending-approval.
    846             final Icon icon = shortcut.getIcon();
    847             switch (icon.getType()) {
    848                 case Icon.TYPE_RESOURCE: {
    849                     return loadDrawableResourceFromPackage(shortcut.getPackage(),
    850                             icon.getResId(), shortcut.getUserHandle(), density);
    851                 }
    852                 case Icon.TYPE_BITMAP:
    853                 case Icon.TYPE_ADAPTIVE_BITMAP: {
    854                     return icon.loadDrawable(mContext);
    855                 }
    856                 default:
    857                     return null; // Shouldn't happen though.
    858             }
    859         } else {
    860             return null; // Has no icon.
    861         }
    862     }
    863 
    864     private Drawable loadDrawableResourceFromPackage(String packageName, int resId,
    865             UserHandle user, int density) {
    866         try {
    867             if (resId == 0) {
    868                 return null; // Shouldn't happen but just in case.
    869             }
    870             final ApplicationInfo ai = getApplicationInfo(packageName, /* flags =*/ 0, user);
    871             final Resources res = mContext.getPackageManager().getResourcesForApplication(ai);
    872             return res.getDrawableForDensity(resId, density);
    873         } catch (NameNotFoundException | Resources.NotFoundException e) {
    874             return null;
    875         }
    876     }
    877 
    878     /**
    879      * Returns the shortcut icon with badging appropriate for the profile.
    880      *
    881      * <p>The calling launcher application must be allowed to access the shortcut information,
    882      * as defined in {@link #hasShortcutHostPermission()}.
    883      *
    884      * @param density Optional density for the icon, or 0 to use the default density. Use
    885      * @return A badged icon for the shortcut.
    886      * @throws IllegalStateException when the user is locked, or when the {@code user} user
    887      * is locked or not running.
    888      *
    889      * @see ShortcutManager
    890      * @see #getShortcutIconDrawable(ShortcutInfo, int)
    891      * @see DisplayMetrics
    892      */
    893     public Drawable getShortcutBadgedIconDrawable(ShortcutInfo shortcut, int density) {
    894         final Drawable originalIcon = getShortcutIconDrawable(shortcut, density);
    895 
    896         return (originalIcon == null) ? null : mContext.getPackageManager().getUserBadgedIcon(
    897                 originalIcon, shortcut.getUserHandle());
    898     }
    899 
    900     /**
    901      * Starts a shortcut.
    902      *
    903      * <p>The calling launcher application must be allowed to access the shortcut information,
    904      * as defined in {@link #hasShortcutHostPermission()}.
    905      *
    906      * @param packageName The target shortcut package name.
    907      * @param shortcutId The target shortcut ID.
    908      * @param sourceBounds The Rect containing the source bounds of the clicked icon.
    909      * @param startActivityOptions Options to pass to startActivity.
    910      * @param user The UserHandle of the profile.
    911      * @throws IllegalStateException when the user is locked, or when the {@code user} user
    912      * is locked or not running.
    913      *
    914      * @throws android.content.ActivityNotFoundException failed to start shortcut. (e.g.
    915      * the shortcut no longer exists, is disabled, the intent receiver activity doesn't exist, etc)
    916      */
    917     public void startShortcut(@NonNull String packageName, @NonNull String shortcutId,
    918             @Nullable Rect sourceBounds, @Nullable Bundle startActivityOptions,
    919             @NonNull UserHandle user) {
    920         logErrorForInvalidProfileAccess(user);
    921 
    922         startShortcut(packageName, shortcutId, sourceBounds, startActivityOptions,
    923                 user.getIdentifier());
    924     }
    925 
    926     /**
    927      * Launches a shortcut.
    928      *
    929      * <p>The calling launcher application must be allowed to access the shortcut information,
    930      * as defined in {@link #hasShortcutHostPermission()}.
    931      *
    932      * @param shortcut The target shortcut.
    933      * @param sourceBounds The Rect containing the source bounds of the clicked icon.
    934      * @param startActivityOptions Options to pass to startActivity.
    935      * @throws IllegalStateException when the user is locked, or when the {@code user} user
    936      * is locked or not running.
    937      *
    938      * @throws android.content.ActivityNotFoundException failed to start shortcut. (e.g.
    939      * the shortcut no longer exists, is disabled, the intent receiver activity doesn't exist, etc)
    940      */
    941     public void startShortcut(@NonNull ShortcutInfo shortcut,
    942             @Nullable Rect sourceBounds, @Nullable Bundle startActivityOptions) {
    943         startShortcut(shortcut.getPackage(), shortcut.getId(),
    944                 sourceBounds, startActivityOptions,
    945                 shortcut.getUserId());
    946     }
    947 
    948     private void startShortcut(@NonNull String packageName, @NonNull String shortcutId,
    949             @Nullable Rect sourceBounds, @Nullable Bundle startActivityOptions,
    950             int userId) {
    951         try {
    952             final boolean success =
    953                     mService.startShortcut(mContext.getPackageName(), packageName, shortcutId,
    954                     sourceBounds, startActivityOptions, userId);
    955             if (!success) {
    956                 throw new ActivityNotFoundException("Shortcut could not be started");
    957             }
    958         } catch (RemoteException e) {
    959             throw e.rethrowFromSystemServer();
    960         }
    961     }
    962 
    963     /**
    964      * Registers a callback for changes to packages in current and managed profiles.
    965      *
    966      * @param callback The callback to register.
    967      */
    968     public void registerCallback(Callback callback) {
    969         registerCallback(callback, null);
    970     }
    971 
    972     /**
    973      * Registers a callback for changes to packages in current and managed profiles.
    974      *
    975      * @param callback The callback to register.
    976      * @param handler that should be used to post callbacks on, may be null.
    977      */
    978     public void registerCallback(Callback callback, Handler handler) {
    979         synchronized (this) {
    980             if (callback != null && findCallbackLocked(callback) < 0) {
    981                 boolean addedFirstCallback = mCallbacks.size() == 0;
    982                 addCallbackLocked(callback, handler);
    983                 if (addedFirstCallback) {
    984                     try {
    985                         mService.addOnAppsChangedListener(mContext.getPackageName(),
    986                                 mAppsChangedListener);
    987                     } catch (RemoteException re) {
    988                         throw re.rethrowFromSystemServer();
    989                     }
    990                 }
    991             }
    992         }
    993     }
    994 
    995     /**
    996      * Unregisters a callback that was previously registered.
    997      *
    998      * @param callback The callback to unregister.
    999      * @see #registerCallback(Callback)
   1000      */
   1001     public void unregisterCallback(Callback callback) {
   1002         synchronized (this) {
   1003             removeCallbackLocked(callback);
   1004             if (mCallbacks.size() == 0) {
   1005                 try {
   1006                     mService.removeOnAppsChangedListener(mAppsChangedListener);
   1007                 } catch (RemoteException re) {
   1008                     throw re.rethrowFromSystemServer();
   1009                 }
   1010             }
   1011         }
   1012     }
   1013 
   1014     /** @return position in mCallbacks for callback or -1 if not present. */
   1015     private int findCallbackLocked(Callback callback) {
   1016         if (callback == null) {
   1017             throw new IllegalArgumentException("Callback cannot be null");
   1018         }
   1019         final int size = mCallbacks.size();
   1020         for (int i = 0; i < size; ++i) {
   1021             if (mCallbacks.get(i).mCallback == callback) {
   1022                 return i;
   1023             }
   1024         }
   1025         return -1;
   1026     }
   1027 
   1028     private void removeCallbackLocked(Callback callback) {
   1029         int pos = findCallbackLocked(callback);
   1030         if (pos >= 0) {
   1031             mCallbacks.remove(pos);
   1032         }
   1033     }
   1034 
   1035     private void addCallbackLocked(Callback callback, Handler handler) {
   1036         // Remove if already present.
   1037         removeCallbackLocked(callback);
   1038         if (handler == null) {
   1039             handler = new Handler();
   1040         }
   1041         CallbackMessageHandler toAdd = new CallbackMessageHandler(handler.getLooper(), callback);
   1042         mCallbacks.add(toAdd);
   1043     }
   1044 
   1045     private IOnAppsChangedListener.Stub mAppsChangedListener = new IOnAppsChangedListener.Stub() {
   1046 
   1047         @Override
   1048         public void onPackageRemoved(UserHandle user, String packageName)
   1049                 throws RemoteException {
   1050             if (DEBUG) {
   1051                 Log.d(TAG, "onPackageRemoved " + user.getIdentifier() + "," + packageName);
   1052             }
   1053             synchronized (LauncherApps.this) {
   1054                 for (CallbackMessageHandler callback : mCallbacks) {
   1055                     callback.postOnPackageRemoved(packageName, user);
   1056                 }
   1057             }
   1058         }
   1059 
   1060         @Override
   1061         public void onPackageChanged(UserHandle user, String packageName) throws RemoteException {
   1062             if (DEBUG) {
   1063                 Log.d(TAG, "onPackageChanged " + user.getIdentifier() + "," + packageName);
   1064             }
   1065             synchronized (LauncherApps.this) {
   1066                 for (CallbackMessageHandler callback : mCallbacks) {
   1067                     callback.postOnPackageChanged(packageName, user);
   1068                 }
   1069             }
   1070         }
   1071 
   1072         @Override
   1073         public void onPackageAdded(UserHandle user, String packageName) throws RemoteException {
   1074             if (DEBUG) {
   1075                 Log.d(TAG, "onPackageAdded " + user.getIdentifier() + "," + packageName);
   1076             }
   1077             synchronized (LauncherApps.this) {
   1078                 for (CallbackMessageHandler callback : mCallbacks) {
   1079                     callback.postOnPackageAdded(packageName, user);
   1080                 }
   1081             }
   1082         }
   1083 
   1084         @Override
   1085         public void onPackagesAvailable(UserHandle user, String[] packageNames, boolean replacing)
   1086                 throws RemoteException {
   1087             if (DEBUG) {
   1088                 Log.d(TAG, "onPackagesAvailable " + user.getIdentifier() + "," + packageNames);
   1089             }
   1090             synchronized (LauncherApps.this) {
   1091                 for (CallbackMessageHandler callback : mCallbacks) {
   1092                     callback.postOnPackagesAvailable(packageNames, user, replacing);
   1093                 }
   1094             }
   1095         }
   1096 
   1097         @Override
   1098         public void onPackagesUnavailable(UserHandle user, String[] packageNames, boolean replacing)
   1099                 throws RemoteException {
   1100             if (DEBUG) {
   1101                 Log.d(TAG, "onPackagesUnavailable " + user.getIdentifier() + "," + packageNames);
   1102             }
   1103             synchronized (LauncherApps.this) {
   1104                 for (CallbackMessageHandler callback : mCallbacks) {
   1105                     callback.postOnPackagesUnavailable(packageNames, user, replacing);
   1106                 }
   1107             }
   1108         }
   1109 
   1110         @Override
   1111         public void onPackagesSuspended(UserHandle user, String[] packageNames)
   1112                 throws RemoteException {
   1113             if (DEBUG) {
   1114                 Log.d(TAG, "onPackagesSuspended " + user.getIdentifier() + "," + packageNames);
   1115             }
   1116             synchronized (LauncherApps.this) {
   1117                 for (CallbackMessageHandler callback : mCallbacks) {
   1118                     callback.postOnPackagesSuspended(packageNames, user);
   1119                 }
   1120             }
   1121         }
   1122 
   1123         @Override
   1124         public void onPackagesUnsuspended(UserHandle user, String[] packageNames)
   1125                 throws RemoteException {
   1126             if (DEBUG) {
   1127                 Log.d(TAG, "onPackagesUnsuspended " + user.getIdentifier() + "," + packageNames);
   1128             }
   1129             synchronized (LauncherApps.this) {
   1130                 for (CallbackMessageHandler callback : mCallbacks) {
   1131                     callback.postOnPackagesUnsuspended(packageNames, user);
   1132                 }
   1133             }
   1134         }
   1135 
   1136         @Override
   1137         public void onShortcutChanged(UserHandle user, String packageName,
   1138                 ParceledListSlice shortcuts) {
   1139             if (DEBUG) {
   1140                 Log.d(TAG, "onShortcutChanged " + user.getIdentifier() + "," + packageName);
   1141             }
   1142             final List<ShortcutInfo> list = shortcuts.getList();
   1143             synchronized (LauncherApps.this) {
   1144                 for (CallbackMessageHandler callback : mCallbacks) {
   1145                     callback.postOnShortcutChanged(packageName, user, list);
   1146                 }
   1147             }
   1148         }
   1149     };
   1150 
   1151     private static class CallbackMessageHandler extends Handler {
   1152         private static final int MSG_ADDED = 1;
   1153         private static final int MSG_REMOVED = 2;
   1154         private static final int MSG_CHANGED = 3;
   1155         private static final int MSG_AVAILABLE = 4;
   1156         private static final int MSG_UNAVAILABLE = 5;
   1157         private static final int MSG_SUSPENDED = 6;
   1158         private static final int MSG_UNSUSPENDED = 7;
   1159         private static final int MSG_SHORTCUT_CHANGED = 8;
   1160 
   1161         private LauncherApps.Callback mCallback;
   1162 
   1163         private static class CallbackInfo {
   1164             String[] packageNames;
   1165             String packageName;
   1166             boolean replacing;
   1167             UserHandle user;
   1168             List<ShortcutInfo> shortcuts;
   1169         }
   1170 
   1171         public CallbackMessageHandler(Looper looper, LauncherApps.Callback callback) {
   1172             super(looper, null, true);
   1173             mCallback = callback;
   1174         }
   1175 
   1176         @Override
   1177         public void handleMessage(Message msg) {
   1178             if (mCallback == null || !(msg.obj instanceof CallbackInfo)) {
   1179                 return;
   1180             }
   1181             CallbackInfo info = (CallbackInfo) msg.obj;
   1182             switch (msg.what) {
   1183                 case MSG_ADDED:
   1184                     mCallback.onPackageAdded(info.packageName, info.user);
   1185                     break;
   1186                 case MSG_REMOVED:
   1187                     mCallback.onPackageRemoved(info.packageName, info.user);
   1188                     break;
   1189                 case MSG_CHANGED:
   1190                     mCallback.onPackageChanged(info.packageName, info.user);
   1191                     break;
   1192                 case MSG_AVAILABLE:
   1193                     mCallback.onPackagesAvailable(info.packageNames, info.user, info.replacing);
   1194                     break;
   1195                 case MSG_UNAVAILABLE:
   1196                     mCallback.onPackagesUnavailable(info.packageNames, info.user, info.replacing);
   1197                     break;
   1198                 case MSG_SUSPENDED:
   1199                     mCallback.onPackagesSuspended(info.packageNames, info.user);
   1200                     break;
   1201                 case MSG_UNSUSPENDED:
   1202                     mCallback.onPackagesUnsuspended(info.packageNames, info.user);
   1203                     break;
   1204                 case MSG_SHORTCUT_CHANGED:
   1205                     mCallback.onShortcutsChanged(info.packageName, info.shortcuts, info.user);
   1206                     break;
   1207             }
   1208         }
   1209 
   1210         public void postOnPackageAdded(String packageName, UserHandle user) {
   1211             CallbackInfo info = new CallbackInfo();
   1212             info.packageName = packageName;
   1213             info.user = user;
   1214             obtainMessage(MSG_ADDED, info).sendToTarget();
   1215         }
   1216 
   1217         public void postOnPackageRemoved(String packageName, UserHandle user) {
   1218             CallbackInfo info = new CallbackInfo();
   1219             info.packageName = packageName;
   1220             info.user = user;
   1221             obtainMessage(MSG_REMOVED, info).sendToTarget();
   1222         }
   1223 
   1224         public void postOnPackageChanged(String packageName, UserHandle user) {
   1225             CallbackInfo info = new CallbackInfo();
   1226             info.packageName = packageName;
   1227             info.user = user;
   1228             obtainMessage(MSG_CHANGED, info).sendToTarget();
   1229         }
   1230 
   1231         public void postOnPackagesAvailable(String[] packageNames, UserHandle user,
   1232                 boolean replacing) {
   1233             CallbackInfo info = new CallbackInfo();
   1234             info.packageNames = packageNames;
   1235             info.replacing = replacing;
   1236             info.user = user;
   1237             obtainMessage(MSG_AVAILABLE, info).sendToTarget();
   1238         }
   1239 
   1240         public void postOnPackagesUnavailable(String[] packageNames, UserHandle user,
   1241                 boolean replacing) {
   1242             CallbackInfo info = new CallbackInfo();
   1243             info.packageNames = packageNames;
   1244             info.replacing = replacing;
   1245             info.user = user;
   1246             obtainMessage(MSG_UNAVAILABLE, info).sendToTarget();
   1247         }
   1248 
   1249         public void postOnPackagesSuspended(String[] packageNames, UserHandle user) {
   1250             CallbackInfo info = new CallbackInfo();
   1251             info.packageNames = packageNames;
   1252             info.user = user;
   1253             obtainMessage(MSG_SUSPENDED, info).sendToTarget();
   1254         }
   1255 
   1256         public void postOnPackagesUnsuspended(String[] packageNames, UserHandle user) {
   1257             CallbackInfo info = new CallbackInfo();
   1258             info.packageNames = packageNames;
   1259             info.user = user;
   1260             obtainMessage(MSG_UNSUSPENDED, info).sendToTarget();
   1261         }
   1262 
   1263         public void postOnShortcutChanged(String packageName, UserHandle user,
   1264                 List<ShortcutInfo> shortcuts) {
   1265             CallbackInfo info = new CallbackInfo();
   1266             info.packageName = packageName;
   1267             info.user = user;
   1268             info.shortcuts = shortcuts;
   1269             obtainMessage(MSG_SHORTCUT_CHANGED, info).sendToTarget();
   1270         }
   1271     }
   1272 
   1273     /**
   1274      * A helper method to extract a {@link PinItemRequest} set to
   1275      * the {@link #EXTRA_PIN_ITEM_REQUEST} extra.
   1276      */
   1277     public PinItemRequest getPinItemRequest(Intent intent) {
   1278         return intent.getParcelableExtra(EXTRA_PIN_ITEM_REQUEST);
   1279     }
   1280 
   1281     /**
   1282      * Represents a "pin shortcut" or a "pin appwidget" request made by an app, which is sent with
   1283      * an {@link #ACTION_CONFIRM_PIN_SHORTCUT} or {@link #ACTION_CONFIRM_PIN_APPWIDGET} intent
   1284      * respectively to the default launcher app.
   1285      *
   1286      * <h3>Request of the {@link #REQUEST_TYPE_SHORTCUT} type.
   1287      *
   1288      * <p>A {@link #REQUEST_TYPE_SHORTCUT} request represents a request to pin a
   1289      * {@link ShortcutInfo}.  If the launcher accepts a request, call {@link #accept()},
   1290      * or {@link #accept(Bundle)} with a null or empty Bundle.  No options are defined for
   1291      * pin-shortcuts requests.
   1292      *
   1293      * <p>{@link #getShortcutInfo()} always returns a non-null {@link ShortcutInfo} for this type.
   1294      *
   1295      * <p>The launcher may receive a request with a {@link ShortcutInfo} that is already pinned, in
   1296      * which case {@link ShortcutInfo#isPinned()} returns true.  This means the user wants to create
   1297      * another pinned shortcut for a shortcut that's already pinned.  If the launcher accepts it,
   1298      * {@link #accept()} must still be called even though the shortcut is already pinned, and
   1299      * create a new pinned shortcut icon for it.
   1300      *
   1301      * <p>See also {@link ShortcutManager} for more details.
   1302      *
   1303      * <h3>Request of the {@link #REQUEST_TYPE_APPWIDGET} type.
   1304      *
   1305      * <p>A {@link #REQUEST_TYPE_SHORTCUT} request represents a request to pin a
   1306      * an AppWidget.  If the launcher accepts a request, call {@link #accept(Bundle)} with
   1307      * the appwidget integer ID set to the
   1308      * {@link android.appwidget.AppWidgetManager#EXTRA_APPWIDGET_ID} extra.
   1309      *
   1310      * <p>{@link #getAppWidgetProviderInfo(Context)} always returns a non-null
   1311      * {@link AppWidgetProviderInfo} for this type.
   1312      *
   1313      * <p>See also {@link AppWidgetManager} for more details.
   1314      *
   1315      * @see #EXTRA_PIN_ITEM_REQUEST
   1316      * @see #getPinItemRequest(Intent)
   1317      */
   1318     public static final class PinItemRequest implements Parcelable {
   1319 
   1320         /** This is a request to pin shortcut. */
   1321         public static final int REQUEST_TYPE_SHORTCUT = 1;
   1322 
   1323         /** This is a request to pin app widget. */
   1324         public static final int REQUEST_TYPE_APPWIDGET = 2;
   1325 
   1326         /** @hide */
   1327         @IntDef(value = {REQUEST_TYPE_SHORTCUT})
   1328         @Retention(RetentionPolicy.SOURCE)
   1329         public @interface RequestType {}
   1330 
   1331         private final int mRequestType;
   1332         private final IPinItemRequest mInner;
   1333 
   1334         /**
   1335          * @hide
   1336          */
   1337         public PinItemRequest(IPinItemRequest inner, int type) {
   1338             mInner = inner;
   1339             mRequestType = type;
   1340         }
   1341 
   1342         /**
   1343          * Represents the type of a request, which is one of the {@code REQUEST_TYPE_} constants.
   1344          *
   1345          * @return one of the {@code REQUEST_TYPE_} constants.
   1346          */
   1347         @RequestType
   1348         public int getRequestType() {
   1349             return mRequestType;
   1350         }
   1351 
   1352         /**
   1353          * {@link ShortcutInfo} sent by the requesting app.
   1354          * Always non-null for a {@link #REQUEST_TYPE_SHORTCUT} request, and always null for a
   1355          * different request type.
   1356          *
   1357          * @return requested {@link ShortcutInfo} when a request is of the
   1358          * {@link #REQUEST_TYPE_SHORTCUT} type.  Null otherwise.
   1359          */
   1360         @Nullable
   1361         public ShortcutInfo getShortcutInfo() {
   1362             try {
   1363                 return mInner.getShortcutInfo();
   1364             } catch (RemoteException e) {
   1365                 throw e.rethrowAsRuntimeException();
   1366             }
   1367         }
   1368 
   1369         /**
   1370          * {@link AppWidgetProviderInfo} sent by the requesting app.
   1371          * Always non-null for a {@link #REQUEST_TYPE_APPWIDGET} request, and always null for a
   1372          * different request type.
   1373          *
   1374          * @return requested {@link AppWidgetProviderInfo} when a request is of the
   1375          * {@link #REQUEST_TYPE_APPWIDGET} type.  Null otherwise.
   1376          */
   1377         @Nullable
   1378         public AppWidgetProviderInfo getAppWidgetProviderInfo(Context context) {
   1379             try {
   1380                 final AppWidgetProviderInfo info = mInner.getAppWidgetProviderInfo();
   1381                 if (info == null) {
   1382                     return null;
   1383                 }
   1384                 info.updateDimensions(context.getResources().getDisplayMetrics());
   1385                 return info;
   1386             } catch (RemoteException e) {
   1387                 throw e.rethrowAsRuntimeException();
   1388             }
   1389         }
   1390 
   1391         /**
   1392          * Any extras sent by the requesting app.
   1393          *
   1394          * @return For a shortcut request, this method always return null.  For an AppWidget
   1395          * request, this method returns the extras passed to the
   1396          * {@link android.appwidget.AppWidgetManager#requestPinAppWidget(
   1397          * ComponentName, Bundle, PendingIntent)} API.  See {@link AppWidgetManager} for details.
   1398          */
   1399         @Nullable
   1400         public Bundle getExtras() {
   1401             try {
   1402                 return mInner.getExtras();
   1403             } catch (RemoteException e) {
   1404                 throw e.rethrowAsRuntimeException();
   1405             }
   1406         }
   1407 
   1408         /**
   1409          * Return whether a request is still valid.
   1410          *
   1411          * @return {@code TRUE} if a request is valid and {@link #accept(Bundle)} may be called.
   1412          */
   1413         public boolean isValid() {
   1414             try {
   1415                 return mInner.isValid();
   1416             } catch (RemoteException e) {
   1417                 return false;
   1418             }
   1419         }
   1420 
   1421         /**
   1422          * Called by the receiving launcher app when the user accepts the request.
   1423          *
   1424          * @param options must be set for a {@link #REQUEST_TYPE_APPWIDGET} request.
   1425          *
   1426          * @return {@code TRUE} if the shortcut or the AppWidget has actually been pinned.
   1427          * {@code FALSE} if the item hasn't been pinned, for example, because the request had
   1428          * already been canceled, in which case the launcher must not pin the requested item.
   1429          */
   1430         public boolean accept(@Nullable Bundle options) {
   1431             try {
   1432                 return mInner.accept(options);
   1433             } catch (RemoteException e) {
   1434                 throw e.rethrowFromSystemServer();
   1435             }
   1436         }
   1437 
   1438         /**
   1439          * Called by the receiving launcher app when the user accepts the request, with no options.
   1440          *
   1441          * @return {@code TRUE} if the shortcut or the AppWidget has actually been pinned.
   1442          * {@code FALSE} if the item hasn't been pinned, for example, because the request had
   1443          * already been canceled, in which case the launcher must not pin the requested item.
   1444          */
   1445         public boolean accept() {
   1446             return accept(/* options= */ null);
   1447         }
   1448 
   1449         private PinItemRequest(Parcel source) {
   1450             final ClassLoader cl = getClass().getClassLoader();
   1451 
   1452             mRequestType = source.readInt();
   1453             mInner = IPinItemRequest.Stub.asInterface(source.readStrongBinder());
   1454         }
   1455 
   1456         @Override
   1457         public void writeToParcel(Parcel dest, int flags) {
   1458             dest.writeInt(mRequestType);
   1459             dest.writeStrongBinder(mInner.asBinder());
   1460         }
   1461 
   1462         public static final Creator<PinItemRequest> CREATOR =
   1463                 new Creator<PinItemRequest>() {
   1464                     public PinItemRequest createFromParcel(Parcel source) {
   1465                         return new PinItemRequest(source);
   1466                     }
   1467                     public PinItemRequest[] newArray(int size) {
   1468                         return new PinItemRequest[size];
   1469                     }
   1470                 };
   1471 
   1472         @Override
   1473         public int describeContents() {
   1474             return 0;
   1475         }
   1476     }
   1477 }
   1478