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.CallbackExecutor;
20 import android.annotation.IntDef;
21 import android.annotation.NonNull;
22 import android.annotation.Nullable;
23 import android.annotation.SdkConstant;
24 import android.annotation.SdkConstant.SdkConstantType;
25 import android.annotation.SystemApi;
26 import android.annotation.SystemService;
27 import android.annotation.TestApi;
28 import android.app.PendingIntent;
29 import android.appwidget.AppWidgetManager;
30 import android.appwidget.AppWidgetProviderInfo;
31 import android.compat.annotation.UnsupportedAppUsage;
32 import android.content.ActivityNotFoundException;
33 import android.content.ComponentName;
34 import android.content.Context;
35 import android.content.Intent;
36 import android.content.IntentSender;
37 import android.content.pm.PackageInstaller.SessionCallback;
38 import android.content.pm.PackageInstaller.SessionCallbackDelegate;
39 import android.content.pm.PackageInstaller.SessionInfo;
40 import android.content.pm.PackageManager.ApplicationInfoFlags;
41 import android.content.pm.PackageManager.NameNotFoundException;
42 import android.content.res.Resources;
43 import android.graphics.Bitmap;
44 import android.graphics.BitmapFactory;
45 import android.graphics.Rect;
46 import android.graphics.drawable.AdaptiveIconDrawable;
47 import android.graphics.drawable.BitmapDrawable;
48 import android.graphics.drawable.Drawable;
49 import android.graphics.drawable.Icon;
50 import android.os.Build;
51 import android.os.Bundle;
52 import android.os.Handler;
53 import android.os.Looper;
54 import android.os.Message;
55 import android.os.Parcel;
56 import android.os.ParcelFileDescriptor;
57 import android.os.Parcelable;
58 import android.os.RemoteException;
59 import android.os.ServiceManager;
60 import android.os.UserHandle;
61 import android.os.UserManager;
62 import android.util.DisplayMetrics;
63 import android.util.Log;
64 
65 import com.android.internal.util.Preconditions;
66 
67 import java.io.IOException;
68 import java.lang.annotation.Retention;
69 import java.lang.annotation.RetentionPolicy;
70 import java.util.ArrayList;
71 import java.util.Arrays;
72 import java.util.Collections;
73 import java.util.Iterator;
74 import java.util.List;
75 import java.util.concurrent.Executor;
76 
77 /**
78  * Class for retrieving a list of launchable activities for the current user and any associated
79  * managed profiles that are visible to the current user, which can be retrieved with
80  * {@link #getProfiles}. This is mainly for use by launchers.
81  *
82  * Apps can be queried for each user profile.
83  * Since the PackageManager will not deliver package broadcasts for other profiles, you can register
84  * for package changes here.
85  * <p>
86  * To watch for managed profiles being added or removed, register for the following broadcasts:
87  * {@link Intent#ACTION_MANAGED_PROFILE_ADDED} and {@link Intent#ACTION_MANAGED_PROFILE_REMOVED}.
88  * <p>
89  * Note as of Android O, apps on a managed profile are no longer allowed to access apps on the
90  * main profile.  Apps can only access profiles returned by {@link #getProfiles()}.
91  */
92 @SystemService(Context.LAUNCHER_APPS_SERVICE)
93 public class LauncherApps {
94 
95     static final String TAG = "LauncherApps";
96     static final boolean DEBUG = false;
97 
98     /**
99      * Activity Action: For the default launcher to show the confirmation dialog to create
100      * a pinned shortcut.
101      *
102      * <p>See the {@link ShortcutManager} javadoc for details.
103      *
104      * <p>
105      * Use {@link #getPinItemRequest(Intent)} to get a {@link PinItemRequest} object,
106      * and call {@link PinItemRequest#accept(Bundle)}
107      * if the user accepts.  If the user doesn't accept, no further action is required.
108      *
109      * @see #EXTRA_PIN_ITEM_REQUEST
110      */
111     @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
112     public static final String ACTION_CONFIRM_PIN_SHORTCUT =
113             "android.content.pm.action.CONFIRM_PIN_SHORTCUT";
114 
115     /**
116      * Activity Action: For the default launcher to show the confirmation dialog to create
117      * a pinned app widget.
118      *
119      * <p>See the {@link android.appwidget.AppWidgetManager#requestPinAppWidget} javadoc for
120      * details.
121      *
122      * <p>
123      * Use {@link #getPinItemRequest(Intent)} to get a {@link PinItemRequest} object,
124      * and call {@link PinItemRequest#accept(Bundle)}
125      * if the user accepts.  If the user doesn't accept, no further action is required.
126      *
127      * @see #EXTRA_PIN_ITEM_REQUEST
128      */
129     @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
130     public static final String ACTION_CONFIRM_PIN_APPWIDGET =
131             "android.content.pm.action.CONFIRM_PIN_APPWIDGET";
132 
133     /**
134      * An extra for {@link #ACTION_CONFIRM_PIN_SHORTCUT} &amp; {@link #ACTION_CONFIRM_PIN_APPWIDGET}
135      * containing a {@link PinItemRequest} of appropriate type asked to pin.
136      *
137      * <p>A helper function {@link #getPinItemRequest(Intent)} can be used
138      * instead of using this constant directly.
139      *
140      * @see #ACTION_CONFIRM_PIN_SHORTCUT
141      * @see #ACTION_CONFIRM_PIN_APPWIDGET
142      */
143     public static final String EXTRA_PIN_ITEM_REQUEST =
144             "android.content.pm.extra.PIN_ITEM_REQUEST";
145 
146     private final Context mContext;
147     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
148     private final ILauncherApps mService;
149     @UnsupportedAppUsage
150     private final PackageManager mPm;
151     private final UserManager mUserManager;
152 
153     private final List<CallbackMessageHandler> mCallbacks = new ArrayList<>();
154     private final List<SessionCallbackDelegate> mDelegates = new ArrayList<>();
155 
156     /**
157      * Callbacks for package changes to this and related managed profiles.
158      */
159     public static abstract class Callback {
160         /**
161          * Indicates that a package was removed from the specified profile.
162          *
163          * If a package is removed while being updated onPackageChanged will be
164          * called instead.
165          *
166          * @param packageName The name of the package that was removed.
167          * @param user The UserHandle of the profile that generated the change.
168          */
onPackageRemoved(String packageName, UserHandle user)169         abstract public void onPackageRemoved(String packageName, UserHandle user);
170 
171         /**
172          * Indicates that a package was added to the specified profile.
173          *
174          * If a package is added while being updated then onPackageChanged will be
175          * called instead.
176          *
177          * @param packageName The name of the package that was added.
178          * @param user The UserHandle of the profile that generated the change.
179          */
onPackageAdded(String packageName, UserHandle user)180         abstract public void onPackageAdded(String packageName, UserHandle user);
181 
182         /**
183          * Indicates that a package was modified in the specified profile.
184          * This can happen, for example, when the package is updated or when
185          * one or more components are enabled or disabled.
186          *
187          * @param packageName The name of the package that has changed.
188          * @param user The UserHandle of the profile that generated the change.
189          */
onPackageChanged(String packageName, UserHandle user)190         abstract public void onPackageChanged(String packageName, UserHandle user);
191 
192         /**
193          * Indicates that one or more packages have become available. For
194          * example, this can happen when a removable storage card has
195          * reappeared.
196          *
197          * @param packageNames The names of the packages that have become
198          *            available.
199          * @param user The UserHandle of the profile that generated the change.
200          * @param replacing Indicates whether these packages are replacing
201          *            existing ones.
202          */
onPackagesAvailable(String[] packageNames, UserHandle user, boolean replacing)203         abstract public void onPackagesAvailable(String[] packageNames, UserHandle user,
204                 boolean replacing);
205 
206         /**
207          * Indicates that one or more packages have become unavailable. For
208          * example, this can happen when a removable storage card has been
209          * removed.
210          *
211          * @param packageNames The names of the packages that have become
212          *            unavailable.
213          * @param user The UserHandle of the profile that generated the change.
214          * @param replacing Indicates whether the packages are about to be
215          *            replaced with new versions.
216          */
onPackagesUnavailable(String[] packageNames, UserHandle user, boolean replacing)217         abstract public void onPackagesUnavailable(String[] packageNames, UserHandle user,
218                 boolean replacing);
219 
220         /**
221          * Indicates that one or more packages have been suspended. For
222          * example, this can happen when a Device Administrator suspends
223          * an applicaton.
224          *
225          * <p>Note: On devices running {@link android.os.Build.VERSION_CODES#P Android P} or higher,
226          * any apps that override {@link #onPackagesSuspended(String[], UserHandle, Bundle)} will
227          * not receive this callback.
228          *
229          * @param packageNames The names of the packages that have just been
230          *            suspended.
231          * @param user The UserHandle of the profile that generated the change.
232          */
onPackagesSuspended(String[] packageNames, UserHandle user)233         public void onPackagesSuspended(String[] packageNames, UserHandle user) {
234         }
235 
236         /**
237          * Indicates that one or more packages have been suspended. A device administrator or an app
238          * with {@code android.permission.SUSPEND_APPS} can do this.
239          *
240          * <p>A suspending app with the permission {@code android.permission.SUSPEND_APPS} can
241          * optionally provide a {@link Bundle} of extra information that it deems helpful for the
242          * launcher to handle the suspended state of these packages. The contents of this
243          * {@link Bundle} are supposed to be a contract between the suspending app and the launcher.
244          *
245          * @param packageNames The names of the packages that have just been suspended.
246          * @param user the user for which the given packages were suspended.
247          * @param launcherExtras A {@link Bundle} of extras for the launcher, if provided to the
248          *                      system, {@code null} otherwise.
249          * @see PackageManager#isPackageSuspended()
250          * @see #getSuspendedPackageLauncherExtras(String, UserHandle)
251          */
onPackagesSuspended(String[] packageNames, UserHandle user, @Nullable Bundle launcherExtras)252         public void onPackagesSuspended(String[] packageNames, UserHandle user,
253                 @Nullable Bundle launcherExtras) {
254             onPackagesSuspended(packageNames, user);
255         }
256 
257         /**
258          * Indicates that one or more packages have been unsuspended. For
259          * example, this can happen when a Device Administrator unsuspends
260          * an applicaton.
261          *
262          * @param packageNames The names of the packages that have just been
263          *            unsuspended.
264          * @param user The UserHandle of the profile that generated the change.
265          */
onPackagesUnsuspended(String[] packageNames, UserHandle user)266         public void onPackagesUnsuspended(String[] packageNames, UserHandle user) {
267         }
268 
269         /**
270          * Indicates that one or more shortcuts of any kind (dynamic, pinned, or manifest)
271          * have been added, updated or removed.
272          *
273          * <p>Only the applications that are allowed to access the shortcut information,
274          * as defined in {@link #hasShortcutHostPermission()}, will receive it.
275          *
276          * @param packageName The name of the package that has the shortcuts.
277          * @param shortcuts All shortcuts from the package (dynamic, manifest and/or pinned).
278          *    Only "key" information will be provided, as defined in
279          *    {@link ShortcutInfo#hasKeyFieldsOnly()}.
280          * @param user The UserHandle of the profile that generated the change.
281          *
282          * @see ShortcutManager
283          */
onShortcutsChanged(@onNull String packageName, @NonNull List<ShortcutInfo> shortcuts, @NonNull UserHandle user)284         public void onShortcutsChanged(@NonNull String packageName,
285                 @NonNull List<ShortcutInfo> shortcuts, @NonNull UserHandle user) {
286         }
287     }
288 
289     /**
290      * Represents a query passed to {@link #getShortcuts(ShortcutQuery, UserHandle)}.
291      */
292     public static class ShortcutQuery {
293         /**
294          * Include dynamic shortcuts in the result.
295          */
296         public static final int FLAG_MATCH_DYNAMIC = 1 << 0;
297 
298         /** @hide kept for unit tests */
299         @Deprecated
300         public static final int FLAG_GET_DYNAMIC = FLAG_MATCH_DYNAMIC;
301 
302         /**
303          * Include pinned shortcuts in the result.
304          *
305          * <p>If you are the selected assistant app, and wishes to fetch all shortcuts that the
306          * user owns on the launcher (or by other launchers, in case the user has multiple), use
307          * {@link #FLAG_MATCH_PINNED_BY_ANY_LAUNCHER} instead.
308          *
309          * <p>If you're a regular launcher app, there's no way to get shortcuts pinned by other
310          * launchers, and {@link #FLAG_MATCH_PINNED_BY_ANY_LAUNCHER} will be ignored. So use this
311          * flag to get own pinned shortcuts.
312          */
313         public static final int FLAG_MATCH_PINNED = 1 << 1;
314 
315         /** @hide kept for unit tests */
316         @Deprecated
317         public static final int FLAG_GET_PINNED = FLAG_MATCH_PINNED;
318 
319         /**
320          * Include manifest shortcuts in the result.
321          */
322         public static final int FLAG_MATCH_MANIFEST = 1 << 3;
323 
324         /** @hide kept for unit tests */
325         @Deprecated
326         public static final int FLAG_GET_MANIFEST = FLAG_MATCH_MANIFEST;
327 
328         /**
329          * Include all pinned shortcuts by any launchers, not just by the caller,
330          * in the result.
331          *
332          * <p>The caller must be the selected assistant app to use this flag, or have the system
333          * {@code ACCESS_SHORTCUTS} permission.
334          *
335          * <p>If you are the selected assistant app, and wishes to fetch all shortcuts that the
336          * user owns on the launcher (or by other launchers, in case the user has multiple), use
337          * {@link #FLAG_MATCH_PINNED_BY_ANY_LAUNCHER} instead.
338          *
339          * <p>If you're a regular launcher app (or any app that's not the selected assistant app)
340          * then this flag will be ignored.
341          */
342         public static final int FLAG_MATCH_PINNED_BY_ANY_LAUNCHER = 1 << 10;
343 
344         /**
345          * FLAG_MATCH_DYNAMIC | FLAG_MATCH_PINNED | FLAG_MATCH_MANIFEST
346          * @hide
347          */
348         public static final int FLAG_MATCH_ALL_KINDS =
349                 FLAG_MATCH_DYNAMIC | FLAG_MATCH_PINNED | FLAG_MATCH_MANIFEST;
350 
351         /**
352          * FLAG_MATCH_DYNAMIC | FLAG_MATCH_PINNED | FLAG_MATCH_MANIFEST | FLAG_MATCH_ALL_PINNED
353          * @hide
354          */
355         public static final int FLAG_MATCH_ALL_KINDS_WITH_ALL_PINNED =
356                 FLAG_MATCH_ALL_KINDS | FLAG_MATCH_PINNED_BY_ANY_LAUNCHER;
357 
358         /** @hide kept for unit tests */
359         @Deprecated
360         public static final int FLAG_GET_ALL_KINDS = FLAG_MATCH_ALL_KINDS;
361 
362         /**
363          * Requests "key" fields only.  See {@link ShortcutInfo#hasKeyFieldsOnly()}'s javadoc to
364          * see which fields fields "key".
365          * This allows quicker access to shortcut information in order to
366          * determine whether the caller's in-memory cache needs to be updated.
367          *
368          * <p>Typically, launcher applications cache all or most shortcut information
369          * in memory in order to show shortcuts without a delay.
370          *
371          * When a given launcher application wants to update its cache, such as when its process
372          * restarts, it can fetch shortcut information with this flag.
373          * The application can then check {@link ShortcutInfo#getLastChangedTimestamp()} for each
374          * shortcut, fetching a shortcut's non-key information only if that shortcut has been
375          * updated.
376          *
377          * @see ShortcutManager
378          */
379         public static final int FLAG_GET_KEY_FIELDS_ONLY = 1 << 2;
380 
381         /** @hide */
382         @IntDef(flag = true, prefix = { "FLAG_" }, value = {
383                 FLAG_MATCH_DYNAMIC,
384                 FLAG_MATCH_PINNED,
385                 FLAG_MATCH_MANIFEST,
386                 FLAG_GET_KEY_FIELDS_ONLY,
387                 FLAG_MATCH_MANIFEST,
388         })
389         @Retention(RetentionPolicy.SOURCE)
390         public @interface QueryFlags {}
391 
392         long mChangedSince;
393 
394         @Nullable
395         String mPackage;
396 
397         @Nullable
398         List<String> mShortcutIds;
399 
400         @Nullable
401         ComponentName mActivity;
402 
403         @QueryFlags
404         int mQueryFlags;
405 
ShortcutQuery()406         public ShortcutQuery() {
407         }
408 
409         /**
410          * If non-zero, returns only shortcuts that have been added or updated
411          * since the given timestamp, expressed in milliseconds since the Epoch&mdash;see
412          * {@link System#currentTimeMillis()}.
413          */
setChangedSince(long changedSince)414         public ShortcutQuery setChangedSince(long changedSince) {
415             mChangedSince = changedSince;
416             return this;
417         }
418 
419         /**
420          * If non-null, returns only shortcuts from the package.
421          */
setPackage(@ullable String packageName)422         public ShortcutQuery setPackage(@Nullable String packageName) {
423             mPackage = packageName;
424             return this;
425         }
426 
427         /**
428          * If non-null, return only the specified shortcuts by ID.  When setting this field,
429          * a package name must also be set with {@link #setPackage}.
430          */
setShortcutIds(@ullable List<String> shortcutIds)431         public ShortcutQuery setShortcutIds(@Nullable List<String> shortcutIds) {
432             mShortcutIds = shortcutIds;
433             return this;
434         }
435 
436         /**
437          * If non-null, returns only shortcuts associated with the activity; i.e.
438          * {@link ShortcutInfo}s whose {@link ShortcutInfo#getActivity()} are equal
439          * to {@code activity}.
440          */
setActivity(@ullable ComponentName activity)441         public ShortcutQuery setActivity(@Nullable ComponentName activity) {
442             mActivity = activity;
443             return this;
444         }
445 
446         /**
447          * Set query options.  At least one of the {@code MATCH} flags should be set.  Otherwise,
448          * no shortcuts will be returned.
449          *
450          * <ul>
451          *     <li>{@link #FLAG_MATCH_DYNAMIC}
452          *     <li>{@link #FLAG_MATCH_PINNED}
453          *     <li>{@link #FLAG_MATCH_MANIFEST}
454          *     <li>{@link #FLAG_GET_KEY_FIELDS_ONLY}
455          * </ul>
456          */
setQueryFlags(@ueryFlags int queryFlags)457         public ShortcutQuery setQueryFlags(@QueryFlags int queryFlags) {
458             mQueryFlags = queryFlags;
459             return this;
460         }
461     }
462 
463     /** @hide */
LauncherApps(Context context, ILauncherApps service)464     public LauncherApps(Context context, ILauncherApps service) {
465         mContext = context;
466         mService = service;
467         mPm = context.getPackageManager();
468         mUserManager = context.getSystemService(UserManager.class);
469     }
470 
471     /** @hide */
472     @TestApi
LauncherApps(Context context)473     public LauncherApps(Context context) {
474         this(context, ILauncherApps.Stub.asInterface(
475                 ServiceManager.getService(Context.LAUNCHER_APPS_SERVICE)));
476     }
477 
478     /**
479      * Show an error log on logcat, when the calling user is a managed profile, and the target
480      * user is different from the calling user, in order to help developers to detect it.
481      */
logErrorForInvalidProfileAccess(@onNull UserHandle target)482     private void logErrorForInvalidProfileAccess(@NonNull UserHandle target) {
483         if (UserHandle.myUserId() != target.getIdentifier() && mUserManager.isManagedProfile()) {
484             Log.w(TAG, "Accessing other profiles/users from managed profile is no longer allowed.");
485         }
486     }
487 
488     /**
489      * Return a list of profiles that the caller can access via the {@link LauncherApps} APIs.
490      *
491      * <p>If the caller is running on a managed profile, it'll return only the current profile.
492      * Otherwise it'll return the same list as {@link UserManager#getUserProfiles()} would.
493      */
getProfiles()494     public List<UserHandle> getProfiles() {
495         if (mUserManager.isManagedProfile()) {
496             // If it's a managed profile, only return the current profile.
497             final List result =  new ArrayList(1);
498             result.add(android.os.Process.myUserHandle());
499             return result;
500         } else {
501             return mUserManager.getUserProfiles();
502         }
503     }
504 
505     /**
506      * Retrieves a list of activities that specify {@link Intent#ACTION_MAIN} and
507      * {@link Intent#CATEGORY_LAUNCHER}, across all apps, for a specified user. If an app doesn't
508      * have any activities that specify <code>ACTION_MAIN</code> or <code>CATEGORY_LAUNCHER</code>,
509      * the system adds a synthesized activity to the list. This synthesized activity represents the
510      * app's details page within system settings.
511      *
512      * <p class="note"><b>Note: </b>It's possible for system apps, such as app stores, to prevent
513      * the system from adding synthesized activities to the returned list.</p>
514      *
515      * <p>As of <a href="/reference/android/os/Build.VERSION_CODES.html#Q">Android Q</a>, at least
516      * one of the app's activities or synthesized activities appears in the returned list unless the
517      * app satisfies at least one of the following conditions:</p>
518      * <ul>
519      * <li>The app is a system app.</li>
520      * <li>The app doesn't request any <a href="/guide/topics/permissions/overview">permissions</a>.
521      * </li>
522      * <li>The app doesn't have a <em>launcher activity</em> that is enabled by default. A launcher
523      * activity has an intent containing the <code>ACTION_MAIN</code> action and the
524      * <code>CATEGORY_LAUNCHER</code> category.</li>
525      * </ul>
526      *
527      * <p>Additionally, the system hides synthesized activities for some or all apps in the
528      * following enterprise-related cases:</p>
529      * <ul>
530      * <li>If the device is a
531      * <a href="https://developers.google.com/android/work/overview#company-owned-devices-for-knowledge-workers">fully
532      * managed device</a>, no synthesized activities for any app appear in the returned list.</li>
533      * <li>If the current user has a
534      * <a href="https://developers.google.com/android/work/overview#employee-owned-devices-byod">work
535      * profile</a>, no synthesized activities for the user's work apps appear in the returned
536      * list.</li>
537      * </ul>
538      *
539      * @param packageName The specific package to query. If null, it checks all installed packages
540      *            in the profile.
541      * @param user The UserHandle of the profile.
542      * @return List of launchable activities. Can be an empty list but will not be null.
543      */
getActivityList(String packageName, UserHandle user)544     public List<LauncherActivityInfo> getActivityList(String packageName, UserHandle user) {
545         logErrorForInvalidProfileAccess(user);
546         try {
547             return convertToActivityList(mService.getLauncherActivities(mContext.getPackageName(),
548                     packageName, user), user);
549         } catch (RemoteException re) {
550             throw re.rethrowFromSystemServer();
551         }
552     }
553 
554     /**
555      * Returns the activity info for a given intent and user handle, if it resolves. Otherwise it
556      * returns null.
557      *
558      * @param intent The intent to find a match for.
559      * @param user The profile to look in for a match.
560      * @return An activity info object if there is a match.
561      */
resolveActivity(Intent intent, UserHandle user)562     public LauncherActivityInfo resolveActivity(Intent intent, UserHandle user) {
563         logErrorForInvalidProfileAccess(user);
564         try {
565             ActivityInfo ai = mService.resolveActivity(mContext.getPackageName(),
566                     intent.getComponent(), user);
567             if (ai != null) {
568                 LauncherActivityInfo info = new LauncherActivityInfo(mContext, ai, user);
569                 return info;
570             }
571         } catch (RemoteException re) {
572             throw re.rethrowFromSystemServer();
573         }
574         return null;
575     }
576 
577     /**
578      * Starts a Main activity in the specified profile.
579      *
580      * @param component The ComponentName of the activity to launch
581      * @param user The UserHandle of the profile
582      * @param sourceBounds The Rect containing the source bounds of the clicked icon
583      * @param opts Options to pass to startActivity
584      */
startMainActivity(ComponentName component, UserHandle user, Rect sourceBounds, Bundle opts)585     public void startMainActivity(ComponentName component, UserHandle user, Rect sourceBounds,
586             Bundle opts) {
587         logErrorForInvalidProfileAccess(user);
588         if (DEBUG) {
589             Log.i(TAG, "StartMainActivity " + component + " " + user.getIdentifier());
590         }
591         try {
592             mService.startActivityAsUser(mContext.getIApplicationThread(),
593                     mContext.getPackageName(),
594                     component, sourceBounds, opts, user);
595         } catch (RemoteException re) {
596             throw re.rethrowFromSystemServer();
597         }
598     }
599 
600     /**
601      * Starts an activity to show the details of the specified session.
602      *
603      * @param sessionInfo The SessionInfo of the session
604      * @param sourceBounds The Rect containing the source bounds of the clicked icon
605      * @param opts Options to pass to startActivity
606      */
startPackageInstallerSessionDetailsActivity(@onNull SessionInfo sessionInfo, @Nullable Rect sourceBounds, @Nullable Bundle opts)607     public void startPackageInstallerSessionDetailsActivity(@NonNull SessionInfo sessionInfo,
608             @Nullable Rect sourceBounds, @Nullable Bundle opts) {
609         try {
610             mService.startSessionDetailsActivityAsUser(mContext.getIApplicationThread(),
611                     mContext.getPackageName(), sessionInfo, sourceBounds, opts,
612                     sessionInfo.getUser());
613         } catch (RemoteException re) {
614             throw re.rethrowFromSystemServer();
615         }
616     }
617 
618     /**
619      * Starts the settings activity to show the application details for a
620      * package in the specified profile.
621      *
622      * @param component The ComponentName of the package to launch settings for.
623      * @param user The UserHandle of the profile
624      * @param sourceBounds The Rect containing the source bounds of the clicked icon
625      * @param opts Options to pass to startActivity
626      */
startAppDetailsActivity(ComponentName component, UserHandle user, Rect sourceBounds, Bundle opts)627     public void startAppDetailsActivity(ComponentName component, UserHandle user,
628             Rect sourceBounds, Bundle opts) {
629         logErrorForInvalidProfileAccess(user);
630         try {
631             mService.showAppDetailsAsUser(mContext.getIApplicationThread(),
632                     mContext.getPackageName(),
633                     component, sourceBounds, opts, user);
634         } catch (RemoteException re) {
635             throw re.rethrowFromSystemServer();
636         }
637     }
638 
639     /**
640      * Retrieves a list of config activities for creating {@link ShortcutInfo}.
641      *
642      * @param packageName The specific package to query. If null, it checks all installed packages
643      *            in the profile.
644      * @param user The UserHandle of the profile.
645      * @return List of config activities. Can be an empty list but will not be null.
646      *
647      * @see Intent#ACTION_CREATE_SHORTCUT
648      * @see #getShortcutConfigActivityIntent(LauncherActivityInfo)
649      */
getShortcutConfigActivityList(@ullable String packageName, @NonNull UserHandle user)650     public List<LauncherActivityInfo> getShortcutConfigActivityList(@Nullable String packageName,
651             @NonNull UserHandle user) {
652         logErrorForInvalidProfileAccess(user);
653         try {
654             return convertToActivityList(mService.getShortcutConfigActivities(
655                     mContext.getPackageName(), packageName, user),
656                     user);
657         } catch (RemoteException re) {
658             throw re.rethrowFromSystemServer();
659         }
660     }
661 
convertToActivityList( @ullable ParceledListSlice<ResolveInfo> activities, UserHandle user)662     private List<LauncherActivityInfo> convertToActivityList(
663             @Nullable ParceledListSlice<ResolveInfo> activities, UserHandle user) {
664         if (activities == null) {
665             return Collections.EMPTY_LIST;
666         }
667         ArrayList<LauncherActivityInfo> lais = new ArrayList<>();
668         for (ResolveInfo ri : activities.getList()) {
669             LauncherActivityInfo lai = new LauncherActivityInfo(mContext, ri.activityInfo, user);
670             if (DEBUG) {
671                 Log.v(TAG, "Returning activity for profile " + user + " : "
672                         + lai.getComponentName());
673             }
674             lais.add(lai);
675         }
676         return lais;
677     }
678 
679     /**
680      * Returns an intent sender which can be used to start the configure activity for creating
681      * custom shortcuts. Use this method if the provider is in another profile as you are not
682      * allowed to start an activity in another profile.
683      *
684      * <p>The caller should receive {@link PinItemRequest} in onActivityResult on
685      * {@link android.app.Activity#RESULT_OK}.
686      *
687      * <p>Callers must be allowed to access the shortcut information, as defined in {@link
688      * #hasShortcutHostPermission()}.
689      *
690      * @param info a configuration activity returned by {@link #getShortcutConfigActivityList}
691      *
692      * @throws IllegalStateException when the user is locked or not running.
693      * @throws SecurityException if {@link #hasShortcutHostPermission()} is false.
694      *
695      * @see #getPinItemRequest(Intent)
696      * @see Intent#ACTION_CREATE_SHORTCUT
697      * @see android.app.Activity#startIntentSenderForResult
698      */
699     @Nullable
getShortcutConfigActivityIntent(@onNull LauncherActivityInfo info)700     public IntentSender getShortcutConfigActivityIntent(@NonNull LauncherActivityInfo info) {
701         try {
702             return mService.getShortcutConfigActivityIntent(
703                     mContext.getPackageName(), info.getComponentName(), info.getUser());
704         } catch (RemoteException re) {
705             throw re.rethrowFromSystemServer();
706         }
707     }
708 
709     /**
710      * Checks if the package is installed and enabled for a profile.
711      *
712      * @param packageName The package to check.
713      * @param user The UserHandle of the profile.
714      *
715      * @return true if the package exists and is enabled.
716      */
isPackageEnabled(String packageName, UserHandle user)717     public boolean isPackageEnabled(String packageName, UserHandle user) {
718         logErrorForInvalidProfileAccess(user);
719         try {
720             return mService.isPackageEnabled(mContext.getPackageName(), packageName, user);
721         } catch (RemoteException re) {
722             throw re.rethrowFromSystemServer();
723         }
724     }
725 
726     /**
727      * Gets the launcher extras supplied to the system when the given package was suspended via
728      * {@code PackageManager#setPackagesSuspended(String[], boolean, PersistableBundle,
729      * PersistableBundle, String)}.
730      *
731      * <p>The contents of this {@link Bundle} are supposed to be a contract between the suspending
732      * app and the launcher.
733      *
734      * <p>Note: This just returns whatever extras were provided to the system, <em>which might
735      * even be {@code null}.</em>
736      *
737      * @param packageName The package for which to fetch the launcher extras.
738      * @param user The {@link UserHandle} of the profile.
739      * @return A {@link Bundle} of launcher extras. Or {@code null} if the package is not currently
740      *         suspended.
741      *
742      * @see Callback#onPackagesSuspended(String[], UserHandle, Bundle)
743      * @see PackageManager#isPackageSuspended()
744      */
getSuspendedPackageLauncherExtras(String packageName, UserHandle user)745     public @Nullable Bundle getSuspendedPackageLauncherExtras(String packageName, UserHandle user) {
746         logErrorForInvalidProfileAccess(user);
747         try {
748             return mService.getSuspendedPackageLauncherExtras(packageName, user);
749         } catch (RemoteException re) {
750             throw re.rethrowFromSystemServer();
751         }
752     }
753 
754     /**
755      * Returns whether a package should be hidden from suggestions to the user. Currently, this
756      * could be done because the package was marked as distracting to the user via
757      * {@code PackageManager.setDistractingPackageRestrictions(String[], int)}.
758      *
759      * @param packageName The package for which to check.
760      * @param user the {@link UserHandle} of the profile.
761      * @return
762      */
shouldHideFromSuggestions(@onNull String packageName, @NonNull UserHandle user)763     public boolean shouldHideFromSuggestions(@NonNull String packageName,
764             @NonNull UserHandle user) {
765         Preconditions.checkNotNull(packageName, "packageName");
766         Preconditions.checkNotNull(user, "user");
767         try {
768             return mService.shouldHideFromSuggestions(packageName, user);
769         } catch (RemoteException re) {
770             throw re.rethrowFromSystemServer();
771         }
772     }
773 
774     /**
775      * Returns {@link ApplicationInfo} about an application installed for a specific user profile.
776      *
777      * @param packageName The package name of the application
778      * @param flags Additional option flags {@link PackageManager#getApplicationInfo}
779      * @param user The UserHandle of the profile.
780      *
781      * @return {@link ApplicationInfo} containing information about the package. Returns
782      *         {@code null} if the package isn't installed for the given profile, or the profile
783      *         isn't enabled.
784      */
getApplicationInfo(@onNull String packageName, @ApplicationInfoFlags int flags, @NonNull UserHandle user)785     public ApplicationInfo getApplicationInfo(@NonNull String packageName,
786             @ApplicationInfoFlags int flags, @NonNull UserHandle user)
787             throws PackageManager.NameNotFoundException {
788         Preconditions.checkNotNull(packageName, "packageName");
789         Preconditions.checkNotNull(user, "user");
790         logErrorForInvalidProfileAccess(user);
791         try {
792             final ApplicationInfo ai = mService
793                     .getApplicationInfo(mContext.getPackageName(), packageName, flags, user);
794             if (ai == null) {
795                 throw new NameNotFoundException("Package " + packageName + " not found for user "
796                         + user.getIdentifier());
797             }
798             return ai;
799         } catch (RemoteException re) {
800             throw re.rethrowFromSystemServer();
801         }
802     }
803 
804     /**
805      * Returns an object describing the app usage limit for the given package.
806      * If there are multiple limits that apply to the package, the one with the smallest
807      * time remaining will be returned.
808      *
809      * @param packageName name of the package whose app usage limit will be returned
810      * @param user the user of the package
811      *
812      * @return an {@link AppUsageLimit} object describing the app time limit containing
813      * the given package with the smallest time remaining, or {@code null} if none exist.
814      * @throws SecurityException when the caller is not the recents app.
815      * @hide
816      */
817     @Nullable
818     @SystemApi
getAppUsageLimit(@onNull String packageName, @NonNull UserHandle user)819     public LauncherApps.AppUsageLimit getAppUsageLimit(@NonNull String packageName,
820             @NonNull UserHandle user) {
821         try {
822             return mService.getAppUsageLimit(mContext.getPackageName(), packageName, user);
823         } catch (RemoteException re) {
824             throw re.rethrowFromSystemServer();
825         }
826     }
827 
828     /**
829      * Checks if the activity exists and it enabled for a profile.
830      *
831      * <p>The activity may still not be exported, in which case {@link #startMainActivity} will
832      * throw a {@link SecurityException} unless the caller has the same UID as the target app's.
833      *
834      * @param component The activity to check.
835      * @param user The UserHandle of the profile.
836      *
837      * @return true if the activity exists and is enabled.
838      */
isActivityEnabled(ComponentName component, UserHandle user)839     public boolean isActivityEnabled(ComponentName component, UserHandle user) {
840         logErrorForInvalidProfileAccess(user);
841         try {
842             return mService.isActivityEnabled(mContext.getPackageName(), component, user);
843         } catch (RemoteException re) {
844             throw re.rethrowFromSystemServer();
845         }
846     }
847 
848     /**
849      * Returns whether the caller can access the shortcut information.  Access is currently
850      * available to:
851      *
852      * <ul>
853      *     <li>The current launcher (or default launcher if there is no set current launcher).</li>
854      *     <li>The currently active voice interaction service.</li>
855      * </ul>
856      *
857      * <p>Note when this method returns {@code false}, it may be a temporary situation because
858      * the user is trying a new launcher application.  The user may decide to change the default
859      * launcher back to the calling application again, so even if a launcher application loses
860      * this permission, it does <b>not</b> have to purge pinned shortcut information.
861      * If the calling launcher application contains pinned shortcuts, they will still work,
862      * even though the caller no longer has the shortcut host permission.
863      *
864      * @throws IllegalStateException when the user is locked.
865      *
866      * @see ShortcutManager
867      */
hasShortcutHostPermission()868     public boolean hasShortcutHostPermission() {
869         try {
870             return mService.hasShortcutHostPermission(mContext.getPackageName());
871         } catch (RemoteException re) {
872             throw re.rethrowFromSystemServer();
873         }
874     }
875 
maybeUpdateDisabledMessage(List<ShortcutInfo> shortcuts)876     private List<ShortcutInfo> maybeUpdateDisabledMessage(List<ShortcutInfo> shortcuts) {
877         if (shortcuts == null) {
878             return null;
879         }
880         for (int i = shortcuts.size() - 1; i >= 0; i--) {
881             final ShortcutInfo si = shortcuts.get(i);
882             final String message = ShortcutInfo.getDisabledReasonForRestoreIssue(mContext,
883                     si.getDisabledReason());
884             if (message != null) {
885                 si.setDisabledMessage(message);
886             }
887         }
888         return shortcuts;
889     }
890 
891     /**
892      * Returns {@link ShortcutInfo}s that match {@code query}.
893      *
894      * <p>Callers must be allowed to access the shortcut information, as defined in {@link
895      * #hasShortcutHostPermission()}.
896      *
897      * @param query result includes shortcuts matching this query.
898      * @param user The UserHandle of the profile.
899      *
900      * @return the IDs of {@link ShortcutInfo}s that match the query.
901      * @throws IllegalStateException when the user is locked, or when the {@code user} user
902      * is locked or not running.
903      *
904      * @see ShortcutManager
905      */
906     @Nullable
getShortcuts(@onNull ShortcutQuery query, @NonNull UserHandle user)907     public List<ShortcutInfo> getShortcuts(@NonNull ShortcutQuery query,
908             @NonNull UserHandle user) {
909         logErrorForInvalidProfileAccess(user);
910         try {
911             // Note this is the only case we need to update the disabled message for shortcuts
912             // that weren't restored.
913             // The restore problem messages are only shown by the user, and publishers will never
914             // see them. The only other API that the launcher gets shortcuts is the shortcut
915             // changed callback, but that only returns shortcuts with the "key" information, so
916             // that won't return disabled message.
917             return maybeUpdateDisabledMessage(mService.getShortcuts(mContext.getPackageName(),
918                     query.mChangedSince, query.mPackage, query.mShortcutIds, query.mActivity,
919                     query.mQueryFlags, user)
920                     .getList());
921         } catch (RemoteException e) {
922             throw e.rethrowFromSystemServer();
923         }
924     }
925 
926     /**
927      * @hide // No longer used.  Use getShortcuts() instead.  Kept for unit tests.
928      */
929     @Nullable
930     @Deprecated
getShortcutInfo(@onNull String packageName, @NonNull List<String> ids, @NonNull UserHandle user)931     public List<ShortcutInfo> getShortcutInfo(@NonNull String packageName,
932             @NonNull List<String> ids, @NonNull UserHandle user) {
933         final ShortcutQuery q = new ShortcutQuery();
934         q.setPackage(packageName);
935         q.setShortcutIds(ids);
936         q.setQueryFlags(ShortcutQuery.FLAG_GET_ALL_KINDS);
937         return getShortcuts(q, user);
938     }
939 
940     /**
941      * Pin shortcuts on a package.
942      *
943      * <p>This API is <b>NOT</b> cumulative; this will replace all pinned shortcuts for the package.
944      * However, different launchers may have different set of pinned shortcuts.
945      *
946      * <p>The calling launcher application must be allowed to access the shortcut information,
947      * as defined in {@link #hasShortcutHostPermission()}.
948      *
949      * @param packageName The target package name.
950      * @param shortcutIds The IDs of the shortcut to be pinned.
951      * @param user The UserHandle of the profile.
952      * @throws IllegalStateException when the user is locked, or when the {@code user} user
953      * is locked or not running.
954      *
955      * @see ShortcutManager
956      */
pinShortcuts(@onNull String packageName, @NonNull List<String> shortcutIds, @NonNull UserHandle user)957     public void pinShortcuts(@NonNull String packageName, @NonNull List<String> shortcutIds,
958             @NonNull UserHandle user) {
959         logErrorForInvalidProfileAccess(user);
960         try {
961             mService.pinShortcuts(mContext.getPackageName(), packageName, shortcutIds, user);
962         } catch (RemoteException e) {
963             throw e.rethrowFromSystemServer();
964         }
965     }
966 
967     /**
968      * @hide kept for testing.
969      */
970     @Deprecated
getShortcutIconResId(@onNull ShortcutInfo shortcut)971     public int getShortcutIconResId(@NonNull ShortcutInfo shortcut) {
972         return shortcut.getIconResourceId();
973     }
974 
975     /**
976      * @hide kept for testing.
977      */
978     @Deprecated
getShortcutIconResId(@onNull String packageName, @NonNull String shortcutId, @NonNull UserHandle user)979     public int getShortcutIconResId(@NonNull String packageName, @NonNull String shortcutId,
980             @NonNull UserHandle user) {
981         final ShortcutQuery q = new ShortcutQuery();
982         q.setPackage(packageName);
983         q.setShortcutIds(Arrays.asList(shortcutId));
984         q.setQueryFlags(ShortcutQuery.FLAG_GET_ALL_KINDS);
985         final List<ShortcutInfo> shortcuts = getShortcuts(q, user);
986 
987         return shortcuts.size() > 0 ? shortcuts.get(0).getIconResourceId() : 0;
988     }
989 
990     /**
991      * @hide internal/unit tests only
992      */
getShortcutIconFd( @onNull ShortcutInfo shortcut)993     public ParcelFileDescriptor getShortcutIconFd(
994             @NonNull ShortcutInfo shortcut) {
995         return getShortcutIconFd(shortcut.getPackage(), shortcut.getId(),
996                 shortcut.getUserId());
997     }
998 
999     /**
1000      * @hide internal/unit tests only
1001      */
getShortcutIconFd( @onNull String packageName, @NonNull String shortcutId, @NonNull UserHandle user)1002     public ParcelFileDescriptor getShortcutIconFd(
1003             @NonNull String packageName, @NonNull String shortcutId, @NonNull UserHandle user) {
1004         return getShortcutIconFd(packageName, shortcutId, user.getIdentifier());
1005     }
1006 
getShortcutIconFd( @onNull String packageName, @NonNull String shortcutId, int userId)1007     private ParcelFileDescriptor getShortcutIconFd(
1008             @NonNull String packageName, @NonNull String shortcutId, int userId) {
1009         try {
1010             return mService.getShortcutIconFd(mContext.getPackageName(),
1011                     packageName, shortcutId, userId);
1012         } catch (RemoteException e) {
1013             throw e.rethrowFromSystemServer();
1014         }
1015     }
1016 
1017     /**
1018      * Returns the icon for this shortcut, without any badging for the profile.
1019      *
1020      * <p>The calling launcher application must be allowed to access the shortcut information,
1021      * as defined in {@link #hasShortcutHostPermission()}.
1022      *
1023      * @param density The preferred density of the icon, zero for default density. Use
1024      * density DPI values from {@link DisplayMetrics}.
1025      *
1026      * @return The drawable associated with the shortcut.
1027      * @throws IllegalStateException when the user is locked, or when the {@code user} user
1028      * is locked or not running.
1029      *
1030      * @see ShortcutManager
1031      * @see #getShortcutBadgedIconDrawable(ShortcutInfo, int)
1032      * @see DisplayMetrics
1033      */
getShortcutIconDrawable(@onNull ShortcutInfo shortcut, int density)1034     public Drawable getShortcutIconDrawable(@NonNull ShortcutInfo shortcut, int density) {
1035         if (shortcut.hasIconFile()) {
1036             final ParcelFileDescriptor pfd = getShortcutIconFd(shortcut);
1037             if (pfd == null) {
1038                 return null;
1039             }
1040             try {
1041                 final Bitmap bmp = BitmapFactory.decodeFileDescriptor(pfd.getFileDescriptor());
1042                 if (bmp != null) {
1043                     BitmapDrawable dr = new BitmapDrawable(mContext.getResources(), bmp);
1044                     if (shortcut.hasAdaptiveBitmap()) {
1045                         return new AdaptiveIconDrawable(null, dr);
1046                     } else {
1047                         return dr;
1048                     }
1049                 }
1050                 return null;
1051             } finally {
1052                 try {
1053                     pfd.close();
1054                 } catch (IOException ignore) {
1055                 }
1056             }
1057         } else if (shortcut.hasIconResource()) {
1058             return loadDrawableResourceFromPackage(shortcut.getPackage(),
1059                     shortcut.getIconResourceId(), shortcut.getUserHandle(), density);
1060         } else if (shortcut.getIcon() != null) {
1061             // This happens if a shortcut is pending-approval.
1062             final Icon icon = shortcut.getIcon();
1063             switch (icon.getType()) {
1064                 case Icon.TYPE_RESOURCE: {
1065                     return loadDrawableResourceFromPackage(shortcut.getPackage(),
1066                             icon.getResId(), shortcut.getUserHandle(), density);
1067                 }
1068                 case Icon.TYPE_BITMAP:
1069                 case Icon.TYPE_ADAPTIVE_BITMAP: {
1070                     return icon.loadDrawable(mContext);
1071                 }
1072                 default:
1073                     return null; // Shouldn't happen though.
1074             }
1075         } else {
1076             return null; // Has no icon.
1077         }
1078     }
1079 
loadDrawableResourceFromPackage(String packageName, int resId, UserHandle user, int density)1080     private Drawable loadDrawableResourceFromPackage(String packageName, int resId,
1081             UserHandle user, int density) {
1082         try {
1083             if (resId == 0) {
1084                 return null; // Shouldn't happen but just in case.
1085             }
1086             final ApplicationInfo ai = getApplicationInfo(packageName, /* flags =*/ 0, user);
1087             final Resources res = mContext.getPackageManager().getResourcesForApplication(ai);
1088             return res.getDrawableForDensity(resId, density);
1089         } catch (NameNotFoundException | Resources.NotFoundException e) {
1090             return null;
1091         }
1092     }
1093 
1094     /**
1095      * Returns the shortcut icon with badging appropriate for the profile.
1096      *
1097      * <p>The calling launcher application must be allowed to access the shortcut information,
1098      * as defined in {@link #hasShortcutHostPermission()}.
1099      *
1100      * @param density Optional density for the icon, or 0 to use the default density. Use
1101      * @return A badged icon for the shortcut.
1102      * @throws IllegalStateException when the user is locked, or when the {@code user} user
1103      * is locked or not running.
1104      *
1105      * @see ShortcutManager
1106      * @see #getShortcutIconDrawable(ShortcutInfo, int)
1107      * @see DisplayMetrics
1108      */
getShortcutBadgedIconDrawable(ShortcutInfo shortcut, int density)1109     public Drawable getShortcutBadgedIconDrawable(ShortcutInfo shortcut, int density) {
1110         final Drawable originalIcon = getShortcutIconDrawable(shortcut, density);
1111 
1112         return (originalIcon == null) ? null : mContext.getPackageManager().getUserBadgedIcon(
1113                 originalIcon, shortcut.getUserHandle());
1114     }
1115 
1116     /**
1117      * Starts a shortcut.
1118      *
1119      * <p>The calling launcher application must be allowed to access the shortcut information,
1120      * as defined in {@link #hasShortcutHostPermission()}.
1121      *
1122      * @param packageName The target shortcut package name.
1123      * @param shortcutId The target shortcut ID.
1124      * @param sourceBounds The Rect containing the source bounds of the clicked icon.
1125      * @param startActivityOptions Options to pass to startActivity.
1126      * @param user The UserHandle of the profile.
1127      * @throws IllegalStateException when the user is locked, or when the {@code user} user
1128      * is locked or not running.
1129      *
1130      * @throws android.content.ActivityNotFoundException failed to start shortcut. (e.g.
1131      * the shortcut no longer exists, is disabled, the intent receiver activity doesn't exist, etc)
1132      */
startShortcut(@onNull String packageName, @NonNull String shortcutId, @Nullable Rect sourceBounds, @Nullable Bundle startActivityOptions, @NonNull UserHandle user)1133     public void startShortcut(@NonNull String packageName, @NonNull String shortcutId,
1134             @Nullable Rect sourceBounds, @Nullable Bundle startActivityOptions,
1135             @NonNull UserHandle user) {
1136         logErrorForInvalidProfileAccess(user);
1137 
1138         startShortcut(packageName, shortcutId, sourceBounds, startActivityOptions,
1139                 user.getIdentifier());
1140     }
1141 
1142     /**
1143      * Launches a shortcut.
1144      *
1145      * <p>The calling launcher application must be allowed to access the shortcut information,
1146      * as defined in {@link #hasShortcutHostPermission()}.
1147      *
1148      * @param shortcut The target shortcut.
1149      * @param sourceBounds The Rect containing the source bounds of the clicked icon.
1150      * @param startActivityOptions Options to pass to startActivity.
1151      * @throws IllegalStateException when the user is locked, or when the {@code user} user
1152      * is locked or not running.
1153      *
1154      * @throws android.content.ActivityNotFoundException failed to start shortcut. (e.g.
1155      * the shortcut no longer exists, is disabled, the intent receiver activity doesn't exist, etc)
1156      */
startShortcut(@onNull ShortcutInfo shortcut, @Nullable Rect sourceBounds, @Nullable Bundle startActivityOptions)1157     public void startShortcut(@NonNull ShortcutInfo shortcut,
1158             @Nullable Rect sourceBounds, @Nullable Bundle startActivityOptions) {
1159         startShortcut(shortcut.getPackage(), shortcut.getId(),
1160                 sourceBounds, startActivityOptions,
1161                 shortcut.getUserId());
1162     }
1163 
1164     @UnsupportedAppUsage
startShortcut(@onNull String packageName, @NonNull String shortcutId, @Nullable Rect sourceBounds, @Nullable Bundle startActivityOptions, int userId)1165     private void startShortcut(@NonNull String packageName, @NonNull String shortcutId,
1166             @Nullable Rect sourceBounds, @Nullable Bundle startActivityOptions,
1167             int userId) {
1168         try {
1169             final boolean success =
1170                     mService.startShortcut(mContext.getPackageName(), packageName, shortcutId,
1171                     sourceBounds, startActivityOptions, userId);
1172             if (!success) {
1173                 throw new ActivityNotFoundException("Shortcut could not be started");
1174             }
1175         } catch (RemoteException e) {
1176             throw e.rethrowFromSystemServer();
1177         }
1178     }
1179 
1180     /**
1181      * Registers a callback for changes to packages in this user and managed profiles.
1182      *
1183      * @param callback The callback to register.
1184      */
registerCallback(Callback callback)1185     public void registerCallback(Callback callback) {
1186         registerCallback(callback, null);
1187     }
1188 
1189     /**
1190      * Registers a callback for changes to packages in this user and managed profiles.
1191      *
1192      * @param callback The callback to register.
1193      * @param handler that should be used to post callbacks on, may be null.
1194      */
registerCallback(Callback callback, Handler handler)1195     public void registerCallback(Callback callback, Handler handler) {
1196         synchronized (this) {
1197             if (callback != null && findCallbackLocked(callback) < 0) {
1198                 boolean addedFirstCallback = mCallbacks.size() == 0;
1199                 addCallbackLocked(callback, handler);
1200                 if (addedFirstCallback) {
1201                     try {
1202                         mService.addOnAppsChangedListener(mContext.getPackageName(),
1203                                 mAppsChangedListener);
1204                     } catch (RemoteException re) {
1205                         throw re.rethrowFromSystemServer();
1206                     }
1207                 }
1208             }
1209         }
1210     }
1211 
1212     /**
1213      * Unregisters a callback that was previously registered.
1214      *
1215      * @param callback The callback to unregister.
1216      * @see #registerCallback(Callback)
1217      */
unregisterCallback(Callback callback)1218     public void unregisterCallback(Callback callback) {
1219         synchronized (this) {
1220             removeCallbackLocked(callback);
1221             if (mCallbacks.size() == 0) {
1222                 try {
1223                     mService.removeOnAppsChangedListener(mAppsChangedListener);
1224                 } catch (RemoteException re) {
1225                     throw re.rethrowFromSystemServer();
1226                 }
1227             }
1228         }
1229     }
1230 
1231     /** @return position in mCallbacks for callback or -1 if not present. */
findCallbackLocked(Callback callback)1232     private int findCallbackLocked(Callback callback) {
1233         if (callback == null) {
1234             throw new IllegalArgumentException("Callback cannot be null");
1235         }
1236         final int size = mCallbacks.size();
1237         for (int i = 0; i < size; ++i) {
1238             if (mCallbacks.get(i).mCallback == callback) {
1239                 return i;
1240             }
1241         }
1242         return -1;
1243     }
1244 
removeCallbackLocked(Callback callback)1245     private void removeCallbackLocked(Callback callback) {
1246         int pos = findCallbackLocked(callback);
1247         if (pos >= 0) {
1248             mCallbacks.remove(pos);
1249         }
1250     }
1251 
addCallbackLocked(Callback callback, Handler handler)1252     private void addCallbackLocked(Callback callback, Handler handler) {
1253         // Remove if already present.
1254         removeCallbackLocked(callback);
1255         if (handler == null) {
1256             handler = new Handler();
1257         }
1258         CallbackMessageHandler toAdd = new CallbackMessageHandler(handler.getLooper(), callback);
1259         mCallbacks.add(toAdd);
1260     }
1261 
1262     private IOnAppsChangedListener.Stub mAppsChangedListener = new IOnAppsChangedListener.Stub() {
1263 
1264         @Override
1265         public void onPackageRemoved(UserHandle user, String packageName)
1266                 throws RemoteException {
1267             if (DEBUG) {
1268                 Log.d(TAG, "onPackageRemoved " + user.getIdentifier() + "," + packageName);
1269             }
1270             synchronized (LauncherApps.this) {
1271                 for (CallbackMessageHandler callback : mCallbacks) {
1272                     callback.postOnPackageRemoved(packageName, user);
1273                 }
1274             }
1275         }
1276 
1277         @Override
1278         public void onPackageChanged(UserHandle user, String packageName) throws RemoteException {
1279             if (DEBUG) {
1280                 Log.d(TAG, "onPackageChanged " + user.getIdentifier() + "," + packageName);
1281             }
1282             synchronized (LauncherApps.this) {
1283                 for (CallbackMessageHandler callback : mCallbacks) {
1284                     callback.postOnPackageChanged(packageName, user);
1285                 }
1286             }
1287         }
1288 
1289         @Override
1290         public void onPackageAdded(UserHandle user, String packageName) throws RemoteException {
1291             if (DEBUG) {
1292                 Log.d(TAG, "onPackageAdded " + user.getIdentifier() + "," + packageName);
1293             }
1294             synchronized (LauncherApps.this) {
1295                 for (CallbackMessageHandler callback : mCallbacks) {
1296                     callback.postOnPackageAdded(packageName, user);
1297                 }
1298             }
1299         }
1300 
1301         @Override
1302         public void onPackagesAvailable(UserHandle user, String[] packageNames, boolean replacing)
1303                 throws RemoteException {
1304             if (DEBUG) {
1305                 Log.d(TAG, "onPackagesAvailable " + user.getIdentifier() + "," + packageNames);
1306             }
1307             synchronized (LauncherApps.this) {
1308                 for (CallbackMessageHandler callback : mCallbacks) {
1309                     callback.postOnPackagesAvailable(packageNames, user, replacing);
1310                 }
1311             }
1312         }
1313 
1314         @Override
1315         public void onPackagesUnavailable(UserHandle user, String[] packageNames, boolean replacing)
1316                 throws RemoteException {
1317             if (DEBUG) {
1318                 Log.d(TAG, "onPackagesUnavailable " + user.getIdentifier() + "," + packageNames);
1319             }
1320             synchronized (LauncherApps.this) {
1321                 for (CallbackMessageHandler callback : mCallbacks) {
1322                     callback.postOnPackagesUnavailable(packageNames, user, replacing);
1323                 }
1324             }
1325         }
1326 
1327         @Override
1328         public void onPackagesSuspended(UserHandle user, String[] packageNames,
1329                 Bundle launcherExtras)
1330                 throws RemoteException {
1331             if (DEBUG) {
1332                 Log.d(TAG, "onPackagesSuspended " + user.getIdentifier() + "," + packageNames);
1333             }
1334             synchronized (LauncherApps.this) {
1335                 for (CallbackMessageHandler callback : mCallbacks) {
1336                     callback.postOnPackagesSuspended(packageNames, launcherExtras, user);
1337                 }
1338             }
1339         }
1340 
1341         @Override
1342         public void onPackagesUnsuspended(UserHandle user, String[] packageNames)
1343                 throws RemoteException {
1344             if (DEBUG) {
1345                 Log.d(TAG, "onPackagesUnsuspended " + user.getIdentifier() + "," + packageNames);
1346             }
1347             synchronized (LauncherApps.this) {
1348                 for (CallbackMessageHandler callback : mCallbacks) {
1349                     callback.postOnPackagesUnsuspended(packageNames, user);
1350                 }
1351             }
1352         }
1353 
1354         @Override
1355         public void onShortcutChanged(UserHandle user, String packageName,
1356                 ParceledListSlice shortcuts) {
1357             if (DEBUG) {
1358                 Log.d(TAG, "onShortcutChanged " + user.getIdentifier() + "," + packageName);
1359             }
1360             final List<ShortcutInfo> list = shortcuts.getList();
1361             synchronized (LauncherApps.this) {
1362                 for (CallbackMessageHandler callback : mCallbacks) {
1363                     callback.postOnShortcutChanged(packageName, user, list);
1364                 }
1365             }
1366         }
1367     };
1368 
1369     private static class CallbackMessageHandler extends Handler {
1370         private static final int MSG_ADDED = 1;
1371         private static final int MSG_REMOVED = 2;
1372         private static final int MSG_CHANGED = 3;
1373         private static final int MSG_AVAILABLE = 4;
1374         private static final int MSG_UNAVAILABLE = 5;
1375         private static final int MSG_SUSPENDED = 6;
1376         private static final int MSG_UNSUSPENDED = 7;
1377         private static final int MSG_SHORTCUT_CHANGED = 8;
1378 
1379         private LauncherApps.Callback mCallback;
1380 
1381         private static class CallbackInfo {
1382             String[] packageNames;
1383             String packageName;
1384             Bundle launcherExtras;
1385             boolean replacing;
1386             UserHandle user;
1387             List<ShortcutInfo> shortcuts;
1388         }
1389 
CallbackMessageHandler(Looper looper, LauncherApps.Callback callback)1390         public CallbackMessageHandler(Looper looper, LauncherApps.Callback callback) {
1391             super(looper, null, true);
1392             mCallback = callback;
1393         }
1394 
1395         @Override
handleMessage(Message msg)1396         public void handleMessage(Message msg) {
1397             if (mCallback == null || !(msg.obj instanceof CallbackInfo)) {
1398                 return;
1399             }
1400             CallbackInfo info = (CallbackInfo) msg.obj;
1401             switch (msg.what) {
1402                 case MSG_ADDED:
1403                     mCallback.onPackageAdded(info.packageName, info.user);
1404                     break;
1405                 case MSG_REMOVED:
1406                     mCallback.onPackageRemoved(info.packageName, info.user);
1407                     break;
1408                 case MSG_CHANGED:
1409                     mCallback.onPackageChanged(info.packageName, info.user);
1410                     break;
1411                 case MSG_AVAILABLE:
1412                     mCallback.onPackagesAvailable(info.packageNames, info.user, info.replacing);
1413                     break;
1414                 case MSG_UNAVAILABLE:
1415                     mCallback.onPackagesUnavailable(info.packageNames, info.user, info.replacing);
1416                     break;
1417                 case MSG_SUSPENDED:
1418                     mCallback.onPackagesSuspended(info.packageNames, info.user, info.launcherExtras
1419                     );
1420                     break;
1421                 case MSG_UNSUSPENDED:
1422                     mCallback.onPackagesUnsuspended(info.packageNames, info.user);
1423                     break;
1424                 case MSG_SHORTCUT_CHANGED:
1425                     mCallback.onShortcutsChanged(info.packageName, info.shortcuts, info.user);
1426                     break;
1427             }
1428         }
1429 
postOnPackageAdded(String packageName, UserHandle user)1430         public void postOnPackageAdded(String packageName, UserHandle user) {
1431             CallbackInfo info = new CallbackInfo();
1432             info.packageName = packageName;
1433             info.user = user;
1434             obtainMessage(MSG_ADDED, info).sendToTarget();
1435         }
1436 
postOnPackageRemoved(String packageName, UserHandle user)1437         public void postOnPackageRemoved(String packageName, UserHandle user) {
1438             CallbackInfo info = new CallbackInfo();
1439             info.packageName = packageName;
1440             info.user = user;
1441             obtainMessage(MSG_REMOVED, info).sendToTarget();
1442         }
1443 
postOnPackageChanged(String packageName, UserHandle user)1444         public void postOnPackageChanged(String packageName, UserHandle user) {
1445             CallbackInfo info = new CallbackInfo();
1446             info.packageName = packageName;
1447             info.user = user;
1448             obtainMessage(MSG_CHANGED, info).sendToTarget();
1449         }
1450 
postOnPackagesAvailable(String[] packageNames, UserHandle user, boolean replacing)1451         public void postOnPackagesAvailable(String[] packageNames, UserHandle user,
1452                 boolean replacing) {
1453             CallbackInfo info = new CallbackInfo();
1454             info.packageNames = packageNames;
1455             info.replacing = replacing;
1456             info.user = user;
1457             obtainMessage(MSG_AVAILABLE, info).sendToTarget();
1458         }
1459 
postOnPackagesUnavailable(String[] packageNames, UserHandle user, boolean replacing)1460         public void postOnPackagesUnavailable(String[] packageNames, UserHandle user,
1461                 boolean replacing) {
1462             CallbackInfo info = new CallbackInfo();
1463             info.packageNames = packageNames;
1464             info.replacing = replacing;
1465             info.user = user;
1466             obtainMessage(MSG_UNAVAILABLE, info).sendToTarget();
1467         }
1468 
postOnPackagesSuspended(String[] packageNames, Bundle launcherExtras, UserHandle user)1469         public void postOnPackagesSuspended(String[] packageNames, Bundle launcherExtras,
1470                 UserHandle user) {
1471             CallbackInfo info = new CallbackInfo();
1472             info.packageNames = packageNames;
1473             info.user = user;
1474             info.launcherExtras = launcherExtras;
1475             obtainMessage(MSG_SUSPENDED, info).sendToTarget();
1476         }
1477 
postOnPackagesUnsuspended(String[] packageNames, UserHandle user)1478         public void postOnPackagesUnsuspended(String[] packageNames, UserHandle user) {
1479             CallbackInfo info = new CallbackInfo();
1480             info.packageNames = packageNames;
1481             info.user = user;
1482             obtainMessage(MSG_UNSUSPENDED, info).sendToTarget();
1483         }
1484 
postOnShortcutChanged(String packageName, UserHandle user, List<ShortcutInfo> shortcuts)1485         public void postOnShortcutChanged(String packageName, UserHandle user,
1486                 List<ShortcutInfo> shortcuts) {
1487             CallbackInfo info = new CallbackInfo();
1488             info.packageName = packageName;
1489             info.user = user;
1490             info.shortcuts = shortcuts;
1491             obtainMessage(MSG_SHORTCUT_CHANGED, info).sendToTarget();
1492         }
1493     }
1494 
1495     /**
1496      * Register a callback to watch for session lifecycle events in this user and managed profiles.
1497      * @param callback The callback to register.
1498      * @param executor {@link Executor} to handle the callbacks, cannot be null.
1499      *
1500      * @see PackageInstaller#registerSessionCallback(SessionCallback)
1501      */
registerPackageInstallerSessionCallback( @onNull @allbackExecutor Executor executor, @NonNull SessionCallback callback)1502     public void registerPackageInstallerSessionCallback(
1503             @NonNull @CallbackExecutor Executor executor, @NonNull SessionCallback callback) {
1504         if (executor == null) {
1505             throw new NullPointerException("Executor must not be null");
1506         }
1507 
1508         synchronized (mDelegates) {
1509             final SessionCallbackDelegate delegate = new SessionCallbackDelegate(callback,
1510                     executor);
1511             try {
1512                 mService.registerPackageInstallerCallback(mContext.getPackageName(),
1513                         delegate);
1514             } catch (RemoteException e) {
1515                 throw e.rethrowFromSystemServer();
1516             }
1517             mDelegates.add(delegate);
1518         }
1519     }
1520 
1521     /**
1522      * Unregisters a callback that was previously registered.
1523      *
1524      * @param callback The callback to unregister.
1525      * @see #registerPackageInstallerSessionCallback(Executor, SessionCallback)
1526      */
unregisterPackageInstallerSessionCallback(@onNull SessionCallback callback)1527     public void unregisterPackageInstallerSessionCallback(@NonNull SessionCallback callback) {
1528         synchronized (mDelegates) {
1529             for (Iterator<SessionCallbackDelegate> i = mDelegates.iterator(); i.hasNext();) {
1530                 final SessionCallbackDelegate delegate = i.next();
1531                 if (delegate.mCallback == callback) {
1532                     mPm.getPackageInstaller().unregisterSessionCallback(delegate.mCallback);
1533                     i.remove();
1534                 }
1535             }
1536         }
1537     }
1538 
1539     /**
1540      * Return list of all known install sessions in this user and managed profiles, regardless
1541      * of the installer.
1542      *
1543      * @see PackageInstaller#getAllSessions()
1544      */
getAllPackageInstallerSessions()1545     public @NonNull List<SessionInfo> getAllPackageInstallerSessions() {
1546         try {
1547             return mService.getAllSessions(mContext.getPackageName()).getList();
1548         } catch (RemoteException e) {
1549             throw e.rethrowFromSystemServer();
1550         }
1551     }
1552 
1553     /**
1554      * A helper method to extract a {@link PinItemRequest} set to
1555      * the {@link #EXTRA_PIN_ITEM_REQUEST} extra.
1556      */
getPinItemRequest(Intent intent)1557     public PinItemRequest getPinItemRequest(Intent intent) {
1558         return intent.getParcelableExtra(EXTRA_PIN_ITEM_REQUEST);
1559     }
1560 
1561     /**
1562      * Represents a "pin shortcut" or a "pin appwidget" request made by an app, which is sent with
1563      * an {@link #ACTION_CONFIRM_PIN_SHORTCUT} or {@link #ACTION_CONFIRM_PIN_APPWIDGET} intent
1564      * respectively to the default launcher app.
1565      *
1566      * <h3>Request of the {@link #REQUEST_TYPE_SHORTCUT} type.
1567      *
1568      * <p>A {@link #REQUEST_TYPE_SHORTCUT} request represents a request to pin a
1569      * {@link ShortcutInfo}.  If the launcher accepts a request, call {@link #accept()},
1570      * or {@link #accept(Bundle)} with a null or empty Bundle.  No options are defined for
1571      * pin-shortcuts requests.
1572      *
1573      * <p>{@link #getShortcutInfo()} always returns a non-null {@link ShortcutInfo} for this type.
1574      *
1575      * <p>The launcher may receive a request with a {@link ShortcutInfo} that is already pinned, in
1576      * which case {@link ShortcutInfo#isPinned()} returns true.  This means the user wants to create
1577      * another pinned shortcut for a shortcut that's already pinned.  If the launcher accepts it,
1578      * {@link #accept()} must still be called even though the shortcut is already pinned, and
1579      * create a new pinned shortcut icon for it.
1580      *
1581      * <p>See also {@link ShortcutManager} for more details.
1582      *
1583      * <h3>Request of the {@link #REQUEST_TYPE_APPWIDGET} type.
1584      *
1585      * <p>A {@link #REQUEST_TYPE_SHORTCUT} request represents a request to pin a
1586      * an AppWidget.  If the launcher accepts a request, call {@link #accept(Bundle)} with
1587      * the appwidget integer ID set to the
1588      * {@link android.appwidget.AppWidgetManager#EXTRA_APPWIDGET_ID} extra.
1589      *
1590      * <p>{@link #getAppWidgetProviderInfo(Context)} always returns a non-null
1591      * {@link AppWidgetProviderInfo} for this type.
1592      *
1593      * <p>See also {@link AppWidgetManager} for more details.
1594      *
1595      * @see #EXTRA_PIN_ITEM_REQUEST
1596      * @see #getPinItemRequest(Intent)
1597      */
1598     public static final class PinItemRequest implements Parcelable {
1599 
1600         /** This is a request to pin shortcut. */
1601         public static final int REQUEST_TYPE_SHORTCUT = 1;
1602 
1603         /** This is a request to pin app widget. */
1604         public static final int REQUEST_TYPE_APPWIDGET = 2;
1605 
1606         /** @hide */
1607         @IntDef(prefix = { "REQUEST_TYPE_" }, value = {
1608                 REQUEST_TYPE_SHORTCUT,
1609                 REQUEST_TYPE_APPWIDGET
1610         })
1611         @Retention(RetentionPolicy.SOURCE)
1612         public @interface RequestType {}
1613 
1614         private final int mRequestType;
1615         private final IPinItemRequest mInner;
1616 
1617         /**
1618          * @hide
1619          */
PinItemRequest(IPinItemRequest inner, int type)1620         public PinItemRequest(IPinItemRequest inner, int type) {
1621             mInner = inner;
1622             mRequestType = type;
1623         }
1624 
1625         /**
1626          * Represents the type of a request, which is one of the {@code REQUEST_TYPE_} constants.
1627          *
1628          * @return one of the {@code REQUEST_TYPE_} constants.
1629          */
1630         @RequestType
getRequestType()1631         public int getRequestType() {
1632             return mRequestType;
1633         }
1634 
1635         /**
1636          * {@link ShortcutInfo} sent by the requesting app.
1637          * Always non-null for a {@link #REQUEST_TYPE_SHORTCUT} request, and always null for a
1638          * different request type.
1639          *
1640          * @return requested {@link ShortcutInfo} when a request is of the
1641          * {@link #REQUEST_TYPE_SHORTCUT} type.  Null otherwise.
1642          */
1643         @Nullable
getShortcutInfo()1644         public ShortcutInfo getShortcutInfo() {
1645             try {
1646                 return mInner.getShortcutInfo();
1647             } catch (RemoteException e) {
1648                 throw e.rethrowAsRuntimeException();
1649             }
1650         }
1651 
1652         /**
1653          * {@link AppWidgetProviderInfo} sent by the requesting app.
1654          * Always non-null for a {@link #REQUEST_TYPE_APPWIDGET} request, and always null for a
1655          * different request type.
1656          *
1657          * <p>Launcher should not show any configuration activity associated with the provider, and
1658          * assume that the widget is already fully configured. Upon accepting the widget, it should
1659          * pass the widgetId in {@link #accept(Bundle)}.
1660          *
1661          * @return requested {@link AppWidgetProviderInfo} when a request is of the
1662          * {@link #REQUEST_TYPE_APPWIDGET} type.  Null otherwise.
1663          */
1664         @Nullable
getAppWidgetProviderInfo(Context context)1665         public AppWidgetProviderInfo getAppWidgetProviderInfo(Context context) {
1666             try {
1667                 final AppWidgetProviderInfo info = mInner.getAppWidgetProviderInfo();
1668                 if (info == null) {
1669                     return null;
1670                 }
1671                 info.updateDimensions(context.getResources().getDisplayMetrics());
1672                 return info;
1673             } catch (RemoteException e) {
1674                 throw e.rethrowAsRuntimeException();
1675             }
1676         }
1677 
1678         /**
1679          * Any extras sent by the requesting app.
1680          *
1681          * @return For a shortcut request, this method always return null.  For an AppWidget
1682          * request, this method returns the extras passed to the
1683          * {@link android.appwidget.AppWidgetManager#requestPinAppWidget(
1684          * ComponentName, Bundle, PendingIntent)} API.  See {@link AppWidgetManager} for details.
1685          */
1686         @Nullable
getExtras()1687         public Bundle getExtras() {
1688             try {
1689                 return mInner.getExtras();
1690             } catch (RemoteException e) {
1691                 throw e.rethrowAsRuntimeException();
1692             }
1693         }
1694 
1695         /**
1696          * Return whether a request is still valid.
1697          *
1698          * @return {@code TRUE} if a request is valid and {@link #accept(Bundle)} may be called.
1699          */
isValid()1700         public boolean isValid() {
1701             try {
1702                 return mInner.isValid();
1703             } catch (RemoteException e) {
1704                 return false;
1705             }
1706         }
1707 
1708         /**
1709          * Called by the receiving launcher app when the user accepts the request.
1710          *
1711          * @param options must be set for a {@link #REQUEST_TYPE_APPWIDGET} request.
1712          *
1713          * @return {@code TRUE} if the shortcut or the AppWidget has actually been pinned.
1714          * {@code FALSE} if the item hasn't been pinned, for example, because the request had
1715          * already been canceled, in which case the launcher must not pin the requested item.
1716          */
accept(@ullable Bundle options)1717         public boolean accept(@Nullable Bundle options) {
1718             try {
1719                 return mInner.accept(options);
1720             } catch (RemoteException e) {
1721                 throw e.rethrowFromSystemServer();
1722             }
1723         }
1724 
1725         /**
1726          * Called by the receiving launcher app when the user accepts the request, with no options.
1727          *
1728          * @return {@code TRUE} if the shortcut or the AppWidget has actually been pinned.
1729          * {@code FALSE} if the item hasn't been pinned, for example, because the request had
1730          * already been canceled, in which case the launcher must not pin the requested item.
1731          */
accept()1732         public boolean accept() {
1733             return accept(/* options= */ null);
1734         }
1735 
PinItemRequest(Parcel source)1736         private PinItemRequest(Parcel source) {
1737             final ClassLoader cl = getClass().getClassLoader();
1738 
1739             mRequestType = source.readInt();
1740             mInner = IPinItemRequest.Stub.asInterface(source.readStrongBinder());
1741         }
1742 
1743         @Override
writeToParcel(Parcel dest, int flags)1744         public void writeToParcel(Parcel dest, int flags) {
1745             dest.writeInt(mRequestType);
1746             dest.writeStrongBinder(mInner.asBinder());
1747         }
1748 
1749         public static final @android.annotation.NonNull Creator<PinItemRequest> CREATOR =
1750                 new Creator<PinItemRequest>() {
1751                     public PinItemRequest createFromParcel(Parcel source) {
1752                         return new PinItemRequest(source);
1753                     }
1754                     public PinItemRequest[] newArray(int size) {
1755                         return new PinItemRequest[size];
1756                     }
1757                 };
1758 
1759         @Override
describeContents()1760         public int describeContents() {
1761             return 0;
1762         }
1763     }
1764 
1765     /**
1766      * A class that encapsulates information about the usage limit set for an app or
1767      * a group of apps.
1768      *
1769      * <p>The launcher can query specifics about the usage limit such as how much usage time
1770      * the limit has and how much of the total usage time is remaining via the APIs available
1771      * in this class.
1772      *
1773      * @see #getAppUsageLimit(String, UserHandle)
1774      * @hide
1775      */
1776     @SystemApi
1777     public static final class AppUsageLimit implements Parcelable {
1778         private final long mTotalUsageLimit;
1779         private final long mUsageRemaining;
1780 
1781         /** @hide */
AppUsageLimit(long totalUsageLimit, long usageRemaining)1782         public AppUsageLimit(long totalUsageLimit, long usageRemaining) {
1783             this.mTotalUsageLimit = totalUsageLimit;
1784             this.mUsageRemaining = usageRemaining;
1785         }
1786 
1787         /**
1788          * Returns the total usage limit in milliseconds set for an app or a group of apps.
1789          *
1790          * @return the total usage limit in milliseconds
1791          */
getTotalUsageLimit()1792         public long getTotalUsageLimit() {
1793             return mTotalUsageLimit;
1794         }
1795 
1796         /**
1797          * Returns the usage remaining in milliseconds for an app or the group of apps
1798          * this limit refers to.
1799          *
1800          * @return the usage remaining in milliseconds
1801          */
getUsageRemaining()1802         public long getUsageRemaining() {
1803             return mUsageRemaining;
1804         }
1805 
AppUsageLimit(Parcel source)1806         private AppUsageLimit(Parcel source) {
1807             mTotalUsageLimit = source.readLong();
1808             mUsageRemaining = source.readLong();
1809         }
1810 
1811         public static final @android.annotation.NonNull Creator<AppUsageLimit> CREATOR = new Creator<AppUsageLimit>() {
1812             @Override
1813             public AppUsageLimit createFromParcel(Parcel source) {
1814                 return new AppUsageLimit(source);
1815             }
1816 
1817             @Override
1818             public AppUsageLimit[] newArray(int size) {
1819                 return new AppUsageLimit[size];
1820             }
1821         };
1822 
1823         @Override
describeContents()1824         public int describeContents() {
1825             return 0;
1826         }
1827 
1828         @Override
writeToParcel(Parcel dest, int flags)1829         public void writeToParcel(Parcel dest, int flags) {
1830             dest.writeLong(mTotalUsageLimit);
1831             dest.writeLong(mUsageRemaining);
1832         }
1833     }
1834 }
1835