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