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 */ 16package android.content.pm; 17 18import android.annotation.NonNull; 19import android.annotation.Nullable; 20import android.annotation.SystemService; 21import android.annotation.TestApi; 22import android.annotation.UserIdInt; 23import android.app.Activity; 24import android.app.usage.UsageStatsManager; 25import android.content.Context; 26import android.content.Intent; 27import android.content.IntentSender; 28import android.graphics.drawable.AdaptiveIconDrawable; 29import android.os.Build.VERSION_CODES; 30import android.os.RemoteException; 31import android.os.ServiceManager; 32import android.os.UserHandle; 33 34import com.android.internal.annotations.VisibleForTesting; 35 36import java.util.List; 37 38/** 39 * The ShortcutManager manages an app's <em>shortcuts</em>. Shortcuts provide users with quick 40 * access to activities other than an app's main activity in the currently-active launcher, provided 41 * that the launcher supports app shortcuts. For example, an email app may publish the "compose new 42 * email" action, which will directly open the compose activity. The {@link ShortcutInfo} class 43 * contains information about each of the shortcuts themselves. 44 * 45 * <p>This page discusses the implementation details of the <code>ShortcutManager</code> class. For 46 * guidance on performing operations on app shortcuts within your app, see the 47 * <a href="/guide/topics/ui/shortcuts.html">App Shortcuts</a> feature guide. 48 * 49 * <h3>Shortcut characteristics</h3> 50 * 51 * This section describes in-depth details about each shortcut type's usage and availability. 52 * 53 * <p class="note"><b>Important security note:</b> All shortcut information is stored in 54 * <a href="/training/articles/direct-boot.html">credential encrypted storage</a>, so your app 55 * cannot access a user's shortcuts until after they've unlocked the device. 56 * 57 * <h4>Static and dynamic shortcuts</h4> 58 * 59 * <p>Static shortcuts and dynamic shortcuts are shown in a supported launcher when the user 60 * performs a specific gesture. On currently-supported launchers, the gesture is a long-press on the 61 * app's launcher icon, but the actual gesture may be different on other launcher apps. 62 * 63 * <p>The {@link LauncherApps} class provides APIs for launcher apps to access shortcuts. 64 * 65 * <h4>Pinned shortcuts</h4> 66 * 67 * <p>Because pinned shortcuts appear in the launcher itself, they're always visible. A pinned 68 * shortcut is removed from the launcher only in the following situations: 69 * <ul> 70 * <li>The user removes it. 71 * <li>The publisher app associated with the shortcut is uninstalled. 72 * <li>The user performs the clear data action on the publisher app from the device's 73 * <b>Settings</b> app. 74 * </ul> 75 * 76 * <p>Because the system performs 77 * <a href="/guide/topics/ui/shortcuts.html#backup-and-restore">backup and restore</a> on pinned 78 * shortcuts automatically, these shortcuts' IDs should contain either stable, constant strings or 79 * server-side identifiers, rather than identifiers generated locally that might not make sense on 80 * other devices. 81 * 82 * <h3>Shortcut display order</h3> 83 * 84 * <p>When the launcher displays an app's shortcuts, they should appear in the following order: 85 * 86 * <ul> 87 * <li>Static shortcuts (if {@link ShortcutInfo#isDeclaredInManifest()} is {@code true}), 88 * and then show dynamic shortcuts (if {@link ShortcutInfo#isDynamic()} is {@code true}). 89 * <li>Within each shortcut type (static and dynamic), sort the shortcuts in order of increasing 90 * rank according to {@link ShortcutInfo#getRank()}. 91 * </ul> 92 * 93 * <p>Shortcut ranks are non-negative, sequential integers that determine the order in which 94 * shortcuts appear, assuming that the shortcuts are all in the same category. You can update ranks 95 * of existing shortcuts when you call {@link #updateShortcuts(List)}, 96 * {@link #addDynamicShortcuts(List)}, or {@link #setDynamicShortcuts(List)}. 97 * 98 * <p class="note"><b>Note:</b> Ranks are auto-adjusted so that they're unique for each type of 99 * shortcut (static or dynamic). For example, if there are 3 dynamic shortcuts with ranks 0, 1 and 100 * 2, adding another dynamic shortcut with a rank of 1 represents a request to place this shortcut 101 * at the second position. In response, the third and fourth shortcuts move closer to the bottom of 102 * the shortcut list, with their ranks changing to 2 and 3, respectively. 103 * 104 * <h3>Options for static shortcuts</h3> 105 * 106 * The following list includes descriptions for the different attributes within a static shortcut: 107 * <dl> 108 * <dt>{@code android:shortcutId}</dt> 109 * <dd>Mandatory shortcut ID. 110 * <p> 111 * This must be a string literal. 112 * A resource string, such as <code>@string/foo</code>, cannot be used. 113 * </dd> 114 * 115 * <dt>{@code android:enabled}</dt> 116 * <dd>Default is {@code true}. Can be set to {@code false} in order 117 * to disable a static shortcut that was published in a previous version and set a custom 118 * disabled message. If a custom disabled message is not needed, then a static shortcut can 119 * be simply removed from the XML file rather than keeping it with {@code enabled="false"}.</dd> 120 * 121 * <dt>{@code android:icon}</dt> 122 * <dd>Shortcut icon.</dd> 123 * 124 * <dt>{@code android:shortcutShortLabel}</dt> 125 * <dd>Mandatory shortcut short label. 126 * See {@link ShortcutInfo.Builder#setShortLabel(CharSequence)}. 127 * <p> 128 * This must be a resource string, such as <code>@string/shortcut_label</code>. 129 * </dd> 130 * 131 * <dt>{@code android:shortcutLongLabel}</dt> 132 * <dd>Shortcut long label. 133 * See {@link ShortcutInfo.Builder#setLongLabel(CharSequence)}. 134 * <p> 135 * This must be a resource string, such as <code>@string/shortcut_long_label</code>. 136 * </dd> 137 * 138 * <dt>{@code android:shortcutDisabledMessage}</dt> 139 * <dd>When {@code android:enabled} is set to 140 * {@code false}, this attribute is used to display a custom disabled message. 141 * <p> 142 * This must be a resource string, such as <code>@string/shortcut_disabled_message</code>. 143 * </dd> 144 * 145 * <dt>{@code intent}</dt> 146 * <dd>Intent to launch when the user selects the shortcut. 147 * {@code android:action} is mandatory. 148 * See <a href="{@docRoot}guide/topics/ui/settings.html#Intents">Using intents</a> for the 149 * other supported tags. 150 * <p>You can provide multiple intents for a single shortcut so that the last defined activity is 151 * launched with the other activities in the 152 * <a href="/guide/components/tasks-and-back-stack.html">back stack</a>. See 153 * {@link android.app.TaskStackBuilder} for details. 154 * <p><b>Note:</b> String resources may not be used within an {@code <intent>} element. 155 * </dd> 156 * <dt>{@code categories}</dt> 157 * <dd>Specify shortcut categories. Currently only 158 * {@link ShortcutInfo#SHORTCUT_CATEGORY_CONVERSATION} is defined in the framework. 159 * </dd> 160 * </dl> 161 * 162 * <h3>Updating shortcuts</h3> 163 * 164 * <p>As an example, suppose {@link #getMaxShortcutCountPerActivity()} is 5: 165 * <ol> 166 * <li>A chat app publishes 5 dynamic shortcuts for the 5 most recent 167 * conversations (c1, c2, ..., c5). 168 * 169 * <li>The user pins all 5 of the shortcuts. 170 * 171 * <li>Later, the user has started 3 additional conversations (c6, c7, and c8), 172 * so the publisher app 173 * re-publishes its dynamic shortcuts. The new dynamic shortcut list is: 174 * c4, c5, ..., c8. 175 * The publisher app has to remove c1, c2, and c3 because it can't have more than 176 * 5 dynamic shortcuts. 177 * 178 * <li>However, even though c1, c2, and c3 are no longer dynamic shortcuts, the pinned 179 * shortcuts for these conversations are still available and launchable. 180 * 181 * <li>At this point, the user can access a total of 8 shortcuts that link to activities in 182 * the publisher app, including the 3 pinned shortcuts, even though an app can have at most 5 183 * dynamic shortcuts. 184 * 185 * <li>The app can use {@link #updateShortcuts(List)} to update <em>any</em> of the existing 186 * 8 shortcuts, when, for example, the chat peers' icons have changed. 187 * <p>The {@link #addDynamicShortcuts(List)} and {@link #setDynamicShortcuts(List)} methods 188 * can also be used to update existing shortcuts with the same IDs, but they <b>cannot</b> be 189 * used for updating non-dynamic, pinned shortcuts because these 2 methods try to convert the 190 * given lists of shortcuts to dynamic shortcuts. 191 * </ol> 192 * 193 * <h3>Shortcut intents</h3> 194 * 195 * <p> 196 * Dynamic shortcuts can be published with any set of {@link Intent#addFlags Intent} flags. 197 * Typically, {@link Intent#FLAG_ACTIVITY_CLEAR_TASK} is specified, possibly along with other 198 * flags; otherwise, if the app is already running, the app is simply brought to 199 * the foreground, and the target activity may not appear. 200 * 201 * <p>Static shortcuts <b>cannot</b> have custom intent flags. 202 * The first intent of a static shortcut will always have {@link Intent#FLAG_ACTIVITY_NEW_TASK} 203 * and {@link Intent#FLAG_ACTIVITY_CLEAR_TASK} set. This means, when the app is already running, all 204 * the existing activities in your app will be destroyed when a static shortcut is launched. 205 * If this behavior is not desirable, you can use a <em>trampoline activity</em>, or an invisible 206 * activity that starts another activity in {@link Activity#onCreate}, then calls 207 * {@link Activity#finish()}: 208 * <ol> 209 * <li>In the <code>AndroidManifest.xml</code> file, the trampoline activity should include the 210 * attribute assignment {@code android:taskAffinity=""}. 211 * <li>In the shortcuts resource file, the intent within the static shortcut should point at 212 * the trampoline activity. 213 * </ol> 214 * 215 * <h3>Handling system locale changes</h3> 216 * 217 * <p>Apps should update dynamic and pinned shortcuts when the system locale changes using the 218 * {@link Intent#ACTION_LOCALE_CHANGED} broadcast. When the system locale changes, 219 * <a href="/guide/topics/ui/shortcuts.html#rate-limit">rate limiting</a> is reset, so even 220 * background apps can add and update dynamic shortcuts until the rate limit is reached again. 221 * 222 * <h3>Shortcut limits</h3> 223 * 224 * <p>Only main activities—activities that handle the {@code MAIN} action and the 225 * {@code LAUNCHER} category—can have shortcuts. If an app has multiple main activities, you 226 * need to define the set of shortcuts for <em>each</em> activity. 227 * 228 * <p>Each launcher icon can have at most {@link #getMaxShortcutCountPerActivity()} number of 229 * static and dynamic shortcuts combined. There is no limit to the number of pinned shortcuts that 230 * an app can create. 231 * 232 * <p>When a dynamic shortcut is pinned, even when the publisher removes it as a dynamic shortcut, 233 * the pinned shortcut is still visible and launchable. This allows an app to have more than 234 * {@link #getMaxShortcutCountPerActivity()} number of shortcuts. 235 * 236 * <h4>Rate limiting</h4> 237 * 238 * <p>When <a href="/guide/topics/ui/shortcuts.html#rate-limit">rate limiting</a> is active, 239 * {@link #isRateLimitingActive()} returns {@code true}. 240 * 241 * <p>Rate limiting is reset upon certain events, so even background apps can call these APIs until 242 * the rate limit is reached again. These events include the following: 243 * <ul> 244 * <li>An app comes to the foreground. 245 * <li>The system locale changes. 246 * <li>The user performs the <strong>inline reply</strong> action on a notification. 247 * </ul> 248 */ 249@SystemService(Context.SHORTCUT_SERVICE) 250public class ShortcutManager { 251 private static final String TAG = "ShortcutManager"; 252 253 private final Context mContext; 254 private final IShortcutService mService; 255 256 /** 257 * @hide 258 */ 259 public ShortcutManager(Context context, IShortcutService service) { 260 mContext = context; 261 mService = service; 262 } 263 264 /** 265 * @hide 266 */ 267 @TestApi 268 public ShortcutManager(Context context) { 269 this(context, IShortcutService.Stub.asInterface( 270 ServiceManager.getService(Context.SHORTCUT_SERVICE))); 271 } 272 273 /** 274 * Publish the list of shortcuts. All existing dynamic shortcuts from the caller app 275 * will be replaced. If there are already pinned shortcuts with the same IDs, 276 * the mutable pinned shortcuts are updated. 277 * 278 * <p>This API will be rate-limited. 279 * 280 * @return {@code true} if the call has succeeded. {@code false} if the call is rate-limited. 281 * 282 * @throws IllegalArgumentException if {@link #getMaxShortcutCountPerActivity()} is exceeded, 283 * or when trying to update immutable shortcuts. 284 * 285 * @throws IllegalStateException when the user is locked. 286 */ 287 public boolean setDynamicShortcuts(@NonNull List<ShortcutInfo> shortcutInfoList) { 288 try { 289 return mService.setDynamicShortcuts(mContext.getPackageName(), 290 new ParceledListSlice(shortcutInfoList), injectMyUserId()); 291 } catch (RemoteException e) { 292 throw e.rethrowFromSystemServer(); 293 } 294 } 295 296 /** 297 * Return all dynamic shortcuts from the caller app. 298 * 299 * <p>This API is intended to be used for examining what shortcuts are currently published. 300 * Re-publishing returned {@link ShortcutInfo}s via APIs such as 301 * {@link #setDynamicShortcuts(List)} may cause loss of information such as icons. 302 * 303 * @throws IllegalStateException when the user is locked. 304 */ 305 @NonNull 306 public List<ShortcutInfo> getDynamicShortcuts() { 307 try { 308 return mService.getDynamicShortcuts(mContext.getPackageName(), injectMyUserId()) 309 .getList(); 310 } catch (RemoteException e) { 311 throw e.rethrowFromSystemServer(); 312 } 313 } 314 315 /** 316 * Return all static (manifest) shortcuts from the caller app. 317 * 318 * <p>This API is intended to be used for examining what shortcuts are currently published. 319 * Re-publishing returned {@link ShortcutInfo}s via APIs such as 320 * {@link #setDynamicShortcuts(List)} may cause loss of information such as icons. 321 * 322 * @throws IllegalStateException when the user is locked. 323 */ 324 @NonNull 325 public List<ShortcutInfo> getManifestShortcuts() { 326 try { 327 return mService.getManifestShortcuts(mContext.getPackageName(), injectMyUserId()) 328 .getList(); 329 } catch (RemoteException e) { 330 throw e.rethrowFromSystemServer(); 331 } 332 } 333 334 /** 335 * Publish the list of dynamic shortcuts. If there are already dynamic or pinned shortcuts with 336 * the same IDs, each mutable shortcut is updated. 337 * 338 * <p>This API will be rate-limited. 339 * 340 * @return {@code true} if the call has succeeded. {@code false} if the call is rate-limited. 341 * 342 * @throws IllegalArgumentException if {@link #getMaxShortcutCountPerActivity()} is exceeded, 343 * or when trying to update immutable shortcuts. 344 * 345 * @throws IllegalStateException when the user is locked. 346 */ 347 public boolean addDynamicShortcuts(@NonNull List<ShortcutInfo> shortcutInfoList) { 348 try { 349 return mService.addDynamicShortcuts(mContext.getPackageName(), 350 new ParceledListSlice(shortcutInfoList), injectMyUserId()); 351 } catch (RemoteException e) { 352 throw e.rethrowFromSystemServer(); 353 } 354 } 355 356 /** 357 * Delete dynamic shortcuts by ID. 358 * 359 * @throws IllegalStateException when the user is locked. 360 */ 361 public void removeDynamicShortcuts(@NonNull List<String> shortcutIds) { 362 try { 363 mService.removeDynamicShortcuts(mContext.getPackageName(), shortcutIds, 364 injectMyUserId()); 365 } catch (RemoteException e) { 366 throw e.rethrowFromSystemServer(); 367 } 368 } 369 370 /** 371 * Delete all dynamic shortcuts from the caller app. 372 * 373 * @throws IllegalStateException when the user is locked. 374 */ 375 public void removeAllDynamicShortcuts() { 376 try { 377 mService.removeAllDynamicShortcuts(mContext.getPackageName(), injectMyUserId()); 378 } catch (RemoteException e) { 379 throw e.rethrowFromSystemServer(); 380 } 381 } 382 383 /** 384 * Return all pinned shortcuts from the caller app. 385 * 386 * <p>This API is intended to be used for examining what shortcuts are currently published. 387 * Re-publishing returned {@link ShortcutInfo}s via APIs such as 388 * {@link #setDynamicShortcuts(List)} may cause loss of information such as icons. 389 * 390 * @throws IllegalStateException when the user is locked. 391 */ 392 @NonNull 393 public List<ShortcutInfo> getPinnedShortcuts() { 394 try { 395 return mService.getPinnedShortcuts(mContext.getPackageName(), injectMyUserId()) 396 .getList(); 397 } catch (RemoteException e) { 398 throw e.rethrowFromSystemServer(); 399 } 400 } 401 402 /** 403 * Update all existing shortcuts with the same IDs. Target shortcuts may be pinned and/or 404 * dynamic, but they must not be immutable. 405 * 406 * <p>This API will be rate-limited. 407 * 408 * @return {@code true} if the call has succeeded. {@code false} if the call is rate-limited. 409 * 410 * @throws IllegalArgumentException If trying to update immutable shortcuts. 411 * 412 * @throws IllegalStateException when the user is locked. 413 */ 414 public boolean updateShortcuts(@NonNull List<ShortcutInfo> shortcutInfoList) { 415 try { 416 return mService.updateShortcuts(mContext.getPackageName(), 417 new ParceledListSlice(shortcutInfoList), injectMyUserId()); 418 } catch (RemoteException e) { 419 throw e.rethrowFromSystemServer(); 420 } 421 } 422 423 /** 424 * Disable pinned shortcuts. For more details, see the Javadoc for the {@link ShortcutManager} 425 * class. 426 * 427 * @throws IllegalArgumentException If trying to disable immutable shortcuts. 428 * 429 * @throws IllegalStateException when the user is locked. 430 */ 431 public void disableShortcuts(@NonNull List<String> shortcutIds) { 432 try { 433 mService.disableShortcuts(mContext.getPackageName(), shortcutIds, 434 /* disabledMessage =*/ null, /* disabledMessageResId =*/ 0, 435 injectMyUserId()); 436 } catch (RemoteException e) { 437 throw e.rethrowFromSystemServer(); 438 } 439 } 440 441 /** 442 * @hide old signature, kept for unit testing. 443 */ 444 public void disableShortcuts(@NonNull List<String> shortcutIds, int disabledMessageResId) { 445 try { 446 mService.disableShortcuts(mContext.getPackageName(), shortcutIds, 447 /* disabledMessage =*/ null, disabledMessageResId, 448 injectMyUserId()); 449 } catch (RemoteException e) { 450 throw e.rethrowFromSystemServer(); 451 } 452 } 453 454 /** 455 * @hide old signature, kept for unit testing. 456 */ 457 public void disableShortcuts(@NonNull List<String> shortcutIds, String disabledMessage) { 458 disableShortcuts(shortcutIds, (CharSequence) disabledMessage); 459 } 460 461 /** 462 * Disable pinned shortcuts, showing the user a custom error message when they try to select 463 * the disabled shortcuts. 464 * For more details, see the Javadoc for the {@link ShortcutManager} class. 465 * 466 * @throws IllegalArgumentException If trying to disable immutable shortcuts. 467 * 468 * @throws IllegalStateException when the user is locked. 469 */ 470 public void disableShortcuts(@NonNull List<String> shortcutIds, CharSequence disabledMessage) { 471 try { 472 mService.disableShortcuts(mContext.getPackageName(), shortcutIds, 473 disabledMessage, /* disabledMessageResId =*/ 0, 474 injectMyUserId()); 475 } catch (RemoteException e) { 476 throw e.rethrowFromSystemServer(); 477 } 478 } 479 480 /** 481 * Re-enable pinned shortcuts that were previously disabled. If the target shortcuts 482 * are already enabled, this method does nothing. 483 * 484 * @throws IllegalArgumentException If trying to enable immutable shortcuts. 485 * 486 * @throws IllegalStateException when the user is locked. 487 */ 488 public void enableShortcuts(@NonNull List<String> shortcutIds) { 489 try { 490 mService.enableShortcuts(mContext.getPackageName(), shortcutIds, injectMyUserId()); 491 } catch (RemoteException e) { 492 throw e.rethrowFromSystemServer(); 493 } 494 } 495 496 497 /** 498 * @hide old signature, kept for unit testing. 499 */ 500 public int getMaxShortcutCountForActivity() { 501 return getMaxShortcutCountPerActivity(); 502 } 503 504 /** 505 * Return the maximum number of static and dynamic shortcuts that each launcher icon 506 * can have at a time. 507 */ 508 public int getMaxShortcutCountPerActivity() { 509 try { 510 return mService.getMaxShortcutCountPerActivity( 511 mContext.getPackageName(), injectMyUserId()); 512 } catch (RemoteException e) { 513 throw e.rethrowFromSystemServer(); 514 } 515 } 516 517 /** 518 * Return the number of times the caller app can call the rate-limited APIs 519 * before the rate limit counter is reset. 520 * 521 * @see #getRateLimitResetTime() 522 * 523 * @hide 524 */ 525 public int getRemainingCallCount() { 526 try { 527 return mService.getRemainingCallCount(mContext.getPackageName(), injectMyUserId()); 528 } catch (RemoteException e) { 529 throw e.rethrowFromSystemServer(); 530 } 531 } 532 533 /** 534 * Return when the rate limit count will be reset next time, in milliseconds since the epoch. 535 * 536 * @see #getRemainingCallCount() 537 * @see System#currentTimeMillis() 538 * 539 * @hide 540 */ 541 public long getRateLimitResetTime() { 542 try { 543 return mService.getRateLimitResetTime(mContext.getPackageName(), injectMyUserId()); 544 } catch (RemoteException e) { 545 throw e.rethrowFromSystemServer(); 546 } 547 } 548 549 /** 550 * Return {@code true} when rate-limiting is active for the caller app. 551 * 552 * <p>See the class level javadoc for details. 553 * 554 * @throws IllegalStateException when the user is locked. 555 */ 556 public boolean isRateLimitingActive() { 557 try { 558 return mService.getRemainingCallCount(mContext.getPackageName(), injectMyUserId()) 559 == 0; 560 } catch (RemoteException e) { 561 throw e.rethrowFromSystemServer(); 562 } 563 } 564 565 /** 566 * Return the max width for icons, in pixels. 567 * 568 * <p> Note that this method returns max width of icon's visible part. Hence, it does not take 569 * into account the inset introduced by {@link AdaptiveIconDrawable}. To calculate bitmap image 570 * to function as {@link AdaptiveIconDrawable}, multiply 571 * 1 + 2 * {@link AdaptiveIconDrawable#getExtraInsetFraction()} to the returned size. 572 */ 573 public int getIconMaxWidth() { 574 try { 575 // TODO Implement it properly using xdpi. 576 return mService.getIconMaxDimensions(mContext.getPackageName(), injectMyUserId()); 577 } catch (RemoteException e) { 578 throw e.rethrowFromSystemServer(); 579 } 580 } 581 582 /** 583 * Return the max height for icons, in pixels. 584 */ 585 public int getIconMaxHeight() { 586 try { 587 // TODO Implement it properly using ydpi. 588 return mService.getIconMaxDimensions(mContext.getPackageName(), injectMyUserId()); 589 } catch (RemoteException e) { 590 throw e.rethrowFromSystemServer(); 591 } 592 } 593 594 /** 595 * Apps that publish shortcuts should call this method whenever the user 596 * selects the shortcut containing the given ID or when the user completes 597 * an action in the app that is equivalent to selecting the shortcut. 598 * For more details, see the Javadoc for the {@link ShortcutManager} class 599 * 600 * <p>The information is accessible via {@link UsageStatsManager#queryEvents} 601 * Typically, launcher apps use this information to build a prediction model 602 * so that they can promote the shortcuts that are likely to be used at the moment. 603 * 604 * @throws IllegalStateException when the user is locked. 605 */ 606 public void reportShortcutUsed(String shortcutId) { 607 try { 608 mService.reportShortcutUsed(mContext.getPackageName(), shortcutId, 609 injectMyUserId()); 610 } catch (RemoteException e) { 611 throw e.rethrowFromSystemServer(); 612 } 613 } 614 615 /** 616 * Return {@code TRUE} if the app is running on a device whose default launcher supports 617 * {@link #requestPinShortcut(ShortcutInfo, IntentSender)}. 618 * 619 * <p>The return value may change in subsequent calls if the user changes the default launcher 620 * app. 621 * 622 * <p><b>Note:</b> See also the support library counterpart 623 * {@link android.support.v4.content.pm.ShortcutManagerCompat#isRequestPinShortcutSupported( 624 * Context)}, which supports Android versions lower than {@link VERSION_CODES#O} using the 625 * legacy private intent {@code com.android.launcher.action.INSTALL_SHORTCUT}. 626 * 627 * @see #requestPinShortcut(ShortcutInfo, IntentSender) 628 */ 629 public boolean isRequestPinShortcutSupported() { 630 try { 631 return mService.isRequestPinItemSupported(injectMyUserId(), 632 LauncherApps.PinItemRequest.REQUEST_TYPE_SHORTCUT); 633 } catch (RemoteException e) { 634 throw e.rethrowFromSystemServer(); 635 } 636 } 637 638 /** 639 * Request to create a pinned shortcut. The default launcher will receive this request and 640 * ask the user for approval. If the user approves it, the shortcut will be created, and 641 * {@code resultIntent} will be sent. If a request is denied by the user, however, no response 642 * will be sent to the caller. 643 * 644 * <p>Only apps with a foreground activity or a foreground service can call this method. 645 * Otherwise, it'll throw {@link IllegalStateException}. 646 * 647 * <p>It's up to the launcher to decide how to handle previous pending requests when the same 648 * package calls this API multiple times in a row. One possible strategy is to ignore any 649 * previous requests. 650 * 651 * <p><b>Note:</b> See also the support library counterpart 652 * {@link android.support.v4.content.pm.ShortcutManagerCompat#requestPinShortcut( 653 * Context, ShortcutInfoCompat, IntentSender)}, 654 * which supports Android versions lower than {@link VERSION_CODES#O} using the 655 * legacy private intent {@code com.android.launcher.action.INSTALL_SHORTCUT}. 656 * 657 * @param shortcut Shortcut to pin. If an app wants to pin an existing (either static 658 * or dynamic) shortcut, then it only needs to have an ID. Although other fields don't have 659 * to be set, the target shortcut must be enabled. 660 * 661 * <p>If it's a new shortcut, all the mandatory fields, such as a short label, must be 662 * set. 663 * @param resultIntent If not null, this intent will be sent when the shortcut is pinned. 664 * Use {@link android.app.PendingIntent#getIntentSender()} to create an {@link IntentSender}. 665 * To avoid background execution limits, use an unexported, manifest-declared receiver. 666 * For more details, see the overview documentation for the {@link ShortcutManager} class. 667 * 668 * @return {@code TRUE} if the launcher supports this feature. Note the API will return without 669 * waiting for the user to respond, so getting {@code TRUE} from this API does *not* mean 670 * the shortcut was pinned successfully. {@code FALSE} if the launcher doesn't support this 671 * feature. 672 * 673 * @see #isRequestPinShortcutSupported() 674 * @see IntentSender 675 * @see android.app.PendingIntent#getIntentSender() 676 * 677 * @throws IllegalArgumentException if a shortcut with the same ID exists and is disabled. 678 * @throws IllegalStateException The caller doesn't have a foreground activity or a foreground 679 * service, or the device is locked. 680 */ 681 public boolean requestPinShortcut(@NonNull ShortcutInfo shortcut, 682 @Nullable IntentSender resultIntent) { 683 try { 684 return mService.requestPinShortcut(mContext.getPackageName(), shortcut, 685 resultIntent, injectMyUserId()); 686 } catch (RemoteException e) { 687 throw e.rethrowFromSystemServer(); 688 } 689 } 690 691 /** 692 * Returns an Intent which can be used by the default launcher to pin a shortcut containing the 693 * given {@link ShortcutInfo}. This method should be used by an Activity to set a result in 694 * response to {@link Intent#ACTION_CREATE_SHORTCUT}. 695 * 696 * @param shortcut New shortcut to pin. If an app wants to pin an existing (either dynamic 697 * or manifest) shortcut, then it only needs to have an ID, and other fields don't have to 698 * be set, in which case, the target shortcut must be enabled. 699 * If it's a new shortcut, all the mandatory fields, such as a short label, must be 700 * set. 701 * @return The intent that should be set as the result for the calling activity, or 702 * <code>null</code> if the current launcher doesn't support shortcuts. 703 * 704 * @see Intent#ACTION_CREATE_SHORTCUT 705 * 706 * @throws IllegalArgumentException if a shortcut with the same ID exists and is disabled. 707 */ 708 public Intent createShortcutResultIntent(@NonNull ShortcutInfo shortcut) { 709 try { 710 return mService.createShortcutResultIntent(mContext.getPackageName(), shortcut, 711 injectMyUserId()); 712 } catch (RemoteException e) { 713 throw e.rethrowFromSystemServer(); 714 } 715 } 716 717 /** 718 * Called internally when an app is considered to have come to the foreground 719 * even when technically it's not. This method resets the throttling for this package. 720 * For example, when the user sends an "inline reply" on a notification, the system UI will 721 * call it. 722 * 723 * @hide 724 */ 725 public void onApplicationActive(@NonNull String packageName, @UserIdInt int userId) { 726 try { 727 mService.onApplicationActive(packageName, userId); 728 } catch (RemoteException e) { 729 throw e.rethrowFromSystemServer(); 730 } 731 } 732 733 /** @hide injection point */ 734 @VisibleForTesting 735 protected int injectMyUserId() { 736 return UserHandle.myUserId(); 737 } 738} 739