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