1 /* 2 * Copyright (C) 2016 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 package android.content.pm; 17 18 import android.Manifest; 19 import android.annotation.IntDef; 20 import android.annotation.NonNull; 21 import android.annotation.Nullable; 22 import android.annotation.RequiresPermission; 23 import android.annotation.SystemApi; 24 import android.annotation.SystemService; 25 import android.annotation.TestApi; 26 import android.annotation.UserIdInt; 27 import android.app.Notification; 28 import android.app.usage.UsageStatsManager; 29 import android.compat.annotation.UnsupportedAppUsage; 30 import android.content.ComponentName; 31 import android.content.Context; 32 import android.content.Intent; 33 import android.content.IntentFilter; 34 import android.content.IntentSender; 35 import android.graphics.drawable.AdaptiveIconDrawable; 36 import android.os.Build; 37 import android.os.Build.VERSION_CODES; 38 import android.os.Parcel; 39 import android.os.Parcelable; 40 import android.os.RemoteException; 41 import android.os.ServiceManager; 42 43 import com.android.internal.annotations.VisibleForTesting; 44 45 import java.lang.annotation.Retention; 46 import java.lang.annotation.RetentionPolicy; 47 import java.util.List; 48 49 /** 50 * <p><code>ShortcutManager</code> executes operations on an app's set of <i>shortcuts</i>, which 51 * represent specific tasks and actions that users can perform within your app. This page lists 52 * components of the <code>ShortcutManager</code> class that you can use to create and manage 53 * sets of shortcuts. 54 * 55 * <p>To learn about methods that retrieve information about a single shortcut—including 56 * identifiers, type, and status—read the <code> 57 * <a href="/reference/android/content/pm/ShortcutInfo.html">ShortcutInfo</a></code> reference. 58 * 59 * <p>For guidance about using shortcuts, see 60 * <a href="/guide/topics/ui/shortcuts/index.html">App shortcuts</a>. 61 * 62 * <h3>Retrieving class instances</h3> 63 * <!-- Provides a heading for the content filled in by the @SystemService annotation below --> 64 */ 65 @SystemService(Context.SHORTCUT_SERVICE) 66 public class ShortcutManager { 67 private static final String TAG = "ShortcutManager"; 68 69 /** 70 * Include manifest shortcuts in the result. 71 * 72 * @see #getShortcuts(int) 73 */ 74 public static final int FLAG_MATCH_MANIFEST = 1 << 0; 75 76 /** 77 * Include dynamic shortcuts in the result. 78 * 79 * @see #getShortcuts(int) 80 */ 81 public static final int FLAG_MATCH_DYNAMIC = 1 << 1; 82 83 /** 84 * Include pinned shortcuts in the result. 85 * 86 * @see #getShortcuts(int) 87 */ 88 public static final int FLAG_MATCH_PINNED = 1 << 2; 89 90 /** 91 * Include cached shortcuts in the result. 92 * 93 * @see #getShortcuts(int) 94 */ 95 public static final int FLAG_MATCH_CACHED = 1 << 3; 96 97 /** @hide */ 98 @IntDef(flag = true, prefix = { "FLAG_MATCH_" }, value = { 99 FLAG_MATCH_MANIFEST, 100 FLAG_MATCH_DYNAMIC, 101 FLAG_MATCH_PINNED, 102 FLAG_MATCH_CACHED, 103 }) 104 @Retention(RetentionPolicy.SOURCE) 105 public @interface ShortcutMatchFlags {} 106 107 private final Context mContext; 108 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023) 109 private final IShortcutService mService; 110 111 /** 112 * @hide 113 */ ShortcutManager(Context context, IShortcutService service)114 public ShortcutManager(Context context, IShortcutService service) { 115 mContext = context; 116 mService = service; 117 } 118 119 /** 120 * @hide 121 */ 122 @TestApi ShortcutManager(Context context)123 public ShortcutManager(Context context) { 124 this(context, IShortcutService.Stub.asInterface( 125 ServiceManager.getService(Context.SHORTCUT_SERVICE))); 126 } 127 128 /** 129 * Publish the list of shortcuts. All existing dynamic shortcuts from the caller app 130 * will be replaced. If there are already pinned shortcuts with the same IDs, 131 * the mutable pinned shortcuts are updated. 132 * 133 * <p>This API will be rate-limited. 134 * 135 * @return {@code true} if the call has succeeded. {@code false} if the call is rate-limited. 136 * 137 * @throws IllegalArgumentException if {@link #getMaxShortcutCountPerActivity()} is exceeded, 138 * or when trying to update immutable shortcuts. 139 * 140 * @throws IllegalStateException when the user is locked. 141 */ setDynamicShortcuts(@onNull List<ShortcutInfo> shortcutInfoList)142 public boolean setDynamicShortcuts(@NonNull List<ShortcutInfo> shortcutInfoList) { 143 try { 144 return mService.setDynamicShortcuts(mContext.getPackageName(), 145 new ParceledListSlice(shortcutInfoList), injectMyUserId()); 146 } catch (RemoteException e) { 147 throw e.rethrowFromSystemServer(); 148 } 149 } 150 151 /** 152 * Return all dynamic shortcuts from the caller app. 153 * 154 * <p>This API is intended to be used for examining what shortcuts are currently published. 155 * Re-publishing returned {@link ShortcutInfo}s via APIs such as 156 * {@link #setDynamicShortcuts(List)} may cause loss of information such as icons. 157 * 158 * @throws IllegalStateException when the user is locked. 159 */ 160 @NonNull getDynamicShortcuts()161 public List<ShortcutInfo> getDynamicShortcuts() { 162 try { 163 return mService.getShortcuts(mContext.getPackageName(), FLAG_MATCH_DYNAMIC, 164 injectMyUserId()).getList(); 165 } catch (RemoteException e) { 166 throw e.rethrowFromSystemServer(); 167 } 168 } 169 170 /** 171 * Return all static (manifest) shortcuts from the caller app. 172 * 173 * <p>This API is intended to be used for examining what shortcuts are currently published. 174 * Re-publishing returned {@link ShortcutInfo}s via APIs such as 175 * {@link #setDynamicShortcuts(List)} may cause loss of information such as icons. 176 * 177 * @throws IllegalStateException when the user is locked. 178 */ 179 @NonNull getManifestShortcuts()180 public List<ShortcutInfo> getManifestShortcuts() { 181 try { 182 return mService.getShortcuts(mContext.getPackageName(), FLAG_MATCH_MANIFEST, 183 injectMyUserId()).getList(); 184 } catch (RemoteException e) { 185 throw e.rethrowFromSystemServer(); 186 } 187 } 188 189 /** 190 * Returns {@link ShortcutInfo}s that match {@code matchFlags}. 191 * 192 * @param matchFlags result includes shortcuts matching this flags. Any combination of: 193 * <ul> 194 * <li>{@link #FLAG_MATCH_MANIFEST} 195 * <li>{@link #FLAG_MATCH_DYNAMIC} 196 * <li>{@link #FLAG_MATCH_PINNED} 197 * <li>{@link #FLAG_MATCH_CACHED} 198 * </ul> 199 200 * @return list of {@link ShortcutInfo}s that match the flag. 201 * 202 * <p>At least one of the {@code MATCH} flags should be set. Otherwise no shortcuts will be 203 * returned. 204 * 205 * @throws IllegalStateException when the user is locked. 206 */ 207 @NonNull getShortcuts(@hortcutMatchFlags int matchFlags)208 public List<ShortcutInfo> getShortcuts(@ShortcutMatchFlags int matchFlags) { 209 try { 210 return mService.getShortcuts(mContext.getPackageName(), matchFlags, injectMyUserId()) 211 .getList(); 212 } catch (RemoteException e) { 213 throw e.rethrowFromSystemServer(); 214 } 215 } 216 217 /** 218 * Publish the list of dynamic shortcuts. If there are already dynamic or pinned shortcuts with 219 * the same IDs, each mutable shortcut is updated. 220 * 221 * <p>This API will be rate-limited. 222 * 223 * @return {@code true} if the call has succeeded. {@code false} if the call is rate-limited. 224 * 225 * @throws IllegalArgumentException if {@link #getMaxShortcutCountPerActivity()} is exceeded, 226 * or when trying to update immutable shortcuts. 227 * 228 * @throws IllegalStateException when the user is locked. 229 */ addDynamicShortcuts(@onNull List<ShortcutInfo> shortcutInfoList)230 public boolean addDynamicShortcuts(@NonNull List<ShortcutInfo> shortcutInfoList) { 231 try { 232 return mService.addDynamicShortcuts(mContext.getPackageName(), 233 new ParceledListSlice(shortcutInfoList), injectMyUserId()); 234 } catch (RemoteException e) { 235 throw e.rethrowFromSystemServer(); 236 } 237 } 238 239 /** 240 * Delete dynamic shortcuts by ID. 241 * 242 * @throws IllegalStateException when the user is locked. 243 */ removeDynamicShortcuts(@onNull List<String> shortcutIds)244 public void removeDynamicShortcuts(@NonNull List<String> shortcutIds) { 245 try { 246 mService.removeDynamicShortcuts(mContext.getPackageName(), shortcutIds, 247 injectMyUserId()); 248 } catch (RemoteException e) { 249 throw e.rethrowFromSystemServer(); 250 } 251 } 252 253 /** 254 * Delete all dynamic shortcuts from the caller app. 255 * 256 * @throws IllegalStateException when the user is locked. 257 */ removeAllDynamicShortcuts()258 public void removeAllDynamicShortcuts() { 259 try { 260 mService.removeAllDynamicShortcuts(mContext.getPackageName(), injectMyUserId()); 261 } catch (RemoteException e) { 262 throw e.rethrowFromSystemServer(); 263 } 264 } 265 266 /** 267 * Delete long lived shortcuts by ID. 268 * 269 * @throws IllegalStateException when the user is locked. 270 */ removeLongLivedShortcuts(@onNull List<String> shortcutIds)271 public void removeLongLivedShortcuts(@NonNull List<String> shortcutIds) { 272 try { 273 mService.removeLongLivedShortcuts(mContext.getPackageName(), shortcutIds, 274 injectMyUserId()); 275 } catch (RemoteException e) { 276 throw e.rethrowFromSystemServer(); 277 } 278 } 279 280 /** 281 * Return all pinned shortcuts from the caller app. 282 * 283 * <p>This API is intended to be used for examining what shortcuts are currently published. 284 * Re-publishing returned {@link ShortcutInfo}s via APIs such as 285 * {@link #setDynamicShortcuts(List)} may cause loss of information such as icons. 286 * 287 * @throws IllegalStateException when the user is locked. 288 */ 289 @NonNull getPinnedShortcuts()290 public List<ShortcutInfo> getPinnedShortcuts() { 291 try { 292 return mService.getShortcuts(mContext.getPackageName(), FLAG_MATCH_PINNED, 293 injectMyUserId()).getList(); 294 } catch (RemoteException e) { 295 throw e.rethrowFromSystemServer(); 296 } 297 } 298 299 /** 300 * Update all existing shortcuts with the same IDs. Target shortcuts may be pinned and/or 301 * dynamic, but they must not be immutable. 302 * 303 * <p>This API will be rate-limited. 304 * 305 * @return {@code true} if the call has succeeded. {@code false} if the call is rate-limited. 306 * 307 * @throws IllegalArgumentException If trying to update immutable shortcuts. 308 * 309 * @throws IllegalStateException when the user is locked. 310 */ updateShortcuts(@onNull List<ShortcutInfo> shortcutInfoList)311 public boolean updateShortcuts(@NonNull List<ShortcutInfo> shortcutInfoList) { 312 try { 313 return mService.updateShortcuts(mContext.getPackageName(), 314 new ParceledListSlice(shortcutInfoList), injectMyUserId()); 315 } catch (RemoteException e) { 316 throw e.rethrowFromSystemServer(); 317 } 318 } 319 320 /** 321 * Disable pinned shortcuts. For more details, read 322 * <a href="/guide/topics/ui/shortcuts/managing-shortcuts.html#disable-shortcuts"> 323 * Disable shortcuts</a>. 324 * 325 * @throws IllegalArgumentException If trying to disable immutable shortcuts. 326 * 327 * @throws IllegalStateException when the user is locked. 328 */ disableShortcuts(@onNull List<String> shortcutIds)329 public void disableShortcuts(@NonNull List<String> shortcutIds) { 330 try { 331 mService.disableShortcuts(mContext.getPackageName(), shortcutIds, 332 /* disabledMessage =*/ null, /* disabledMessageResId =*/ 0, 333 injectMyUserId()); 334 } catch (RemoteException e) { 335 throw e.rethrowFromSystemServer(); 336 } 337 } 338 339 /** 340 * @hide old signature, kept for unit testing. 341 */ disableShortcuts(@onNull List<String> shortcutIds, int disabledMessageResId)342 public void disableShortcuts(@NonNull List<String> shortcutIds, int disabledMessageResId) { 343 try { 344 mService.disableShortcuts(mContext.getPackageName(), shortcutIds, 345 /* disabledMessage =*/ null, disabledMessageResId, 346 injectMyUserId()); 347 } catch (RemoteException e) { 348 throw e.rethrowFromSystemServer(); 349 } 350 } 351 352 /** 353 * @hide old signature, kept for unit testing. 354 */ disableShortcuts(@onNull List<String> shortcutIds, String disabledMessage)355 public void disableShortcuts(@NonNull List<String> shortcutIds, String disabledMessage) { 356 disableShortcuts(shortcutIds, (CharSequence) disabledMessage); 357 } 358 359 /** 360 * Disable pinned shortcuts, showing the user a custom error message when they try to select 361 * the disabled shortcuts. 362 * For more details, read 363 * <a href="/guide/topics/ui/shortcuts/managing-shortcuts.html#disable-shortcuts"> 364 * Disable shortcuts</a>. 365 * 366 * @throws IllegalArgumentException If trying to disable immutable shortcuts. 367 * 368 * @throws IllegalStateException when the user is locked. 369 */ disableShortcuts(@onNull List<String> shortcutIds, CharSequence disabledMessage)370 public void disableShortcuts(@NonNull List<String> shortcutIds, CharSequence disabledMessage) { 371 try { 372 mService.disableShortcuts(mContext.getPackageName(), shortcutIds, 373 disabledMessage, /* disabledMessageResId =*/ 0, 374 injectMyUserId()); 375 } catch (RemoteException e) { 376 throw e.rethrowFromSystemServer(); 377 } 378 } 379 380 /** 381 * Re-enable pinned shortcuts that were previously disabled. If the target shortcuts 382 * are already enabled, this method does nothing. 383 * 384 * @throws IllegalArgumentException If trying to enable immutable shortcuts. 385 * 386 * @throws IllegalStateException when the user is locked. 387 */ enableShortcuts(@onNull List<String> shortcutIds)388 public void enableShortcuts(@NonNull List<String> shortcutIds) { 389 try { 390 mService.enableShortcuts(mContext.getPackageName(), shortcutIds, injectMyUserId()); 391 } catch (RemoteException e) { 392 throw e.rethrowFromSystemServer(); 393 } 394 } 395 396 397 /** 398 * @hide old signature, kept for unit testing. 399 */ getMaxShortcutCountForActivity()400 public int getMaxShortcutCountForActivity() { 401 return getMaxShortcutCountPerActivity(); 402 } 403 404 /** 405 * Return the maximum number of static and dynamic shortcuts that each launcher icon 406 * can have at a time. 407 */ getMaxShortcutCountPerActivity()408 public int getMaxShortcutCountPerActivity() { 409 try { 410 return mService.getMaxShortcutCountPerActivity( 411 mContext.getPackageName(), injectMyUserId()); 412 } catch (RemoteException e) { 413 throw e.rethrowFromSystemServer(); 414 } 415 } 416 417 /** 418 * Return the number of times the caller app can call the rate-limited APIs 419 * before the rate limit counter is reset. 420 * 421 * @see #getRateLimitResetTime() 422 * 423 * @hide 424 */ getRemainingCallCount()425 public int getRemainingCallCount() { 426 try { 427 return mService.getRemainingCallCount(mContext.getPackageName(), injectMyUserId()); 428 } catch (RemoteException e) { 429 throw e.rethrowFromSystemServer(); 430 } 431 } 432 433 /** 434 * Return when the rate limit count will be reset next time, in milliseconds since the epoch. 435 * 436 * @see #getRemainingCallCount() 437 * @see System#currentTimeMillis() 438 * 439 * @hide 440 */ getRateLimitResetTime()441 public long getRateLimitResetTime() { 442 try { 443 return mService.getRateLimitResetTime(mContext.getPackageName(), injectMyUserId()); 444 } catch (RemoteException e) { 445 throw e.rethrowFromSystemServer(); 446 } 447 } 448 449 /** 450 * Return {@code true} when rate-limiting is active for the caller app. 451 * 452 * <p>For details, see <a href="/guide/topics/ui/shortcuts/managing-shortcuts#rate-limiting"> 453 * Rate limiting</a>. 454 * 455 * @throws IllegalStateException when the user is locked. 456 */ isRateLimitingActive()457 public boolean isRateLimitingActive() { 458 try { 459 return mService.getRemainingCallCount(mContext.getPackageName(), injectMyUserId()) 460 == 0; 461 } catch (RemoteException e) { 462 throw e.rethrowFromSystemServer(); 463 } 464 } 465 466 /** 467 * Return the max width for icons, in pixels. 468 * 469 * <p> Note that this method returns max width of icon's visible part. Hence, it does not take 470 * into account the inset introduced by {@link AdaptiveIconDrawable}. To calculate bitmap image 471 * to function as {@link AdaptiveIconDrawable}, multiply 472 * 1 + 2 * {@link AdaptiveIconDrawable#getExtraInsetFraction()} to the returned size. 473 */ getIconMaxWidth()474 public int getIconMaxWidth() { 475 try { 476 // TODO Implement it properly using xdpi. 477 return mService.getIconMaxDimensions(mContext.getPackageName(), injectMyUserId()); 478 } catch (RemoteException e) { 479 throw e.rethrowFromSystemServer(); 480 } 481 } 482 483 /** 484 * Return the max height for icons, in pixels. 485 */ getIconMaxHeight()486 public int getIconMaxHeight() { 487 try { 488 // TODO Implement it properly using ydpi. 489 return mService.getIconMaxDimensions(mContext.getPackageName(), injectMyUserId()); 490 } catch (RemoteException e) { 491 throw e.rethrowFromSystemServer(); 492 } 493 } 494 495 /** 496 * Apps that publish shortcuts should call this method whenever the user 497 * selects the shortcut containing the given ID or when the user completes 498 * an action in the app that is equivalent to selecting the shortcut. 499 * For more details, read about 500 * <a href="/guide/topics/ui/shortcuts/managing-shortcuts.html#track-usage"> 501 * tracking shortcut usage</a>. 502 * 503 * <p>The information is accessible via {@link UsageStatsManager#queryEvents} 504 * Typically, launcher apps use this information to build a prediction model 505 * so that they can promote the shortcuts that are likely to be used at the moment. 506 * 507 * @throws IllegalStateException when the user is locked. 508 */ reportShortcutUsed(String shortcutId)509 public void reportShortcutUsed(String shortcutId) { 510 try { 511 mService.reportShortcutUsed(mContext.getPackageName(), shortcutId, 512 injectMyUserId()); 513 } catch (RemoteException e) { 514 throw e.rethrowFromSystemServer(); 515 } 516 } 517 518 /** 519 * Return {@code TRUE} if the app is running on a device whose default launcher supports 520 * {@link #requestPinShortcut(ShortcutInfo, IntentSender)}. 521 * 522 * <p>The return value may change in subsequent calls if the user changes the default launcher 523 * app. 524 * 525 * <p><b>Note:</b> See also the support library counterpart 526 * {@link android.support.v4.content.pm.ShortcutManagerCompat#isRequestPinShortcutSupported( 527 * Context)}, which supports Android versions lower than {@link VERSION_CODES#O} using the 528 * legacy private intent {@code com.android.launcher.action.INSTALL_SHORTCUT}. 529 * 530 * @see #requestPinShortcut(ShortcutInfo, IntentSender) 531 */ isRequestPinShortcutSupported()532 public boolean isRequestPinShortcutSupported() { 533 try { 534 return mService.isRequestPinItemSupported(injectMyUserId(), 535 LauncherApps.PinItemRequest.REQUEST_TYPE_SHORTCUT); 536 } catch (RemoteException e) { 537 throw e.rethrowFromSystemServer(); 538 } 539 } 540 541 /** 542 * Request to create a pinned shortcut. The default launcher will receive this request and 543 * ask the user for approval. If the user approves it, the shortcut will be created, and 544 * {@code resultIntent} will be sent. If a request is denied by the user, however, no response 545 * will be sent to the caller. 546 * 547 * <p>Only apps with a foreground activity or a foreground service can call this method. 548 * Otherwise, it'll throw {@link IllegalStateException}. 549 * 550 * <p>It's up to the launcher to decide how to handle previous pending requests when the same 551 * package calls this API multiple times in a row. One possible strategy is to ignore any 552 * previous requests. 553 * 554 * <p><b>Note:</b> See also the support library counterpart 555 * {@link android.support.v4.content.pm.ShortcutManagerCompat#requestPinShortcut( 556 * Context, ShortcutInfoCompat, IntentSender)}, 557 * which supports Android versions lower than {@link VERSION_CODES#O} using the 558 * legacy private intent {@code com.android.launcher.action.INSTALL_SHORTCUT}. 559 * 560 * @param shortcut Shortcut to pin. If an app wants to pin an existing (either static 561 * or dynamic) shortcut, then it only needs to have an ID. Although other fields don't have 562 * to be set, the target shortcut must be enabled. 563 * 564 * <p>If it's a new shortcut, all the mandatory fields, such as a short label, must be 565 * set. 566 * @param resultIntent If not null, this intent will be sent when the shortcut is pinned. 567 * Use {@link android.app.PendingIntent#getIntentSender()} to create an {@link IntentSender}. 568 * To avoid background execution limits, use an unexported, manifest-declared receiver. 569 * For more details, see 570 * <a href="/guide/topics/ui/shortcuts/creating-shortcuts.html#pinned"> 571 * Creating pinned shortcuts</a>. 572 * 573 * @return {@code TRUE} if the launcher supports this feature. Note the API will return without 574 * waiting for the user to respond, so getting {@code TRUE} from this API does *not* mean 575 * the shortcut was pinned successfully. {@code FALSE} if the launcher doesn't support this 576 * feature. 577 * 578 * @see #isRequestPinShortcutSupported() 579 * @see IntentSender 580 * @see android.app.PendingIntent#getIntentSender() 581 * 582 * @throws IllegalArgumentException if a shortcut with the same ID exists and is disabled. 583 * @throws IllegalStateException The caller doesn't have a foreground activity or a foreground 584 * service, or the device is locked. 585 */ requestPinShortcut(@onNull ShortcutInfo shortcut, @Nullable IntentSender resultIntent)586 public boolean requestPinShortcut(@NonNull ShortcutInfo shortcut, 587 @Nullable IntentSender resultIntent) { 588 try { 589 return mService.requestPinShortcut(mContext.getPackageName(), shortcut, 590 resultIntent, injectMyUserId()); 591 } catch (RemoteException e) { 592 throw e.rethrowFromSystemServer(); 593 } 594 } 595 596 /** 597 * Returns an Intent which can be used by the default launcher to pin a shortcut containing the 598 * given {@link ShortcutInfo}. This method should be used by an Activity to set a result in 599 * response to {@link Intent#ACTION_CREATE_SHORTCUT}. 600 * 601 * @param shortcut New shortcut to pin. If an app wants to pin an existing (either dynamic 602 * or manifest) shortcut, then it only needs to have an ID, and other fields don't have to 603 * be set, in which case, the target shortcut must be enabled. 604 * If it's a new shortcut, all the mandatory fields, such as a short label, must be 605 * set. 606 * @return The intent that should be set as the result for the calling activity, or 607 * <code>null</code> if the current launcher doesn't support shortcuts. 608 * 609 * @see Intent#ACTION_CREATE_SHORTCUT 610 * 611 * @throws IllegalArgumentException if a shortcut with the same ID exists and is disabled. 612 */ createShortcutResultIntent(@onNull ShortcutInfo shortcut)613 public Intent createShortcutResultIntent(@NonNull ShortcutInfo shortcut) { 614 try { 615 return mService.createShortcutResultIntent(mContext.getPackageName(), shortcut, 616 injectMyUserId()); 617 } catch (RemoteException e) { 618 throw e.rethrowFromSystemServer(); 619 } 620 } 621 622 /** 623 * Called internally when an app is considered to have come to the foreground 624 * even when technically it's not. This method resets the throttling for this package. 625 * For example, when the user sends an "inline reply" on a notification, the system UI will 626 * call it. 627 * 628 * @hide 629 */ onApplicationActive(@onNull String packageName, @UserIdInt int userId)630 public void onApplicationActive(@NonNull String packageName, @UserIdInt int userId) { 631 try { 632 mService.onApplicationActive(packageName, userId); 633 } catch (RemoteException e) { 634 throw e.rethrowFromSystemServer(); 635 } 636 } 637 638 /** @hide injection point */ 639 @VisibleForTesting injectMyUserId()640 protected int injectMyUserId() { 641 return mContext.getUserId(); 642 } 643 644 /** 645 * Used by framework's ShareSheet (ChooserActivity.java) to retrieve all of the direct share 646 * targets that match the given IntentFilter. 647 * 648 * @param filter IntentFilter that will be used to retrieve the matching {@link ShortcutInfo}s. 649 * @return List of {@link ShareShortcutInfo}s that match the given IntentFilter. 650 * @hide 651 */ 652 @NonNull 653 @SystemApi 654 @RequiresPermission(Manifest.permission.MANAGE_APP_PREDICTIONS) getShareTargets(@onNull IntentFilter filter)655 public List<ShareShortcutInfo> getShareTargets(@NonNull IntentFilter filter) { 656 try { 657 return mService.getShareTargets(mContext.getPackageName(), filter, 658 injectMyUserId()).getList(); 659 } catch (RemoteException e) { 660 throw e.rethrowFromSystemServer(); 661 } 662 } 663 664 /** 665 * Represents the result of a query return by {@link #getShareTargets(IntentFilter)}. 666 * 667 * @hide 668 */ 669 @SystemApi 670 public static final class ShareShortcutInfo implements Parcelable { 671 private final ShortcutInfo mShortcutInfo; 672 private final ComponentName mTargetComponent; 673 674 /** 675 * @hide 676 */ ShareShortcutInfo(@onNull ShortcutInfo shortcutInfo, @NonNull ComponentName targetComponent)677 public ShareShortcutInfo(@NonNull ShortcutInfo shortcutInfo, 678 @NonNull ComponentName targetComponent) { 679 if (shortcutInfo == null) { 680 throw new NullPointerException("shortcut info is null"); 681 } 682 if (targetComponent == null) { 683 throw new NullPointerException("target component is null"); 684 } 685 686 mShortcutInfo = shortcutInfo; 687 mTargetComponent = targetComponent; 688 } 689 ShareShortcutInfo(@onNull Parcel in)690 private ShareShortcutInfo(@NonNull Parcel in) { 691 mShortcutInfo = in.readParcelable(ShortcutInfo.class.getClassLoader()); 692 mTargetComponent = in.readParcelable(ComponentName.class.getClassLoader()); 693 } 694 695 @NonNull getShortcutInfo()696 public ShortcutInfo getShortcutInfo() { 697 return mShortcutInfo; 698 } 699 700 @NonNull getTargetComponent()701 public ComponentName getTargetComponent() { 702 return mTargetComponent; 703 } 704 705 @Override describeContents()706 public int describeContents() { 707 return 0; 708 } 709 710 @Override writeToParcel(@onNull Parcel dest, int flags)711 public void writeToParcel(@NonNull Parcel dest, int flags) { 712 dest.writeParcelable(mShortcutInfo, flags); 713 dest.writeParcelable(mTargetComponent, flags); 714 } 715 716 public static final @NonNull Parcelable.Creator<ShareShortcutInfo> CREATOR = 717 new Parcelable.Creator<ShareShortcutInfo>() { 718 public ShareShortcutInfo createFromParcel(Parcel in) { 719 return new ShareShortcutInfo(in); 720 } 721 722 public ShareShortcutInfo[] newArray(int size) { 723 return new ShareShortcutInfo[size]; 724 } 725 }; 726 } 727 728 /** 729 * Used by framework's ShareSheet (ChooserActivity.java) to check if a given package has share 730 * target definitions in it's resources. 731 * 732 * @param packageName Package to check for share targets. 733 * @return True if the package has any share target definitions, False otherwise. 734 * @hide 735 */ 736 @SystemApi hasShareTargets(@onNull String packageName)737 public boolean hasShareTargets(@NonNull String packageName) { 738 try { 739 return mService.hasShareTargets(mContext.getPackageName(), packageName, 740 injectMyUserId()); 741 } catch (RemoteException e) { 742 throw e.rethrowFromSystemServer(); 743 } 744 } 745 746 /** 747 * Publish a single dynamic shortcut. If there are already dynamic or pinned shortcuts with the 748 * same ID, each mutable shortcut is updated. 749 * 750 * <p>This method is useful when posting notifications which are tagged with shortcut IDs; In 751 * order to make sure shortcuts exist and are up-to-date, without the need to explicitly handle 752 * the shortcut count limit. 753 * @see android.app.NotificationManager#notify(int, Notification) 754 * @see Notification.Builder#setShortcutId(String) 755 * 756 * <p>If {@link #getMaxShortcutCountPerActivity()} is already reached, an existing shortcut with 757 * the lowest rank will be removed to add space for the new shortcut. 758 * 759 * <p>If the rank of the shortcut is not explicitly set, it will be set to zero, and shortcut 760 * will be added to the top of the list. 761 * 762 * @throws IllegalArgumentException if trying to update an immutable shortcut. 763 * 764 * @throws IllegalStateException when the user is locked. 765 */ pushDynamicShortcut(@onNull ShortcutInfo shortcut)766 public void pushDynamicShortcut(@NonNull ShortcutInfo shortcut) { 767 try { 768 mService.pushDynamicShortcut(mContext.getPackageName(), shortcut, injectMyUserId()); 769 } catch (RemoteException e) { 770 throw e.rethrowFromSystemServer(); 771 } 772 } 773 774 } 775