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