diff --git a/core/java/android/content/pm/LauncherApps.java b/core/java/android/content/pm/LauncherApps.java index 528fe20023915..2133222c7f544 100644 --- a/core/java/android/content/pm/LauncherApps.java +++ b/core/java/android/content/pm/LauncherApps.java @@ -164,17 +164,19 @@ public class LauncherApps { } /** - * Indicates that one or more shortcuts (which may be dynamic and/or pinned) + * Indicates that one or more shortcuts of any kinds (dynamic, pinned, or manifest) * have been added, updated or removed. * *

Only the applications that are allowed to access the shortcut information, * as defined in {@link #hasShortcutHostPermission()}, will receive it. * * @param packageName The name of the package that has the shortcuts. - * @param shortcuts all shortcuts from the package (dynamic, manifest and/or pinned). - * Only "key" information will be provided, as defined in + * @param shortcuts all shortcuts from the package (dynamic, manifest and/or pinned) will + * be passed. Only "key" information will be provided, as defined in * {@link ShortcutInfo#hasKeyFieldsOnly()}. * @param user The UserHandle of the profile that generated the change. + * + * @see ShortcutManager */ public void onShortcutsChanged(@NonNull String packageName, @NonNull List shortcuts, @NonNull UserHandle user) { @@ -222,7 +224,17 @@ public class LauncherApps { /** * Requests "key" fields only. See {@link ShortcutInfo#hasKeyFieldsOnly()} for which - * fields are available. + * fields are available. This allows quicker access to shortcut information in order to + * determine in-memory cache in the caller needs to be updated. + * + *

Typically, launcher applications cache all or most shortcuts' information + * in memory in order to show shortcuts without a delay. When they want to update their + * cache (e.g. when their process restart), they can fetch all shortcuts' information with + * with this flag, then check {@link ShortcutInfo#getLastChangedTimestamp()} for each + * shortcut and issue a second call to fetch the non-key information of only updated + * shortcuts. + * + * @see ShortcutManager */ public static final int FLAG_GET_KEY_FIELDS_ONLY = 1 << 2; @@ -255,8 +267,8 @@ public class LauncherApps { } /** - * If non-zero, returns only shortcuts that have been added or updated since the timestamp, - * which is a milliseconds since the Epoch. + * If non-zero, returns only shortcuts that have been added or updated since the timestamp. + * Units are as per {@link System#currentTimeMillis()}. */ public ShortcutQuery setChangedSince(long changedSince) { mChangedSince = changedSince; @@ -273,7 +285,7 @@ public class LauncherApps { /** * If non-null, return only the specified shortcuts by ID. When setting this field, - * a packange name must also be set with {@link #setPackage}. + * a package name must also be set with {@link #setPackage}. */ public ShortcutQuery setShortcutIds(@Nullable List shortcutIds) { mShortcutIds = shortcutIds; @@ -291,7 +303,13 @@ public class LauncherApps { } /** - * Set query options. + * Set query options. At least one of the {@code MATCH} flags should be set. (Otherwise + * no shortcuts will be returned.) + * + * @see {@link #FLAG_MATCH_DYNAMIC} + * @see {@link #FLAG_MATCH_PINNED} + * @see {@link #FLAG_MATCH_MANIFEST} + * @see {@link #FLAG_GET_KEY_FIELDS_ONLY} */ public ShortcutQuery setQueryFlags(@QueryFlags int queryFlags) { mQueryFlags = queryFlags; @@ -460,10 +478,14 @@ public class LauncherApps { * *

Only the default launcher can access the shortcut information. * - *

Note when this method returns {@code false}, that may be a temporary situation because + *

Note when this method returns {@code false}, it may be a temporary situation because * the user is trying a new launcher application. The user may decide to change the default - * launcher to the calling application again, so even if a launcher application loses + * launcher back to the calling application again, so even if a launcher application loses * this permission, it does not have to purge pinned shortcut information. + * Also in this situation, pinned shortcuts can still be started, even though the caller + * no longer has the shortcut host permission. + * + * @see ShortcutManager */ public boolean hasShortcutHostPermission() { try { @@ -474,7 +496,7 @@ public class LauncherApps { } /** - * Returns the IDs of {@link ShortcutInfo}s that match {@code query}. + * Returns {@link ShortcutInfo}s that match {@code query}. * *

Callers must be allowed to access the shortcut information, as defined in {@link * #hasShortcutHostPermission()}. @@ -483,6 +505,8 @@ public class LauncherApps { * @param user The UserHandle of the profile. * * @return the IDs of {@link ShortcutInfo}s that match the query. + * + * @see ShortcutManager */ @Nullable public List getShortcuts(@NonNull ShortcutQuery query, @@ -523,6 +547,8 @@ public class LauncherApps { * @param packageName The target package name. * @param shortcutIds The IDs of the shortcut to be pinned. * @param user The UserHandle of the profile. + * + * @see ShortcutManager */ public void pinShortcuts(@NonNull String packageName, @NonNull List shortcutIds, @NonNull UserHandle user) { @@ -586,11 +612,17 @@ public class LauncherApps { /** * Returns the icon for this shortcut, without any badging for the profile. * + *

Callers must be allowed to access the shortcut information, as defined in {@link + * #hasShortcutHostPermission()}. + * * @param density The preferred density of the icon, zero for default density. Use * density DPI values from {@link DisplayMetrics}. + * + * @return The drawable associated with the shortcut. + * + * @see ShortcutManager * @see #getShortcutBadgedIconDrawable(ShortcutInfo, int) * @see DisplayMetrics - * @return The drawable associated with the shortcut. */ public Drawable getShortcutIconDrawable(@NonNull ShortcutInfo shortcut, int density) { if (shortcut.hasIconFile()) { @@ -628,10 +660,15 @@ public class LauncherApps { /** * Returns the shortcut icon with badging appropriate for the profile. * + *

Callers must be allowed to access the shortcut information, as defined in {@link + * #hasShortcutHostPermission()}. + * * @param density Optional density for the icon, or 0 to use the default density. Use - * {@link DisplayMetrics} for DPI values. - * @see DisplayMetrics * @return A badged icon for the shortcut. + * + * @see ShortcutManager + * @see #getShortcutBadgedIconDrawable(ShortcutInfo, int) + * @see DisplayMetrics */ public Drawable getShortcutBadgedIconDrawable(ShortcutInfo shortcut, int density) { final Drawable originalIcon = getShortcutIconDrawable(shortcut, density); @@ -641,7 +678,7 @@ public class LauncherApps { } /** - * Launches a shortcut. + * Starts a shortcut. * *

Callers must be allowed to access the shortcut information, as defined in {@link * #hasShortcutHostPermission()}. diff --git a/core/java/android/content/pm/ShortcutInfo.java b/core/java/android/content/pm/ShortcutInfo.java index 39e15e01bab4c..8ea77d6428a8a 100644 --- a/core/java/android/content/pm/ShortcutInfo.java +++ b/core/java/android/content/pm/ShortcutInfo.java @@ -22,8 +22,10 @@ import android.annotation.UserIdInt; import android.content.ComponentName; import android.content.Context; import android.content.Intent; +import android.content.pm.LauncherApps.ShortcutQuery; import android.content.res.Resources; import android.content.res.Resources.NotFoundException; +import android.graphics.Bitmap; import android.graphics.drawable.Icon; import android.os.Bundle; import android.os.Parcel; @@ -42,20 +44,10 @@ import java.lang.annotation.RetentionPolicy; import java.util.List; import java.util.Set; -// TODO Enhance javadoc /** + * Represents a "launcher shortcut" that can be published via {@link ShortcutManager}. * - * Represents a shortcut from an application. - * - *

Notes about icons: - *

- * - * @see {@link ShortcutManager}. + * @see ShortcutManager */ public final class ShortcutInfo implements Parcelable { static final String TAG = "Shortcut"; @@ -149,7 +141,7 @@ public final class ShortcutInfo implements Parcelable { public @interface CloneFlags {} /** - * Shortcut category for + * Shortcut category for messaging related actions, such as chat. */ public static final String SHORTCUT_CATEGORY_CONVERSATION = "android.shortcut.conversation"; @@ -665,6 +657,8 @@ public final class ShortcutInfo implements Parcelable { /** * Builder class for {@link ShortcutInfo} objects. + * + * @see ShortcutManager */ public static class Builder { private final Context mContext; @@ -727,19 +721,25 @@ public final class ShortcutInfo implements Parcelable { } /** - * Sets the target activity. A shortcut will be shown with this activity on the launcher. + * Sets the target activity. A shortcut will be shown along with this activity's icon + * on the launcher. * - *

Only "main" activities -- i.e. ones with an intent filter for - * {@link Intent#ACTION_MAIN} and {@link Intent#CATEGORY_LAUNCHER} can be target activities. + *

This is a mandatory field when publishing a new shortcut with + * {@link ShortcutManager#addDynamicShortcuts(List)} or + * {@link ShortcutManager#setDynamicShortcuts(List)}. * - *

By default, the first main activity defined in the application manifest will be + *

* - *

This has nothing to do with the activity that this shortcut will launch. This is - * a hint to the launcher app about which launcher icon to associate this shortcut with. + * @see ShortcutInfo#getActivity() */ @NonNull public Builder setActivity(@NonNull ComponentName activity) { @@ -748,18 +748,23 @@ public final class ShortcutInfo implements Parcelable { } /** - * Sets an icon. + * Sets an icon of a shortcut. * - *

- * - *

For performance and security reasons, icons will NOT be available on instances - * returned by {@link ShortcutManager} or {@link LauncherApps}. Default launcher application - * can use {@link LauncherApps#getShortcutIconDrawable(ShortcutInfo, int)} + *

Icons are not available on {@link ShortcutInfo} instances + * returned by {@link ShortcutManager} or {@link LauncherApps}. The default launcher + * application can use {@link LauncherApps#getShortcutIconDrawable(ShortcutInfo, int)} * or {@link LauncherApps#getShortcutBadgedIconDrawable(ShortcutInfo, int)} to fetch * shortcut icons. + * + *

Tints set with {@link Icon#setTint} or {@link Icon#setTintList} are not supported + * and will be ignored. + * + *

Only icons created with {@link Icon#createWithBitmap(Bitmap)} and + * {@link Icon#createWithResource} are supported. Other types such as URI based icons + * are not supported. + * + * @see LauncherApps#getShortcutIconDrawable(ShortcutInfo, int) + * @see LauncherApps#getShortcutBadgedIconDrawable(ShortcutInfo, int) */ @NonNull public Builder setIcon(Icon icon) { @@ -781,11 +786,15 @@ public final class ShortcutInfo implements Parcelable { /** * Sets the short title of a shortcut. * - *

This is a mandatory field, unless it's passed to - * {@link ShortcutManager#updateShortcuts(List)}. + *

This is a mandatory field when publishing a new shortcut with + * {@link ShortcutManager#addDynamicShortcuts(List)} or + * {@link ShortcutManager#setDynamicShortcuts(List)}. * - *

This field is intended for a concise description of a shortcut displayed under - * an icon. The recommend max length is 10 characters. + *

This field is intended for a concise description of a shortcut. + * + *

The recommended max length is 10 characters. + * + * @see ShortcutInfo#getShortLabel() */ @NonNull public Builder setShortLabel(@NonNull CharSequence shortLabel) { @@ -809,8 +818,11 @@ public final class ShortcutInfo implements Parcelable { * Sets the text of a shortcut. * *

This field is intended to be more descriptive than the shortcut title. The launcher - * shows this instead of the short title, when it has enough space. - * The recommend max length is 25 characters. + * shows this instead of the short title when it has enough space. + * + *

The recommend max length is 25 characters. + * + * @see ShortcutInfo#getLongLabel() */ @NonNull public Builder setLongLabel(@NonNull CharSequence longLabel) { @@ -854,6 +866,11 @@ public final class ShortcutInfo implements Parcelable { return this; } + /** + * Sets the message that should be shown when a shortcut is launched when disabled. + * + * @see ShortcutInfo#getDisabledMessage() + */ @NonNull public Builder setDisabledMessage(@NonNull CharSequence disabledMessage) { Preconditions.checkState( @@ -869,6 +886,7 @@ public final class ShortcutInfo implements Parcelable { * categorise shortcuts. * * @see #SHORTCUT_CATEGORY_CONVERSATION + * @see ShortcutInfo#getCategories() */ @NonNull public Builder setCategories(Set categories) { @@ -877,8 +895,22 @@ public final class ShortcutInfo implements Parcelable { } /** - * Sets the intent of a shortcut. This is a mandatory field. The extras must only contain - * persistable information. (See {@link PersistableBundle}). + * Sets the intent of a shortcut. + * + *

This is a mandatory field when publishing a new shortcut with + * {@link ShortcutManager#addDynamicShortcuts(List)} or + * {@link ShortcutManager#setDynamicShortcuts(List)}. + * + *

A shortcut can launch any intent that the publisher application has a permission to + * launch -- for example, a shortcut can launch an unexported activity within the publisher + * application. + * + *

A shortcut intent doesn't have to point at the target activity. + * + *

{@code intent} can contain extras, but only values of the primitive types are + * supported so the system can persist them. + * + * @see ShortcutInfo#getIntent() */ @NonNull public Builder setIntent(@NonNull Intent intent) { @@ -890,6 +922,8 @@ public final class ShortcutInfo implements Parcelable { /** * "Rank" of a shortcut, which is a non-negative value that's used by the launcher app * to sort shortcuts. + * + * See {@link ShortcutInfo#getRank()} for details. */ @NonNull public Builder setRank(int rank) { @@ -903,7 +937,7 @@ public final class ShortcutInfo implements Parcelable { * Extras that application can set to any purposes. * *

Applications can store any meta-data of - * shortcuts in this, and retrieve later from {@link ShortcutInfo#getExtras()}. + * shortcuts in extras, and retrieve later from {@link ShortcutInfo#getExtras()}. */ @NonNull public Builder setExtras(@NonNull PersistableBundle extras) { @@ -921,7 +955,11 @@ public final class ShortcutInfo implements Parcelable { } /** - * Return the ID of the shortcut. + * Returns the ID of a shortcut. + * + *

Shortcut IDs are unique within each publisher application, and must be stable across + * devices to that shortcuts will still be valid when restored. See {@link ShortcutManager} + * for details. */ @NonNull public String getId() { @@ -929,7 +967,7 @@ public final class ShortcutInfo implements Parcelable { } /** - * Return the package name of the creator application. + * Return the package name of the publisher application. */ @NonNull public String getPackage() { @@ -937,11 +975,10 @@ public final class ShortcutInfo implements Parcelable { } /** - * Return the target activity, which may be null, in which case the shortcut is not associated - * with a specific activity. + * Return the target activity. * - *

This has nothing to do with the activity that this shortcut will launch. This is - * a hint to the launcher app that on which launcher icon this shortcut should be shown. + *

This has nothing to do with the activity that this shortcut will launch. Launcher + * applications should show a shortcut along with the launcher icon for this activity. * * @see Builder#setActivity */ @@ -956,11 +993,7 @@ public final class ShortcutInfo implements Parcelable { } /** - * Icon. - * - * For performance reasons, this will NOT be available when an instance is returned - * by {@link ShortcutManager} or {@link LauncherApps}. A launcher application needs to use - * other APIs in LauncherApps to fetch the bitmap. + * Returns the shortcut icon. * * @hide */ @@ -996,10 +1029,9 @@ public final class ShortcutInfo implements Parcelable { } /** - * Return the shorter version of the shortcut title. + * Return the shorter description of a shortcut. * - *

All shortcuts must have a non-empty title, but this method will return null when - * {@link #hasKeyFieldsOnly()} is true. + * @see Builder#setShortLabel(CharSequence) */ @Nullable public CharSequence getShortLabel() { @@ -1012,7 +1044,9 @@ public final class ShortcutInfo implements Parcelable { } /** - * Return the shortcut text. + * Return the longer description of a shortcut. + * + * @see Builder#setLongLabel(CharSequence) */ @Nullable public CharSequence getLongLabel() { @@ -1026,6 +1060,8 @@ public final class ShortcutInfo implements Parcelable { /** * Return the message that should be shown when a shortcut in disabled state is launched. + * + * @see Builder#setDisabledMessage(CharSequence) */ @Nullable public CharSequence getDisabledMessage() { @@ -1039,6 +1075,8 @@ public final class ShortcutInfo implements Parcelable { /** * Return the categories. + * + * @see Builder#setCategories(Set) */ @Nullable public Set getCategories() { @@ -1048,12 +1086,11 @@ public final class ShortcutInfo implements Parcelable { /** * Return the intent. * - *

All shortcuts must have an intent, but this method will return null when - * {@link #hasKeyFieldsOnly()} is true. + *

Launcher applications cannot see the intent. If a {@link ShortcutInfo} is + * obtained via {@link LauncherApps}, then this method will always return null. + * Launchers can only start a shortcut intent with {@link LauncherApps#startShortcut}. * - *

Launcher apps cannot see the intent. If a {@link ShortcutInfo} is obtained via - * {@link LauncherApps}, then this method will always return null. Launcher apps can only - * start a shortcut intent with {@link LauncherApps#startShortcut}. + * @see Builder#setIntent(Intent) */ @Nullable public Intent getIntent() { @@ -1096,6 +1133,10 @@ public final class ShortcutInfo implements Parcelable { * *

"Floating" shortcuts (i.e. shortcuts that are neither dynamic nor manifest) will all * have rank 0, because there's no sorting for them. + * + * See the {@link ShortcutManager}'s class javadoc for details. + * + * @see Builder#setRank(int) */ public int getRank() { return mRank; @@ -1139,6 +1180,8 @@ public final class ShortcutInfo implements Parcelable { /** * Extras that application can set to any purposes. + * + * @see Builder#setExtras(PersistableBundle) */ @Nullable public PersistableBundle getExtras() { @@ -1151,7 +1194,7 @@ public final class ShortcutInfo implements Parcelable { } /** - * {@link UserHandle} on which the publisher created shortcuts. + * {@link UserHandle} on which the publisher created a shortcut. */ public UserHandle getUserHandle() { return UserHandle.of(mUserId); @@ -1201,16 +1244,13 @@ public final class ShortcutInfo implements Parcelable { } /** - * Return whether a shortcut is published via AndroidManifest.xml or not. If {@code true}, + * Return whether a shortcut is published AndroidManifest.xml or not. If {@code true}, * it's also {@link #isImmutable()}. * *

When an app is upgraded and a shortcut is no longer published from AndroidManifest.xml, * this will be set to {@code false}. If the shortcut is not pinned, then it'll just disappear. * However, if it's pinned, it will still be alive, and {@link #isEnabled()} will be * {@code false} and {@link #isImmutable()} will be {@code true}. - * - *

NOTE this is whether a shortcut is published from the current version's - * AndroidManifest.xml. */ public boolean isDeclaredInManifest() { return hasFlags(FLAG_MANIFEST); @@ -1311,6 +1351,12 @@ public final class ShortcutInfo implements Parcelable { *

  • {@link #isEnabled()} *
  • {@link #getUserHandle()} * + * + *

    {@link ShortcutInfo}s passed to + * {@link LauncherApps.Callback#onShortcutsChanged(String, List, UserHandle)} + * as well as returned by {@link LauncherApps#getShortcuts(ShortcutQuery, UserHandle)} with + * the {@link ShortcutQuery#FLAG_GET_KEY_FIELDS_ONLY} option will only have key information + * for performance reasons. */ public boolean hasKeyFieldsOnly() { return hasFlags(FLAG_KEY_FIELDS_ONLY); diff --git a/core/java/android/content/pm/ShortcutManager.java b/core/java/android/content/pm/ShortcutManager.java index 1af63a01ce2bc..f6c0be07db84a 100644 --- a/core/java/android/content/pm/ShortcutManager.java +++ b/core/java/android/content/pm/ShortcutManager.java @@ -20,6 +20,7 @@ import android.annotation.TestApi; import android.annotation.UserIdInt; import android.app.usage.UsageStatsManager; import android.content.Context; +import android.content.Intent; import android.os.RemoteException; import android.os.ServiceManager; import android.os.UserHandle; @@ -28,62 +29,333 @@ import com.android.internal.annotations.VisibleForTesting; import java.util.List; -// TODO Enhance javadoc /** - * TODO: Update to reflect DR changes, such as manifest shortcuts.
    + * ShortcutManager manages "launcher shortcuts" (or simply "shortcuts"). Shortcuts provide user + * with quick + * ways to access activities other than the main activity from the launcher to users. For example, + * an email application may publish the "compose new email" action which will directly open the + * compose activity. The {@link ShortcutInfo} class represents shortcuts. * - * {@link ShortcutManager} manages shortcuts created by applications. + *

    Dynamic Shortcuts and Manifest Shortcuts

    * - *

    Dynamic shortcuts and pinned shortcuts

    + * There are two ways to publish shortcuts: manifest shortcuts and dynamic shortcuts. * - * An application can publish shortcuts with {@link #setDynamicShortcuts(List)} and - * {@link #addDynamicShortcuts(List)}. There can be at most - * {@link #getMaxShortcutCountPerActivity()} number of dynamic shortcuts at a time from the - * same application. - * A dynamic shortcut can be deleted with {@link #removeDynamicShortcuts(List)}, and apps - * can also use {@link #removeAllDynamicShortcuts()} to delete all dynamic shortcuts. + * * - *

    The number of pinned shortcuts does not affect the number of dynamic shortcuts that can be - * published by an application at a time. - * No matter how many pinned shortcuts that Launcher has for an application, the - * application can still always publish {@link #getMaxShortcutCountPerActivity()} number of - * dynamic - * shortcuts. + *

    Only "main" activities (i.e. activities that handle the {@code MAIN} action and the + * {@code LAUNCHER} category) can have shortcuts. If an application has multiple main activities, + * they will have different set of shortcuts. * - *

    Shortcut IDs

    + *

    Dynamic shortcuts and manifest shortcuts are shown by launcher applications when the user + * takes a certain action (e.g. long-press) on an application launcher icon. * - * Each shortcut must have an ID, which must be unique within each application. When a shortcut is - * published, existing shortcuts with the same ID will be updated. Note this may include a - * pinned shortcut. + *

    Each launcher icon can have at most {@link #getMaxShortcutCountPerActivity()} number of + * dynamic and manifest shortcuts combined. + * + * + *

    Pinning Shortcuts

    + * + * Launcher applications allow users to "pin" shortcuts so they're easier to access. Both manifest + * and dynamic shortcuts can be pinned, to avoid user's confusion. + * Pinned shortcuts cannot be removed by publisher + * applications -- they are only removed when the publisher is uninstalled. (Or the user performs + * "clear data" on the publisher application on the Settings application.) + * + *

    Publisher can however "disable" pinned shortcuts so they cannot be launched. See below + * for details. + * + * + *

    Updating and Disabling Shortcuts

    + * + *

    When a dynamic shortcut is pinned, even when the publisher removes it as a dynamic shortcut, + * the pinned shortcut will still be available and launchable. This allows an application to have + * more than {@link #getMaxShortcutCountPerActivity()} number of shortcuts -- for example, suppose + * {@link #getMaxShortcutCountPerActivity()} is 5: + *

    + * {@link #addDynamicShortcuts(List)} and {@link #setDynamicShortcuts(List)} can also be used + * to update existing shortcuts with the same IDs, but they cannot be used for + * non-dynamic pinned shortcuts because these two APIs will always try to make the passed + * shortcuts dynamic. + * + * + *

    Disabling Manifest Shortcuts

    + * Sometimes pinned shortcuts become obsolete and may not be usable. For example, a pinned shortcut + * to a group chat will be unusable when the group chat room is deleted. In cases like this, + * applications should use {@link #disableShortcuts(List)}, which will remove the specified dynamic + * shortcuts and also make the pinned shortcuts un-launchable, if any. + * {@link #disableShortcuts(List, CharSequence)} can also be used to disable shortcuts with + * a custom error message that will be shown when the user starts the shortcut. + * + *

    Disabling Manifest Shortcuts

    + * When an application is upgraded and the new version no longer has a manifest shortcut that + * the previous version had, this shortcut will no longer be published as a manifest shortcut. + * + *

    If the shortcut is pinned, then the pinned shortcut will remain on the launcher, but will be + * disabled. Note in this case, the pinned shortcut is no longer a manifest shortcut, but is + * still immutable and cannot be updated with the {@link ShortcutManager} APIs. + * + * + *

    Publishing Dynamic Shortcuts

    + * + * Applications can publish dynamic shortcuts with {@link #setDynamicShortcuts(List)} + * or {@link #addDynamicShortcuts(List)}. {@link #updateShortcuts(List)} can also be used to + * update existing (mutable) shortcuts. + * Use {@link #removeDynamicShortcuts(List)} or {@link #removeAllDynamicShortcuts()} to remove + * dynamic shortcuts. + * + *

    Example: + *

    + * ShortcutManager shortcutManager = getSystemService(ShortcutManager.class);
    + *
    + * ShortcutInfo shortcut = new ShortcutInfo.Builder(this, "id1")
    + *     .setIntent(new Intent(Intent.ACTION_VIEW, Uri.parse("http://www.mysite.com/")))
    + *     .setShortLabel("Web site")
    + *     .setLongLabel("Open the web site")
    + *     .setIcon(Icon.createWithResource(context, R.drawable.icon_website))
    + *     .build();
    + *
    + * shortcutManager.setDynamicShortcuts(Arrays.asList(shortcut));
    + * 
    + * + * + *

    Publishing Manifest Shortcuts

    + * + * In order to add manifest shortcuts to your application, first add + * {@code } to your main activity in + * AndroidManifest.xml. + *
    + * <manifest xmlns:android="http://schemas.android.com/apk/res/android"
    + *   package="com.example.myapplication">
    + *   <application . . .>
    + *     <activity android:name="Main">
    + *       <intent-filter>
    + *         <action android:name="android.intent.action.MAIN" />
    + *         <category android:name="android.intent.category.LAUNCHER" />
    + *       </intent-filter>
    + *       <meta-data android:name="android.app.shortcuts" android:resource="@xml/shortcuts"/>
    + *     </activity>
    + *   </application>
    + * </manifest>
    + * 
    + * + * Then define shortcuts in res/xml/shortcuts.xml. + *
    + * <shortcuts xmlns:android="http://schemas.android.com/apk/res/android" >
    + *   <shortcut
    + *     android:shortcutId="compose"
    + *     android:enabled="true"
    + *     android:icon="@drawable/compose_icon"
    + *     android:shortcutShortLabel="@string/compose_shortcut_short_label1"
    + *     android:shortcutLongLabel="@string/compose_shortcut_short_label1"
    + *     android:shortcutDisabledMessage="@string/compose_disabled_message1"
    + *     >
    + *     <intent
    + *       android:action="android.intent.action.VIEW"
    + *       android:targetPackage="com.example.myapplication"
    + *       android:targetClass="com.example.myapplication.ComposeActivity" />
    + *     <categories android:name="android.shortcut.conversation" />
    + *   </shortcut>
    + *   <!-- more shortcut can go here -->
    + * </shortcuts>
    + * 
    + * + * + *

    Updating Shortcuts v.s. Re-publishing New One with Different ID

    + * In order to avoid users' confusion, {@link #updateShortcuts(List)} should not be used to update + * a shortcut to something that is conceptually different. + * + *

    For example, a phone application may publish the most frequently called contact as a dynamic + * shortcut. Over the time, this contact may change, but when it changes the application should + * publish a new contact with a different ID with either + * {@link #setDynamicShortcuts(List)} or {@link #addDynamicShortcuts(List)}, rather than updating + * the existing shortcut with {@link #updateShortcuts(List)}. + * + * This is because when the shortcut is pinned, changing it to a different contact + * will likely confuse the user. + * + *

    On the other hand, when the contact's information (e.g. the name or picture) has changed, + * then the application should use {@link #updateShortcuts(List)} so that the pinned shortcut + * will be updated too. + * + * + *

    Shortcut Display Order

    + * When the launcher show the shortcuts for a launcher icon, the showing order should be the + * following: + * + *

    Shortcut ranks are non-negative sequential integers for each target activity. Ranks of + * existing shortcuts can be updated with + * {@link #updateShortcuts(List)} ({@link #addDynamicShortcuts(List)} and + * {@link #setDynamicShortcuts(List)} may be used too). + * + *

    Ranks will be auto-adjusted so that they're unique for each target activity for each category + * (dynamic or manifest). For example, if there are 3 dynamic shortcuts with ranks 0, 1 and 2, + * adding another dynamic shortcut with rank = 1 means to place this shortcut at the second + * position. The third and forth shortcuts (that were originally second and third) will be adjusted + * to 2 and 3 respectively. + * + *

    Rate Limiting

    + * + * Calls to {@link #setDynamicShortcuts(List)}, {@link #addDynamicShortcuts(List)} and + * {@link #updateShortcuts(List)} may be rate-limited when called by background applications (i.e. + * applications with no foreground activity or service). When rate-limited, these APIs will return + * {@code false}. + * + *

    Applications with a foreground activity or service will not be rate-limited. + * + *

    Rate-limiting will be reset upon certain events, so that even background applications + * will be able to call these APIs again (until they are rate-limited again). + *

    + * + *

    Resetting rate-limiting for testing

    + * + * If your application is rate-limited during development or testing, you can use the + * "Reset ShortcutManager rate-limiting" development option, or the following adb command to reset + * it. + *
    + * adb shell cmd shortcut reset-throttling [ --user USER-ID ]
    + * 
    + * + *

    Handling System Locale Change

    + * + * Applications should update dynamic and pinned shortcuts when the system locale changes + * using the {@link Intent#ACTION_LOCALE_CHANGED} broadcast. + * + *

    When the system locale changes, rate-limiting will be reset, so even background applications + * what were previously rate-limited will be able to call {@link #updateShortcuts(List)}. * * *

    Backup and Restore

    * - * Pinned shortcuts will be backed up and restored across devices. This means all information - * within shortcuts, including IDs, must be meaningful on different devices. + * When an application has {@code android:allowBackup="true"} in its AndroidManifest.xml, pinned + * shortcuts will be backed up automatically and restored when the user sets up a new device. + * + *

    What will be backed up and what will not be backed up

    * - *

    Note that: *

    * + *

    Because dynamic shortcuts will not restored, it is recommended that applications check + * currently published dynamic shortcuts with {@link #getDynamicShortcuts()} when they start, + * and re-publish dynamic shortcuts when necessary. * - *

    APIs for launcher

    + *
    + * public class MainActivity extends Activity {
    + *     public void onCreate(Bundle savedInstanceState) {
    + *         super.onCreate(savedInstanceState);
      *
    - * Launcher applications should use {@link LauncherApps} to get shortcuts that are published from
    - * applications.  Launcher applications can also pin shortcuts with
    - * {@link LauncherApps#pinShortcuts(String, List, UserHandle)}.
    + *         ShortcutManager shortcutManager = getSystemService(ShortcutManager.class);
    + *
    + *         if (shortcutManager.getDynamicShortcuts().size() == 0) {
    + *             // Application restored; re-publish dynamic shortcuts.
    + *
    + *             if (shortcutManager.getPinnedShortcuts().size() > 0) {
    + *                 // Pinned shortcuts have been restored.  use updateShortcuts() to make sure
    + *                 // they have up-to-date information.
    + *             }
    + *         }
    + *     }
    + *     :
    + *
    + * }
    + * 
    + * + * + *

    Backup/restore and shortcut IDs

    + * + * Because pinned shortcuts will be backed up and restored on new devices, shortcut IDs should be + * meaningful across devices; that is, IDs should be either stable constant strings, or server-side + * identifiers, rather than identifiers generated locally that may not make sense on other devices. + * + * + *

    Report Shortcut Usage and Prediction

    + * + * Launcher applications may be capable of predicting which shortcuts will most likely be used at + * the moment with the shortcut usage history data. + * + *

    In order to provide launchers with such data, publisher applications should report which + * shortcut is used with {@link #reportShortcutUsed(String)} when a shortcut is started, + * or when an action equivalent to a shortcut is taken by the user even if it wasn't started + * with the shortcut. + * + *

    For example, suppose a GPS navigation application exposes "navigate to work" as a shortcut. + * Then it should report it when the user starts this shortcut, and also when the user navigates + * to work within the application without using the shortcut. This helps the launcher application + * learn that the user wants to navigate to work at a certain time every weekday, so that the + * launcher can show this shortcut in a suggestion list. + * + *

    Launcher API

    + * + * {@link LauncherApps} provides APIs for launcher applications to access shortcuts. */ public class ShortcutManager { private static final String TAG = "ShortcutManager"; @@ -110,14 +382,15 @@ public class ShortcutManager { /** * Publish a list of shortcuts. All existing dynamic shortcuts from the caller application - * will be replaced. + * will be replaced. If there's already pinned shortcuts with the same IDs, they will all be + * updated, unless they're immutable. * *

    This API will be rate-limited. * * @return {@code true} if the call has succeeded. {@code false} if the call is rate-limited. * - * @throws IllegalArgumentException if {@code shortcutInfoList} contains more than - * {@link #getMaxShortcutCountPerActivity()} shortcuts. + * @throws IllegalArgumentException if {@link #getMaxShortcutCountPerActivity()} is exceeded, + * or trying to update immutable shortcuts. */ public boolean setDynamicShortcuts(@NonNull List shortcutInfoList) { try { @@ -129,8 +402,7 @@ public class ShortcutManager { } /** - * Return all dynamic shortcuts from the caller application. The number of result items - * will not exceed the value returned by {@link #getMaxShortcutCountPerActivity()}. + * Return all dynamic shortcuts from the caller application. */ @NonNull public List getDynamicShortcuts() { @@ -143,7 +415,7 @@ public class ShortcutManager { } /** - * TODO Javadoc + * Return all manifest shortcuts from the caller application. */ @NonNull public List getManifestShortcuts() { @@ -157,14 +429,14 @@ public class ShortcutManager { /** * Publish list of dynamic shortcuts. If there's already dynamic or pinned shortcuts with - * the same IDs, they will all be updated. + * the same IDs, they will all be updated, unless they're immutable. * *

    This API will be rate-limited. * * @return {@code true} if the call has succeeded. {@code false} if the call is rate-limited. * - * @throws IllegalArgumentException if the caller application has already published the - * max number of dynamic shortcuts. + * @throws IllegalArgumentException if {@link #getMaxShortcutCountPerActivity()} is exceeded, + * or trying to update immutable shortcuts. */ public boolean addDynamicShortcuts(@NonNull List shortcutInfoList) { try { @@ -212,11 +484,14 @@ public class ShortcutManager { } /** - * Update all existing shortcuts with the same IDs. Shortcuts may be pinned and/or dynamic. + * Update all existing shortcuts with the same IDs. Target shortcuts may be pinned and/or + * dynamic, but may not be immutable. * *

    This API will be rate-limited. * * @return {@code true} if the call has succeeded. {@code false} if the call is rate-limited. + * + * @throws IllegalArgumentException if trying to update immutable shortcuts. */ public boolean updateShortcuts(List shortcutInfoList) { try { @@ -228,7 +503,7 @@ public class ShortcutManager { } /** - * TODO Javadoc + * Disable pinned shortcuts. See {@link ShortcutManager}'s class javadoc for details. */ public void disableShortcuts(@NonNull List shortcutIds) { try { @@ -261,7 +536,8 @@ public class ShortcutManager { } /** - * TODO Javadoc + * Disable pinned shortcuts with a custom error message. + * See {@link ShortcutManager}'s class javadoc for details. */ public void disableShortcuts(@NonNull List shortcutIds, CharSequence disabledMessage) { try { @@ -274,7 +550,7 @@ public class ShortcutManager { } /** - * TODO Javadoc + * Re-enable disabled pinned shortcuts. */ public void enableShortcuts(@NonNull List shortcutIds) { try { @@ -293,7 +569,7 @@ public class ShortcutManager { } /** - * Return the max number of dynamic shortcuts + manifest shortcuts that each launcher icon + * Return the max number of dynamic and manifest shortcuts that each launcher icon * can have at a time. */ public int getMaxShortcutCountPerActivity() { @@ -362,12 +638,9 @@ public class ShortcutManager { } /** - * Applications that publish shortcuts should call this method whenever an action that's - * equivalent to an existing shortcut has been taken by the user. This includes not only when - * the user manually taps a shortcut, but when the user takes an equivalent action within the - * application -- for example, when a music player application has a shortcut to playlist X, - * then the application should not only report it when the playlist is opened from the - * shortcut, but also when the user plays the playlist within the application. + * Applications that publish shortcuts should call this method whenever a shortcut is started + * or an action equivalent to a shortcut is taken. See the {@link ShortcutManager} class + * javadoc for details. * *

    The information is accessible via {@link UsageStatsManager#queryEvents} * Typically, launcher applications use this information to build a prediction model