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.annotation.NonNull; 19 import android.annotation.TestApi; 20 import android.annotation.UserIdInt; 21 import android.app.Activity; 22 import android.app.usage.UsageStatsManager; 23 import android.content.Context; 24 import android.content.Intent; 25 import android.os.RemoteException; 26 import android.os.ServiceManager; 27 import android.os.UserHandle; 28 29 import com.android.internal.annotations.VisibleForTesting; 30 31 import java.util.List; 32 33 /** 34 * The ShortcutManager manages "launcher shortcuts" (or simply "shortcuts"). Shortcuts provide 35 * users 36 * with quick access to activities other than an application's main activity in the currently-active 37 * launcher. For example, 38 * an email application may publish the "compose new email" action, which will directly open the 39 * compose activity. The {@link ShortcutInfo} class contains information about each of the 40 * shortcuts themselves. 41 * 42 * <h3>Dynamic Shortcuts and Manifest Shortcuts</h3> 43 * 44 * There are two ways to publish shortcuts: manifest shortcuts and dynamic shortcuts. 45 * 46 * <ul> 47 * <li>Manifest shortcuts are declared in a resource 48 * XML, which is referenced in the publisher application's <code>AndroidManifest.xml</code> file. 49 * Manifest shortcuts are published when an application is installed, 50 * and the details of these shortcuts change when an application is upgraded with an updated XML 51 * file. 52 * Manifest shortcuts are immutable, and their 53 * definitions, such as icons and labels, cannot be changed dynamically without upgrading the 54 * publisher application. 55 * 56 * <li>Dynamic shortcuts are published at runtime using the {@link ShortcutManager} APIs. 57 * Applications can publish, update, and remove dynamic shortcuts at runtime. 58 * </ul> 59 * 60 * <p>Only "main" activities—activities that handle the {@code MAIN} action and the 61 * {@code LAUNCHER} category—can have shortcuts. 62 * If an application has multiple main activities, these activities will have different sets 63 * of shortcuts. 64 * 65 * <p>Dynamic shortcuts and manifest shortcuts are shown in the currently active launcher when 66 * the user long-presses on an application launcher icon. The actual gesture may be different 67 * depending on the launcher application. 68 * 69 * <p>Each launcher icon can have at most {@link #getMaxShortcutCountPerActivity()} number of 70 * dynamic and manifest shortcuts combined. 71 * 72 * 73 * <h3>Pinning Shortcuts</h3> 74 * 75 * Launcher applications allow users to "pin" shortcuts so they're easier to access. Both manifest 76 * and dynamic shortcuts can be pinned. 77 * Pinned shortcuts <b>cannot</b> be removed by publisher 78 * applications; they're removed only when the user removes them, 79 * when the publisher application is uninstalled, or when the 80 * user performs the "clear data" action on the publisher application from the device's Settings 81 * application. 82 * 83 * <p>However, the publisher application can <em>disable</em> pinned shortcuts so they cannot be 84 * started. See the following sections for details. 85 * 86 * 87 * <h3>Updating and Disabling Shortcuts</h3> 88 * 89 * <p>When a dynamic shortcut is pinned, even when the publisher removes it as a dynamic shortcut, 90 * the pinned shortcut will still be visible and launchable. This allows an application to have 91 * more than {@link #getMaxShortcutCountPerActivity()} number of shortcuts. 92 * 93 * <p>For example, suppose {@link #getMaxShortcutCountPerActivity()} is 5: 94 * <ul> 95 * <li>A chat application publishes 5 dynamic shortcuts for the 5 most recent 96 * conversations, "c1" - "c5". 97 * 98 * <li>The user pins all 5 of the shortcuts. 99 * 100 * <li>Later, the user has started 3 additional conversations ("c6", "c7", and "c8"), 101 * so the publisher application 102 * re-publishes its dynamic shortcuts. The new dynamic shortcut list is: 103 * "c4", "c5", "c6", "c7", and "c8". 104 * The publisher application has to remove "c1", "c2", and "c3" because it can't have more than 105 * 5 dynamic shortcuts. 106 * 107 * <li>However, even though "c1", "c2" and "c3" are no longer dynamic shortcuts, the pinned 108 * shortcuts for these conversations are still available and launchable. 109 * 110 * <li>At this point, the user can access a total of 8 shortcuts that link to activities in 111 * the publisher application, including the 3 pinned 112 * shortcuts, even though it's allowed to have at most 5 dynamic shortcuts. 113 * 114 * <li>The application can use {@link #updateShortcuts(List)} to update any of the existing 115 * 8 shortcuts, when, for example, the chat peers' icons have changed. 116 * </ul> 117 * The {@link #addDynamicShortcuts(List)} and {@link #setDynamicShortcuts(List)} methods 118 * can also be used 119 * to update existing shortcuts with the same IDs, but they <b>cannot</b> be used 120 * for updating non-dynamic, pinned shortcuts because these two methods try to convert the given 121 * lists of shortcuts to dynamic shortcuts. 122 * 123 * 124 * <h4>Disabling Manifest Shortcuts</h4> 125 * When an application is upgraded and the new version 126 * no longer uses a manifest shortcut that appeared in the previous version, this deprecated 127 * shortcut will no longer be published as a manifest shortcut. 128 * 129 * <p>If the deprecated shortcut is pinned, then the pinned shortcut will remain on the launcher, 130 * but it will be disabled automatically. 131 * Note that, in this case, the pinned shortcut is no longer a manifest shortcut, but it's 132 * still <b>immutable</b> and cannot be updated using the {@link ShortcutManager} APIs. 133 * 134 * 135 * <h4>Disabling Dynamic Shortcuts</h4> 136 * Sometimes pinned shortcuts become obsolete and may not be usable. For example, a pinned shortcut 137 * to a group chat will be unusable when the associated group chat is deleted. In cases like this, 138 * applications should use {@link #disableShortcuts(List)}, which will remove the specified dynamic 139 * shortcuts and also make any specified pinned shortcuts un-launchable. 140 * The {@link #disableShortcuts(List, CharSequence)} method can also be used to disabled shortcuts 141 * and show users a custom error message when they attempt to launch the disabled shortcuts. 142 * 143 * 144 * <h3>Publishing Manifest Shortcuts</h3> 145 * 146 * In order to add manifest shortcuts to your application, first add 147 * {@code <meta-data android:name="android.app.shortcuts" />} to your main activity in 148 * AndroidManifest.xml: 149 * <pre> 150 * <manifest xmlns:android="http://schemas.android.com/apk/res/android" 151 * package="com.example.myapplication"> 152 * <application . . .> 153 * <activity android:name="Main"> 154 * <intent-filter> 155 * <action android:name="android.intent.action.MAIN" /> 156 * <category android:name="android.intent.category.LAUNCHER" /> 157 * </intent-filter> 158 * <b><meta-data android:name="android.app.shortcuts" android:resource="@xml/shortcuts"/></b> 159 * </activity> 160 * </application> 161 * </manifest> 162 * </pre> 163 * 164 * Then, define your application's manifest shortcuts in the <code>res/xml/shortcuts.xml</code> 165 * file: 166 * <pre> 167 * <shortcuts xmlns:android="http://schemas.android.com/apk/res/android" > 168 * <shortcut 169 * android:shortcutId="compose" 170 * android:enabled="true" 171 * android:icon="@drawable/compose_icon" 172 * android:shortcutShortLabel="@string/compose_shortcut_short_label1" 173 * android:shortcutLongLabel="@string/compose_shortcut_long_label1" 174 * android:shortcutDisabledMessage="@string/compose_disabled_message1" 175 * > 176 * <intent 177 * android:action="android.intent.action.VIEW" 178 * android:targetPackage="com.example.myapplication" 179 * android:targetClass="com.example.myapplication.ComposeActivity" /> 180 * <!-- more intents can go here; see below --> 181 * <categories android:name="android.shortcut.conversation" /> 182 * </shortcut> 183 * <!-- more shortcuts can go here --> 184 * </shortcuts> 185 * </pre> 186 * 187 * The following list includes descriptions for the different attributes within a manifest shortcut: 188 * <dl> 189 * <dt>android:shortcutId</dt> 190 * <dd>Mandatory shortcut ID</dd> 191 * 192 * <dt>android:enabled</dt> 193 * <dd>Default is {@code true}. Can be set to {@code false} in order 194 * to disable a manifest shortcut that was published in a previous version and and set a custom 195 * disabled message. If a custom disabled message is not needed, then a manifest shortcut can 196 * be simply removed from the XML file rather than keeping it with {@code enabled="false"}.</dd> 197 * 198 * <dt>android:icon</dt> 199 * <dd>Shortcut icon.</dd> 200 * 201 * <dt>android:shortcutShortLabel</dt> 202 * <dd>Mandatory shortcut short label. 203 * See {@link ShortcutInfo.Builder#setShortLabel(CharSequence)}.</dd> 204 * 205 * <dt>android:shortcutLongLabel</dt> 206 * <dd>Shortcut long label. 207 * See {@link ShortcutInfo.Builder#setLongLabel(CharSequence)}.</dd> 208 * 209 * <dt>android:shortcutDisabledMessage</dt> 210 * <dd>When {@code android:enabled} is set to 211 * {@code false}, this attribute is used to display a custom disabled message.</dd> 212 * 213 * <dt>intent</dt> 214 * <dd>Intent to launch when the user selects the shortcut. 215 * {@code android:action} is mandatory. 216 * See <a href="{@docRoot}guide/topics/ui/settings.html#Intents">Using intents</a> for the 217 * other supported tags. 218 * You can provide multiple intents for a single shortcut so that an activity is launched 219 * with other activities in the back stack. See {@link android.app.TaskStackBuilder} for details. 220 * </dd> 221 * <dt>categories</dt> 222 * <dd>Specify shortcut categories. Currently only 223 * {@link ShortcutInfo#SHORTCUT_CATEGORY_CONVERSATION} is defined in the framework. 224 * </dd> 225 * </dl> 226 * 227 * <h3>Publishing Dynamic Shortcuts</h3> 228 * 229 * Applications can publish dynamic shortcuts with {@link #setDynamicShortcuts(List)} 230 * or {@link #addDynamicShortcuts(List)}. The {@link #updateShortcuts(List)} method can also be 231 * used to update existing, mutable shortcuts. 232 * Use {@link #removeDynamicShortcuts(List)} or {@link #removeAllDynamicShortcuts()} to remove 233 * dynamic shortcuts. 234 * 235 * <p>Example: 236 * <pre> 237 * ShortcutManager shortcutManager = getSystemService(ShortcutManager.class); 238 * 239 * ShortcutInfo shortcut = new ShortcutInfo.Builder(this, "id1") 240 * .setIntent(new Intent(Intent.ACTION_VIEW, Uri.parse("http://www.mysite.com/"))) 241 * .setShortLabel("Web site") 242 * .setLongLabel("Open the web site") 243 * .setIcon(Icon.createWithResource(context, R.drawable.icon_website)) 244 * .build(); 245 * 246 * shortcutManager.setDynamicShortcuts(Arrays.asList(shortcut)); 247 * </pre> 248 * 249 * 250 * <h3>Shortcut Intents</h3> 251 * Dynamic shortcuts can be published with any set of {@link Intent#addFlags Intent} flags. 252 * Typically, {@link Intent#FLAG_ACTIVITY_CLEAR_TASK} is specified, possibly along with other 253 * flags; otherwise, if the application is already running, the application is simply brought to 254 * the foreground, and the target activity may not appear. 255 * 256 * <p>The {@link ShortcutInfo.Builder#setIntents(Intent[])} method can be used instead of 257 * {@link ShortcutInfo.Builder#setIntent(Intent)} with {@link android.app.TaskStackBuilder} 258 * in order to launch an activity with other activities in the back stack. 259 * When the user selects a shortcut to load an activity with a back stack, 260 * then presses the back key, a "parent" activity will be shown instead of the user being 261 * navigated back to the launcher. 262 * 263 * <p>Manifest shortcuts can also have multiple intents to achieve the same effect. 264 * In order to associate multiple {@link Intent} objects with a shortcut, simply list multiple 265 * <code><intent></code> elements within a single <code><shortcut></code> element. 266 * The last intent specifies what the user will see when they launch a shortcut. 267 * 268 * <p>Manifest shortcuts <b>cannot</b> have custom intent flags. 269 * The first intent of a manifest shortcut will always have {@link Intent#FLAG_ACTIVITY_NEW_TASK} 270 * and {@link Intent#FLAG_ACTIVITY_CLEAR_TASK} set. 271 * This means, when the application is already running, all the existing activities will be 272 * destroyed when a manifest shortcut is launched. 273 * If this behavior is not desirable, you can use a <em>trampoline activity</em>, 274 * or an invisible activity that starts another activity in {@link Activity#onCreate}, 275 * then calls {@link Activity#finish()}. 276 * The first activity should include an attribute setting 277 * of {@code android:taskAffinity=""} in the application's <code>AndroidManifest.xml</code> 278 * file, and the intent within the manifest shortcut should point at this first activity. 279 * 280 * 281 * <h3>Showing New Information in a Shortcut</h3> 282 * In order to avoid confusion, you should not use {@link #updateShortcuts(List)} to update 283 * a shortcut so that it contains conceptually different information. 284 * 285 * <p>For example, a phone application may publish the most frequently called contact as a dynamic 286 * shortcut. Over time, this contact may change; when it does, the application should 287 * represent the changed contact with a new shortcut that contains a different ID, using either 288 * {@link #setDynamicShortcuts(List)} or {@link #addDynamicShortcuts(List)}, rather than updating 289 * the existing shortcut with {@link #updateShortcuts(List)}. 290 * This is because when the shortcut is pinned, changing 291 * it to reference a different contact will likely confuse the user. 292 * 293 * <p>On the other hand, when the 294 * contact's information has changed, such as the name or picture, the application should 295 * use {@link #updateShortcuts(List)} so that the pinned shortcut is updated too. 296 * 297 * 298 * <h3>Shortcut Display Order</h3> 299 * When the launcher displays the shortcuts that are associated with a particular launcher icon, 300 * the shortcuts should appear in the following order: 301 * <ul> 302 * <li>First show manifest shortcuts 303 * (if {@link ShortcutInfo#isDeclaredInManifest()} is {@code true}), 304 * and then show dynamic shortcuts (if {@link ShortcutInfo#isDynamic()} is {@code true}). 305 * <li>Within each category of shortcuts (manifest and dynamic), sort the shortcuts in order 306 * of increasing rank according to {@link ShortcutInfo#getRank()}. 307 * </ul> 308 * <p>Shortcut ranks are non-negative sequential integers 309 * that determine the order in which shortcuts appear, assuming that the shortcuts are all in 310 * the same category. 311 * Ranks of existing shortcuts can be updated with 312 * {@link #updateShortcuts(List)}; you can use {@link #addDynamicShortcuts(List)} and 313 * {@link #setDynamicShortcuts(List)}, too. 314 * 315 * <p>Ranks are auto-adjusted so that they're unique for each target activity in each category 316 * (dynamic or manifest). For example, if there are 3 dynamic shortcuts with ranks 0, 1 and 2, 317 * adding another dynamic shortcut with a rank of 1 represents a request to place this shortcut at 318 * the second position. 319 * In response, the third and fourth shortcuts move closer to the bottom of the shortcut list, 320 * with their ranks changing to 2 and 3, respectively. 321 * 322 * <h3>Rate Limiting</h3> 323 * 324 * Calls to {@link #setDynamicShortcuts(List)}, {@link #addDynamicShortcuts(List)}, and 325 * {@link #updateShortcuts(List)} may be rate-limited when called by background applications, or 326 * applications with no foreground activity or service. When you attempt to call these methods 327 * from a background application after exceeding the rate limit, these APIs return {@code false}. 328 * 329 * <p>Applications with a foreground activity or service are not rate-limited. 330 * 331 * <p>Rate-limiting will be reset upon certain events, so that even background applications 332 * can call these APIs again until they are rate limit is reached again. 333 * These events include the following: 334 * <ul> 335 * <li>When an application comes to the foreground. 336 * <li>When the system locale changes. 337 * <li>When the user performs an "inline reply" action on a notification. 338 * </ul> 339 * 340 * <p>When rate-limiting is active, {@link #isRateLimitingActive()} returns {@code true}. 341 * 342 * <h4>Resetting rate-limiting for testing</h4> 343 * 344 * If your application is rate-limited during development or testing, you can use the 345 * "Reset ShortcutManager rate-limiting" development option or the following adb command to reset 346 * it: 347 * <pre> 348 * adb shell cmd shortcut reset-throttling [ --user USER-ID ] 349 * </pre> 350 * 351 * <h3>Handling System Locale Changes</h3> 352 * 353 * Applications should update dynamic and pinned shortcuts when the system locale changes 354 * using the {@link Intent#ACTION_LOCALE_CHANGED} broadcast. 355 * 356 * <p>When the system locale changes, rate-limiting is reset, so even background applications 357 * can set dynamic shortcuts, add dynamic shortcuts, and update shortcuts until the rate limit 358 * is reached again. 359 * 360 * 361 * <h3>Backup and Restore</h3> 362 * 363 * When an application has the {@code android:allowBackup="true"} attribute assignment included 364 * in its <code>AndroidManifest.xml</code> file, pinned shortcuts are 365 * backed up automatically and are restored when the user sets up a new device. 366 * 367 * <h4>Categories of Shortcuts that are Backed Up</h4> 368 * 369 * <ul> 370 * <li>Pinned shortcuts are backed up. Bitmap icons are not backed up by the system, 371 * but launcher applications should back them up and restore them so that the user still sees icons 372 * for pinned shortcuts on the launcher. Applications can always use 373 * {@link #updateShortcuts(List)} to re-publish icons. 374 * 375 * <li>Manifest shortcuts are not backed up, but when an application is re-installed on a new 376 * device, they are re-published from the <code>AndroidManifest.xml</code> file, anyway. 377 * 378 * <li>Dynamic shortcuts are <b>not</b> backed up. 379 * </ul> 380 * 381 * <p>Because dynamic shortcuts are not restored, it is recommended that applications check 382 * currently-published dynamic shortcuts using {@link #getDynamicShortcuts()} 383 * each time they are launched, and they should re-publish 384 * dynamic shortcuts when necessary. 385 * 386 * <pre> 387 * public class MainActivity extends Activity { 388 * public void onCreate(Bundle savedInstanceState) { 389 * super.onCreate(savedInstanceState); 390 * 391 * ShortcutManager shortcutManager = getSystemService(ShortcutManager.class); 392 * 393 * if (shortcutManager.getDynamicShortcuts().size() == 0) { 394 * // Application restored; re-publish dynamic shortcuts. 395 * 396 * if (shortcutManager.getPinnedShortcuts().size() > 0) { 397 * // Pinned shortcuts have been restored. Use updateShortcuts() to make sure 398 * // they have up-to-date information. 399 * } 400 * } 401 * } 402 * : 403 * 404 * } 405 * </pre> 406 * 407 * 408 * <h4>Backup/restore and shortcut IDs</h4> 409 * 410 * Because pinned shortcuts are backed up and restored on new devices, shortcut IDs should be 411 * meaningful across devices; that is, IDs should contain either stable, constant strings 412 * or server-side identifiers, 413 * rather than identifiers generated locally that might not make sense on other devices. 414 * 415 * 416 * <h3>Report Shortcut Usage and Prediction</h3> 417 * 418 * Launcher applications may be capable of predicting which shortcuts will most likely be 419 * used at a given time by examining the shortcut usage history data. 420 * 421 * <p>In order to provide launchers with such data, publisher applications should 422 * report the shortcuts that are used with {@link #reportShortcutUsed(String)} 423 * when a shortcut is selected, 424 * <b>or when an action equivalent to a shortcut is taken by the user even if it wasn't started 425 * with the shortcut</b>. 426 * 427 * <p>For example, suppose a GPS navigation application supports "navigate to work" as a shortcut. 428 * It should then report when the user selects this shortcut <b>and</b> when the user chooses 429 * to navigate to work within the application itself. 430 * This helps the launcher application 431 * learn that the user wants to navigate to work at a certain time every 432 * weekday, and it can then show this shortcut in a suggestion list at the right time. 433 * 434 * <h3>Launcher API</h3> 435 * 436 * The {@link LauncherApps} class provides APIs for launcher applications to access shortcuts. 437 * 438 * 439 * <h3>Direct Boot and Shortcuts</h3> 440 * 441 * All shortcut information is stored in credential encrypted storage, so no shortcuts can be 442 * accessed when the user is locked. 443 */ 444 public class ShortcutManager { 445 private static final String TAG = "ShortcutManager"; 446 447 private final Context mContext; 448 private final IShortcutService mService; 449 450 /** 451 * @hide 452 */ ShortcutManager(Context context, IShortcutService service)453 public ShortcutManager(Context context, IShortcutService service) { 454 mContext = context; 455 mService = service; 456 } 457 458 /** 459 * @hide 460 */ 461 @TestApi ShortcutManager(Context context)462 public ShortcutManager(Context context) { 463 this(context, IShortcutService.Stub.asInterface( 464 ServiceManager.getService(Context.SHORTCUT_SERVICE))); 465 } 466 467 /** 468 * Publish the list of shortcuts. All existing dynamic shortcuts from the caller application 469 * will be replaced. If there are already pinned shortcuts with the same IDs, 470 * the mutable pinned shortcuts are updated. 471 * 472 * <p>This API will be rate-limited. 473 * 474 * @return {@code true} if the call has succeeded. {@code false} if the call is rate-limited. 475 * 476 * @throws IllegalArgumentException if {@link #getMaxShortcutCountPerActivity()} is exceeded, 477 * or when trying to update immutable shortcuts. 478 * 479 * @throws IllegalStateException when the user is locked. 480 */ setDynamicShortcuts(@onNull List<ShortcutInfo> shortcutInfoList)481 public boolean setDynamicShortcuts(@NonNull List<ShortcutInfo> shortcutInfoList) { 482 try { 483 return mService.setDynamicShortcuts(mContext.getPackageName(), 484 new ParceledListSlice(shortcutInfoList), injectMyUserId()); 485 } catch (RemoteException e) { 486 throw e.rethrowFromSystemServer(); 487 } 488 } 489 490 /** 491 * Return all dynamic shortcuts from the caller application. 492 * 493 * @throws IllegalStateException when the user is locked. 494 */ 495 @NonNull getDynamicShortcuts()496 public List<ShortcutInfo> getDynamicShortcuts() { 497 try { 498 return mService.getDynamicShortcuts(mContext.getPackageName(), injectMyUserId()) 499 .getList(); 500 } catch (RemoteException e) { 501 throw e.rethrowFromSystemServer(); 502 } 503 } 504 505 /** 506 * Return all manifest shortcuts from the caller application. 507 * 508 * @throws IllegalStateException when the user is locked. 509 */ 510 @NonNull getManifestShortcuts()511 public List<ShortcutInfo> getManifestShortcuts() { 512 try { 513 return mService.getManifestShortcuts(mContext.getPackageName(), injectMyUserId()) 514 .getList(); 515 } catch (RemoteException e) { 516 throw e.rethrowFromSystemServer(); 517 } 518 } 519 520 /** 521 * Publish the list of dynamic shortcuts. If there are already dynamic or pinned shortcuts with 522 * the same IDs, each mutable shortcut is updated. 523 * 524 * <p>This API will be rate-limited. 525 * 526 * @return {@code true} if the call has succeeded. {@code false} if the call is rate-limited. 527 * 528 * @throws IllegalArgumentException if {@link #getMaxShortcutCountPerActivity()} is exceeded, 529 * or when trying to update immutable shortcuts. 530 * 531 * @throws IllegalStateException when the user is locked. 532 */ addDynamicShortcuts(@onNull List<ShortcutInfo> shortcutInfoList)533 public boolean addDynamicShortcuts(@NonNull List<ShortcutInfo> shortcutInfoList) { 534 try { 535 return mService.addDynamicShortcuts(mContext.getPackageName(), 536 new ParceledListSlice(shortcutInfoList), injectMyUserId()); 537 } catch (RemoteException e) { 538 throw e.rethrowFromSystemServer(); 539 } 540 } 541 542 /** 543 * Delete dynamic shortcuts by ID. 544 * 545 * @throws IllegalStateException when the user is locked. 546 */ removeDynamicShortcuts(@onNull List<String> shortcutIds)547 public void removeDynamicShortcuts(@NonNull List<String> shortcutIds) { 548 try { 549 mService.removeDynamicShortcuts(mContext.getPackageName(), shortcutIds, 550 injectMyUserId()); 551 } catch (RemoteException e) { 552 throw e.rethrowFromSystemServer(); 553 } 554 } 555 556 /** 557 * Delete all dynamic shortcuts from the caller application. 558 * 559 * @throws IllegalStateException when the user is locked. 560 */ removeAllDynamicShortcuts()561 public void removeAllDynamicShortcuts() { 562 try { 563 mService.removeAllDynamicShortcuts(mContext.getPackageName(), injectMyUserId()); 564 } catch (RemoteException e) { 565 throw e.rethrowFromSystemServer(); 566 } 567 } 568 569 /** 570 * Return all pinned shortcuts from the caller application. 571 * 572 * @throws IllegalStateException when the user is locked. 573 */ 574 @NonNull getPinnedShortcuts()575 public List<ShortcutInfo> getPinnedShortcuts() { 576 try { 577 return mService.getPinnedShortcuts(mContext.getPackageName(), injectMyUserId()) 578 .getList(); 579 } catch (RemoteException e) { 580 throw e.rethrowFromSystemServer(); 581 } 582 } 583 584 /** 585 * Update all existing shortcuts with the same IDs. Target shortcuts may be pinned and/or 586 * dynamic, but they must not be immutable. 587 * 588 * <p>This API will be rate-limited. 589 * 590 * @return {@code true} if the call has succeeded. {@code false} if the call is rate-limited. 591 * 592 * @throws IllegalArgumentException If trying to update immutable shortcuts. 593 * 594 * @throws IllegalStateException when the user is locked. 595 */ updateShortcuts(List<ShortcutInfo> shortcutInfoList)596 public boolean updateShortcuts(List<ShortcutInfo> shortcutInfoList) { 597 try { 598 return mService.updateShortcuts(mContext.getPackageName(), 599 new ParceledListSlice(shortcutInfoList), injectMyUserId()); 600 } catch (RemoteException e) { 601 throw e.rethrowFromSystemServer(); 602 } 603 } 604 605 /** 606 * Disable pinned shortcuts. For more details, see the Javadoc for the {@link ShortcutManager} 607 * class. 608 * 609 * @throws IllegalArgumentException If trying to disable immutable shortcuts. 610 * 611 * @throws IllegalStateException when the user is locked. 612 */ disableShortcuts(@onNull List<String> shortcutIds)613 public void disableShortcuts(@NonNull List<String> shortcutIds) { 614 try { 615 mService.disableShortcuts(mContext.getPackageName(), shortcutIds, 616 /* disabledMessage =*/ null, /* disabledMessageResId =*/ 0, 617 injectMyUserId()); 618 } catch (RemoteException e) { 619 throw e.rethrowFromSystemServer(); 620 } 621 } 622 623 /** 624 * @hide old signature, kept for unit testing. 625 */ disableShortcuts(@onNull List<String> shortcutIds, int disabledMessageResId)626 public void disableShortcuts(@NonNull List<String> shortcutIds, int disabledMessageResId) { 627 try { 628 mService.disableShortcuts(mContext.getPackageName(), shortcutIds, 629 /* disabledMessage =*/ null, disabledMessageResId, 630 injectMyUserId()); 631 } catch (RemoteException e) { 632 throw e.rethrowFromSystemServer(); 633 } 634 } 635 636 /** 637 * @hide old signature, kept for unit testing. 638 */ disableShortcuts(@onNull List<String> shortcutIds, String disabledMessage)639 public void disableShortcuts(@NonNull List<String> shortcutIds, String disabledMessage) { 640 disableShortcuts(shortcutIds, (CharSequence) disabledMessage); 641 } 642 643 /** 644 * Disable pinned shortcuts, showing the user a custom error message when they try to select 645 * the disabled shortcuts. 646 * For more details, see the Javadoc for the {@link ShortcutManager} class. 647 * 648 * @throws IllegalArgumentException If trying to disable immutable shortcuts. 649 * 650 * @throws IllegalStateException when the user is locked. 651 */ disableShortcuts(@onNull List<String> shortcutIds, CharSequence disabledMessage)652 public void disableShortcuts(@NonNull List<String> shortcutIds, CharSequence disabledMessage) { 653 try { 654 mService.disableShortcuts(mContext.getPackageName(), shortcutIds, 655 disabledMessage, /* disabledMessageResId =*/ 0, 656 injectMyUserId()); 657 } catch (RemoteException e) { 658 throw e.rethrowFromSystemServer(); 659 } 660 } 661 662 /** 663 * Re-enable pinned shortcuts that were previously disabled. If the target shortcuts 664 * already enabled, this method does nothing. 665 * 666 * @throws IllegalArgumentException If trying to enable immutable shortcuts. 667 * 668 * @throws IllegalStateException when the user is locked. 669 */ enableShortcuts(@onNull List<String> shortcutIds)670 public void enableShortcuts(@NonNull List<String> shortcutIds) { 671 try { 672 mService.enableShortcuts(mContext.getPackageName(), shortcutIds, injectMyUserId()); 673 } catch (RemoteException e) { 674 throw e.rethrowFromSystemServer(); 675 } 676 } 677 678 679 /** 680 * @hide old signature, kept for unit testing. 681 */ getMaxShortcutCountForActivity()682 public int getMaxShortcutCountForActivity() { 683 return getMaxShortcutCountPerActivity(); 684 } 685 686 /** 687 * Return the maximum number of dynamic and manifest shortcuts that each launcher icon 688 * can have at a time. 689 */ getMaxShortcutCountPerActivity()690 public int getMaxShortcutCountPerActivity() { 691 try { 692 return mService.getMaxShortcutCountPerActivity( 693 mContext.getPackageName(), injectMyUserId()); 694 } catch (RemoteException e) { 695 throw e.rethrowFromSystemServer(); 696 } 697 } 698 699 /** 700 * Return the number of times the caller application can call the rate-limited APIs 701 * before the rate limit counter is reset. 702 * 703 * @see #getRateLimitResetTime() 704 * 705 * @hide 706 */ getRemainingCallCount()707 public int getRemainingCallCount() { 708 try { 709 return mService.getRemainingCallCount(mContext.getPackageName(), injectMyUserId()); 710 } catch (RemoteException e) { 711 throw e.rethrowFromSystemServer(); 712 } 713 } 714 715 /** 716 * Return when the rate limit count will be reset next time, in milliseconds since the epoch. 717 * 718 * @see #getRemainingCallCount() 719 * @see System#currentTimeMillis() 720 * 721 * @hide 722 */ getRateLimitResetTime()723 public long getRateLimitResetTime() { 724 try { 725 return mService.getRateLimitResetTime(mContext.getPackageName(), injectMyUserId()); 726 } catch (RemoteException e) { 727 throw e.rethrowFromSystemServer(); 728 } 729 } 730 731 /** 732 * Return {@code true} when rate-limiting is active for the caller application. 733 * 734 * <p>See the class level javadoc for details. 735 * 736 * @throws IllegalStateException when the user is locked. 737 */ isRateLimitingActive()738 public boolean isRateLimitingActive() { 739 try { 740 return mService.getRemainingCallCount(mContext.getPackageName(), injectMyUserId()) 741 == 0; 742 } catch (RemoteException e) { 743 throw e.rethrowFromSystemServer(); 744 } 745 } 746 747 /** 748 * Return the max width for icons, in pixels. 749 */ getIconMaxWidth()750 public int getIconMaxWidth() { 751 try { 752 // TODO Implement it properly using xdpi. 753 return mService.getIconMaxDimensions(mContext.getPackageName(), injectMyUserId()); 754 } catch (RemoteException e) { 755 throw e.rethrowFromSystemServer(); 756 } 757 } 758 759 /** 760 * Return the max height for icons, in pixels. 761 */ getIconMaxHeight()762 public int getIconMaxHeight() { 763 try { 764 // TODO Implement it properly using ydpi. 765 return mService.getIconMaxDimensions(mContext.getPackageName(), injectMyUserId()); 766 } catch (RemoteException e) { 767 throw e.rethrowFromSystemServer(); 768 } 769 } 770 771 /** 772 * Applications that publish shortcuts should call this method 773 * whenever the user selects the shortcut containing the given ID or when the user completes 774 * an action in the application that is equivalent to selecting the shortcut. 775 * For more details, see the Javadoc for the {@link ShortcutManager} class 776 * 777 * <p>The information is accessible via {@link UsageStatsManager#queryEvents} 778 * Typically, launcher applications use this information to build a prediction model 779 * so that they can promote the shortcuts that are likely to be used at the moment. 780 * 781 * @throws IllegalStateException when the user is locked. 782 */ reportShortcutUsed(String shortcutId)783 public void reportShortcutUsed(String shortcutId) { 784 try { 785 mService.reportShortcutUsed(mContext.getPackageName(), shortcutId, 786 injectMyUserId()); 787 } catch (RemoteException e) { 788 throw e.rethrowFromSystemServer(); 789 } 790 } 791 792 /** 793 * Called internally when an application is considered to have come to foreground 794 * even when technically it's not. This method resets the throttling for this package. 795 * For example, when the user sends an "inline reply" on an notification, the system UI will 796 * call it. 797 * 798 * @hide 799 */ onApplicationActive(@onNull String packageName, @UserIdInt int userId)800 public void onApplicationActive(@NonNull String packageName, @UserIdInt int userId) { 801 try { 802 mService.onApplicationActive(packageName, userId); 803 } catch (RemoteException e) { 804 throw e.rethrowFromSystemServer(); 805 } 806 } 807 808 /** @hide injection point */ 809 @VisibleForTesting injectMyUserId()810 protected int injectMyUserId() { 811 return UserHandle.myUserId(); 812 } 813 } 814