• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 static android.Manifest.permission;
20 import static android.Manifest.permission.ACCESS_HIDDEN_PROFILES;
21 import static android.Manifest.permission.ACCESS_HIDDEN_PROFILES_FULL;
22 import static android.Manifest.permission.READ_FRAME_BUFFER;
23 
24 import android.annotation.CallbackExecutor;
25 import android.annotation.FlaggedApi;
26 import android.annotation.IntDef;
27 import android.annotation.NonNull;
28 import android.annotation.Nullable;
29 import android.annotation.RequiresPermission;
30 import android.annotation.SdkConstant;
31 import android.annotation.SdkConstant.SdkConstantType;
32 import android.annotation.SuppressLint;
33 import android.annotation.SystemApi;
34 import android.annotation.SystemService;
35 import android.annotation.TestApi;
36 import android.app.PendingIntent;
37 import android.appwidget.AppWidgetManager;
38 import android.appwidget.AppWidgetProviderInfo;
39 import android.compat.annotation.UnsupportedAppUsage;
40 import android.content.ActivityNotFoundException;
41 import android.content.ComponentName;
42 import android.content.Context;
43 import android.content.Intent;
44 import android.content.IntentSender;
45 import android.content.LocusId;
46 import android.content.pm.PackageInstaller.SessionCallback;
47 import android.content.pm.PackageInstaller.SessionCallbackDelegate;
48 import android.content.pm.PackageInstaller.SessionInfo;
49 import android.content.pm.PackageManager.ApplicationInfoFlagsBits;
50 import android.content.pm.PackageManager.NameNotFoundException;
51 import android.content.res.Resources;
52 import android.graphics.Bitmap;
53 import android.graphics.BitmapFactory;
54 import android.graphics.Rect;
55 import android.graphics.drawable.AdaptiveIconDrawable;
56 import android.graphics.drawable.BitmapDrawable;
57 import android.graphics.drawable.Drawable;
58 import android.graphics.drawable.Icon;
59 import android.net.Uri;
60 import android.os.Build;
61 import android.os.Bundle;
62 import android.os.Flags;
63 import android.os.Handler;
64 import android.os.Looper;
65 import android.os.Message;
66 import android.os.Parcel;
67 import android.os.ParcelFileDescriptor;
68 import android.os.Parcelable;
69 import android.os.RemoteException;
70 import android.os.ServiceManager;
71 import android.os.UserHandle;
72 import android.os.UserManager;
73 import android.util.ArrayMap;
74 import android.util.DisplayMetrics;
75 import android.util.Log;
76 import android.util.Pair;
77 import android.window.IDumpCallback;
78 
79 import com.android.internal.annotations.VisibleForTesting;
80 import com.android.internal.util.function.pooled.PooledLambda;
81 
82 import java.io.IOException;
83 import java.lang.annotation.Retention;
84 import java.lang.annotation.RetentionPolicy;
85 import java.lang.ref.WeakReference;
86 import java.util.ArrayList;
87 import java.util.Arrays;
88 import java.util.Collections;
89 import java.util.HashMap;
90 import java.util.Iterator;
91 import java.util.List;
92 import java.util.Map;
93 import java.util.Objects;
94 import java.util.concurrent.Executor;
95 
96 /**
97  * Class for retrieving a list of launchable activities for the current user and any associated
98  * managed profiles that are visible to the current user, which can be retrieved with
99  * {@link #getProfiles}. This is mainly for use by launchers.
100  *
101  * Apps can be queried for each user profile.
102  * Since the PackageManager will not deliver package broadcasts for other profiles, you can register
103  * for package changes here.
104  * <p>
105  * To watch for managed profiles being added or removed, register for the following broadcasts:
106  * {@link Intent#ACTION_MANAGED_PROFILE_ADDED} and {@link Intent#ACTION_MANAGED_PROFILE_REMOVED}.
107  * <p>
108  * Note as of Android O, apps on a managed profile are no longer allowed to access apps on the
109  * main profile.  Apps can only access profiles returned by {@link #getProfiles()}.
110  */
111 @SystemService(Context.LAUNCHER_APPS_SERVICE)
112 public class LauncherApps {
113 
114     static final String TAG = "LauncherApps";
115     static final boolean DEBUG = false;
116 
117     /**
118      * Activity Action: For the default launcher to show the confirmation dialog to create
119      * a pinned shortcut.
120      *
121      * <p>See the {@link ShortcutManager} javadoc for details.
122      *
123      * <p>
124      * Use {@link #getPinItemRequest(Intent)} to get a {@link PinItemRequest} object,
125      * and call {@link PinItemRequest#accept(Bundle)}
126      * if the user accepts.  If the user doesn't accept, no further action is required.
127      *
128      * @see #EXTRA_PIN_ITEM_REQUEST
129      */
130     @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
131     public static final String ACTION_CONFIRM_PIN_SHORTCUT =
132             "android.content.pm.action.CONFIRM_PIN_SHORTCUT";
133 
134     /**
135      * Activity Action: For the default launcher to show the confirmation dialog to create
136      * a pinned app widget.
137      *
138      * <p>See the {@link android.appwidget.AppWidgetManager#requestPinAppWidget} javadoc for
139      * details.
140      *
141      * <p>
142      * Use {@link #getPinItemRequest(Intent)} to get a {@link PinItemRequest} object,
143      * and call {@link PinItemRequest#accept(Bundle)}
144      * if the user accepts.  If the user doesn't accept, no further action is required.
145      *
146      * @see #EXTRA_PIN_ITEM_REQUEST
147      */
148     @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
149     public static final String ACTION_CONFIRM_PIN_APPWIDGET =
150             "android.content.pm.action.CONFIRM_PIN_APPWIDGET";
151 
152     /**
153      * An extra for {@link #ACTION_CONFIRM_PIN_SHORTCUT} &amp; {@link #ACTION_CONFIRM_PIN_APPWIDGET}
154      * containing a {@link PinItemRequest} of appropriate type asked to pin.
155      *
156      * <p>A helper function {@link #getPinItemRequest(Intent)} can be used
157      * instead of using this constant directly.
158      *
159      * @see #ACTION_CONFIRM_PIN_SHORTCUT
160      * @see #ACTION_CONFIRM_PIN_APPWIDGET
161      */
162     public static final String EXTRA_PIN_ITEM_REQUEST =
163             "android.content.pm.extra.PIN_ITEM_REQUEST";
164 
165     /**
166      * Cache shortcuts which are used in notifications.
167      * @hide
168      */
169     public static final int FLAG_CACHE_NOTIFICATION_SHORTCUTS = 0;
170 
171     /**
172      * Cache shortcuts which are used in bubbles.
173      * @hide
174      */
175     public static final int FLAG_CACHE_BUBBLE_SHORTCUTS = 1;
176 
177     /**
178      * Cache shortcuts which are used in People Tile.
179      * @hide
180      */
181     public static final int FLAG_CACHE_PEOPLE_TILE_SHORTCUTS = 2;
182 
183     private static final String LAUNCHER_USER_INFO_EXTRA_KEY = "launcher_user_info";
184 
185     /** @hide */
186     @IntDef(flag = false, prefix = { "FLAG_CACHE_" }, value = {
187             FLAG_CACHE_NOTIFICATION_SHORTCUTS,
188             FLAG_CACHE_BUBBLE_SHORTCUTS,
189             FLAG_CACHE_PEOPLE_TILE_SHORTCUTS
190     })
191     @Retention(RetentionPolicy.SOURCE)
192     public @interface ShortcutCacheFlags {}
193 
194     private final Context mContext;
195     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
196     private final ILauncherApps mService;
197     @UnsupportedAppUsage
198     private final PackageManager mPm;
199     private final UserManager mUserManager;
200 
201     private final List<CallbackMessageHandler> mCallbacks = new ArrayList<>();
202     private final List<SessionCallbackDelegate> mDelegates = new ArrayList<>();
203 
204     private final Map<ShortcutChangeCallback, Pair<Executor, IShortcutChangeCallback>>
205             mShortcutChangeCallbacks = new HashMap<>();
206 
207     /**
208      * Callbacks for package changes to this and related managed profiles.
209      */
210     public static abstract class Callback {
211         /**
212          * Indicates that a package was removed from the specified profile.
213          *
214          * If a package is removed while being updated onPackageChanged will be
215          * called instead.
216          *
217          * @param packageName The name of the package that was removed.
218          * @param user The UserHandle of the profile that generated the change.
219          */
onPackageRemoved(String packageName, UserHandle user)220         abstract public void onPackageRemoved(String packageName, UserHandle user);
221 
222         /**
223          * Indicates that a package was added to the specified profile.
224          *
225          * If a package is added while being updated then onPackageChanged will be
226          * called instead.
227          *
228          * @param packageName The name of the package that was added.
229          * @param user The UserHandle of the profile that generated the change.
230          */
onPackageAdded(String packageName, UserHandle user)231         abstract public void onPackageAdded(String packageName, UserHandle user);
232 
233         /**
234          * Indicates that a package was modified in the specified profile.
235          * This can happen, for example, when the package is updated or when
236          * one or more components are enabled or disabled.
237          *
238          * @param packageName The name of the package that has changed.
239          * @param user The UserHandle of the profile that generated the change.
240          */
onPackageChanged(String packageName, UserHandle user)241         abstract public void onPackageChanged(String packageName, UserHandle user);
242 
243         /**
244          * Indicates that one or more packages have become available. For
245          * example, this can happen when a removable storage card has
246          * reappeared.
247          *
248          * @param packageNames The names of the packages that have become
249          *            available.
250          * @param user The UserHandle of the profile that generated the change.
251          * @param replacing Indicates whether these packages are replacing
252          *            existing ones.
253          */
onPackagesAvailable(String[] packageNames, UserHandle user, boolean replacing)254         abstract public void onPackagesAvailable(String[] packageNames, UserHandle user,
255                 boolean replacing);
256 
257         /**
258          * Indicates that one or more packages have become unavailable. For
259          * example, this can happen when a removable storage card has been
260          * removed.
261          *
262          * @param packageNames The names of the packages that have become
263          *            unavailable.
264          * @param user The UserHandle of the profile that generated the change.
265          * @param replacing Indicates whether the packages are about to be
266          *            replaced with new versions.
267          */
onPackagesUnavailable(String[] packageNames, UserHandle user, boolean replacing)268         abstract public void onPackagesUnavailable(String[] packageNames, UserHandle user,
269                 boolean replacing);
270 
271         /**
272          * Indicates that one or more packages have been suspended. For
273          * example, this can happen when a Device Administrator suspends
274          * an applicaton.
275          *
276          * <p>Note: On devices running {@link android.os.Build.VERSION_CODES#P Android P} or higher,
277          * any apps that override {@link #onPackagesSuspended(String[], UserHandle, Bundle)} will
278          * not receive this callback.
279          *
280          * @param packageNames The names of the packages that have just been
281          *            suspended.
282          * @param user The UserHandle of the profile that generated the change.
283          */
onPackagesSuspended(String[] packageNames, UserHandle user)284         public void onPackagesSuspended(String[] packageNames, UserHandle user) {
285         }
286 
287         /**
288          * Indicates that one or more packages have been suspended. A device administrator or an app
289          * with {@code android.permission.SUSPEND_APPS} can do this.
290          *
291          * <p>A suspending app with the permission {@code android.permission.SUSPEND_APPS} can
292          * optionally provide a {@link Bundle} of extra information that it deems helpful for the
293          * launcher to handle the suspended state of these packages. The contents of this
294          * {@link Bundle} are supposed to be a contract between the suspending app and the launcher.
295          *
296          * @param packageNames The names of the packages that have just been suspended.
297          * @param user the user for which the given packages were suspended.
298          * @param launcherExtras A {@link Bundle} of extras for the launcher, if provided to the
299          *                      system, {@code null} otherwise.
300          * @see PackageManager#isPackageSuspended()
301          * @see #getSuspendedPackageLauncherExtras(String, UserHandle)
302          * @deprecated {@code launcherExtras} should be obtained by using
303          * {@link #getSuspendedPackageLauncherExtras(String, UserHandle)}. For all other cases,
304          * {@link #onPackagesSuspended(String[], UserHandle)} should be used.
305          */
306         @Deprecated
onPackagesSuspended(String[] packageNames, UserHandle user, @Nullable Bundle launcherExtras)307         public void onPackagesSuspended(String[] packageNames, UserHandle user,
308                 @Nullable Bundle launcherExtras) {
309             onPackagesSuspended(packageNames, user);
310         }
311 
312         /**
313          * Indicates that one or more packages have been unsuspended. For
314          * example, this can happen when a Device Administrator unsuspends
315          * an applicaton.
316          *
317          * @param packageNames The names of the packages that have just been
318          *            unsuspended.
319          * @param user The UserHandle of the profile that generated the change.
320          */
onPackagesUnsuspended(String[] packageNames, UserHandle user)321         public void onPackagesUnsuspended(String[] packageNames, UserHandle user) {
322         }
323 
324         /**
325          * Indicates that one or more shortcuts of any kind (dynamic, pinned, or manifest)
326          * have been added, updated or removed.
327          *
328          * <p>Only the applications that are allowed to access the shortcut information,
329          * as defined in {@link #hasShortcutHostPermission()}, will receive it.
330          *
331          * @param packageName The name of the package that has the shortcuts.
332          * @param shortcuts All shortcuts from the package (dynamic, manifest and/or pinned).
333          *    Only "key" information will be provided, as defined in
334          *    {@link ShortcutInfo#hasKeyFieldsOnly()}.
335          * @param user The UserHandle of the profile that generated the change.
336          *
337          * @see ShortcutManager
338          */
onShortcutsChanged(@onNull String packageName, @NonNull List<ShortcutInfo> shortcuts, @NonNull UserHandle user)339         public void onShortcutsChanged(@NonNull String packageName,
340                 @NonNull List<ShortcutInfo> shortcuts, @NonNull UserHandle user) {
341         }
342 
343         /**
344          * Indicates that the loading progress of an installed package has changed.
345          *
346          * @param packageName The name of the package that has changed.
347          * @param user The UserHandle of the profile that generated the change.
348          * @param progress The new progress value, between [0, 1].
349          */
onPackageLoadingProgressChanged(@onNull String packageName, @NonNull UserHandle user, float progress)350         public void onPackageLoadingProgressChanged(@NonNull String packageName,
351                 @NonNull UserHandle user, float progress) {}
352 
353         /**
354          * Indicates {@link LauncherUserInfo} configs for a user have changed. The new
355          * {@link LauncherUserInfo} is given as a parameter.
356          *
357          * {@link LauncherUserInfo#getUserConfig} to get the updated user configs.
358          *
359          * @param launcherUserInfo The LauncherUserInfo of the user/profile whose configs have
360          *                         changed.
361          */
362         @FlaggedApi(android.multiuser.Flags.FLAG_ADD_LAUNCHER_USER_CONFIG)
onUserConfigChanged(@onNull LauncherUserInfo launcherUserInfo)363         public void onUserConfigChanged(@NonNull LauncherUserInfo launcherUserInfo) {
364         }
365     }
366 
367     /**
368      * Represents a query passed to {@link #getShortcuts(ShortcutQuery, UserHandle)}.
369      */
370     public static class ShortcutQuery {
371         /**
372          * Include dynamic shortcuts in the result.
373          */
374         public static final int FLAG_MATCH_DYNAMIC = 1 << 0;
375 
376         /** @hide kept for unit tests */
377         @Deprecated
378         public static final int FLAG_GET_DYNAMIC = FLAG_MATCH_DYNAMIC;
379 
380         /**
381          * Include pinned shortcuts in the result.
382          *
383          * <p>If you are the selected assistant app, and wishes to fetch all shortcuts that the
384          * user owns on the launcher (or by other launchers, in case the user has multiple), use
385          * {@link #FLAG_MATCH_PINNED_BY_ANY_LAUNCHER} instead.
386          *
387          * <p>If you're a regular launcher app, there's no way to get shortcuts pinned by other
388          * launchers, and {@link #FLAG_MATCH_PINNED_BY_ANY_LAUNCHER} will be ignored. So use this
389          * flag to get own pinned shortcuts.
390          */
391         public static final int FLAG_MATCH_PINNED = 1 << 1;
392 
393         /** @hide kept for unit tests */
394         @Deprecated
395         public static final int FLAG_GET_PINNED = FLAG_MATCH_PINNED;
396 
397         /**
398          * Include manifest shortcuts in the result.
399          */
400         public static final int FLAG_MATCH_MANIFEST = 1 << 3;
401 
402         /**
403          * Include cached shortcuts in the result.
404          */
405         public static final int FLAG_MATCH_CACHED = 1 << 4;
406 
407         /** @hide kept for unit tests */
408         @Deprecated
409         public static final int FLAG_GET_MANIFEST = FLAG_MATCH_MANIFEST;
410 
411         /**
412          * Include all pinned shortcuts by any launchers, not just by the caller,
413          * in the result.
414          *
415          * <p>The caller must be the selected assistant app to use this flag, or have the system
416          * {@code ACCESS_SHORTCUTS} permission.
417          *
418          * <p>If you are the selected assistant app, and wishes to fetch all shortcuts that the
419          * user owns on the launcher (or by other launchers, in case the user has multiple), use
420          * {@link #FLAG_MATCH_PINNED_BY_ANY_LAUNCHER} instead.
421          *
422          * <p>If you're a regular launcher app (or any app that's not the selected assistant app)
423          * then this flag will be ignored.
424          */
425         public static final int FLAG_MATCH_PINNED_BY_ANY_LAUNCHER = 1 << 10;
426 
427         /**
428          * FLAG_MATCH_DYNAMIC | FLAG_MATCH_PINNED | FLAG_MATCH_MANIFEST | FLAG_MATCH_CACHED
429          * @hide
430          */
431         public static final int FLAG_MATCH_ALL_KINDS =
432                 FLAG_MATCH_DYNAMIC | FLAG_MATCH_PINNED | FLAG_MATCH_MANIFEST | FLAG_MATCH_CACHED;
433 
434         /**
435          * FLAG_MATCH_DYNAMIC | FLAG_MATCH_PINNED | FLAG_MATCH_MANIFEST | FLAG_MATCH_ALL_PINNED
436          * @hide
437          */
438         public static final int FLAG_MATCH_ALL_KINDS_WITH_ALL_PINNED =
439                 FLAG_MATCH_ALL_KINDS | FLAG_MATCH_PINNED_BY_ANY_LAUNCHER;
440 
441         /** @hide kept for unit tests */
442         @Deprecated
443         public static final int FLAG_GET_ALL_KINDS = FLAG_MATCH_ALL_KINDS;
444 
445         /**
446          * Requests "key" fields only.  See {@link ShortcutInfo#hasKeyFieldsOnly()}'s javadoc to
447          * see which fields fields "key".
448          * This allows quicker access to shortcut information in order to
449          * determine whether the caller's in-memory cache needs to be updated.
450          *
451          * <p>Typically, launcher applications cache all or most shortcut information
452          * in memory in order to show shortcuts without a delay.
453          *
454          * When a given launcher application wants to update its cache, such as when its process
455          * restarts, it can fetch shortcut information with this flag.
456          * The application can then check {@link ShortcutInfo#getLastChangedTimestamp()} for each
457          * shortcut, fetching a shortcut's non-key information only if that shortcut has been
458          * updated.
459          *
460          * @see ShortcutManager
461          */
462         public static final int FLAG_GET_KEY_FIELDS_ONLY = 1 << 2;
463 
464         /**
465          * Populate the persons field in the result. See {@link ShortcutInfo#getPersons()}.
466          *
467          * <p>The caller must have the system {@code ACCESS_SHORTCUTS} permission.
468          *
469          * @hide
470          */
471         @SystemApi
472         @RequiresPermission(android.Manifest.permission.ACCESS_SHORTCUTS)
473         public static final int FLAG_GET_PERSONS_DATA = 1 << 11;
474 
475         /**
476          * Includes shortcuts from persistence layer in the search result.
477          *
478          * <p>The caller should make the query on a worker thread since accessing persistence layer
479          * is considered asynchronous.
480          *
481          * @hide
482          */
483         @SystemApi
484         public static final int FLAG_GET_PERSISTED_DATA = 1 << 12;
485 
486         /** @hide */
487         @IntDef(flag = true, prefix = { "FLAG_" }, value = {
488                 FLAG_MATCH_DYNAMIC,
489                 FLAG_MATCH_PINNED,
490                 FLAG_MATCH_MANIFEST,
491                 FLAG_MATCH_CACHED,
492                 FLAG_MATCH_PINNED_BY_ANY_LAUNCHER,
493                 FLAG_GET_KEY_FIELDS_ONLY,
494                 FLAG_GET_PERSONS_DATA,
495                 FLAG_GET_PERSISTED_DATA
496         })
497         @Retention(RetentionPolicy.SOURCE)
498         public @interface QueryFlags {}
499 
500         long mChangedSince;
501 
502         @Nullable
503         String mPackage;
504 
505         @Nullable
506         List<String> mShortcutIds;
507 
508         @Nullable
509         List<LocusId> mLocusIds;
510 
511         @Nullable
512         ComponentName mActivity;
513 
514         @QueryFlags
515         int mQueryFlags;
516 
ShortcutQuery()517         public ShortcutQuery() {
518         }
519 
520         /**
521          * If non-zero, returns only shortcuts that have been added or updated
522          * since the given timestamp, expressed in milliseconds since the Epoch&mdash;see
523          * {@link System#currentTimeMillis()}.
524          */
setChangedSince(long changedSince)525         public ShortcutQuery setChangedSince(long changedSince) {
526             mChangedSince = changedSince;
527             return this;
528         }
529 
530         /**
531          * If non-null, returns only shortcuts from the package.
532          */
setPackage(@ullable String packageName)533         public ShortcutQuery setPackage(@Nullable String packageName) {
534             mPackage = packageName;
535             return this;
536         }
537 
538         /**
539          * If non-null, return only the specified shortcuts by ID.  When setting this field,
540          * a package name must also be set with {@link #setPackage}.
541          */
setShortcutIds(@ullable List<String> shortcutIds)542         public ShortcutQuery setShortcutIds(@Nullable List<String> shortcutIds) {
543             mShortcutIds = shortcutIds;
544             return this;
545         }
546 
547         /**
548          * If non-null, return only the specified shortcuts by locus ID.  When setting this field,
549          * a package name must also be set with {@link #setPackage}.
550          */
551         @NonNull
setLocusIds(@ullable List<LocusId> locusIds)552         public ShortcutQuery setLocusIds(@Nullable List<LocusId> locusIds) {
553             mLocusIds = locusIds;
554             return this;
555         }
556 
557         /**
558          * If non-null, returns only shortcuts associated with the activity; i.e.
559          * {@link ShortcutInfo}s whose {@link ShortcutInfo#getActivity()} are equal
560          * to {@code activity}.
561          */
setActivity(@ullable ComponentName activity)562         public ShortcutQuery setActivity(@Nullable ComponentName activity) {
563             mActivity = activity;
564             return this;
565         }
566 
567         /**
568          * Set query options.  At least one of the {@code MATCH} flags should be set.  Otherwise,
569          * no shortcuts will be returned.
570          *
571          * <ul>
572          *     <li>{@link #FLAG_MATCH_DYNAMIC}
573          *     <li>{@link #FLAG_MATCH_PINNED}
574          *     <li>{@link #FLAG_MATCH_MANIFEST}
575          *     <li>{@link #FLAG_MATCH_CACHED}
576          *     <li>{@link #FLAG_GET_KEY_FIELDS_ONLY}
577          * </ul>
578          */
setQueryFlags(@ueryFlags int queryFlags)579         public ShortcutQuery setQueryFlags(@QueryFlags int queryFlags) {
580             mQueryFlags = queryFlags;
581             return this;
582         }
583     }
584 
585     /**
586      * Callbacks for shortcut changes to this and related managed profiles.
587      *
588      * @hide
589      */
590     public interface ShortcutChangeCallback {
591         /**
592          * Indicates that one or more shortcuts, that match the {@link ShortcutQuery} used to
593          * register this callback, have been added or updated.
594          * @see LauncherApps#registerShortcutChangeCallback(ShortcutChangeCallback, ShortcutQuery,
595          * Executor)
596          *
597          * <p>Only the applications that are allowed to access the shortcut information,
598          * as defined in {@link #hasShortcutHostPermission()}, will receive it.
599          *
600          * @param packageName The name of the package that has the shortcuts.
601          * @param shortcuts Shortcuts from the package that have updated or added. Only "key"
602          *    information will be provided, as defined in {@link ShortcutInfo#hasKeyFieldsOnly()}.
603          * @param user The UserHandle of the profile that generated the change.
604          *
605          * @see ShortcutManager
606          */
onShortcutsAddedOrUpdated(@onNull String packageName, @NonNull List<ShortcutInfo> shortcuts, @NonNull UserHandle user)607         default void onShortcutsAddedOrUpdated(@NonNull String packageName,
608                 @NonNull List<ShortcutInfo> shortcuts, @NonNull UserHandle user) {}
609 
610         /**
611          * Indicates that one or more shortcuts, that match the {@link ShortcutQuery} used to
612          * register this callback, have been removed.
613          * @see LauncherApps#registerShortcutChangeCallback(ShortcutChangeCallback, ShortcutQuery,
614          * Executor)
615          *
616          * <p>Only the applications that are allowed to access the shortcut information,
617          * as defined in {@link #hasShortcutHostPermission()}, will receive it.
618          *
619          * @param packageName The name of the package that has the shortcuts.
620          * @param shortcuts Shortcuts from the package that have been removed. Only "key"
621          *    information will be provided, as defined in {@link ShortcutInfo#hasKeyFieldsOnly()}.
622          * @param user The UserHandle of the profile that generated the change.
623          *
624          * @see ShortcutManager
625          */
onShortcutsRemoved(@onNull String packageName, @NonNull List<ShortcutInfo> shortcuts, @NonNull UserHandle user)626         default void onShortcutsRemoved(@NonNull String packageName,
627                 @NonNull List<ShortcutInfo> shortcuts, @NonNull UserHandle user) {}
628     }
629 
630     /**
631      * Callback proxy class for {@link ShortcutChangeCallback}
632      *
633      * @hide
634      */
635     private static class ShortcutChangeCallbackProxy extends
636             android.content.pm.IShortcutChangeCallback.Stub {
637         private final WeakReference<Pair<Executor, ShortcutChangeCallback>> mRemoteReferences;
638 
ShortcutChangeCallbackProxy(Executor executor, ShortcutChangeCallback callback)639         ShortcutChangeCallbackProxy(Executor executor, ShortcutChangeCallback callback) {
640             mRemoteReferences = new WeakReference<>(new Pair<>(executor, callback));
641         }
642 
643         @Override
onShortcutsAddedOrUpdated(@onNull String packageName, @NonNull List<ShortcutInfo> shortcuts, @NonNull UserHandle user)644         public void onShortcutsAddedOrUpdated(@NonNull String packageName,
645                 @NonNull List<ShortcutInfo> shortcuts, @NonNull UserHandle user) {
646             Pair<Executor, ShortcutChangeCallback> remoteReferences = mRemoteReferences.get();
647             if (remoteReferences == null) {
648                 // Binder is dead.
649                 return;
650             }
651 
652             final Executor executor = remoteReferences.first;
653             final ShortcutChangeCallback callback = remoteReferences.second;
654             executor.execute(
655                     PooledLambda.obtainRunnable(ShortcutChangeCallback::onShortcutsAddedOrUpdated,
656                             callback, packageName, shortcuts, user).recycleOnUse());
657         }
658 
659         @Override
onShortcutsRemoved(@onNull String packageName, @NonNull List<ShortcutInfo> shortcuts, @NonNull UserHandle user)660         public void onShortcutsRemoved(@NonNull String packageName,
661                 @NonNull List<ShortcutInfo> shortcuts, @NonNull UserHandle user) {
662             Pair<Executor, ShortcutChangeCallback> remoteReferences = mRemoteReferences.get();
663             if (remoteReferences == null) {
664                 // Binder is dead.
665                 return;
666             }
667 
668             final Executor executor = remoteReferences.first;
669             final ShortcutChangeCallback callback = remoteReferences.second;
670             executor.execute(
671                     PooledLambda.obtainRunnable(ShortcutChangeCallback::onShortcutsRemoved,
672                             callback, packageName, shortcuts, user).recycleOnUse());
673         }
674     }
675 
676     /** @hide */
LauncherApps(Context context, ILauncherApps service)677     public LauncherApps(Context context, ILauncherApps service) {
678         mContext = context;
679         mService = service;
680         mPm = context.getPackageManager();
681         mUserManager = context.getSystemService(UserManager.class);
682     }
683 
684     /** @hide */
685     @TestApi
LauncherApps(Context context)686     public LauncherApps(Context context) {
687         this(context, ILauncherApps.Stub.asInterface(
688                 ServiceManager.getService(Context.LAUNCHER_APPS_SERVICE)));
689     }
690 
691     /**
692      * Show an error log on logcat, when the calling user is a managed profile, the target
693      * user is different from the calling user, and it is not called from a package that has the
694      * {@link permission.INTERACT_ACROSS_USERS_FULL} permission, in order to help
695      * developers to detect it.
696      */
logErrorForInvalidProfileAccess(@onNull UserHandle target)697     private void logErrorForInvalidProfileAccess(@NonNull UserHandle target) {
698         if (UserHandle.myUserId() != target.getIdentifier() && mUserManager.isManagedProfile()
699                     && mContext.checkSelfPermission(permission.INTERACT_ACROSS_USERS_FULL)
700                             != PackageManager.PERMISSION_GRANTED) {
701             Log.w(TAG, "Accessing other profiles/users from managed profile is no longer allowed.");
702         }
703     }
704 
705     /**
706      * Return a list of profiles that the caller can access via the {@link LauncherApps} APIs.
707      *
708      * <p>If the caller is running on a managed profile, it'll return only the current profile.
709      * Otherwise it'll return the same list as {@link UserManager#getUserProfiles()} would.
710      *
711      * <p>To get hidden profile {@link UserManager#USER_TYPE_PROFILE_PRIVATE},
712      * caller should have normal {@link android.Manifest.permission#ACCESS_HIDDEN_PROFILES}
713      * permission and the {@link android.app.role.RoleManager#ROLE_HOME} role.
714      */
715     // Alternatively, a system app can access this api for private profile if they've been granted
716     // with the {@code android.Manifest.permission#ACCESS_HIDDEN_PROFILES_FULL} permission.
717     @SuppressLint("RequiresPermission")
718     @RequiresPermission(conditional = true,
719             anyOf = {ACCESS_HIDDEN_PROFILES_FULL, ACCESS_HIDDEN_PROFILES})
getProfiles()720     public List<UserHandle> getProfiles() {
721         if (mUserManager.isManagedProfile()
722                 || (android.multiuser.Flags.enableLauncherAppsHiddenProfileChecks()
723                     && android.os.Flags.allowPrivateProfile()
724                     && android.multiuser.Flags.enablePrivateSpaceFeatures()
725                     && mUserManager.isPrivateProfile())) {
726             // If it's a managed or private profile, only return the current profile.
727             final List result = new ArrayList(1);
728             result.add(android.os.Process.myUserHandle());
729             return result;
730         } else {
731             if (android.multiuser.Flags.enableLauncherAppsHiddenProfileChecks()) {
732                 try {
733                     return mService.getUserProfiles();
734                 } catch (RemoteException re) {
735                     throw re.rethrowFromSystemServer();
736                 }
737             }
738 
739             return mUserManager.getUserProfiles();
740         }
741     }
742 
743     /**
744      * Retrieves a list of activities that specify {@link Intent#ACTION_MAIN} and
745      * {@link Intent#CATEGORY_LAUNCHER}, across all apps, for a specified user. If an app doesn't
746      * have any activities that specify <code>ACTION_MAIN</code> or <code>CATEGORY_LAUNCHER</code>,
747      * the system adds a synthesized activity to the list. This synthesized activity represents the
748      * app's details page within system settings.
749      *
750      * <p class="note"><b>Note: </b>It's possible for system apps, such as app stores, to prevent
751      * the system from adding synthesized activities to the returned list.</p>
752      *
753      * <p>As of <a href="/reference/android/os/Build.VERSION_CODES.html#Q">Android Q</a>, at least
754      * one of the app's activities or synthesized activities appears in the returned list unless the
755      * app satisfies at least one of the following conditions:</p>
756      * <ul>
757      * <li>The app is a system app.</li>
758      * <li>The app doesn't request any <a href="/guide/topics/permissions/overview">permissions</a>.
759      * </li>
760      * <li>The app doesn't have a <em>launcher activity</em> that is enabled by default. A launcher
761      * activity has an intent containing the <code>ACTION_MAIN</code> action and the
762      * <code>CATEGORY_LAUNCHER</code> category.</li>
763      * </ul>
764      *
765      * <p>Additionally, the system hides synthesized activities for some or all apps in the
766      * following enterprise-related cases:</p>
767      * <ul>
768      * <li>If the device is a
769      * <a href="https://developers.google.com/android/work/overview#company-owned-devices-for-knowledge-workers">fully
770      * managed device</a>, no synthesized activities for any app appear in the returned list.</li>
771      * <li>If the current user has a
772      * <a href="https://developers.google.com/android/work/overview#employee-owned-devices-byod">work
773      * profile</a>, no synthesized activities for the user's work apps appear in the returned
774      * list.</li>
775      * </ul>
776      *
777      * <p>If the user in question is a hidden profile {@link UserManager#USER_TYPE_PROFILE_PRIVATE},
778      * caller should have normal {@link android.Manifest.permission#ACCESS_HIDDEN_PROFILES}
779      * permission and the {@link android.app.role.RoleManager#ROLE_HOME} role.
780      *
781      * @param packageName The specific package to query. If null, it checks all installed packages
782      *            in the profile.
783      * @param user The UserHandle of the profile.
784      * @return List of launchable activities. Can be an empty list but will not be null.
785      */
786     // Alternatively, a system app can access this api for private profile if they've been granted
787     // with the {@code android.Manifest.permission#ACCESS_HIDDEN_PROFILES_FULL} permission.
788     @SuppressLint("RequiresPermission")
789     @RequiresPermission(conditional = true,
790             anyOf = {ACCESS_HIDDEN_PROFILES_FULL, ACCESS_HIDDEN_PROFILES})
getActivityList(String packageName, UserHandle user)791     public List<LauncherActivityInfo> getActivityList(String packageName, UserHandle user) {
792         logErrorForInvalidProfileAccess(user);
793         try {
794             return convertToActivityList(mService.getLauncherActivities(mContext.getPackageName(),
795                     packageName, user), user);
796         } catch (RemoteException re) {
797             throw re.rethrowFromSystemServer();
798         }
799     }
800 
801     /**
802      * Returns a mutable PendingIntent that would start the same activity started from
803      * {@link #startMainActivity(ComponentName, UserHandle, Rect, Bundle)}.  The caller needs to
804      * take care in ensuring that the mutable intent returned is not passed to untrusted parties.
805      *
806      * @param component The ComponentName of the activity to launch
807      * @param startActivityOptions This parameter is no longer supported
808      * @param user The UserHandle of the profile
809      * @hide
810      */
811     @RequiresPermission(android.Manifest.permission.START_TASKS_FROM_RECENTS)
812     @Nullable
getMainActivityLaunchIntent(@onNull ComponentName component, @Nullable Bundle startActivityOptions, @NonNull UserHandle user)813     public PendingIntent getMainActivityLaunchIntent(@NonNull ComponentName component,
814             @Nullable Bundle startActivityOptions, @NonNull UserHandle user) {
815         logErrorForInvalidProfileAccess(user);
816         if (DEBUG) {
817             Log.i(TAG, "GetMainActivityLaunchIntent " + component + " " + user);
818         }
819         try {
820             return mService.getActivityLaunchIntent(mContext.getPackageName(), component, user);
821         } catch (RemoteException re) {
822             throw re.rethrowFromSystemServer();
823         }
824     }
825 
826     /**
827      * Returns information related to a user which is useful for displaying UI elements
828      * to distinguish it from other users (eg, badges).
829      *
830      * <p>If the user in question is a hidden profile {@link UserManager#USER_TYPE_PROFILE_PRIVATE},
831      * caller should have normal {@link android.Manifest.permission#ACCESS_HIDDEN_PROFILES}
832      * permission and the {@link android.app.role.RoleManager#ROLE_HOME} role.
833      *
834      * @param userHandle user handle of the user for which LauncherUserInfo is requested.
835      * @return the {@link LauncherUserInfo} object related to the user specified, null in case
836      * the user is inaccessible.
837      */
838     // Alternatively, a system app can access this api for private profile if they've been granted
839     // with the {@code android.Manifest.permission#ACCESS_HIDDEN_PROFILES_FULL} permission.
840     @Nullable
841     @SuppressLint("RequiresPermission")
842     @FlaggedApi(Flags.FLAG_ALLOW_PRIVATE_PROFILE)
843     @RequiresPermission(conditional = true,
844             anyOf = {ACCESS_HIDDEN_PROFILES_FULL, ACCESS_HIDDEN_PROFILES})
getLauncherUserInfo(@onNull UserHandle userHandle)845     public final LauncherUserInfo getLauncherUserInfo(@NonNull UserHandle userHandle) {
846         if (DEBUG) {
847             Log.i(TAG, "getLauncherUserInfo " + userHandle);
848         }
849         try {
850             return mService.getLauncherUserInfo(userHandle);
851         } catch (RemoteException re) {
852             throw re.rethrowFromSystemServer();
853         }
854     }
855 
856 
857     /**
858      * Returns an intent sender which can be used to start the App Market activity (Installer
859      * Activity).
860      * This method is primarily used to get an intent sender which starts App Market activity for
861      * another profile, if the caller is not otherwise allowed to start activity in that profile.
862      *
863      * <p>When packageName is set, intent sender to start the App Market Activity which installed
864      * the package in calling user will be returned, but for the profile passed.
865      *
866      * <p>When packageName is not set, intent sender to launch the default App Market Activity for
867      * the profile will be returned. In case there are multiple App Market Activities available for
868      * the profile, IntentPicker will be started, allowing user to choose the preferred activity.
869      *
870      * <p>The method will fall back to the behaviour of not having the packageName set, in case:
871      * <ul>
872      *     <li>No activity for the packageName is found in calling user-space.</li>
873      *     <li>The App Market Activity which installed the package in calling user-space is not
874      *         present.</li>
875      *     <li>The App Market Activity which installed the package in calling user-space is not
876      *         present in the profile passed.</li>
877      * </ul>
878      * </p>
879      *
880      * <p>If the user in question is a hidden profile {@link UserManager#USER_TYPE_PROFILE_PRIVATE},
881      * caller should have normal {@link android.Manifest.permission#ACCESS_HIDDEN_PROFILES}
882      * permission and the {@link android.app.role.RoleManager#ROLE_HOME} role.
883      *
884      * @param packageName the package for which intent sender to launch App Market Activity is
885      *                    required.
886      * @param user the profile for which intent sender to launch App Market Activity is required.
887      * @return {@link IntentSender} object which launches the App Market Activity, null in case
888      *         there is no such activity.
889      */
890     // Alternatively, a system app can access this api for private profile if they've been granted
891     // with the {@code android.Manifest.permission#ACCESS_HIDDEN_PROFILES_FULL} permission.
892     @Nullable
893     @SuppressLint("RequiresPermission")
894     @FlaggedApi(Flags.FLAG_ALLOW_PRIVATE_PROFILE)
895     @RequiresPermission(conditional = true,
896             anyOf = {ACCESS_HIDDEN_PROFILES_FULL, ACCESS_HIDDEN_PROFILES})
getAppMarketActivityIntent(@ullable String packageName, @NonNull UserHandle user)897     public IntentSender getAppMarketActivityIntent(@Nullable String packageName,
898             @NonNull UserHandle user) {
899         if (DEBUG) {
900             Log.i(TAG, "getAppMarketActivityIntent for package: " + packageName
901                     + " user: " + user);
902         }
903         try {
904             return mService.getAppMarketActivityIntent(mContext.getPackageName(),
905                     packageName, user);
906         } catch (RemoteException re) {
907             throw re.rethrowFromSystemServer();
908         }
909     }
910 
911     /**
912      * Returns the list of the system packages that are installed at user creation.
913      *
914      * <p>An empty list denotes that all system packages should be treated as pre-installed for that
915      * user at creation.
916      *
917      * <p>If the user in question is a hidden profile {@link UserManager#USER_TYPE_PROFILE_PRIVATE},
918      * caller should have normal {@link android.Manifest.permission#ACCESS_HIDDEN_PROFILES}
919      * permission and the {@link android.app.role.RoleManager#ROLE_HOME} role.
920      *
921      * @param userHandle the user for which installed system packages are required.
922      * @return {@link List} of {@link String}, representing the package name of the installed
923      *        package. Can be empty but not null.
924      */
925     // Alternatively, a system app can access this api for private profile if they've been granted
926     // with the {@code android.Manifest.permission#ACCESS_HIDDEN_PROFILES_FULL} permission.
927     @FlaggedApi(Flags.FLAG_ALLOW_PRIVATE_PROFILE)
928     @NonNull
929     @SuppressLint("RequiresPermission")
930     @RequiresPermission(conditional = true,
931             anyOf = {ACCESS_HIDDEN_PROFILES_FULL, ACCESS_HIDDEN_PROFILES})
getPreInstalledSystemPackages(@onNull UserHandle userHandle)932     public List<String> getPreInstalledSystemPackages(@NonNull UserHandle userHandle) {
933         if (DEBUG) {
934             Log.i(TAG, "getPreInstalledSystemPackages for user: " + userHandle);
935         }
936         try {
937             return mService.getPreInstalledSystemPackages(userHandle);
938         } catch (RemoteException re) {
939             throw re.rethrowFromSystemServer();
940         }
941     }
942 
943     /**
944      * Returns {@link IntentSender} which can be used to start the Private Space Settings Activity.
945      *
946      * <p> Caller should have {@link android.app.role.RoleManager#ROLE_HOME} and either of the
947      * permissions required.</p>
948      *
949      * @return {@link IntentSender} object which launches the Private Space Settings Activity, if
950      * successful, null otherwise.
951      */
952     // Alternatively, a system app can access this api for private profile if they've been granted
953     // with the {@code android.Manifest.permission#ACCESS_HIDDEN_PROFILES_FULL} permission.
954     @Nullable
955     @FlaggedApi(Flags.FLAG_GET_PRIVATE_SPACE_SETTINGS)
956     @RequiresPermission(conditional = true,
957             anyOf = {ACCESS_HIDDEN_PROFILES_FULL, ACCESS_HIDDEN_PROFILES})
getPrivateSpaceSettingsIntent()958     public IntentSender getPrivateSpaceSettingsIntent() {
959         try {
960             return mService.getPrivateSpaceSettingsIntent();
961         } catch (RemoteException re) {
962             throw re.rethrowFromSystemServer();
963         }
964     }
965 
966     /**
967      * Returns the activity info for a given intent and user handle, if it resolves. Otherwise it
968      * returns null.
969      *
970      * <p>If the user in question is a hidden profile {@link UserManager#USER_TYPE_PROFILE_PRIVATE},
971      * caller should have normal {@link android.Manifest.permission#ACCESS_HIDDEN_PROFILES}
972      * permission and the {@link android.app.role.RoleManager#ROLE_HOME} role.
973      *
974      * @param intent The intent to find a match for.
975      * @param user The profile to look in for a match.
976      * @return An activity info object if there is a match.
977      */
978     // Alternatively, a system app can access this api for private profile if they've been granted
979     // with the {@code android.Manifest.permission#ACCESS_HIDDEN_PROFILES_FULL} permission.
980     @SuppressLint("RequiresPermission")
981     @RequiresPermission(conditional = true,
982             anyOf = {ACCESS_HIDDEN_PROFILES_FULL, ACCESS_HIDDEN_PROFILES})
resolveActivity(Intent intent, UserHandle user)983     public LauncherActivityInfo resolveActivity(Intent intent, UserHandle user) {
984         logErrorForInvalidProfileAccess(user);
985         try {
986             LauncherActivityInfoInternal ai = mService.resolveLauncherActivityInternal(
987                     mContext.getPackageName(), intent.getComponent(), user);
988             if (ai == null) {
989                 return null;
990             }
991             return new LauncherActivityInfo(mContext, ai);
992         } catch (RemoteException re) {
993             throw re.rethrowFromSystemServer();
994         }
995     }
996 
997     /**
998      * Returns overrides for the activities that should be launched for the shortcuts of certain
999      * package names.
1000      *
1001      * @return {@link Map} whose keys are package names and whose values are the
1002      * {@link LauncherActivityInfo}s that should be used for those packages' shortcuts. If there are
1003      * no activity overrides, an empty {@link Map} will be returned.
1004      *
1005      * @hide
1006      */
1007     @NonNull
getActivityOverrides()1008     public Map<String, LauncherActivityInfo> getActivityOverrides() {
1009         Map<String, LauncherActivityInfo> activityOverrides = new ArrayMap<>();
1010         try {
1011             Map<String, LauncherActivityInfoInternal> activityOverridesInternal =
1012                     mService.getActivityOverrides(mContext.getPackageName(), mContext.getUserId());
1013             for (Map.Entry<String, LauncherActivityInfoInternal> packageToOverride :
1014                     activityOverridesInternal.entrySet()) {
1015                 activityOverrides.put(
1016                         packageToOverride.getKey(),
1017                         new LauncherActivityInfo(
1018                                 mContext,
1019                                 packageToOverride.getValue()
1020                         )
1021                 );
1022             }
1023         } catch (RemoteException re) {
1024             throw re.rethrowFromSystemServer();
1025         }
1026         return activityOverrides;
1027     }
1028 
1029     /**
1030      * Starts a Main activity in the specified profile.
1031      *
1032      * <p>If the user in question is a hidden profile {@link UserManager#USER_TYPE_PROFILE_PRIVATE},
1033      * caller should have normal {@link android.Manifest.permission#ACCESS_HIDDEN_PROFILES}
1034      * permission and the {@link android.app.role.RoleManager#ROLE_HOME} role.
1035      *
1036      * @param component The ComponentName of the activity to launch
1037      * @param user The UserHandle of the profile
1038      * @param sourceBounds The Rect containing the source bounds of the clicked icon
1039      * @param opts Options to pass to startActivity
1040      */
1041     // Alternatively, a system app can access this api for private profile if they've been granted
1042     // with the {@code android.Manifest.permission#ACCESS_HIDDEN_PROFILES_FULL} permission.
1043     @SuppressLint("RequiresPermission")
1044     @RequiresPermission(conditional = true,
1045             anyOf = {ACCESS_HIDDEN_PROFILES_FULL, ACCESS_HIDDEN_PROFILES})
startMainActivity(ComponentName component, UserHandle user, Rect sourceBounds, Bundle opts)1046     public void startMainActivity(ComponentName component, UserHandle user, Rect sourceBounds,
1047             Bundle opts) {
1048         logErrorForInvalidProfileAccess(user);
1049         if (DEBUG) {
1050             Log.i(TAG, "StartMainActivity " + component + " " + user.getIdentifier());
1051         }
1052         try {
1053             mService.startActivityAsUser(mContext.getIApplicationThread(),
1054                     mContext.getPackageName(), mContext.getAttributionTag(),
1055                     component, sourceBounds, opts, user);
1056         } catch (RemoteException re) {
1057             throw re.rethrowFromSystemServer();
1058         }
1059     }
1060 
1061     /**
1062      * Starts an activity to show the details of the specified session.
1063      *
1064      * @param sessionInfo The SessionInfo of the session
1065      * @param sourceBounds The Rect containing the source bounds of the clicked icon
1066      * @param opts Options to pass to startActivity
1067      */
startPackageInstallerSessionDetailsActivity(@onNull SessionInfo sessionInfo, @Nullable Rect sourceBounds, @Nullable Bundle opts)1068     public void startPackageInstallerSessionDetailsActivity(@NonNull SessionInfo sessionInfo,
1069             @Nullable Rect sourceBounds, @Nullable Bundle opts) {
1070         try {
1071             mService.startSessionDetailsActivityAsUser(mContext.getIApplicationThread(),
1072                     mContext.getPackageName(), mContext.getAttributionTag(), sessionInfo,
1073                     sourceBounds, opts, sessionInfo.getUser());
1074         } catch (RemoteException re) {
1075             throw re.rethrowFromSystemServer();
1076         }
1077     }
1078 
1079     /**
1080      * Starts the settings activity to show the application details for a
1081      * package in the specified profile.
1082      *
1083      * <p>If the user in question is a hidden profile {@link UserManager#USER_TYPE_PROFILE_PRIVATE},
1084      * caller should have normal {@link android.Manifest.permission#ACCESS_HIDDEN_PROFILES}
1085      * permission and the {@link android.app.role.RoleManager#ROLE_HOME} role.
1086      *
1087      * @param component The ComponentName of the package to launch settings for.
1088      * @param user The UserHandle of the profile
1089      * @param sourceBounds The Rect containing the source bounds of the clicked icon
1090      * @param opts Options to pass to startActivity
1091      */
1092     // Alternatively, a system app can access this api for private profile if they've been granted
1093     // with the {@code android.Manifest.permission#ACCESS_HIDDEN_PROFILES_FULL} permission.
1094     @SuppressLint("RequiresPermission")
1095     @RequiresPermission(conditional = true,
1096             anyOf = {ACCESS_HIDDEN_PROFILES_FULL, ACCESS_HIDDEN_PROFILES})
startAppDetailsActivity(ComponentName component, UserHandle user, Rect sourceBounds, Bundle opts)1097     public void startAppDetailsActivity(ComponentName component, UserHandle user,
1098             Rect sourceBounds, Bundle opts) {
1099         logErrorForInvalidProfileAccess(user);
1100         try {
1101             mService.showAppDetailsAsUser(mContext.getIApplicationThread(),
1102                     mContext.getPackageName(), mContext.getAttributionTag(),
1103                     component, sourceBounds, opts, user);
1104         } catch (RemoteException re) {
1105             throw re.rethrowFromSystemServer();
1106         }
1107     }
1108 
1109     /**
1110      * Returns PendingIntent associated with specified shortcut.
1111      *
1112      * @param packageName The packageName of the shortcut
1113      * @param shortcutId The id of the shortcut
1114      * @param opts This parameter is no longer supported
1115      * @param user The UserHandle of the profile
1116      */
1117     @Nullable
getShortcutIntent(@onNull final String packageName, @NonNull final String shortcutId, @Nullable final Bundle opts, @NonNull final UserHandle user)1118     public PendingIntent getShortcutIntent(@NonNull final String packageName,
1119             @NonNull final String shortcutId, @Nullable final Bundle opts,
1120             @NonNull final UserHandle user) {
1121         logErrorForInvalidProfileAccess(user);
1122         if (DEBUG) {
1123             Log.i(TAG, "GetShortcutIntent " + packageName + "/" + shortcutId + " " + user);
1124         }
1125         try {
1126             // due to b/209607104, opts will be ignored
1127             return mService.getShortcutIntent(
1128                     mContext.getPackageName(), packageName, shortcutId, null /* opts */, user);
1129         } catch (RemoteException re) {
1130             throw re.rethrowFromSystemServer();
1131         }
1132     }
1133 
1134     /**
1135      * Retrieves a list of config activities for creating {@link ShortcutInfo}.
1136      *
1137      * @param packageName The specific package to query. If null, it checks all installed packages
1138      *            in the profile.
1139      * @param user The UserHandle of the profile.
1140      * @return List of config activities. Can be an empty list but will not be null. Empty list will
1141      * be returned for user-profiles that have items restricted on home screen.
1142      *
1143      * @see Intent#ACTION_CREATE_SHORTCUT
1144      * @see #getShortcutConfigActivityIntent(LauncherActivityInfo)
1145      */
getShortcutConfigActivityList(@ullable String packageName, @NonNull UserHandle user)1146     public List<LauncherActivityInfo> getShortcutConfigActivityList(@Nullable String packageName,
1147             @NonNull UserHandle user) {
1148         logErrorForInvalidProfileAccess(user);
1149         try {
1150             return convertToActivityList(mService.getShortcutConfigActivities(
1151                     mContext.getPackageName(), packageName, user),
1152                     user);
1153         } catch (RemoteException re) {
1154             throw re.rethrowFromSystemServer();
1155         }
1156     }
1157 
convertToActivityList( @ullable ParceledListSlice<LauncherActivityInfoInternal> internals, UserHandle user)1158     private List<LauncherActivityInfo> convertToActivityList(
1159             @Nullable ParceledListSlice<LauncherActivityInfoInternal> internals, UserHandle user) {
1160         if (internals == null || internals.getList().isEmpty()) {
1161             return Collections.EMPTY_LIST;
1162         }
1163         ArrayList<LauncherActivityInfo> lais = new ArrayList<>();
1164         for (LauncherActivityInfoInternal internal : internals.getList()) {
1165             LauncherActivityInfo lai = new LauncherActivityInfo(mContext, internal);
1166             if (DEBUG) {
1167                 Log.v(TAG, "Returning activity for profile " + user + " : "
1168                         + lai.getComponentName());
1169             }
1170             lais.add(lai);
1171         }
1172         return lais;
1173     }
1174 
1175     /**
1176      * Returns an intent sender which can be used to start the configure activity for creating
1177      * custom shortcuts. Use this method if the provider is in another profile as you are not
1178      * allowed to start an activity in another profile.
1179      *
1180      * <p>The caller should receive {@link PinItemRequest} in onActivityResult on
1181      * {@link android.app.Activity#RESULT_OK}.
1182      *
1183      * <p>Callers must be allowed to access the shortcut information, as defined in {@link
1184      * #hasShortcutHostPermission()}.
1185      *
1186      * @param info a configuration activity returned by {@link #getShortcutConfigActivityList}
1187      *
1188      * @throws IllegalStateException when the user is locked or not running.
1189      * @throws SecurityException if {@link #hasShortcutHostPermission()} is false.
1190      *
1191      * @see #getPinItemRequest(Intent)
1192      * @see Intent#ACTION_CREATE_SHORTCUT
1193      * @see android.app.Activity#startIntentSenderForResult
1194      */
1195     @Nullable
getShortcutConfigActivityIntent(@onNull LauncherActivityInfo info)1196     public IntentSender getShortcutConfigActivityIntent(@NonNull LauncherActivityInfo info) {
1197         try {
1198             return mService.getShortcutConfigActivityIntent(
1199                     mContext.getPackageName(), info.getComponentName(), info.getUser());
1200         } catch (RemoteException re) {
1201             throw re.rethrowFromSystemServer();
1202         }
1203     }
1204 
1205     /**
1206      * Checks if the package is installed and enabled for a profile.
1207      *
1208      * <p>If the user in question is a hidden profile {@link UserManager#USER_TYPE_PROFILE_PRIVATE},
1209      * caller should have normal {@link android.Manifest.permission#ACCESS_HIDDEN_PROFILES}
1210      * permission and the {@link android.app.role.RoleManager#ROLE_HOME} role.
1211      *
1212      * @param packageName The package to check.
1213      * @param user The UserHandle of the profile.
1214      *
1215      * @return true if the package exists and is enabled.
1216      */
1217     // Alternatively, a system app can access this api for private profile if they've been granted
1218     // with the {@code android.Manifest.permission#ACCESS_HIDDEN_PROFILES_FULL} permission.
1219     @SuppressLint("RequiresPermission")
1220     @RequiresPermission(conditional = true,
1221             anyOf = {ACCESS_HIDDEN_PROFILES_FULL, ACCESS_HIDDEN_PROFILES})
isPackageEnabled(String packageName, UserHandle user)1222     public boolean isPackageEnabled(String packageName, UserHandle user) {
1223         logErrorForInvalidProfileAccess(user);
1224         try {
1225             return mService.isPackageEnabled(mContext.getPackageName(), packageName, user);
1226         } catch (RemoteException re) {
1227             throw re.rethrowFromSystemServer();
1228         }
1229     }
1230 
1231     /**
1232      * Gets the launcher extras supplied to the system when the given package was suspended via
1233      * {@code PackageManager#setPackagesSuspended(String[], boolean, PersistableBundle,
1234      * PersistableBundle, String)}.
1235      *
1236      * <p>The contents of this {@link Bundle} are supposed to be a contract between the suspending
1237      * app and the launcher.
1238      *
1239      * <p>If the user in question is a hidden profile {@link UserManager#USER_TYPE_PROFILE_PRIVATE},
1240      * caller should have normal {@link android.Manifest.permission#ACCESS_HIDDEN_PROFILES}
1241      * permission and the {@link android.app.role.RoleManager#ROLE_HOME} role.
1242      *
1243      * <p>Note: This just returns whatever extras were provided to the system, <em>which might
1244      * even be {@code null}.</em>
1245      *
1246      * @param packageName The package for which to fetch the launcher extras.
1247      * @param user The {@link UserHandle} of the profile.
1248      * @return A {@link Bundle} of launcher extras. Or {@code null} if the package is not currently
1249      *         suspended.
1250      *
1251      * @see Callback#onPackagesSuspended(String[], UserHandle, Bundle)
1252      * @see PackageManager#isPackageSuspended()
1253      */
1254     // Alternatively, a system app can access this api for private profile if they've been granted
1255     // with the {@code android.Manifest.permission#ACCESS_HIDDEN_PROFILES_FULL} permission.
1256     @SuppressLint("RequiresPermission")
1257     @RequiresPermission(conditional = true,
1258             anyOf = {ACCESS_HIDDEN_PROFILES_FULL, ACCESS_HIDDEN_PROFILES})
getSuspendedPackageLauncherExtras(String packageName, UserHandle user)1259     public @Nullable Bundle getSuspendedPackageLauncherExtras(String packageName, UserHandle user) {
1260         logErrorForInvalidProfileAccess(user);
1261         try {
1262             return mService.getSuspendedPackageLauncherExtras(packageName, user);
1263         } catch (RemoteException re) {
1264             throw re.rethrowFromSystemServer();
1265         }
1266     }
1267 
1268     /**
1269      * Returns whether a package should be hidden from suggestions to the user. Currently, this
1270      * could be done because the package was marked as distracting to the user via
1271      * {@code PackageManager.setDistractingPackageRestrictions(String[], int)}.
1272      *
1273      * <p>If the user in question is a hidden profile {@link UserManager#USER_TYPE_PROFILE_PRIVATE},
1274      * caller should have normal {@link android.Manifest.permission#ACCESS_HIDDEN_PROFILES}
1275      * permission and the {@link android.app.role.RoleManager#ROLE_HOME} role.
1276      *
1277      * @param packageName The package for which to check.
1278      * @param user the {@link UserHandle} of the profile.
1279      * @return
1280      */
1281     // Alternatively, a system app can access this api for private profile if they've been granted
1282     // with the {@code android.Manifest.permission#ACCESS_HIDDEN_PROFILES_FULL} permission.
1283     @SuppressLint("RequiresPermission")
1284     @RequiresPermission(conditional = true,
1285             anyOf = {ACCESS_HIDDEN_PROFILES_FULL, ACCESS_HIDDEN_PROFILES})
shouldHideFromSuggestions(@onNull String packageName, @NonNull UserHandle user)1286     public boolean shouldHideFromSuggestions(@NonNull String packageName,
1287             @NonNull UserHandle user) {
1288         Objects.requireNonNull(packageName, "packageName");
1289         Objects.requireNonNull(user, "user");
1290         try {
1291             return mService.shouldHideFromSuggestions(packageName, user);
1292         } catch (RemoteException re) {
1293             throw re.rethrowFromSystemServer();
1294         }
1295     }
1296 
1297     /**
1298      * Returns {@link ApplicationInfo} about an application installed for a specific user profile.
1299      *
1300      * <p>If the user in question is a hidden profile {@link UserManager#USER_TYPE_PROFILE_PRIVATE},
1301      * caller should have normal {@link android.Manifest.permission#ACCESS_HIDDEN_PROFILES}
1302      * permission and the {@link android.app.role.RoleManager#ROLE_HOME} role.
1303      *
1304      * @param packageName The package name of the application
1305      * @param flags Additional option flags {@link PackageManager#getApplicationInfo}
1306      * @param user The UserHandle of the profile.
1307      *
1308      * @return {@link ApplicationInfo} containing information about the package. Returns
1309      *         {@code null} if the package isn't installed for the given profile, or the profile
1310      *         isn't enabled.
1311      */
1312     // Alternatively, a system app can access this api for private profile if they've been granted
1313     // with the {@code android.Manifest.permission#ACCESS_HIDDEN_PROFILES_FULL} permission.
1314     @SuppressLint("RequiresPermission")
1315     @RequiresPermission(conditional = true,
1316             anyOf = {ACCESS_HIDDEN_PROFILES_FULL, ACCESS_HIDDEN_PROFILES})
getApplicationInfo(@onNull String packageName, @ApplicationInfoFlagsBits int flags, @NonNull UserHandle user)1317     public ApplicationInfo getApplicationInfo(@NonNull String packageName,
1318             @ApplicationInfoFlagsBits int flags, @NonNull UserHandle user)
1319             throws PackageManager.NameNotFoundException {
1320         Objects.requireNonNull(packageName, "packageName");
1321         Objects.requireNonNull(user, "user");
1322         logErrorForInvalidProfileAccess(user);
1323         try {
1324             final ApplicationInfo ai = mService
1325                     .getApplicationInfo(mContext.getPackageName(), packageName, flags, user);
1326             if (ai == null) {
1327                 throw new NameNotFoundException("Package " + packageName + " not found for user "
1328                         + user.getIdentifier());
1329             }
1330             return ai;
1331         } catch (RemoteException re) {
1332             throw re.rethrowFromSystemServer();
1333         }
1334     }
1335 
1336     /**
1337      * Returns an object describing the app usage limit for the given package.
1338      * If there are multiple limits that apply to the package, the one with the smallest
1339      * time remaining will be returned.
1340      *
1341      * @param packageName name of the package whose app usage limit will be returned
1342      * @param user the user of the package
1343      *
1344      * @return an {@link AppUsageLimit} object describing the app time limit containing
1345      * the given package with the smallest time remaining, or {@code null} if none exist.
1346      * @throws SecurityException when the caller is not the recents app.
1347      * @hide
1348      */
1349     @Nullable
1350     @SystemApi
getAppUsageLimit(@onNull String packageName, @NonNull UserHandle user)1351     public LauncherApps.AppUsageLimit getAppUsageLimit(@NonNull String packageName,
1352             @NonNull UserHandle user) {
1353         try {
1354             return mService.getAppUsageLimit(mContext.getPackageName(), packageName, user);
1355         } catch (RemoteException re) {
1356             throw re.rethrowFromSystemServer();
1357         }
1358     }
1359 
1360     /**
1361      * Checks if the activity exists and it enabled for a profile.
1362      *
1363      * <p>The activity may still not be exported, in which case {@link #startMainActivity} will
1364      * throw a {@link SecurityException} unless the caller has the same UID as the target app's.
1365      *
1366      * <p>If the user in question is a hidden profile {@link UserManager#USER_TYPE_PROFILE_PRIVATE},
1367      * caller should have normal {@link android.Manifest.permission#ACCESS_HIDDEN_PROFILES}
1368      * permission and the {@link android.app.role.RoleManager#ROLE_HOME} role.
1369      *
1370      * @param component The activity to check.
1371      * @param user The UserHandle of the profile.
1372      *
1373      * @return true if the activity exists and is enabled.
1374      */
1375     // Alternatively, a system app can access this api for private profile if they've been granted
1376     // with the {@code android.Manifest.permission#ACCESS_HIDDEN_PROFILES_FULL} permission.
1377     @SuppressLint("RequiresPermission")
1378     @RequiresPermission(conditional = true,
1379             anyOf = {ACCESS_HIDDEN_PROFILES_FULL, ACCESS_HIDDEN_PROFILES})
isActivityEnabled(ComponentName component, UserHandle user)1380     public boolean isActivityEnabled(ComponentName component, UserHandle user) {
1381         logErrorForInvalidProfileAccess(user);
1382         try {
1383             return mService.isActivityEnabled(mContext.getPackageName(), component, user);
1384         } catch (RemoteException re) {
1385             throw re.rethrowFromSystemServer();
1386         }
1387     }
1388 
1389     /**
1390      * Returns whether the caller can access the shortcut information.  Access is currently
1391      * available to:
1392      *
1393      * <ul>
1394      *     <li>The current launcher (or default launcher if there is no set current launcher).</li>
1395      *     <li>The currently active voice interaction service.</li>
1396      * </ul>
1397      *
1398      * <p>Note when this method returns {@code false}, it may be a temporary situation because
1399      * the user is trying a new launcher application.  The user may decide to change the default
1400      * launcher back to the calling application again, so even if a launcher application loses
1401      * this permission, it does <b>not</b> have to purge pinned shortcut information.
1402      * If the calling launcher application contains pinned shortcuts, they will still work,
1403      * even though the caller no longer has the shortcut host permission.
1404      *
1405      * @throws IllegalStateException when the user is locked.
1406      *
1407      * @see ShortcutManager
1408      */
hasShortcutHostPermission()1409     public boolean hasShortcutHostPermission() {
1410         try {
1411             return mService.hasShortcutHostPermission(mContext.getPackageName());
1412         } catch (RemoteException re) {
1413             throw re.rethrowFromSystemServer();
1414         }
1415     }
1416 
maybeUpdateDisabledMessage(List<ShortcutInfo> shortcuts)1417     private List<ShortcutInfo> maybeUpdateDisabledMessage(List<ShortcutInfo> shortcuts) {
1418         if (shortcuts == null) {
1419             return null;
1420         }
1421         for (int i = shortcuts.size() - 1; i >= 0; i--) {
1422             final ShortcutInfo si = shortcuts.get(i);
1423             final String message = ShortcutInfo.getDisabledReasonForRestoreIssue(mContext,
1424                     si.getDisabledReason());
1425             if (message != null) {
1426                 si.setDisabledMessage(message);
1427             }
1428         }
1429         return shortcuts;
1430     }
1431 
1432     /**
1433      * Register a callback to be called right before the wmtrace data is moved to the bugreport.
1434      * @hide
1435      */
1436     @RequiresPermission(READ_FRAME_BUFFER)
registerDumpCallback(IDumpCallback cb)1437     public void registerDumpCallback(IDumpCallback cb) {
1438         try {
1439             mService.registerDumpCallback(cb);
1440         } catch (RemoteException e) {
1441             e.rethrowAsRuntimeException();
1442         }
1443     }
1444 
1445     /**
1446      * Saves view capture data to the default location.
1447      * @hide
1448      */
1449     @RequiresPermission(READ_FRAME_BUFFER)
saveViewCaptureData()1450     public void saveViewCaptureData() {
1451         try {
1452             mService.saveViewCaptureData();
1453         } catch (RemoteException e) {
1454             e.rethrowAsRuntimeException();
1455         }
1456     }
1457 
1458     /**
1459      * Unregister a callback, so that it won't be called when LauncherApps dumps.
1460      * @hide
1461      */
1462     @RequiresPermission(READ_FRAME_BUFFER)
unRegisterDumpCallback(IDumpCallback cb)1463     public void unRegisterDumpCallback(IDumpCallback cb) {
1464         try {
1465             mService.unRegisterDumpCallback(cb);
1466         } catch (RemoteException e) {
1467             e.rethrowAsRuntimeException();
1468         }
1469     }
1470 
1471     /**
1472      * Returns {@link ShortcutInfo}s that match {@code query}.
1473      *
1474      * <p>Callers must be allowed to access the shortcut information, as defined in {@link
1475      * #hasShortcutHostPermission()}.
1476      *
1477      * @param query result includes shortcuts matching this query.
1478      * @param user The UserHandle of the profile.
1479      *
1480      * @return the IDs of {@link ShortcutInfo}s that match the query.
1481      * @throws IllegalStateException when the user is locked, or when the {@code user} user
1482      * is locked or not running.
1483      *
1484      * @see ShortcutManager
1485      */
1486     @Nullable
getShortcuts(@onNull ShortcutQuery query, @NonNull UserHandle user)1487     public List<ShortcutInfo> getShortcuts(@NonNull ShortcutQuery query,
1488             @NonNull UserHandle user) {
1489         logErrorForInvalidProfileAccess(user);
1490         try {
1491             // Note this is the only case we need to update the disabled message for shortcuts
1492             // that weren't restored.
1493             // The restore problem messages are only shown by the user, and publishers will never
1494             // see them. The only other API that the launcher gets shortcuts is the shortcut
1495             // changed callback, but that only returns shortcuts with the "key" information, so
1496             // that won't return disabled message.
1497             return maybeUpdateDisabledMessage(mService.getShortcuts(mContext.getPackageName(),
1498                                 new ShortcutQueryWrapper(query), user)
1499                         .getList());
1500         } catch (RemoteException e) {
1501             throw e.rethrowFromSystemServer();
1502         }
1503     }
1504 
1505     /**
1506      * @hide // No longer used.  Use getShortcuts() instead.  Kept for unit tests.
1507      */
1508     @Nullable
1509     @Deprecated
getShortcutInfo(@onNull String packageName, @NonNull List<String> ids, @NonNull UserHandle user)1510     public List<ShortcutInfo> getShortcutInfo(@NonNull String packageName,
1511             @NonNull List<String> ids, @NonNull UserHandle user) {
1512         final ShortcutQuery q = new ShortcutQuery();
1513         q.setPackage(packageName);
1514         q.setShortcutIds(ids);
1515         q.setQueryFlags(ShortcutQuery.FLAG_GET_ALL_KINDS);
1516         return getShortcuts(q, user);
1517     }
1518 
1519     /**
1520      * Pin shortcuts on a package.
1521      *
1522      * <p>This API is <b>NOT</b> cumulative; this will replace all pinned shortcuts for the package.
1523      * However, different launchers may have different set of pinned shortcuts.
1524      *
1525      * <p>The calling launcher application must be allowed to access the shortcut information,
1526      * as defined in {@link #hasShortcutHostPermission()}.
1527      *
1528      * <p>For user-profiles with items restricted on home screen, caller must have the required
1529      * permission.
1530      *
1531      * @param packageName The target package name.
1532      * @param shortcutIds The IDs of the shortcut to be pinned.
1533      * @param user The UserHandle of the profile.
1534      * @throws IllegalStateException when the user is locked, or when the {@code user} user
1535      * is locked or not running.
1536      *
1537      * @see ShortcutManager
1538      */
1539     @RequiresPermission(conditional = true, value = android.Manifest.permission.ACCESS_SHORTCUTS)
pinShortcuts(@onNull String packageName, @NonNull List<String> shortcutIds, @NonNull UserHandle user)1540     public void pinShortcuts(@NonNull String packageName, @NonNull List<String> shortcutIds,
1541             @NonNull UserHandle user) {
1542         logErrorForInvalidProfileAccess(user);
1543         try {
1544             mService.pinShortcuts(mContext.getPackageName(), packageName, shortcutIds, user);
1545         } catch (RemoteException e) {
1546             throw e.rethrowFromSystemServer();
1547         }
1548     }
1549 
1550     /**
1551      * Mark shortcuts as cached for a package.
1552      *
1553      * <p>Only dynamic long lived shortcuts can be cached. None dynamic or non long lived shortcuts
1554      * in the list will be ignored.
1555      *
1556      * <p>Unlike pinned shortcuts, where different callers can have different sets of pinned
1557      * shortcuts, cached state is per shortcut only, and even if multiple callers cache the same
1558      * shortcut, it can be uncached by any valid caller.
1559      *
1560      * @param packageName The target package name.
1561      * @param shortcutIds The IDs of the shortcut to be cached.
1562      * @param user The UserHandle of the profile.
1563      * @param cacheFlags One of the values in:
1564      * <ul>
1565      *     <li>{@link #FLAG_CACHE_NOTIFICATION_SHORTCUTS}
1566      *     <li>{@link #FLAG_CACHE_BUBBLE_SHORTCUTS}
1567      *     <li>{@link #FLAG_CACHE_PEOPLE_TILE_SHORTCUTS}
1568      * </ul>
1569      * @throws IllegalStateException when the user is locked, or when the {@code user} user
1570      * is locked or not running.
1571      *
1572      * @see ShortcutManager
1573      *
1574      * @hide
1575      */
1576     @RequiresPermission(android.Manifest.permission.ACCESS_SHORTCUTS)
cacheShortcuts(@onNull String packageName, @NonNull List<String> shortcutIds, @NonNull UserHandle user, @ShortcutCacheFlags int cacheFlags)1577     public void cacheShortcuts(@NonNull String packageName, @NonNull List<String> shortcutIds,
1578             @NonNull UserHandle user, @ShortcutCacheFlags int cacheFlags) {
1579         logErrorForInvalidProfileAccess(user);
1580         try {
1581             mService.cacheShortcuts(
1582                     mContext.getPackageName(), packageName, shortcutIds, user, cacheFlags);
1583         } catch (RemoteException e) {
1584             throw e.rethrowFromSystemServer();
1585         }
1586     }
1587 
1588     /**
1589      * Remove cached flag from shortcuts for a package.
1590      *
1591      * @param packageName The target package name.
1592      * @param shortcutIds The IDs of the shortcut to be uncached.
1593      * @param user The UserHandle of the profile.
1594      * @param cacheFlags One of the values in:
1595      * <ul>
1596      *     <li>{@link #FLAG_CACHE_NOTIFICATION_SHORTCUTS}
1597      *     <li>{@link #FLAG_CACHE_BUBBLE_SHORTCUTS}
1598      *     <li>{@link #FLAG_CACHE_PEOPLE_TILE_SHORTCUTS}
1599      * </ul>
1600      * @throws IllegalStateException when the user is locked, or when the {@code user} user
1601      * is locked or not running.
1602      *
1603      * @see ShortcutManager
1604      *
1605      * @hide
1606      */
1607     @RequiresPermission(android.Manifest.permission.ACCESS_SHORTCUTS)
uncacheShortcuts(@onNull String packageName, @NonNull List<String> shortcutIds, @NonNull UserHandle user, @ShortcutCacheFlags int cacheFlags)1608     public void uncacheShortcuts(@NonNull String packageName, @NonNull List<String> shortcutIds,
1609             @NonNull UserHandle user, @ShortcutCacheFlags int cacheFlags) {
1610         logErrorForInvalidProfileAccess(user);
1611         try {
1612             mService.uncacheShortcuts(
1613                     mContext.getPackageName(), packageName, shortcutIds, user, cacheFlags);
1614         } catch (RemoteException e) {
1615             throw e.rethrowFromSystemServer();
1616         }
1617     }
1618 
1619     /**
1620      * @hide kept for testing.
1621      */
1622     @Deprecated
getShortcutIconResId(@onNull ShortcutInfo shortcut)1623     public int getShortcutIconResId(@NonNull ShortcutInfo shortcut) {
1624         return shortcut.getIconResourceId();
1625     }
1626 
1627     /**
1628      * @hide kept for testing.
1629      */
1630     @Deprecated
getShortcutIconResId(@onNull String packageName, @NonNull String shortcutId, @NonNull UserHandle user)1631     public int getShortcutIconResId(@NonNull String packageName, @NonNull String shortcutId,
1632             @NonNull UserHandle user) {
1633         final ShortcutQuery q = new ShortcutQuery();
1634         q.setPackage(packageName);
1635         q.setShortcutIds(Arrays.asList(shortcutId));
1636         q.setQueryFlags(ShortcutQuery.FLAG_GET_ALL_KINDS);
1637         final List<ShortcutInfo> shortcuts = getShortcuts(q, user);
1638 
1639         return shortcuts.size() > 0 ? shortcuts.get(0).getIconResourceId() : 0;
1640     }
1641 
1642     /**
1643      * @hide internal/unit tests only
1644      */
getShortcutIconFd( @onNull ShortcutInfo shortcut)1645     public ParcelFileDescriptor getShortcutIconFd(
1646             @NonNull ShortcutInfo shortcut) {
1647         return getShortcutIconFd(shortcut.getPackage(), shortcut.getId(),
1648                 shortcut.getUserId());
1649     }
1650 
1651     /**
1652      * @hide internal/unit tests only
1653      */
getShortcutIconFd( @onNull String packageName, @NonNull String shortcutId, @NonNull UserHandle user)1654     public ParcelFileDescriptor getShortcutIconFd(
1655             @NonNull String packageName, @NonNull String shortcutId, @NonNull UserHandle user) {
1656         return getShortcutIconFd(packageName, shortcutId, user.getIdentifier());
1657     }
1658 
getShortcutIconFd( @onNull String packageName, @NonNull String shortcutId, int userId)1659     private ParcelFileDescriptor getShortcutIconFd(
1660             @NonNull String packageName, @NonNull String shortcutId, int userId) {
1661         try {
1662             return mService.getShortcutIconFd(mContext.getPackageName(),
1663                     packageName, shortcutId, userId);
1664         } catch (RemoteException e) {
1665             throw e.rethrowFromSystemServer();
1666         }
1667     }
1668 
1669     /**
1670      * @hide internal/unit tests only
1671      */
1672     @VisibleForTesting
getUriShortcutIconFd(@onNull ShortcutInfo shortcut)1673     public ParcelFileDescriptor getUriShortcutIconFd(@NonNull ShortcutInfo shortcut) {
1674         return getUriShortcutIconFd(shortcut.getPackage(), shortcut.getId(), shortcut.getUserId());
1675     }
1676 
getUriShortcutIconFd(@onNull String packageName, @NonNull String shortcutId, int userId)1677     private ParcelFileDescriptor getUriShortcutIconFd(@NonNull String packageName,
1678             @NonNull String shortcutId, int userId) {
1679         String uri = getShortcutIconUri(packageName, shortcutId, userId);
1680         if (uri == null) {
1681             return null;
1682         }
1683         try {
1684             return mContext.getContentResolver().openFileDescriptor(Uri.parse(uri), "r");
1685         } catch (Exception e) {
1686             Log.e(TAG, "Failed to open icon file: " + uri, e);
1687             return null;
1688         }
1689     }
1690 
getShortcutIconUri(@onNull String packageName, @NonNull String shortcutId, int userId)1691     private String getShortcutIconUri(@NonNull String packageName,
1692             @NonNull String shortcutId, int userId) {
1693         String uri = null;
1694         try {
1695             uri = mService.getShortcutIconUri(mContext.getPackageName(), packageName, shortcutId,
1696                     userId);
1697         } catch (RemoteException e) {
1698             throw e.rethrowFromSystemServer();
1699         }
1700         return uri;
1701     }
1702 
1703     /**
1704      * Returns the icon for this shortcut, without any badging for the profile.
1705      *
1706      * <p>The calling launcher application must be allowed to access the shortcut information,
1707      * as defined in {@link #hasShortcutHostPermission()}.
1708      *
1709      * @param density The preferred density of the icon, zero for default density. Use
1710      * density DPI values from {@link DisplayMetrics}.
1711      *
1712      * @return The drawable associated with the shortcut.
1713      * @throws IllegalStateException when the user is locked, or when the {@code user} user
1714      * is locked or not running.
1715      *
1716      * @see ShortcutManager
1717      * @see #getShortcutBadgedIconDrawable(ShortcutInfo, int)
1718      * @see DisplayMetrics
1719      */
getShortcutIconDrawable(@onNull ShortcutInfo shortcut, int density)1720     public Drawable getShortcutIconDrawable(@NonNull ShortcutInfo shortcut, int density) {
1721         if (shortcut.hasIconFile()) {
1722             final ParcelFileDescriptor pfd = getShortcutIconFd(shortcut);
1723             return loadDrawableFromFileDescriptor(pfd, shortcut.hasAdaptiveBitmap());
1724         } else if (shortcut.hasIconUri()) {
1725             final ParcelFileDescriptor pfd = getUriShortcutIconFd(shortcut);
1726             return loadDrawableFromFileDescriptor(pfd, shortcut.hasAdaptiveBitmap());
1727         } else if (shortcut.hasIconResource()) {
1728             return loadDrawableResourceFromPackage(shortcut.getPackage(),
1729                     shortcut.getIconResourceId(), shortcut.getUserHandle(), density);
1730         } else if (shortcut.getIcon() != null) {
1731             // This happens if a shortcut is pending-approval.
1732             final Icon icon = shortcut.getIcon();
1733             switch (icon.getType()) {
1734                 case Icon.TYPE_RESOURCE: {
1735                     return loadDrawableResourceFromPackage(shortcut.getPackage(),
1736                             icon.getResId(), shortcut.getUserHandle(), density);
1737                 }
1738                 case Icon.TYPE_BITMAP:
1739                 case Icon.TYPE_ADAPTIVE_BITMAP: {
1740                     return icon.loadDrawable(mContext);
1741                 }
1742                 default:
1743                     return null; // Shouldn't happen though.
1744             }
1745         } else {
1746             return null; // Has no icon.
1747         }
1748     }
1749 
loadDrawableFromFileDescriptor(ParcelFileDescriptor pfd, boolean adaptive)1750     private Drawable loadDrawableFromFileDescriptor(ParcelFileDescriptor pfd, boolean adaptive) {
1751         if (pfd == null) {
1752             return null;
1753         }
1754         try {
1755             final Bitmap bmp = BitmapFactory.decodeFileDescriptor(pfd.getFileDescriptor());
1756             if (bmp != null) {
1757                 BitmapDrawable dr = new BitmapDrawable(mContext.getResources(), bmp);
1758                 if (adaptive) {
1759                     return new AdaptiveIconDrawable(null, dr);
1760                 } else {
1761                     return dr;
1762                 }
1763             }
1764             return null;
1765         } finally {
1766             try {
1767                 pfd.close();
1768             } catch (IOException ignore) {
1769             }
1770         }
1771     }
1772 
1773     /**
1774      * @hide
1775      */
getShortcutIcon(@onNull ShortcutInfo shortcut)1776     public Icon getShortcutIcon(@NonNull ShortcutInfo shortcut) {
1777         if (shortcut.hasIconFile()) {
1778             final ParcelFileDescriptor pfd = getShortcutIconFd(shortcut);
1779             if (pfd == null) {
1780                 return null;
1781             }
1782             try {
1783                 final Bitmap bmp = BitmapFactory.decodeFileDescriptor(pfd.getFileDescriptor());
1784                 if (bmp != null) {
1785                     if (shortcut.hasAdaptiveBitmap()) {
1786                         return Icon.createWithAdaptiveBitmap(bmp);
1787                     } else {
1788                         return Icon.createWithBitmap(bmp);
1789                     }
1790                 }
1791                 return null;
1792             } finally {
1793                 try {
1794                     pfd.close();
1795                 } catch (IOException ignore) {
1796                 }
1797             }
1798         } else if (shortcut.hasIconUri()) {
1799             String uri = getShortcutIconUri(shortcut.getPackage(), shortcut.getId(),
1800                     shortcut.getUserId());
1801             if (uri == null) {
1802                 return null;
1803             }
1804             if (shortcut.hasAdaptiveBitmap()) {
1805                 return Icon.createWithAdaptiveBitmapContentUri(uri);
1806             } else {
1807                 return Icon.createWithContentUri(uri);
1808             }
1809         } else if (shortcut.hasIconResource()) {
1810             return Icon.createWithResource(shortcut.getPackage(), shortcut.getIconResourceId());
1811         } else {
1812             return shortcut.getIcon();
1813         }
1814     }
1815 
loadDrawableResourceFromPackage(String packageName, int resId, UserHandle user, int density)1816     private Drawable loadDrawableResourceFromPackage(String packageName, int resId,
1817             UserHandle user, int density) {
1818         try {
1819             if (resId == 0) {
1820                 return null; // Shouldn't happen but just in case.
1821             }
1822             final ApplicationInfo ai = getApplicationInfo(packageName, /* flags =*/ 0, user);
1823             final Resources res = mContext.getPackageManager().getResourcesForApplication(ai);
1824             return res.getDrawableForDensity(resId, density);
1825         } catch (NameNotFoundException | Resources.NotFoundException e) {
1826             return null;
1827         }
1828     }
1829 
1830     /**
1831      * Returns the shortcut icon with badging appropriate for the profile.
1832      *
1833      * <p>The calling launcher application must be allowed to access the shortcut information,
1834      * as defined in {@link #hasShortcutHostPermission()}.
1835      *
1836      * @param density Optional density for the icon, or 0 to use the default density. Use
1837      * @return A badged icon for the shortcut.
1838      * @throws IllegalStateException when the user is locked, or when the {@code user} user
1839      * is locked or not running.
1840      *
1841      * @see ShortcutManager
1842      * @see #getShortcutIconDrawable(ShortcutInfo, int)
1843      * @see DisplayMetrics
1844      */
getShortcutBadgedIconDrawable(ShortcutInfo shortcut, int density)1845     public Drawable getShortcutBadgedIconDrawable(ShortcutInfo shortcut, int density) {
1846         final Drawable originalIcon = getShortcutIconDrawable(shortcut, density);
1847 
1848         return (originalIcon == null) ? null : mContext.getPackageManager().getUserBadgedIcon(
1849                 originalIcon, shortcut.getUserHandle());
1850     }
1851 
1852     /**
1853      * Starts a shortcut.
1854      *
1855      * <p>The calling launcher application must be allowed to access the shortcut information,
1856      * as defined in {@link #hasShortcutHostPermission()}.
1857      *
1858      * @param packageName The target shortcut package name.
1859      * @param shortcutId The target shortcut ID.
1860      * @param sourceBounds The Rect containing the source bounds of the clicked icon.
1861      * @param startActivityOptions Options to pass to startActivity.
1862      * @param user The UserHandle of the profile.
1863      * @throws IllegalStateException when the user is locked, or when the {@code user} user
1864      * is locked or not running.
1865      *
1866      * @throws android.content.ActivityNotFoundException failed to start shortcut. (e.g.
1867      * the shortcut no longer exists, is disabled, the intent receiver activity doesn't exist, etc)
1868      */
startShortcut(@onNull String packageName, @NonNull String shortcutId, @Nullable Rect sourceBounds, @Nullable Bundle startActivityOptions, @NonNull UserHandle user)1869     public void startShortcut(@NonNull String packageName, @NonNull String shortcutId,
1870             @Nullable Rect sourceBounds, @Nullable Bundle startActivityOptions,
1871             @NonNull UserHandle user) {
1872         logErrorForInvalidProfileAccess(user);
1873 
1874         startShortcut(packageName, shortcutId, sourceBounds, startActivityOptions,
1875                 user.getIdentifier());
1876     }
1877 
1878     /**
1879      * Launches a shortcut.
1880      *
1881      * <p>The calling launcher application must be allowed to access the shortcut information,
1882      * as defined in {@link #hasShortcutHostPermission()}.
1883      *
1884      * @param shortcut The target shortcut.
1885      * @param sourceBounds The Rect containing the source bounds of the clicked icon.
1886      * @param startActivityOptions Options to pass to startActivity.
1887      * @throws IllegalStateException when the user is locked, or when the {@code user} user
1888      * is locked or not running.
1889      *
1890      * @throws android.content.ActivityNotFoundException failed to start shortcut. (e.g.
1891      * the shortcut no longer exists, is disabled, the intent receiver activity doesn't exist, etc)
1892      */
startShortcut(@onNull ShortcutInfo shortcut, @Nullable Rect sourceBounds, @Nullable Bundle startActivityOptions)1893     public void startShortcut(@NonNull ShortcutInfo shortcut,
1894             @Nullable Rect sourceBounds, @Nullable Bundle startActivityOptions) {
1895         startShortcut(shortcut.getPackage(), shortcut.getId(),
1896                 sourceBounds, startActivityOptions,
1897                 shortcut.getUserId());
1898     }
1899 
1900     @UnsupportedAppUsage
startShortcut(@onNull String packageName, @NonNull String shortcutId, @Nullable Rect sourceBounds, @Nullable Bundle startActivityOptions, int userId)1901     private void startShortcut(@NonNull String packageName, @NonNull String shortcutId,
1902             @Nullable Rect sourceBounds, @Nullable Bundle startActivityOptions,
1903             int userId) {
1904         try {
1905             final boolean success = mService.startShortcut(mContext.getPackageName(), packageName,
1906                     null /* default featureId */, shortcutId, sourceBounds, startActivityOptions,
1907                     userId);
1908             if (!success) {
1909                 throw new ActivityNotFoundException("Shortcut could not be started");
1910             }
1911         } catch (RemoteException e) {
1912             throw e.rethrowFromSystemServer();
1913         }
1914     }
1915 
1916     /**
1917      * Registers a callback for changes to packages in this user and managed profiles.
1918      *
1919      * <p>To receive callbacks for hidden profile {@link UserManager#USER_TYPE_PROFILE_PRIVATE},
1920      * caller should have normal {@link android.Manifest.permission#ACCESS_HIDDEN_PROFILES}
1921      * permission and the {@link android.app.role.RoleManager#ROLE_HOME} role.
1922      *
1923      * <p>This callback will also receive changes to the {@link LauncherUserInfo#getUserConfig()},
1924      * allowing clients to monitor updates to the user-specific configuration.
1925      *
1926      * @param callback The callback to register.
1927      */
1928     // Alternatively, a system app can access this api for private profile if they've been granted
1929     // with the {@code android.Manifest.permission#ACCESS_HIDDEN_PROFILES_FULL} permission.
1930     @SuppressLint("RequiresPermission")
1931     @RequiresPermission(conditional = true,
1932             anyOf = {ACCESS_HIDDEN_PROFILES_FULL, ACCESS_HIDDEN_PROFILES})
registerCallback(Callback callback)1933     public void registerCallback(Callback callback) {
1934         registerCallback(callback, null);
1935     }
1936 
1937     /**
1938      * Registers a callback for changes to packages in this user and managed profiles.
1939      *
1940      * <p>To receive callbacks for hidden profile {@link UserManager#USER_TYPE_PROFILE_PRIVATE},
1941      * caller should have normal {@link android.Manifest.permission#ACCESS_HIDDEN_PROFILES}
1942      * permission and the {@link android.app.role.RoleManager#ROLE_HOME} role.
1943      *
1944      * <p>This callback will also receive changes to the {@link LauncherUserInfo#getUserConfig()},
1945      * allowing clients to monitor updates to the user-specific configuration.
1946      *
1947      * @param callback The callback to register.
1948      * @param handler that should be used to post callbacks on, may be null.
1949      */
1950     // Alternatively, a system app can access this api for private profile if they've been granted
1951     // with the {@code android.Manifest.permission#ACCESS_HIDDEN_PROFILES_FULL} permission.
1952     @SuppressLint("RequiresPermission")
1953     @RequiresPermission(conditional = true,
1954             anyOf = {ACCESS_HIDDEN_PROFILES_FULL, ACCESS_HIDDEN_PROFILES})
registerCallback(Callback callback, Handler handler)1955     public void registerCallback(Callback callback, Handler handler) {
1956         synchronized (this) {
1957             if (callback != null && findCallbackLocked(callback) < 0) {
1958                 boolean addedFirstCallback = mCallbacks.size() == 0;
1959                 addCallbackLocked(callback, handler);
1960                 if (addedFirstCallback) {
1961                     try {
1962                         mService.addOnAppsChangedListener(mContext.getPackageName(),
1963                                 mAppsChangedListener);
1964                     } catch (RemoteException re) {
1965                         throw re.rethrowFromSystemServer();
1966                     }
1967                 }
1968             }
1969         }
1970     }
1971 
1972     /**
1973      * Unregisters a callback that was previously registered.
1974      *
1975      * @param callback The callback to unregister.
1976      * @see #registerCallback(Callback)
1977      */
unregisterCallback(Callback callback)1978     public void unregisterCallback(Callback callback) {
1979         synchronized (this) {
1980             removeCallbackLocked(callback);
1981             if (mCallbacks.size() == 0) {
1982                 try {
1983                     mService.removeOnAppsChangedListener(mAppsChangedListener);
1984                 } catch (RemoteException re) {
1985                     throw re.rethrowFromSystemServer();
1986                 }
1987             }
1988         }
1989     }
1990 
1991     /**
1992      * Disable different archive compatibility options of the launcher for the caller of this
1993      * method.
1994      *
1995      * @see ArchiveCompatibilityParams for individual options.
1996      */
1997     @FlaggedApi(android.content.pm.Flags.FLAG_ARCHIVING)
setArchiveCompatibility(@onNull ArchiveCompatibilityParams params)1998     public void setArchiveCompatibility(@NonNull ArchiveCompatibilityParams params) {
1999         try {
2000             mService.setArchiveCompatibilityOptions(params.isEnableIconOverlay(),
2001                     params.isEnableUnarchivalConfirmation());
2002         } catch (RemoteException re) {
2003             throw re.rethrowFromSystemServer();
2004         }
2005     }
2006 
2007     /** @return position in mCallbacks for callback or -1 if not present. */
findCallbackLocked(Callback callback)2008     private int findCallbackLocked(Callback callback) {
2009         if (callback == null) {
2010             throw new IllegalArgumentException("Callback cannot be null");
2011         }
2012         final int size = mCallbacks.size();
2013         for (int i = 0; i < size; ++i) {
2014             if (mCallbacks.get(i).mCallback == callback) {
2015                 return i;
2016             }
2017         }
2018         return -1;
2019     }
2020 
removeCallbackLocked(Callback callback)2021     private void removeCallbackLocked(Callback callback) {
2022         int pos = findCallbackLocked(callback);
2023         if (pos >= 0) {
2024             mCallbacks.remove(pos);
2025         }
2026     }
2027 
addCallbackLocked(Callback callback, Handler handler)2028     private void addCallbackLocked(Callback callback, Handler handler) {
2029         // Remove if already present.
2030         removeCallbackLocked(callback);
2031         if (handler == null) {
2032             handler = new Handler();
2033         }
2034         CallbackMessageHandler toAdd = new CallbackMessageHandler(handler.getLooper(), callback);
2035         mCallbacks.add(toAdd);
2036     }
2037 
2038     private final IOnAppsChangedListener.Stub mAppsChangedListener =
2039             new IOnAppsChangedListener.Stub() {
2040 
2041         @Override
2042         public void onPackageRemoved(UserHandle user, String packageName)
2043                 throws RemoteException {
2044             if (DEBUG) {
2045                 Log.d(TAG, "onPackageRemoved " + user.getIdentifier() + "," + packageName);
2046             }
2047             synchronized (LauncherApps.this) {
2048                 for (CallbackMessageHandler callback : mCallbacks) {
2049                     callback.postOnPackageRemoved(packageName, user);
2050                 }
2051             }
2052         }
2053 
2054         @Override
2055         public void onPackageChanged(UserHandle user, String packageName) throws RemoteException {
2056             if (DEBUG) {
2057                 Log.d(TAG, "onPackageChanged " + user.getIdentifier() + "," + packageName);
2058             }
2059             synchronized (LauncherApps.this) {
2060                 for (CallbackMessageHandler callback : mCallbacks) {
2061                     callback.postOnPackageChanged(packageName, user);
2062                 }
2063             }
2064         }
2065 
2066         @Override
2067         public void onPackageAdded(UserHandle user, String packageName) throws RemoteException {
2068             if (DEBUG) {
2069                 Log.d(TAG, "onPackageAdded " + user.getIdentifier() + "," + packageName);
2070             }
2071             synchronized (LauncherApps.this) {
2072                 for (CallbackMessageHandler callback : mCallbacks) {
2073                     callback.postOnPackageAdded(packageName, user);
2074                 }
2075             }
2076         }
2077 
2078         @Override
2079         public void onPackagesAvailable(UserHandle user, String[] packageNames, boolean replacing)
2080                 throws RemoteException {
2081             if (DEBUG) {
2082                 Log.d(TAG, "onPackagesAvailable " + user.getIdentifier() + ","
2083                         + Arrays.toString(packageNames));
2084             }
2085             synchronized (LauncherApps.this) {
2086                 for (CallbackMessageHandler callback : mCallbacks) {
2087                     callback.postOnPackagesAvailable(packageNames, user, replacing);
2088                 }
2089             }
2090         }
2091 
2092         @Override
2093         public void onPackagesUnavailable(UserHandle user, String[] packageNames, boolean replacing)
2094                 throws RemoteException {
2095             if (DEBUG) {
2096                 Log.d(TAG, "onPackagesUnavailable " + user.getIdentifier() + ","
2097                         + Arrays.toString(packageNames));
2098             }
2099             synchronized (LauncherApps.this) {
2100                 for (CallbackMessageHandler callback : mCallbacks) {
2101                     callback.postOnPackagesUnavailable(packageNames, user, replacing);
2102                 }
2103             }
2104         }
2105 
2106         @Override
2107         public void onPackagesSuspended(UserHandle user, String[] packageNames,
2108                 Bundle launcherExtras)
2109                 throws RemoteException {
2110             if (DEBUG) {
2111                 Log.d(TAG, "onPackagesSuspended " + user.getIdentifier() + ","
2112                         + Arrays.toString(packageNames));
2113             }
2114             synchronized (LauncherApps.this) {
2115                 for (CallbackMessageHandler callback : mCallbacks) {
2116                     callback.postOnPackagesSuspended(packageNames, launcherExtras, user);
2117                 }
2118             }
2119         }
2120 
2121         @Override
2122         public void onPackagesUnsuspended(UserHandle user, String[] packageNames)
2123                 throws RemoteException {
2124             if (DEBUG) {
2125                 Log.d(TAG, "onPackagesUnsuspended " + user.getIdentifier() + ","
2126                         + Arrays.toString(packageNames));
2127             }
2128             synchronized (LauncherApps.this) {
2129                 for (CallbackMessageHandler callback : mCallbacks) {
2130                     callback.postOnPackagesUnsuspended(packageNames, user);
2131                 }
2132             }
2133         }
2134 
2135         @Override
2136         public void onShortcutChanged(UserHandle user, String packageName,
2137                 ParceledListSlice shortcuts) {
2138             if (DEBUG) {
2139                 Log.d(TAG, "onShortcutChanged " + user.getIdentifier() + "," + packageName);
2140             }
2141             final List<ShortcutInfo> list = shortcuts.getList();
2142             synchronized (LauncherApps.this) {
2143                 for (CallbackMessageHandler callback : mCallbacks) {
2144                     callback.postOnShortcutChanged(packageName, user, list);
2145                 }
2146             }
2147         }
2148 
2149         public void onPackageLoadingProgressChanged(UserHandle user, String packageName,
2150                 float progress) {
2151             if (DEBUG) {
2152                 Log.d(TAG, "onPackageLoadingProgressChanged " + user.getIdentifier() + ","
2153                         + packageName + "," + progress);
2154             }
2155             synchronized (LauncherApps.this) {
2156                 for (CallbackMessageHandler callback : mCallbacks) {
2157                     callback.postOnPackageLoadingProgressChanged(user, packageName, progress);
2158                 }
2159             }
2160         }
2161 
2162         public void onUserConfigChanged(LauncherUserInfo launcherUserInfo) {
2163             if (DEBUG) {
2164                 if (Flags.allowPrivateProfile()
2165                         && android.multiuser.Flags.addLauncherUserConfig()) {
2166                     Log.d(TAG, "OnUserConfigChanged for user type " + launcherUserInfo.getUserType()
2167                             + ", new userConfig: " + launcherUserInfo.getUserConfig());
2168                 }
2169             }
2170             synchronized (LauncherApps.this) {
2171                 for (CallbackMessageHandler callback : mCallbacks) {
2172                     callback.postOnUserConfigChanged(launcherUserInfo);
2173                 }
2174             }
2175         }
2176     };
2177 
2178     /**
2179      * Used to enable Archiving compatibility options with {@link #setArchiveCompatibility}.
2180      */
2181     @FlaggedApi(android.content.pm.Flags.FLAG_ARCHIVING)
2182     public static class ArchiveCompatibilityParams {
2183         private boolean mEnableIconOverlay = true;
2184 
2185         private boolean mEnableUnarchivalConfirmation = true;
2186 
2187         /** @hide */
isEnableIconOverlay()2188         public boolean isEnableIconOverlay() {
2189             return mEnableIconOverlay;
2190         }
2191 
2192         /** @hide */
isEnableUnarchivalConfirmation()2193         public boolean isEnableUnarchivalConfirmation() {
2194             return mEnableUnarchivalConfirmation;
2195         }
2196 
2197         /**
2198          * If true, provides a cloud overlay for archived apps to ensure users are aware that a
2199          * certain app is archived. True by default.
2200          *
2201          * <p> Launchers might want to disable this operation if they want to provide custom user
2202          * experience to differentiate archived apps.
2203          */
setEnableIconOverlay(boolean enableIconOverlay)2204         public void setEnableIconOverlay(boolean enableIconOverlay) {
2205             this.mEnableIconOverlay = enableIconOverlay;
2206         }
2207 
2208         /**
2209          * If true, the user is shown a confirmation dialog when they click an archived app, which
2210          * explains that the app will be downloaded and restored in the background. True by default.
2211          *
2212          * <p> Launchers might want to disable this operation if they provide sufficient,
2213          * alternative user guidance to highlight that an unarchival is starting and ongoing once an
2214          * archived app is tapped. E.g., this could be achieved by showing the unarchival progress
2215          * around the icon.
2216          */
setEnableUnarchivalConfirmation(boolean enableUnarchivalConfirmation)2217         public void setEnableUnarchivalConfirmation(boolean enableUnarchivalConfirmation) {
2218             this.mEnableUnarchivalConfirmation = enableUnarchivalConfirmation;
2219         }
2220     }
2221 
2222     private static class CallbackMessageHandler extends Handler {
2223         private static final int MSG_ADDED = 1;
2224         private static final int MSG_REMOVED = 2;
2225         private static final int MSG_CHANGED = 3;
2226         private static final int MSG_AVAILABLE = 4;
2227         private static final int MSG_UNAVAILABLE = 5;
2228         private static final int MSG_SUSPENDED = 6;
2229         private static final int MSG_UNSUSPENDED = 7;
2230         private static final int MSG_SHORTCUT_CHANGED = 8;
2231         private static final int MSG_LOADING_PROGRESS_CHANGED = 9;
2232         private static final int MSG_USER_CONFIG_CHANGED = 10;
2233 
2234         private final LauncherApps.Callback mCallback;
2235 
2236         private static class CallbackInfo {
2237             String[] packageNames;
2238             String packageName;
2239             Bundle launcherExtras;
2240             boolean replacing;
2241             UserHandle user;
2242             List<ShortcutInfo> shortcuts;
2243             float mLoadingProgress;
2244         }
2245 
CallbackMessageHandler(Looper looper, LauncherApps.Callback callback)2246         public CallbackMessageHandler(Looper looper, LauncherApps.Callback callback) {
2247             super(looper, null, true);
2248             mCallback = callback;
2249         }
2250 
2251         @Override
handleMessage(Message msg)2252         public void handleMessage(Message msg) {
2253             if (mCallback == null || !(msg.obj instanceof CallbackInfo)) {
2254                 return;
2255             }
2256             CallbackInfo info = (CallbackInfo) msg.obj;
2257             switch (msg.what) {
2258                 case MSG_ADDED:
2259                     mCallback.onPackageAdded(info.packageName, info.user);
2260                     break;
2261                 case MSG_REMOVED:
2262                     mCallback.onPackageRemoved(info.packageName, info.user);
2263                     break;
2264                 case MSG_CHANGED:
2265                     mCallback.onPackageChanged(info.packageName, info.user);
2266                     break;
2267                 case MSG_AVAILABLE:
2268                     mCallback.onPackagesAvailable(info.packageNames, info.user, info.replacing);
2269                     break;
2270                 case MSG_UNAVAILABLE:
2271                     mCallback.onPackagesUnavailable(info.packageNames, info.user, info.replacing);
2272                     break;
2273                 case MSG_SUSPENDED:
2274                     mCallback.onPackagesSuspended(info.packageNames, info.user, info.launcherExtras
2275                     );
2276                     break;
2277                 case MSG_UNSUSPENDED:
2278                     mCallback.onPackagesUnsuspended(info.packageNames, info.user);
2279                     break;
2280                 case MSG_SHORTCUT_CHANGED:
2281                     mCallback.onShortcutsChanged(info.packageName, info.shortcuts, info.user);
2282                     break;
2283                 case MSG_LOADING_PROGRESS_CHANGED:
2284                     mCallback.onPackageLoadingProgressChanged(info.packageName, info.user,
2285                             info.mLoadingProgress);
2286                     break;
2287                 case MSG_USER_CONFIG_CHANGED:
2288                     if (Flags.allowPrivateProfile()
2289                             && android.multiuser.Flags.addLauncherUserConfig()) {
2290                         mCallback.onUserConfigChanged(Objects.requireNonNull(
2291                                 info.launcherExtras.getParcelable(LAUNCHER_USER_INFO_EXTRA_KEY,
2292                                         LauncherUserInfo.class)));
2293                     }
2294                     break;
2295             }
2296         }
2297 
postOnPackageAdded(String packageName, UserHandle user)2298         public void postOnPackageAdded(String packageName, UserHandle user) {
2299             CallbackInfo info = new CallbackInfo();
2300             info.packageName = packageName;
2301             info.user = user;
2302             obtainMessage(MSG_ADDED, info).sendToTarget();
2303         }
2304 
postOnPackageRemoved(String packageName, UserHandle user)2305         public void postOnPackageRemoved(String packageName, UserHandle user) {
2306             CallbackInfo info = new CallbackInfo();
2307             info.packageName = packageName;
2308             info.user = user;
2309             obtainMessage(MSG_REMOVED, info).sendToTarget();
2310         }
2311 
postOnPackageChanged(String packageName, UserHandle user)2312         public void postOnPackageChanged(String packageName, UserHandle user) {
2313             CallbackInfo info = new CallbackInfo();
2314             info.packageName = packageName;
2315             info.user = user;
2316             obtainMessage(MSG_CHANGED, info).sendToTarget();
2317         }
2318 
postOnPackagesAvailable(String[] packageNames, UserHandle user, boolean replacing)2319         public void postOnPackagesAvailable(String[] packageNames, UserHandle user,
2320                 boolean replacing) {
2321             CallbackInfo info = new CallbackInfo();
2322             info.packageNames = packageNames;
2323             info.replacing = replacing;
2324             info.user = user;
2325             obtainMessage(MSG_AVAILABLE, info).sendToTarget();
2326         }
2327 
postOnPackagesUnavailable(String[] packageNames, UserHandle user, boolean replacing)2328         public void postOnPackagesUnavailable(String[] packageNames, UserHandle user,
2329                 boolean replacing) {
2330             CallbackInfo info = new CallbackInfo();
2331             info.packageNames = packageNames;
2332             info.replacing = replacing;
2333             info.user = user;
2334             obtainMessage(MSG_UNAVAILABLE, info).sendToTarget();
2335         }
2336 
postOnPackagesSuspended(String[] packageNames, Bundle launcherExtras, UserHandle user)2337         public void postOnPackagesSuspended(String[] packageNames, Bundle launcherExtras,
2338                 UserHandle user) {
2339             CallbackInfo info = new CallbackInfo();
2340             info.packageNames = packageNames;
2341             info.user = user;
2342             info.launcherExtras = launcherExtras;
2343             obtainMessage(MSG_SUSPENDED, info).sendToTarget();
2344         }
2345 
postOnPackagesUnsuspended(String[] packageNames, UserHandle user)2346         public void postOnPackagesUnsuspended(String[] packageNames, UserHandle user) {
2347             CallbackInfo info = new CallbackInfo();
2348             info.packageNames = packageNames;
2349             info.user = user;
2350             obtainMessage(MSG_UNSUSPENDED, info).sendToTarget();
2351         }
2352 
postOnShortcutChanged(String packageName, UserHandle user, List<ShortcutInfo> shortcuts)2353         public void postOnShortcutChanged(String packageName, UserHandle user,
2354                 List<ShortcutInfo> shortcuts) {
2355             CallbackInfo info = new CallbackInfo();
2356             info.packageName = packageName;
2357             info.user = user;
2358             info.shortcuts = shortcuts;
2359             obtainMessage(MSG_SHORTCUT_CHANGED, info).sendToTarget();
2360         }
2361 
postOnPackageLoadingProgressChanged(UserHandle user, String packageName, float progress)2362         public void postOnPackageLoadingProgressChanged(UserHandle user, String packageName,
2363                 float progress) {
2364             CallbackInfo info = new CallbackInfo();
2365             info.packageName = packageName;
2366             info.user = user;
2367             info.mLoadingProgress = progress;
2368             obtainMessage(MSG_LOADING_PROGRESS_CHANGED, info).sendToTarget();
2369         }
2370 
postOnUserConfigChanged(LauncherUserInfo launcherUserInfo)2371         public void postOnUserConfigChanged(LauncherUserInfo launcherUserInfo) {
2372             CallbackInfo info = new CallbackInfo();
2373             info.launcherExtras = new Bundle();
2374             info.launcherExtras.putParcelable(LAUNCHER_USER_INFO_EXTRA_KEY, launcherUserInfo);
2375             obtainMessage(MSG_USER_CONFIG_CHANGED, info).sendToTarget();
2376         }
2377     }
2378 
2379     /**
2380      * Register a callback to watch for session lifecycle events in this user and managed profiles.
2381      * Callers need to either declare &lt;queries&gt; element with the specific package name in the
2382      * app's manifest, have the android.permission.QUERY_ALL_PACKAGES, or be the session owner to
2383      * watch for these events.
2384      *
2385      * <p> Session callbacks are not sent for user-profiles that have items restricted on home
2386      * screen.
2387      *
2388      * @param callback The callback to register.
2389      * @param executor {@link Executor} to handle the callbacks, cannot be null.
2390      *
2391      * @see PackageInstaller#registerSessionCallback(SessionCallback)
2392      */
registerPackageInstallerSessionCallback( @onNull @allbackExecutor Executor executor, @NonNull SessionCallback callback)2393     public void registerPackageInstallerSessionCallback(
2394             @NonNull @CallbackExecutor Executor executor, @NonNull SessionCallback callback) {
2395         if (executor == null) {
2396             throw new NullPointerException("Executor must not be null");
2397         }
2398 
2399         synchronized (mDelegates) {
2400             final SessionCallbackDelegate delegate = new SessionCallbackDelegate(callback,
2401                     executor);
2402             try {
2403                 mService.registerPackageInstallerCallback(mContext.getPackageName(),
2404                         delegate);
2405             } catch (RemoteException e) {
2406                 throw e.rethrowFromSystemServer();
2407             }
2408             mDelegates.add(delegate);
2409         }
2410     }
2411 
2412     /**
2413      * Unregisters a callback that was previously registered.
2414      *
2415      * @param callback The callback to unregister.
2416      * @see #registerPackageInstallerSessionCallback(Executor, SessionCallback)
2417      */
unregisterPackageInstallerSessionCallback(@onNull SessionCallback callback)2418     public void unregisterPackageInstallerSessionCallback(@NonNull SessionCallback callback) {
2419         synchronized (mDelegates) {
2420             for (Iterator<SessionCallbackDelegate> i = mDelegates.iterator(); i.hasNext();) {
2421                 final SessionCallbackDelegate delegate = i.next();
2422                 if (delegate.mCallback == callback) {
2423                     mPm.getPackageInstaller().unregisterSessionCallback(delegate.mCallback);
2424                     i.remove();
2425                 }
2426             }
2427         }
2428     }
2429 
2430     /**
2431      * Return list of all known install sessions in this user and managed profiles, regardless
2432      * of the installer. Callers need to either declare &lt;queries&gt; element with the specific
2433      * package name in the app's manifest, have the android.permission.QUERY_ALL_PACKAGES, or be
2434      * the session owner to retrieve these details.
2435      *
2436      * <p>To receive callbacks for hidden profile {@link UserManager#USER_TYPE_PROFILE_PRIVATE},
2437      * caller should have normal {@link android.Manifest.permission#ACCESS_HIDDEN_PROFILES}
2438      * permission and the {@link android.app.role.RoleManager#ROLE_HOME} role.
2439      *
2440      * @see PackageInstaller#getAllSessions()
2441      */
2442     @SuppressLint("RequiresPermission")
2443     @RequiresPermission(conditional = true,
2444             anyOf = {ACCESS_HIDDEN_PROFILES_FULL, ACCESS_HIDDEN_PROFILES})
getAllPackageInstallerSessions()2445     public @NonNull List<SessionInfo> getAllPackageInstallerSessions() {
2446         try {
2447             return mService.getAllSessions(mContext.getPackageName()).getList();
2448         } catch (RemoteException e) {
2449             throw e.rethrowFromSystemServer();
2450         }
2451     }
2452 
2453     /**
2454      * Register a callback to watch for shortcut change events in this user and managed profiles.
2455      *
2456      * @param callback The callback to register.
2457      * @param query {@link ShortcutQuery} to match and filter the shortcut events. Only matching
2458      * shortcuts will be returned by the callback.
2459      * @param executor {@link Executor} to handle the callbacks. To dispatch callbacks to the main
2460      * thread of your application, you can use {@link android.content.Context#getMainExecutor()}.
2461      *
2462      * @hide
2463      */
registerShortcutChangeCallback(@onNull ShortcutChangeCallback callback, @NonNull ShortcutQuery query, @NonNull @CallbackExecutor Executor executor)2464     public void registerShortcutChangeCallback(@NonNull ShortcutChangeCallback callback,
2465             @NonNull ShortcutQuery query, @NonNull @CallbackExecutor Executor executor) {
2466         Objects.requireNonNull(callback, "Callback cannot be null");
2467         Objects.requireNonNull(query, "Query cannot be null");
2468         Objects.requireNonNull(executor, "Executor cannot be null");
2469 
2470         synchronized (mShortcutChangeCallbacks) {
2471             IShortcutChangeCallback proxy = new ShortcutChangeCallbackProxy(executor, callback);
2472             mShortcutChangeCallbacks.put(callback, new Pair<>(executor, proxy));
2473             try {
2474                 mService.registerShortcutChangeCallback(mContext.getPackageName(),
2475                         new ShortcutQueryWrapper(query), proxy);
2476             } catch (RemoteException e) {
2477                 throw e.rethrowFromSystemServer();
2478             }
2479         }
2480     }
2481 
2482     /**
2483      * Unregisters a callback that was previously registered.
2484      * @see #registerShortcutChangeCallback(ShortcutChangeCallback, ShortcutQuery, Executor)
2485      *
2486      * @param callback Callback to be unregistered.
2487      *
2488      * @hide
2489      */
unregisterShortcutChangeCallback(@onNull ShortcutChangeCallback callback)2490     public void unregisterShortcutChangeCallback(@NonNull ShortcutChangeCallback callback) {
2491         Objects.requireNonNull(callback, "Callback cannot be null");
2492 
2493         synchronized (mShortcutChangeCallbacks) {
2494             if (mShortcutChangeCallbacks.containsKey(callback)) {
2495                 IShortcutChangeCallback proxy = mShortcutChangeCallbacks.remove(callback).second;
2496                 try {
2497                     mService.unregisterShortcutChangeCallback(mContext.getPackageName(), proxy);
2498                 } catch (RemoteException e) {
2499                     throw e.rethrowFromSystemServer();
2500                 }
2501             }
2502         }
2503     }
2504 
2505     /**
2506      * A helper method to extract a {@link PinItemRequest} set to
2507      * the {@link #EXTRA_PIN_ITEM_REQUEST} extra.
2508      */
getPinItemRequest(Intent intent)2509     public PinItemRequest getPinItemRequest(Intent intent) {
2510         return intent.getParcelableExtra(EXTRA_PIN_ITEM_REQUEST, android.content.pm.LauncherApps.PinItemRequest.class);
2511     }
2512 
2513     /**
2514      * Represents a "pin shortcut" or a "pin appwidget" request made by an app, which is sent with
2515      * an {@link #ACTION_CONFIRM_PIN_SHORTCUT} or {@link #ACTION_CONFIRM_PIN_APPWIDGET} intent
2516      * respectively to the default launcher app.
2517      *
2518      * <h3>Request of the {@link #REQUEST_TYPE_SHORTCUT} type.</h3>
2519      *
2520      * <p>A {@link #REQUEST_TYPE_SHORTCUT} request represents a request to pin a
2521      * {@link ShortcutInfo}.  If the launcher accepts a request, call {@link #accept()},
2522      * or {@link #accept(Bundle)} with a null or empty Bundle.  No options are defined for
2523      * pin-shortcuts requests.
2524      *
2525      * <p>{@link #getShortcutInfo()} always returns a non-null {@link ShortcutInfo} for this type.
2526      *
2527      * <p>The launcher may receive a request with a {@link ShortcutInfo} that is already pinned, in
2528      * which case {@link ShortcutInfo#isPinned()} returns true.  This means the user wants to create
2529      * another pinned shortcut for a shortcut that's already pinned.  If the launcher accepts it,
2530      * {@link #accept()} must still be called even though the shortcut is already pinned, and
2531      * create a new pinned shortcut icon for it.
2532      *
2533      * <p>See also {@link ShortcutManager} for more details.
2534      *
2535      * <h3>Request of the {@link #REQUEST_TYPE_APPWIDGET} type.</h3>
2536      *
2537      * <p>A {@link #REQUEST_TYPE_SHORTCUT} request represents a request to pin a
2538      * an AppWidget.  If the launcher accepts a request, call {@link #accept(Bundle)} with
2539      * the appwidget integer ID set to the
2540      * {@link android.appwidget.AppWidgetManager#EXTRA_APPWIDGET_ID} extra.
2541      *
2542      * <p>{@link #getAppWidgetProviderInfo(Context)} always returns a non-null
2543      * {@link AppWidgetProviderInfo} for this type.
2544      *
2545      * <p>See also {@link AppWidgetManager} for more details.
2546      *
2547      * @see #EXTRA_PIN_ITEM_REQUEST
2548      * @see #getPinItemRequest(Intent)
2549      */
2550     public static final class PinItemRequest implements Parcelable {
2551 
2552         /** This is a request to pin shortcut. */
2553         public static final int REQUEST_TYPE_SHORTCUT = 1;
2554 
2555         /** This is a request to pin app widget. */
2556         public static final int REQUEST_TYPE_APPWIDGET = 2;
2557 
2558         /** @hide */
2559         @IntDef(prefix = { "REQUEST_TYPE_" }, value = {
2560                 REQUEST_TYPE_SHORTCUT,
2561                 REQUEST_TYPE_APPWIDGET
2562         })
2563         @Retention(RetentionPolicy.SOURCE)
2564         public @interface RequestType {}
2565 
2566         private final int mRequestType;
2567         private final IPinItemRequest mInner;
2568 
2569         /**
2570          * @hide
2571          */
PinItemRequest(IPinItemRequest inner, int type)2572         public PinItemRequest(IPinItemRequest inner, int type) {
2573             mInner = inner;
2574             mRequestType = type;
2575         }
2576 
2577         /**
2578          * Represents the type of a request, which is one of the {@code REQUEST_TYPE_} constants.
2579          *
2580          * @return one of the {@code REQUEST_TYPE_} constants.
2581          */
2582         @RequestType
getRequestType()2583         public int getRequestType() {
2584             return mRequestType;
2585         }
2586 
2587         /**
2588          * {@link ShortcutInfo} sent by the requesting app.
2589          * Always non-null for a {@link #REQUEST_TYPE_SHORTCUT} request, and always null for a
2590          * different request type.
2591          *
2592          * @return requested {@link ShortcutInfo} when a request is of the
2593          * {@link #REQUEST_TYPE_SHORTCUT} type.  Null otherwise.
2594          */
2595         @Nullable
getShortcutInfo()2596         public ShortcutInfo getShortcutInfo() {
2597             try {
2598                 return mInner.getShortcutInfo();
2599             } catch (RemoteException e) {
2600                 throw e.rethrowAsRuntimeException();
2601             }
2602         }
2603 
2604         /**
2605          * {@link AppWidgetProviderInfo} sent by the requesting app.
2606          * Always non-null for a {@link #REQUEST_TYPE_APPWIDGET} request, and always null for a
2607          * different request type.
2608          *
2609          * <p>Launcher should not show any configuration activity associated with the provider, and
2610          * assume that the widget is already fully configured. Upon accepting the widget, it should
2611          * pass the widgetId in {@link #accept(Bundle)}.
2612          *
2613          * @return requested {@link AppWidgetProviderInfo} when a request is of the
2614          * {@link #REQUEST_TYPE_APPWIDGET} type.  Null otherwise.
2615          */
2616         @Nullable
getAppWidgetProviderInfo(Context context)2617         public AppWidgetProviderInfo getAppWidgetProviderInfo(Context context) {
2618             try {
2619                 final AppWidgetProviderInfo info = mInner.getAppWidgetProviderInfo();
2620                 if (info == null) {
2621                     return null;
2622                 }
2623                 info.updateDimensions(context.getResources().getDisplayMetrics());
2624                 return info;
2625             } catch (RemoteException e) {
2626                 throw e.rethrowAsRuntimeException();
2627             }
2628         }
2629 
2630         /**
2631          * Any extras sent by the requesting app.
2632          *
2633          * @return For a shortcut request, this method always return null.  For an AppWidget
2634          * request, this method returns the extras passed to the
2635          * {@link android.appwidget.AppWidgetManager#requestPinAppWidget(
2636          * ComponentName, Bundle, PendingIntent)} API.  See {@link AppWidgetManager} for details.
2637          */
2638         @Nullable
getExtras()2639         public Bundle getExtras() {
2640             try {
2641                 return mInner.getExtras();
2642             } catch (RemoteException e) {
2643                 throw e.rethrowAsRuntimeException();
2644             }
2645         }
2646 
2647         /**
2648          * Return whether a request is still valid.
2649          *
2650          * @return {@code TRUE} if a request is valid and {@link #accept(Bundle)} may be called.
2651          */
isValid()2652         public boolean isValid() {
2653             try {
2654                 return mInner.isValid();
2655             } catch (RemoteException e) {
2656                 return false;
2657             }
2658         }
2659 
2660         /**
2661          * Called by the receiving launcher app when the user accepts the request.
2662          *
2663          * @param options must be set for a {@link #REQUEST_TYPE_APPWIDGET} request.
2664          *
2665          * @return {@code TRUE} if the shortcut or the AppWidget has actually been pinned.
2666          * {@code FALSE} if the item hasn't been pinned, for example, because the request had
2667          * already been canceled, in which case the launcher must not pin the requested item.
2668          */
accept(@ullable Bundle options)2669         public boolean accept(@Nullable Bundle options) {
2670             try {
2671                 return mInner.accept(options);
2672             } catch (RemoteException e) {
2673                 throw e.rethrowFromSystemServer();
2674             }
2675         }
2676 
2677         /**
2678          * Called by the receiving launcher app when the user accepts the request, with no options.
2679          *
2680          * @return {@code TRUE} if the shortcut or the AppWidget has actually been pinned.
2681          * {@code FALSE} if the item hasn't been pinned, for example, because the request had
2682          * already been canceled, in which case the launcher must not pin the requested item.
2683          */
accept()2684         public boolean accept() {
2685             return accept(/* options= */ null);
2686         }
2687 
PinItemRequest(Parcel source)2688         private PinItemRequest(Parcel source) {
2689             final ClassLoader cl = getClass().getClassLoader();
2690 
2691             mRequestType = source.readInt();
2692             mInner = IPinItemRequest.Stub.asInterface(source.readStrongBinder());
2693         }
2694 
2695         @Override
writeToParcel(Parcel dest, int flags)2696         public void writeToParcel(Parcel dest, int flags) {
2697             dest.writeInt(mRequestType);
2698             dest.writeStrongBinder(mInner.asBinder());
2699         }
2700 
2701         public static final @android.annotation.NonNull Creator<PinItemRequest> CREATOR =
2702                 new Creator<PinItemRequest>() {
2703                     public PinItemRequest createFromParcel(Parcel source) {
2704                         return new PinItemRequest(source);
2705                     }
2706                     public PinItemRequest[] newArray(int size) {
2707                         return new PinItemRequest[size];
2708                     }
2709                 };
2710 
2711         @Override
describeContents()2712         public int describeContents() {
2713             return 0;
2714         }
2715     }
2716 
2717     /**
2718      * A class that encapsulates information about the usage limit set for an app or
2719      * a group of apps.
2720      *
2721      * <p>The launcher can query specifics about the usage limit such as how much usage time
2722      * the limit has and how much of the total usage time is remaining via the APIs available
2723      * in this class.
2724      *
2725      * @see #getAppUsageLimit(String, UserHandle)
2726      * @hide
2727      */
2728     @SystemApi
2729     public static final class AppUsageLimit implements Parcelable {
2730         private final long mTotalUsageLimit;
2731         private final long mUsageRemaining;
2732 
2733         /** @hide */
AppUsageLimit(long totalUsageLimit, long usageRemaining)2734         public AppUsageLimit(long totalUsageLimit, long usageRemaining) {
2735             this.mTotalUsageLimit = totalUsageLimit;
2736             this.mUsageRemaining = usageRemaining;
2737         }
2738 
2739         /**
2740          * Returns the total usage limit in milliseconds set for an app or a group of apps.
2741          *
2742          * @return the total usage limit in milliseconds
2743          */
getTotalUsageLimit()2744         public long getTotalUsageLimit() {
2745             return mTotalUsageLimit;
2746         }
2747 
2748         /**
2749          * Returns the usage remaining in milliseconds for an app or the group of apps
2750          * this limit refers to.
2751          *
2752          * @return the usage remaining in milliseconds
2753          */
getUsageRemaining()2754         public long getUsageRemaining() {
2755             return mUsageRemaining;
2756         }
2757 
AppUsageLimit(Parcel source)2758         private AppUsageLimit(Parcel source) {
2759             mTotalUsageLimit = source.readLong();
2760             mUsageRemaining = source.readLong();
2761         }
2762 
2763         public static final @android.annotation.NonNull Creator<AppUsageLimit> CREATOR = new Creator<AppUsageLimit>() {
2764             @Override
2765             public AppUsageLimit createFromParcel(Parcel source) {
2766                 return new AppUsageLimit(source);
2767             }
2768 
2769             @Override
2770             public AppUsageLimit[] newArray(int size) {
2771                 return new AppUsageLimit[size];
2772             }
2773         };
2774 
2775         @Override
describeContents()2776         public int describeContents() {
2777             return 0;
2778         }
2779 
2780         @Override
writeToParcel(Parcel dest, int flags)2781         public void writeToParcel(Parcel dest, int flags) {
2782             dest.writeLong(mTotalUsageLimit);
2783             dest.writeLong(mUsageRemaining);
2784         }
2785     }
2786 }
2787