• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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&mdash;activities that handle the {@code MAIN} action and the
61  * {@code LAUNCHER} category&mdash;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  * &lt;manifest xmlns:android=&quot;http://schemas.android.com/apk/res/android&quot;
151  *   package=&quot;com.example.myapplication&quot;&gt;
152  *   &lt;application . . .&gt;
153  *     &lt;activity android:name=&quot;Main&quot;&gt;
154  *       &lt;intent-filter&gt;
155  *         &lt;action android:name=&quot;android.intent.action.MAIN&quot; /&gt;
156  *         &lt;category android:name=&quot;android.intent.category.LAUNCHER&quot; /&gt;
157  *       &lt;/intent-filter&gt;
158  *       <b>&lt;meta-data android:name=&quot;android.app.shortcuts&quot; android:resource=&quot;@xml/shortcuts&quot;/&gt;</b>
159  *     &lt;/activity&gt;
160  *   &lt;/application&gt;
161  * &lt;/manifest&gt;
162  * </pre>
163  *
164  * Then, define your application's manifest shortcuts in the <code>res/xml/shortcuts.xml</code>
165  * file:
166  * <pre>
167  * &lt;shortcuts xmlns:android=&quot;http://schemas.android.com/apk/res/android&quot; &gt;
168  *   &lt;shortcut
169  *     android:shortcutId=&quot;compose&quot;
170  *     android:enabled=&quot;true&quot;
171  *     android:icon=&quot;@drawable/compose_icon&quot;
172  *     android:shortcutShortLabel=&quot;@string/compose_shortcut_short_label1&quot;
173  *     android:shortcutLongLabel=&quot;@string/compose_shortcut_long_label1&quot;
174  *     android:shortcutDisabledMessage=&quot;@string/compose_disabled_message1&quot;
175  *     &gt;
176  *     &lt;intent
177  *       android:action=&quot;android.intent.action.VIEW&quot;
178  *       android:targetPackage=&quot;com.example.myapplication&quot;
179  *       android:targetClass=&quot;com.example.myapplication.ComposeActivity&quot; /&gt;
180  *     &lt;!-- more intents can go here; see below --&gt;
181  *     &lt;categories android:name=&quot;android.shortcut.conversation&quot; /&gt;
182  *   &lt;/shortcut&gt;
183  *   &lt;!-- more shortcuts can go here --&gt;
184  * &lt;/shortcuts&gt;
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>&lt;intent&gt;</code> elements within a single <code>&lt;shortcut&gt;</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