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} & {@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—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 <queries> 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 <queries> 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