Merge "Support multiple intents in ShortcutInfo" into nyc-mr1-dev
diff --git a/core/java/android/app/ActivityManagerInternal.java b/core/java/android/app/ActivityManagerInternal.java
index fc3596e..83e2678 100644
--- a/core/java/android/app/ActivityManagerInternal.java
+++ b/core/java/android/app/ActivityManagerInternal.java
@@ -165,10 +165,10 @@
             int userId);
 
     /**
-     * Start an activity {@code intent} as if {@code packageName} on user {@code userId} did it.
+     * Start activity {@code intents} as if {@code packageName} on user {@code userId} did it.
      *
      * @return error codes used by {@link IActivityManager#startActivity} and its siblings.
      */
-    public abstract int startActivityAsPackage(String packageName,
-            int userId, Intent intent, Bundle bOptions);
+    public abstract int startActivitiesAsPackage(String packageName,
+            int userId, Intent[] intents, Bundle bOptions);
 }
diff --git a/core/java/android/content/pm/ShortcutInfo.java b/core/java/android/content/pm/ShortcutInfo.java
index 54f1b76..0ec1623 100644
--- a/core/java/android/content/pm/ShortcutInfo.java
+++ b/core/java/android/content/pm/ShortcutInfo.java
@@ -182,16 +182,16 @@
     private ArraySet<String> mCategories;
 
     /**
-     * Intent *with extras removed*.
+     * Intents *with extras removed*.
      */
     @Nullable
-    private Intent mIntent;
+    private Intent[] mIntents;
 
     /**
-     * Extras for the intent.
+     * Extras for the intents.
      */
     @Nullable
-    private PersistableBundle mIntentPersistableExtras;
+    private PersistableBundle[] mIntentPersistableExtrases;
 
     private int mRank;
 
@@ -241,20 +241,36 @@
         mDisabledMessage = b.mDisabledMessage;
         mDisabledMessageResId = b.mDisabledMessageResId;
         mCategories = cloneCategories(b.mCategories);
-        mIntent = b.mIntent;
-        if (mIntent != null) {
-            final Bundle intentExtras = mIntent.getExtras();
-            if (intentExtras != null) {
-                mIntent.replaceExtras((Bundle) null);
-                mIntentPersistableExtras = new PersistableBundle(intentExtras);
-            }
-        }
+        mIntents = cloneIntents(b.mIntents);
+        fixUpIntentExtras();
         mRank = b.mRank;
         mExtras = b.mExtras;
         updateTimestamp();
     }
 
-    private ArraySet<String> cloneCategories(Set<String> source) {
+    /**
+     * Extract extras from {@link #mIntents} and set them to {@link #mIntentPersistableExtrases}
+     * as {@link PersistableBundle}, and remove extras from the original intents.
+     */
+    private void fixUpIntentExtras() {
+        if (mIntents == null) {
+            mIntentPersistableExtrases = null;
+            return;
+        }
+        mIntentPersistableExtrases = new PersistableBundle[mIntents.length];
+        for (int i = 0; i < mIntents.length; i++) {
+            final Intent intent = mIntents[i];
+            final Bundle extras = intent.getExtras();
+            if (extras == null) {
+                mIntentPersistableExtrases[i] = null;
+            } else {
+                mIntentPersistableExtrases[i] = new PersistableBundle(extras);
+                intent.replaceExtras((Bundle) null);
+            }
+        }
+    }
+
+    private static ArraySet<String> cloneCategories(Set<String> source) {
         if (source == null) {
             return null;
         }
@@ -267,6 +283,32 @@
         return ret;
     }
 
+    private static Intent[] cloneIntents(Intent[] intents) {
+        if (intents == null) {
+            return null;
+        }
+        final Intent[] ret = new Intent[intents.length];
+        for (int i = 0; i < ret.length; i++) {
+            if (intents[i] != null) {
+                ret[i] = new Intent(intents[i]);
+            }
+        }
+        return ret;
+    }
+
+    private static PersistableBundle[] clonePersistableBundle(PersistableBundle[] bundle) {
+        if (bundle == null) {
+            return null;
+        }
+        final PersistableBundle[] ret = new PersistableBundle[bundle.length];
+        for (int i = 0; i < ret.length; i++) {
+            if (bundle[i] != null) {
+                ret[i] = new PersistableBundle(bundle[i]);
+            }
+        }
+        return ret;
+    }
+
     /**
      * Throws if any of the mandatory fields is not set.
      *
@@ -278,7 +320,8 @@
         if (mTitle == null && mTitleResId == 0) {
             throw new IllegalArgumentException("Short label must be provided");
         }
-        Preconditions.checkNotNull(mIntent, "Shortcut Intent must be provided");
+        Preconditions.checkNotNull(mIntents, "Shortcut Intent must be provided");
+        Preconditions.checkArgument(mIntents.length > 0, "Shortcut Intent must be provided");
     }
 
     /**
@@ -310,8 +353,9 @@
             mDisabledMessageResId = source.mDisabledMessageResId;
             mCategories = cloneCategories(source.mCategories);
             if ((cloneFlags & CLONE_REMOVE_INTENT) == 0) {
-                mIntent = source.mIntent;
-                mIntentPersistableExtras = source.mIntentPersistableExtras;
+                mIntents = cloneIntents(source.mIntents);
+                mIntentPersistableExtrases =
+                        clonePersistableBundle(source.mIntentPersistableExtrases);
             }
             mRank = source.mRank;
             mExtras = source.mExtras;
@@ -620,9 +664,10 @@
         if (source.mCategories != null) {
             mCategories = cloneCategories(source.mCategories);
         }
-        if (source.mIntent != null) {
-            mIntent = source.mIntent;
-            mIntentPersistableExtras = source.mIntentPersistableExtras;
+        if (source.mIntents != null) {
+            mIntents = cloneIntents(source.mIntents);
+            mIntentPersistableExtrases =
+                    clonePersistableBundle(source.mIntentPersistableExtrases);
         }
         if (source.mRank != RANK_NOT_SET) {
             mRank = source.mRank;
@@ -684,7 +729,7 @@
 
         private Set<String> mCategories;
 
-        private Intent mIntent;
+        private Intent[] mIntents;
 
         private int mRank = RANK_NOT_SET;
 
@@ -912,12 +957,11 @@
          * supported so the system can persist them.
          *
          * @see ShortcutInfo#getIntent()
+         * @see #setIntents(Intent[])
          */
         @NonNull
         public Builder setIntent(@NonNull Intent intent) {
-            mIntent = Preconditions.checkNotNull(intent, "intent cannot be null");
-            Preconditions.checkNotNull(mIntent.getAction(), "intent's action must be set");
-            return this;
+            return setIntents(new Intent[]{intent});
         }
 
         /**
@@ -930,7 +974,15 @@
          */
         @NonNull
         public Builder setIntents(@NonNull Intent[] intents) {
-            throw new RuntimeException("NOT SUPPORTED YET");
+            Preconditions.checkNotNull(intents, "intents cannot be null");
+            Preconditions.checkNotNull(intents.length, "intents cannot be empty");
+            for (Intent intent : intents) {
+                Preconditions.checkNotNull(intent, "intents cannot contain null");
+                Preconditions.checkNotNull(intent.getAction(), "intent's action must be set");
+            }
+            // Make sure always clone incoming intents.
+            mIntents = cloneIntents(intents);
+            return this;
         }
 
         /**
@@ -1098,7 +1150,7 @@
     }
 
     /**
-     * Return the intent.  (Or the last intent set with {@link Builder#setIntents(Intent[])}.
+     * Return the intent. If setIntents() was used, then return the last intent in the array.
      *
      * <p>Launcher applications <b>cannot</b> see the intent.  If a {@link ShortcutInfo} is
      * obtained via {@link LauncherApps}, then this method will always return null.
@@ -1108,13 +1160,12 @@
      */
     @Nullable
     public Intent getIntent() {
-        if (mIntent == null) {
+        if (mIntents == null || mIntents.length == 0) {
             return null;
         }
-        final Intent intent = new Intent(mIntent);
-        intent.replaceExtras(
-                mIntentPersistableExtras != null ? new Bundle(mIntentPersistableExtras) : null);
-        return intent;
+        final int last = mIntents.length - 1;
+        final Intent intent = new Intent(mIntents[last]);
+        return setIntentExtras(intent, mIntentPersistableExtrases[last]);
     }
 
     /**
@@ -1127,27 +1178,34 @@
      * @see Builder#setIntents(Intent[])
      */
     @Nullable
-    public Intent getIntents() {
-        throw new RuntimeException("NOT SUPPORTED YET");
+    public Intent[] getIntents() {
+        final Intent[] ret = new Intent[mIntents.length];
+
+        for (int i = 0; i < ret.length; i++) {
+            ret[i] = new Intent(mIntents[i]);
+            setIntentExtras(ret[i], mIntentPersistableExtrases[i]);
+        }
+
+        return ret;
     }
 
     /**
-     * Return "raw" intent, which is the original intent without the extras.
+     * Return "raw" intents, which is the original intents without the extras.
      * @hide
      */
     @Nullable
-    public Intent getIntentNoExtras() {
-        return mIntent;
+    public Intent[] getIntentsNoExtras() {
+        return mIntents;
     }
 
     /**
-     * The extras in the intent.  We convert extras into {@link PersistableBundle} so we can
+     * The extras in the intents.  We convert extras into {@link PersistableBundle} so we can
      * persist them.
      * @hide
      */
     @Nullable
-    public PersistableBundle getIntentPersistableExtras() {
-        return mIntentPersistableExtras;
+    public PersistableBundle[] getIntentPersistableExtrases() {
+        return mIntentPersistableExtrases;
     }
 
     /**
@@ -1500,19 +1558,22 @@
      *
      * @hide
      */
-    public void setIntent(Intent intent) throws IllegalArgumentException {
-        Preconditions.checkNotNull(intent);
+    public void setIntents(Intent[] intents) throws IllegalArgumentException {
+        Preconditions.checkNotNull(intents);
+        Preconditions.checkArgument(intents.length > 0);
 
-        final Bundle intentExtras = intent.getExtras();
+        mIntents = cloneIntents(intents);
+        fixUpIntentExtras();
+    }
 
-        mIntent = intent;
-
-        if (intentExtras != null) {
+    /** @hide */
+    public static Intent setIntentExtras(Intent intent, PersistableBundle extras) {
+        if (extras == null) {
             intent.replaceExtras((Bundle) null);
-            mIntentPersistableExtras = new PersistableBundle(intentExtras);
         } else {
-            mIntentPersistableExtras = null;
+            intent.replaceExtras(new Bundle(extras));
         }
+        return intent;
     }
 
     /**
@@ -1546,8 +1607,8 @@
         mTextResId = source.readInt();
         mDisabledMessage = source.readCharSequence();
         mDisabledMessageResId = source.readInt();
-        mIntent = source.readParcelable(cl);
-        mIntentPersistableExtras = source.readParcelable(cl);
+        mIntents = source.readParcelableArray(cl, Intent.class);
+        mIntentPersistableExtrases = source.readParcelableArray(cl, PersistableBundle.class);
         mRank = source.readInt();
         mExtras = source.readParcelable(cl);
         mBitmapPath = source.readString();
@@ -1592,8 +1653,8 @@
         dest.writeCharSequence(mDisabledMessage);
         dest.writeInt(mDisabledMessageResId);
 
-        dest.writeParcelable(mIntent, flags);
-        dest.writeParcelable(mIntentPersistableExtras, flags);
+        dest.writeParcelableArray(mIntents, flags);
+        dest.writeParcelableArray(mIntentPersistableExtrases, flags);
         dest.writeInt(mRank);
         dest.writeParcelable(mExtras, flags);
         dest.writeString(mBitmapPath);
@@ -1723,11 +1784,27 @@
         sb.append(", timestamp=");
         sb.append(mLastChangedTimestamp);
 
-        sb.append(", intent=");
-        sb.append(mIntent);
-
-        sb.append(", intentExtras=");
-        sb.append(secure ? "***" : mIntentPersistableExtras);
+        sb.append(", intents=");
+        if (mIntents == null) {
+            sb.append("null");
+        } else {
+            if (secure) {
+                sb.append("size:");
+                sb.append(mIntents.length);
+            } else {
+                final int size = mIntents.length;
+                sb.append("[");
+                String sep = "";
+                for (int i = 0; i < size; i++) {
+                    sb.append(sep);
+                    sep = ", ";
+                    sb.append(mIntents[i]);
+                    sb.append("/");
+                    sb.append(mIntentPersistableExtrases[i]);
+                }
+                sb.append("]");
+            }
+        }
 
         sb.append(", extras=");
         sb.append(mExtras);
@@ -1754,9 +1831,8 @@
             Icon icon, CharSequence title, int titleResId, String titleResName,
             CharSequence text, int textResId, String textResName,
             CharSequence disabledMessage, int disabledMessageResId, String disabledMessageResName,
-            Set<String> categories,
-            Intent intent, PersistableBundle intentPersistableExtras,
-            int rank, PersistableBundle extras, long lastChangedTimestamp,
+            Set<String> categories, Intent[] intentsWithExtras, int rank, PersistableBundle extras,
+            long lastChangedTimestamp,
             int flags, int iconResId, String iconResName, String bitmapPath) {
         mUserId = userId;
         mId = id;
@@ -1773,8 +1849,8 @@
         mDisabledMessageResId = disabledMessageResId;
         mDisabledMessageResName = disabledMessageResName;
         mCategories = cloneCategories(categories);
-        mIntent = intent;
-        mIntentPersistableExtras = intentPersistableExtras;
+        mIntents = cloneIntents(intentsWithExtras);
+        fixUpIntentExtras();
         mRank = rank;
         mExtras = extras;
         mLastChangedTimestamp = lastChangedTimestamp;
diff --git a/core/java/android/content/pm/ShortcutServiceInternal.java b/core/java/android/content/pm/ShortcutServiceInternal.java
index f994d7e..af56105 100644
--- a/core/java/android/content/pm/ShortcutServiceInternal.java
+++ b/core/java/android/content/pm/ShortcutServiceInternal.java
@@ -53,7 +53,8 @@
             @NonNull String callingPackage, @NonNull String packageName,
             @NonNull List<String> shortcutIds, int userId);
 
-    public abstract Intent createShortcutIntent(int launcherUserId, @NonNull String callingPackage,
+    public abstract Intent[] createShortcutIntents(
+            int launcherUserId, @NonNull String callingPackage,
             @NonNull String packageName, @NonNull String shortcutId, int userId);
 
     public abstract void addListener(@NonNull ShortcutChangeListener listener);
diff --git a/core/java/android/os/Parcel.java b/core/java/android/os/Parcel.java
index 74dcc07..f6e6ad6 100644
--- a/core/java/android/os/Parcel.java
+++ b/core/java/android/os/Parcel.java
@@ -36,6 +36,7 @@
 import java.io.ObjectOutputStream;
 import java.io.ObjectStreamClass;
 import java.io.Serializable;
+import java.lang.reflect.Array;
 import java.lang.reflect.Field;
 import java.lang.reflect.Modifier;
 import java.util.ArrayList;
@@ -2571,6 +2572,20 @@
         return p;
     }
 
+    /** @hide */
+    public final <T extends Parcelable> T[] readParcelableArray(ClassLoader loader,
+            Class<T> clazz) {
+        int N = readInt();
+        if (N < 0) {
+            return null;
+        }
+        T[] p = (T[]) Array.newInstance(clazz, N);
+        for (int i = 0; i < N; i++) {
+            p[i] = readParcelable(loader);
+        }
+        return p;
+    }
+
     /**
      * Read and return a new Serializable object from the parcel.
      * @return the Serializable object, or null if the Serializable name
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index d426dd0..59e3096 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -21800,10 +21800,13 @@
         }
 
         @Override
-        public int startActivityAsPackage(String packageName, int userId, Intent intent,
+        public int startActivitiesAsPackage(String packageName, int userId, Intent[] intents,
                 Bundle bOptions) {
-            Preconditions.checkNotNull(intent, "intent");
-            final String resolvedType = intent.resolveTypeIfNeeded(mContext.getContentResolver());
+            Preconditions.checkNotNull(intents, "intents");
+            final String[] resolvedTypes = new String[intents.length];
+            for (int i = 0; i < intents.length; i++) {
+                resolvedTypes[i] = intents[i].resolveTypeIfNeeded(mContext.getContentResolver());
+            }
 
             // UID of the package on user userId.
             // "= 0" is needed because otherwise catch(RemoteException) would make it look like
@@ -21817,9 +21820,8 @@
             }
 
             synchronized (ActivityManagerService.this) {
-                return startActivityInPackage(packageUid, packageName, intent, resolvedType,
-                        /*resultTo*/ null, /*resultWho*/ null, /*requestCode*/ 0, /*startFlags*/ 0,
-                        bOptions, userId, /*container*/ null, /*inTask*/ null);
+                return startActivitiesInPackage(packageUid, packageName, intents, resolvedTypes,
+                        /*resultTo*/ null, bOptions, userId);
             }
         }
     }
diff --git a/services/core/java/com/android/server/pm/LauncherAppsService.java b/services/core/java/com/android/server/pm/LauncherAppsService.java
index 1913b61..b4dd587 100644
--- a/services/core/java/com/android/server/pm/LauncherAppsService.java
+++ b/services/core/java/com/android/server/pm/LauncherAppsService.java
@@ -452,27 +452,28 @@
                 ensureShortcutPermission(callingPackage, userId);
             }
 
-            final Intent intent = mShortcutServiceInternal.createShortcutIntent(getCallingUserId(),
-                    callingPackage, packageName, shortcutId, userId);
-            if (intent == null) {
+            final Intent[] intents = mShortcutServiceInternal.createShortcutIntents(
+                    getCallingUserId(), callingPackage, packageName, shortcutId, userId);
+            if (intents == null || intents.length == 0) {
                 return false;
             }
             // Note the target activity doesn't have to be exported.
 
-            intent.setSourceBounds(sourceBounds);
-            intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+            // TODO Use sourceBounds
 
-            return startShortcutIntentAsPublisher(
-                    intent, packageName, startActivityOptions, userId);
+            intents[0].addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+
+            return startShortcutIntentsAsPublisher(
+                    intents, packageName, startActivityOptions, userId);
         }
 
-        private boolean startShortcutIntentAsPublisher(@NonNull Intent intent,
+        private boolean startShortcutIntentsAsPublisher(@NonNull Intent[] intents,
                 @NonNull String publisherPackage, Bundle startActivityOptions, int userId) {
             final int code;
             final long ident = injectClearCallingIdentity();
             try {
-                code = mActivityManagerInternal.startActivityAsPackage(publisherPackage,
-                        userId, intent, startActivityOptions);
+                code = mActivityManagerInternal.startActivitiesAsPackage(publisherPackage,
+                        userId, intents, startActivityOptions);
                 if (code >= ActivityManager.START_SUCCESS) {
                     return true; // Success
                 } else {
diff --git a/services/core/java/com/android/server/pm/ShortcutPackage.java b/services/core/java/com/android/server/pm/ShortcutPackage.java
index 7d57f33..51c9619 100644
--- a/services/core/java/com/android/server/pm/ShortcutPackage.java
+++ b/services/core/java/com/android/server/pm/ShortcutPackage.java
@@ -23,6 +23,7 @@
 import android.content.pm.PackageInfo;
 import android.content.pm.ShortcutInfo;
 import android.content.res.Resources;
+import android.os.Bundle;
 import android.os.PersistableBundle;
 import android.text.format.Formatter;
 import android.util.ArrayMap;
@@ -63,7 +64,8 @@
     private static final String TAG_VERIFY = ShortcutService.TAG + ".verify";
 
     static final String TAG_ROOT = "package";
-    private static final String TAG_INTENT_EXTRAS = "intent-extras";
+    private static final String TAG_INTENT_EXTRAS_LEGACY = "intent-extras";
+    private static final String TAG_INTENT = "intent";
     private static final String TAG_EXTRAS = "extras";
     private static final String TAG_SHORTCUT = "shortcut";
     private static final String TAG_CATEGORIES = "categories";
@@ -82,7 +84,8 @@
     private static final String ATTR_DISABLED_MESSAGE = "dmessage";
     private static final String ATTR_DISABLED_MESSAGE_RES_ID = "dmessageid";
     private static final String ATTR_DISABLED_MESSAGE_RES_NAME = "dmessagename";
-    private static final String ATTR_INTENT = "intent";
+    private static final String ATTR_INTENT_LEGACY = "intent";
+    private static final String ATTR_INTENT_NO_EXTRA = "intent-base";
     private static final String ATTR_RANK = "rank";
     private static final String ATTR_TIMESTAMP = "timestamp";
     private static final String ATTR_FLAGS = "flags";
@@ -1288,7 +1291,6 @@
                 si.getDisabledMessageResourceId());
         ShortcutService.writeAttr(out, ATTR_DISABLED_MESSAGE_RES_NAME,
                 si.getDisabledMessageResName());
-        ShortcutService.writeAttr(out, ATTR_INTENT, si.getIntentNoExtras());
         ShortcutService.writeAttr(out, ATTR_TIMESTAMP,
                 si.getLastChangedTimestamp());
         if (forBackup) {
@@ -1317,9 +1319,16 @@
                 out.endTag(null, TAG_CATEGORIES);
             }
         }
+        final Intent[] intentsNoExtras = si.getIntentsNoExtras();
+        final PersistableBundle[] intentsExtras = si.getIntentPersistableExtrases();
+        final int numIntents = intentsNoExtras.length;
+        for (int i = 0; i < numIntents; i++) {
+            out.startTag(null, TAG_INTENT);
+            ShortcutService.writeAttr(out, ATTR_INTENT_NO_EXTRA, intentsNoExtras[i]);
+            ShortcutService.writeTagExtra(out, TAG_EXTRAS, intentsExtras[i]);
+            out.endTag(null, TAG_INTENT);
+        }
 
-        ShortcutService.writeTagExtra(out, TAG_INTENT_EXTRAS,
-                si.getIntentPersistableExtras());
         ShortcutService.writeTagExtra(out, TAG_EXTRAS, si.getExtras());
 
         out.endTag(null, TAG_SHORTCUT);
@@ -1382,8 +1391,9 @@
         String disabledMessage;
         int disabledMessageResId;
         String disabledMessageResName;
-        Intent intent;
-        PersistableBundle intentPersistableExtras = null;
+        Intent intentLegacy;
+        PersistableBundle intentPersistableExtrasLegacy = null;
+        ArrayList<Intent> intents = new ArrayList<>();
         int rank;
         PersistableBundle extras = null;
         long lastChangedTimestamp;
@@ -1407,7 +1417,7 @@
                 ATTR_DISABLED_MESSAGE_RES_ID);
         disabledMessageResName = ShortcutService.parseStringAttribute(parser,
                 ATTR_DISABLED_MESSAGE_RES_NAME);
-        intent = ShortcutService.parseIntentAttribute(parser, ATTR_INTENT);
+        intentLegacy = ShortcutService.parseIntentAttributeNoDefault(parser, ATTR_INTENT_LEGACY);
         rank = (int) ShortcutService.parseLongAttribute(parser, ATTR_RANK);
         lastChangedTimestamp = ShortcutService.parseLongAttribute(parser, ATTR_TIMESTAMP);
         flags = (int) ShortcutService.parseLongAttribute(parser, ATTR_FLAGS);
@@ -1429,8 +1439,11 @@
                         depth, type, tag));
             }
             switch (tag) {
-                case TAG_INTENT_EXTRAS:
-                    intentPersistableExtras = PersistableBundle.restoreFromXml(parser);
+                case TAG_INTENT_EXTRAS_LEGACY:
+                    intentPersistableExtrasLegacy = PersistableBundle.restoreFromXml(parser);
+                    continue;
+                case TAG_INTENT:
+                    intents.add(parseIntent(parser));
                     continue;
                 case TAG_EXTRAS:
                     extras = PersistableBundle.restoreFromXml(parser);
@@ -1453,15 +1466,53 @@
             throw ShortcutService.throwForInvalidTag(depth, tag);
         }
 
+        if (intentLegacy != null) {
+            // For the legacy file format which supported only one intent per shortcut.
+            ShortcutInfo.setIntentExtras(intentLegacy, intentPersistableExtrasLegacy);
+            intents.clear();
+            intents.add(intentLegacy);
+        }
+
         return new ShortcutInfo(
                 userId, id, packageName, activityComponent, /* icon =*/ null,
                 title, titleResId, titleResName, text, textResId, textResName,
                 disabledMessage, disabledMessageResId, disabledMessageResName,
-                categories, intent,
-                intentPersistableExtras, rank, extras, lastChangedTimestamp, flags,
+                categories,
+                intents.toArray(new Intent[intents.size()]),
+                rank, extras, lastChangedTimestamp, flags,
                 iconResId, iconResName, bitmapPath);
     }
 
+    private static Intent parseIntent(XmlPullParser parser)
+            throws IOException, XmlPullParserException {
+
+        Intent intent = ShortcutService.parseIntentAttribute(parser,
+                ATTR_INTENT_NO_EXTRA);
+
+        final int outerDepth = parser.getDepth();
+        int type;
+        while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
+                && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
+            if (type != XmlPullParser.START_TAG) {
+                continue;
+            }
+            final int depth = parser.getDepth();
+            final String tag = parser.getName();
+            if (ShortcutService.DEBUG_LOAD) {
+                Slog.d(TAG, String.format("  depth=%d type=%d name=%s",
+                        depth, type, tag));
+            }
+            switch (tag) {
+                case TAG_EXTRAS:
+                    ShortcutInfo.setIntentExtras(intent,
+                            PersistableBundle.restoreFromXml(parser));
+                    continue;
+            }
+            throw ShortcutService.throwForInvalidTag(depth, tag);
+        }
+        return intent;
+    }
+
     @VisibleForTesting
     List<ShortcutInfo> getAllShortcutsForTest() {
         return new ArrayList<>(mShortcuts.values());
diff --git a/services/core/java/com/android/server/pm/ShortcutPackageInfo.java b/services/core/java/com/android/server/pm/ShortcutPackageInfo.java
index 7f5d931..e7b66fc 100644
--- a/services/core/java/com/android/server/pm/ShortcutPackageInfo.java
+++ b/services/core/java/com/android/server/pm/ShortcutPackageInfo.java
@@ -171,7 +171,7 @@
 
         final int versionCode = ShortcutService.parseIntAttribute(parser, ATTR_VERSION);
 
-        final long lastUpdateTime = ShortcutService.parseIntAttribute(
+        final long lastUpdateTime = ShortcutService.parseLongAttribute(
                 parser, ATTR_LAST_UPDATE_TIME);
 
         // When restoring from backup, it's always shadow.
diff --git a/services/core/java/com/android/server/pm/ShortcutParser.java b/services/core/java/com/android/server/pm/ShortcutParser.java
index 3f302d6..2a2a4b2 100644
--- a/services/core/java/com/android/server/pm/ShortcutParser.java
+++ b/services/core/java/com/android/server/pm/ShortcutParser.java
@@ -127,6 +127,7 @@
             ShortcutInfo currentShortcut = null;
 
             Set<String> categories = null;
+            final ArrayList<Intent> intents = new ArrayList<>();
 
             outer:
             while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
@@ -143,9 +144,15 @@
                     final ShortcutInfo si = currentShortcut;
                     currentShortcut = null; // Make sure to null out for the next iteration.
 
-                    if (si.getIntent() == null) {
-                        Log.e(TAG, "Shortcut " + si.getId() + " has no intent. Skipping it.");
-                        continue;
+                    if (si.isEnabled()) {
+                        if (intents.size() == 0) {
+                            Log.e(TAG, "Shortcut " + si.getId() + " has no intent. Skipping it.");
+                            continue;
+                        }
+                    } else {
+                        // Just set the default intent to disabled shortcuts.
+                        intents.clear();
+                        intents.add(new Intent(Intent.ACTION_VIEW));
                     }
 
                     if (numShortcuts >= maxShortcuts) {
@@ -153,6 +160,23 @@
                                 + activityInfo.getComponentName() + ". Skipping the rest.");
                         return result;
                     }
+
+                    // Same flag as what TaskStackBuilder adds.
+                    intents.get(0).addFlags(
+                            Intent.FLAG_ACTIVITY_NEW_TASK |
+                            Intent.FLAG_ACTIVITY_CLEAR_TASK |
+                            Intent.FLAG_ACTIVITY_TASK_ON_HOME);
+                    try {
+                        si.setIntents(intents.toArray(new Intent[intents.size()]));
+                    } catch (RuntimeException e) {
+                        // This shouldn't happen because intents in XML can't have complicated
+                        // extras, but just in case Intent.parseIntent() supports such a thing one
+                        // day.
+                        Log.e(TAG, "Shortcut's extras contain un-persistable values. Skipping it.");
+                        continue;
+                    }
+                    intents.clear();
+
                     if (categories != null) {
                         si.setCategories(categories);
                         categories = null;
@@ -196,17 +220,12 @@
                             }
                         }
                     }
-                    if (!si.isEnabled()) {
-                        // Just set the default intent to disabled shortcuts.
-                        si.setIntent(new Intent(Intent.ACTION_VIEW));
-                    }
                     currentShortcut = si;
                     categories = null;
                     continue;
                 }
                 if (depth == 3 && TAG_INTENT.equals(tag)) {
                     if ((currentShortcut == null)
-                            || (currentShortcut.getIntentNoExtras() != null)
                             || !currentShortcut.isEnabled()) {
                         Log.e(TAG, "Ignoring excessive intent tag.");
                         continue;
@@ -216,17 +235,10 @@
                             parser, attrs);
                     if (TextUtils.isEmpty(intent.getAction())) {
                         Log.e(TAG, "Shortcut intent action must be provided. activity=" + activity);
+                        currentShortcut = null; // Invalidate the current shortcut.
                         continue;
                     }
-                    try {
-                        currentShortcut.setIntent(intent);
-                    } catch (RuntimeException e) {
-                        // This shouldn't happen because intents in XML can't have complicated
-                        // extras, but just in case Intent.parseIntent() supports such a thing one
-                        // day.
-                        Log.e(TAG, "Shortcut's extras contain un-persistable values. Skipping it.");
-                        continue;
-                    }
+                    intents.add(intent);
                     continue;
                 }
                 if (depth == 3 && TAG_CATEGORIES.equals(tag)) {
@@ -345,7 +357,6 @@
                 null, // disabled message res name
                 null, // categories
                 null, // intent
-                null, // intent extras
                 rank,
                 null, // extras
                 service.injectCurrentTimeMillis(),
diff --git a/services/core/java/com/android/server/pm/ShortcutService.java b/services/core/java/com/android/server/pm/ShortcutService.java
index a91e284..e6a9739 100644
--- a/services/core/java/com/android/server/pm/ShortcutService.java
+++ b/services/core/java/com/android/server/pm/ShortcutService.java
@@ -687,7 +687,7 @@
     }
 
     @Nullable
-    static Intent parseIntentAttribute(XmlPullParser parser, String attribute) {
+    static Intent parseIntentAttributeNoDefault(XmlPullParser parser, String attribute) {
         final String value = parseStringAttribute(parser, attribute);
         Intent parsed = null;
         if (!TextUtils.isEmpty(value)) {
@@ -697,6 +697,12 @@
                 Slog.e(TAG, "Error parsing intent", e);
             }
         }
+        return parsed;
+    }
+
+    @Nullable
+    static Intent parseIntentAttribute(XmlPullParser parser, String attribute) {
+        Intent parsed = parseIntentAttributeNoDefault(parser, attribute);
         if (parsed == null) {
             // Default intent.
             parsed = new Intent(Intent.ACTION_VIEW);
@@ -2240,7 +2246,7 @@
         }
 
         @Override
-        public Intent createShortcutIntent(int launcherUserId,
+        public Intent[] createShortcutIntents(int launcherUserId,
                 @NonNull String callingPackage,
                 @NonNull String packageName, @NonNull String shortcutId, int userId) {
             // Calling permission must be checked by LauncherAppsImpl.
@@ -2259,7 +2265,7 @@
                     Log.e(TAG, "Shortcut " + shortcutId + " does not exist or disabled");
                     return null;
                 }
-                return si.getIntent();
+                return si.getIntents();
             }
         }
 
diff --git a/services/tests/servicestests/res/xml/shortcut_error_4.xml b/services/tests/servicestests/res/xml/shortcut_error_4.xml
index 3697bb4..f680e99 100644
--- a/services/tests/servicestests/res/xml/shortcut_error_4.xml
+++ b/services/tests/servicestests/res/xml/shortcut_error_4.xml
@@ -19,7 +19,9 @@
         android:shortcutId="ms1"
         android:shortcutShortLabel="@string/shortcut_title1"
         >
-        <intent android:action="action1" />
+        <intent android:action="action1" >
+            <extra android:name="key1" android:value="value1" />
+        </intent>
     </shortcut>
 
     <!-- Invalid: no intent -->
@@ -28,13 +30,17 @@
         android:shortcutShortLabel="@string/shortcut_title1"
         />
 
-    <!-- Valid: more than one intent; first one will be picked. -->
+    <!-- Valid: more than one intent -->
     <shortcut
         android:shortcutId="ms2"
         android:shortcutShortLabel="@string/shortcut_title1"
         >
-        <intent android:action="action2_1" />
-        <intent android:action="action2_2" />
+        <intent android:action="action2_1" >
+            <extra android:name="key1" android:value="value1" />
+        </intent>
+        <intent android:action="action2_2">
+            <extra android:name="key2" android:value="value2" />
+        </intent>
     </shortcut>
 
     <!-- Valid: disabled shortcut doesn't need an intent -->
@@ -53,11 +59,12 @@
         <intent android:action="action4" />
     </shortcut>
 
-    <!-- Invalid, no intent action -->
+    <!-- Invalid, no intent action (if any of the intents is invalid, the entire shortcut will be invalid.) -->
     <shortcut
         android:shortcutId="ms_ignored2"
         android:shortcutShortLabel="@string/shortcut_title1"
         >
         <intent android:data="x"/>
+        <intent android:action="actionx"/>
     </shortcut>
 </shortcuts>
diff --git a/services/tests/servicestests/src/com/android/server/pm/BaseShortcutManagerTest.java b/services/tests/servicestests/src/com/android/server/pm/BaseShortcutManagerTest.java
index 5864255..ff1c3b6 100644
--- a/services/tests/servicestests/src/com/android/server/pm/BaseShortcutManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/BaseShortcutManagerTest.java
@@ -34,14 +34,12 @@
 import static org.mockito.Mockito.when;
 
 import android.annotation.NonNull;
-import android.annotation.Nullable;
-import android.annotation.RequiresPermission;
 import android.annotation.UserIdInt;
 import android.app.Activity;
-import android.app.ActivityManager;
 import android.app.ActivityManagerInternal;
 import android.app.IUidObserver;
 import android.app.usage.UsageStatsManagerInternal;
+import android.content.ActivityNotFoundException;
 import android.content.BroadcastReceiver;
 import android.content.ComponentName;
 import android.content.Context;
@@ -190,11 +188,6 @@
         }
 
         @Override
-        public void startActivityAsUser(@RequiresPermission Intent intent, @Nullable Bundle options,
-                UserHandle userId) {
-        }
-
-        @Override
         public int getUserId() {
             return UserHandle.USER_SYSTEM;
         }
@@ -706,17 +699,6 @@
         mUnlockedUsers.put(USER_11, true);
         mUnlockedUsers.put(USER_P0, true);
 
-        // Set up mMockActivityManagerInternal.
-        // By default, startActivityAsPackage() will simply forward to startActivityAsUser().
-        doAnswer(new AnswerWithSystemCheck<>(inv -> {
-            mServiceContext.startActivityAsUser(
-                    (Intent) inv.getArguments()[2],
-                    (Bundle) inv.getArguments()[3],
-                    UserHandle.of((Integer) inv.getArguments()[1]));
-            return ActivityManager.START_SUCCESS;
-        })).when(mMockActivityManagerInternal).startActivityAsPackage(anyString(), anyInt(),
-                any(Intent.class), any(Bundle.class));
-
         // Set up resources
         setUpAppResources();
 
@@ -1303,6 +1285,35 @@
         return s;
     }
 
+    protected ShortcutInfo makeShortcutWithIntents(String id, Intent... intents) {
+        return makeShortcut(
+                id, "Title-" + id, /* activity =*/ null, /* icon =*/ null,
+                intents, /* rank =*/ 0);
+    }
+
+    /**
+     * Make a shortcut with details.
+     */
+    protected ShortcutInfo makeShortcut(String id, String title, ComponentName activity,
+            Icon icon, Intent[] intents, int rank) {
+        final ShortcutInfo.Builder  b = new ShortcutInfo.Builder(mClientContext, id)
+                .setActivity(new ComponentName(mClientContext.getPackageName(), "dummy"))
+                .setShortLabel(title)
+                .setRank(rank)
+                .setIntents(intents);
+        if (icon != null) {
+            b.setIcon(icon);
+        }
+        if (activity != null) {
+            b.setActivity(activity);
+        }
+        final ShortcutInfo s = b.build();
+
+        s.setTimestamp(mInjectedCurrentTimeMillis); // HACK
+
+        return s;
+    }
+
     /**
      * Make a shortcut with details.
      */
@@ -1388,33 +1399,53 @@
         assertTrue(getPackageShortcut(packageName, shortcutId, userId) == null);
     }
 
+    protected Intent[] launchShortcutAndGetIntentsInner(Runnable shortcutStarter,
+            @NonNull String packageName, @NonNull String shortcutId, int userId) {
+        reset(mMockActivityManagerInternal);
+        shortcutStarter.run();
+
+        final ArgumentCaptor<Intent[]> intentsCaptor = ArgumentCaptor.forClass(Intent[].class);
+        verify(mMockActivityManagerInternal).startActivitiesAsPackage(
+                eq(packageName),
+                eq(userId),
+                intentsCaptor.capture(),
+                any(Bundle.class));
+        return intentsCaptor.getValue();
+    }
+
+    protected Intent[] launchShortcutAndGetIntents(
+            @NonNull String packageName, @NonNull String shortcutId, int userId) {
+        return launchShortcutAndGetIntentsInner(
+                () -> {
+                    mLauncherApps.startShortcut(packageName, shortcutId, null, null,
+                            UserHandle.of(userId));
+                }, packageName, shortcutId, userId
+        );
+    }
+
     protected Intent launchShortcutAndGetIntent(
             @NonNull String packageName, @NonNull String shortcutId, int userId) {
-        reset(mServiceContext);
-        mLauncherApps.startShortcut(packageName, shortcutId, null, null,
-                UserHandle.of(userId));
+        final Intent[] intents = launchShortcutAndGetIntents(packageName, shortcutId, userId);
+        assertEquals(1, intents.length);
+        return intents[0];
+    }
 
-        final ArgumentCaptor<Intent> intentCaptor = ArgumentCaptor.forClass(Intent.class);
-        verify(mServiceContext).startActivityAsUser(
-                intentCaptor.capture(),
-                any(Bundle.class),
-                eq(UserHandle.of(userId)));
-        return intentCaptor.getValue();
+    protected Intent[] launchShortcutAndGetIntents_withShortcutInfo(
+            @NonNull String packageName, @NonNull String shortcutId, int userId) {
+        return launchShortcutAndGetIntentsInner(
+                () -> {
+                    mLauncherApps.startShortcut(
+                            getShortcutInfoAsLauncher(packageName, shortcutId, userId), null, null);
+                }, packageName, shortcutId, userId
+        );
     }
 
     protected Intent launchShortcutAndGetIntent_withShortcutInfo(
             @NonNull String packageName, @NonNull String shortcutId, int userId) {
-        reset(mServiceContext);
-
-        mLauncherApps.startShortcut(
-                getShortcutInfoAsLauncher(packageName, shortcutId, userId), null, null);
-
-        final ArgumentCaptor<Intent> intentCaptor = ArgumentCaptor.forClass(Intent.class);
-        verify(mServiceContext).startActivityAsUser(
-                intentCaptor.capture(),
-                any(Bundle.class),
-                eq(UserHandle.of(userId)));
-        return intentCaptor.getValue();
+        final Intent[] intents = launchShortcutAndGetIntents_withShortcutInfo(
+                packageName, shortcutId, userId);
+        assertEquals(1, intents.length);
+        return intents[0];
     }
 
     protected void assertShortcutLaunchable(@NonNull String packageName, @NonNull String shortcutId,
@@ -1423,9 +1454,25 @@
         assertNotNull(launchShortcutAndGetIntent_withShortcutInfo(packageName, shortcutId, userId));
     }
 
-    protected void assertShortcutNotLaunchable(@NonNull String packageName,
+    protected void assertShortcutNotLaunched(@NonNull String packageName,
+            @NonNull String shortcutId, int userId) {
+        reset(mMockActivityManagerInternal);
+        try {
+            mLauncherApps.startShortcut(packageName, shortcutId, null, null,
+                    UserHandle.of(userId));
+            fail("ActivityNotFoundException was not thrown");
+        } catch (ActivityNotFoundException expected) {
+        }
+        // This shouldn't have been called.
+        verify(mMockActivityManagerInternal, times(0)).startActivitiesAsPackage(
+                anyString(),
+                anyInt(),
+                any(Intent[].class),
+                any(Bundle.class));
+    }
+
+    protected void assertStartShortcutThrowsException(@NonNull String packageName,
             @NonNull String shortcutId, int userId, Class<?> expectedException) {
-        reset(mServiceContext);
         Exception thrown = null;
         try {
             mLauncherApps.startShortcut(packageName, shortcutId, null, null,
@@ -1433,11 +1480,6 @@
         } catch (Exception e) {
             thrown = e;
         }
-        // This shouldn't have been called.
-        verify(mServiceContext, times(0)).startActivityAsUser(
-                any(Intent.class),
-                any(Bundle.class),
-                any(UserHandle.class));
         assertNotNull("Exception was not thrown", thrown);
         assertEquals("Exception type different", expectedException, thrown.getClass());
     }
diff --git a/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest1.java b/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest1.java
index 55fa625f..5206507 100644
--- a/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest1.java
+++ b/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest1.java
@@ -58,10 +58,12 @@
 import static org.mockito.Matchers.anyString;
 import static org.mockito.Matchers.eq;
 import static org.mockito.Mockito.doAnswer;
+import static org.mockito.Mockito.doReturn;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.reset;
 import static org.mockito.Mockito.times;
 import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
 
 import android.Manifest.permission;
 import android.app.ActivityManager;
@@ -1681,7 +1683,7 @@
                     .areAllPinned()
                     .areAllNotWithKeyFieldsOnly()
                     .areAllDisabled();
-            assertShortcutNotLaunchable(CALLING_PACKAGE_1, "s2", USER_0,
+            assertStartShortcutThrowsException(CALLING_PACKAGE_1, "s2", USER_0,
                     ActivityNotFoundException.class);
 
             // Here, s4 is still enabled and launchable, but s3 is disabled.
@@ -1698,7 +1700,7 @@
                     .selectByIds("s4")
                     .areAllEnabled();
 
-            assertShortcutNotLaunchable(CALLING_PACKAGE_2, "s3", USER_0,
+            assertStartShortcutThrowsException(CALLING_PACKAGE_2, "s3", USER_0,
                     ActivityNotFoundException.class);
             assertShortcutLaunchable(CALLING_PACKAGE_2, "s4", USER_0);
 
@@ -2130,17 +2132,17 @@
             assertShortcutLaunchable(CALLING_PACKAGE_2, "s2", USER_0);
             assertShortcutLaunchable(CALLING_PACKAGE_2, "s3", USER_0);
 
-            assertShortcutNotLaunchable(CALLING_PACKAGE_1, "s1", USER_10,
+            assertStartShortcutThrowsException(CALLING_PACKAGE_1, "s1", USER_10,
                     SecurityException.class);
-            assertShortcutNotLaunchable(CALLING_PACKAGE_1, "s2", USER_10,
+            assertStartShortcutThrowsException(CALLING_PACKAGE_1, "s2", USER_10,
                     SecurityException.class);
-            assertShortcutNotLaunchable(CALLING_PACKAGE_1, "s3", USER_10,
+            assertStartShortcutThrowsException(CALLING_PACKAGE_1, "s3", USER_10,
                     SecurityException.class);
-            assertShortcutNotLaunchable(CALLING_PACKAGE_1, "s4", USER_10,
+            assertStartShortcutThrowsException(CALLING_PACKAGE_1, "s4", USER_10,
                     SecurityException.class);
-            assertShortcutNotLaunchable(CALLING_PACKAGE_1, "s5", USER_10,
+            assertStartShortcutThrowsException(CALLING_PACKAGE_1, "s5", USER_10,
                     SecurityException.class);
-            assertShortcutNotLaunchable(CALLING_PACKAGE_1, "s6", USER_10,
+            assertStartShortcutThrowsException(CALLING_PACKAGE_1, "s6", USER_10,
                     SecurityException.class);
         });
         runWithCaller(LAUNCHER_1, USER_P0, () -> {
@@ -2178,17 +2180,17 @@
             assertShortcutLaunchable(CALLING_PACKAGE_2, "s2", USER_0);
             assertShortcutLaunchable(CALLING_PACKAGE_2, "s3", USER_0);
 
-            assertShortcutNotLaunchable(CALLING_PACKAGE_1, "s1", USER_10,
+            assertStartShortcutThrowsException(CALLING_PACKAGE_1, "s1", USER_10,
                     SecurityException.class);
-            assertShortcutNotLaunchable(CALLING_PACKAGE_1, "s2", USER_10,
+            assertStartShortcutThrowsException(CALLING_PACKAGE_1, "s2", USER_10,
                     SecurityException.class);
-            assertShortcutNotLaunchable(CALLING_PACKAGE_1, "s3", USER_10,
+            assertStartShortcutThrowsException(CALLING_PACKAGE_1, "s3", USER_10,
                     SecurityException.class);
-            assertShortcutNotLaunchable(CALLING_PACKAGE_1, "s4", USER_10,
+            assertStartShortcutThrowsException(CALLING_PACKAGE_1, "s4", USER_10,
                     SecurityException.class);
-            assertShortcutNotLaunchable(CALLING_PACKAGE_1, "s5", USER_10,
+            assertStartShortcutThrowsException(CALLING_PACKAGE_1, "s5", USER_10,
                     SecurityException.class);
-            assertShortcutNotLaunchable(CALLING_PACKAGE_1, "s6", USER_10,
+            assertStartShortcutThrowsException(CALLING_PACKAGE_1, "s6", USER_10,
                     SecurityException.class);
         });
         runWithCaller(LAUNCHER_2, USER_P0, () -> {
@@ -2226,17 +2228,17 @@
             assertShortcutLaunchable(CALLING_PACKAGE_2, "s2", USER_0);
             assertShortcutLaunchable(CALLING_PACKAGE_2, "s3", USER_0);
 
-            assertShortcutNotLaunchable(CALLING_PACKAGE_1, "s1", USER_10,
+            assertStartShortcutThrowsException(CALLING_PACKAGE_1, "s1", USER_10,
                     SecurityException.class);
-            assertShortcutNotLaunchable(CALLING_PACKAGE_1, "s2", USER_10,
+            assertStartShortcutThrowsException(CALLING_PACKAGE_1, "s2", USER_10,
                     SecurityException.class);
-            assertShortcutNotLaunchable(CALLING_PACKAGE_1, "s3", USER_10,
+            assertStartShortcutThrowsException(CALLING_PACKAGE_1, "s3", USER_10,
                     SecurityException.class);
-            assertShortcutNotLaunchable(CALLING_PACKAGE_1, "s4", USER_10,
+            assertStartShortcutThrowsException(CALLING_PACKAGE_1, "s4", USER_10,
                     SecurityException.class);
-            assertShortcutNotLaunchable(CALLING_PACKAGE_1, "s5", USER_10,
+            assertStartShortcutThrowsException(CALLING_PACKAGE_1, "s5", USER_10,
                     SecurityException.class);
-            assertShortcutNotLaunchable(CALLING_PACKAGE_1, "s6", USER_10,
+            assertStartShortcutThrowsException(CALLING_PACKAGE_1, "s6", USER_10,
                     SecurityException.class);
         });
         runWithCaller(LAUNCHER_2, USER_10, () -> {
@@ -2297,26 +2299,26 @@
                     "s1", "s2", "s3");
 
             assertShortcutLaunchable(CALLING_PACKAGE_1, "s1", USER_0);
-            assertShortcutNotLaunchable(CALLING_PACKAGE_1, "s2", USER_0,
+            assertStartShortcutThrowsException(CALLING_PACKAGE_1, "s2", USER_0,
                     ActivityNotFoundException.class);
-            assertShortcutNotLaunchable(CALLING_PACKAGE_1, "s3", USER_0,
+            assertStartShortcutThrowsException(CALLING_PACKAGE_1, "s3", USER_0,
                     ActivityNotFoundException.class);
 
             assertShortcutLaunchable(CALLING_PACKAGE_2, "s1", USER_0);
             assertShortcutLaunchable(CALLING_PACKAGE_2, "s2", USER_0);
             assertShortcutLaunchable(CALLING_PACKAGE_2, "s3", USER_0);
 
-            assertShortcutNotLaunchable(CALLING_PACKAGE_1, "s1", USER_10,
+            assertStartShortcutThrowsException(CALLING_PACKAGE_1, "s1", USER_10,
                     SecurityException.class);
-            assertShortcutNotLaunchable(CALLING_PACKAGE_1, "s2", USER_10,
+            assertStartShortcutThrowsException(CALLING_PACKAGE_1, "s2", USER_10,
                     SecurityException.class);
-            assertShortcutNotLaunchable(CALLING_PACKAGE_1, "s3", USER_10,
+            assertStartShortcutThrowsException(CALLING_PACKAGE_1, "s3", USER_10,
                     SecurityException.class);
-            assertShortcutNotLaunchable(CALLING_PACKAGE_1, "s4", USER_10,
+            assertStartShortcutThrowsException(CALLING_PACKAGE_1, "s4", USER_10,
                     SecurityException.class);
-            assertShortcutNotLaunchable(CALLING_PACKAGE_1, "s5", USER_10,
+            assertStartShortcutThrowsException(CALLING_PACKAGE_1, "s5", USER_10,
                     SecurityException.class);
-            assertShortcutNotLaunchable(CALLING_PACKAGE_1, "s6", USER_10,
+            assertStartShortcutThrowsException(CALLING_PACKAGE_1, "s6", USER_10,
                     SecurityException.class);
         });
         runWithCaller(LAUNCHER_1, USER_P0, () -> {
@@ -2348,24 +2350,24 @@
 
             assertShortcutLaunchable(CALLING_PACKAGE_1, "s1", USER_0);
             assertShortcutLaunchable(CALLING_PACKAGE_1, "s2", USER_0);
-            assertShortcutNotLaunchable(CALLING_PACKAGE_1, "s3", USER_0,
+            assertStartShortcutThrowsException(CALLING_PACKAGE_1, "s3", USER_0,
                     ActivityNotFoundException.class);
 
             assertShortcutLaunchable(CALLING_PACKAGE_2, "s1", USER_0);
             assertShortcutLaunchable(CALLING_PACKAGE_2, "s2", USER_0);
             assertShortcutLaunchable(CALLING_PACKAGE_2, "s3", USER_0);
 
-            assertShortcutNotLaunchable(CALLING_PACKAGE_1, "s1", USER_10,
+            assertStartShortcutThrowsException(CALLING_PACKAGE_1, "s1", USER_10,
                     SecurityException.class);
-            assertShortcutNotLaunchable(CALLING_PACKAGE_1, "s2", USER_10,
+            assertStartShortcutThrowsException(CALLING_PACKAGE_1, "s2", USER_10,
                     SecurityException.class);
-            assertShortcutNotLaunchable(CALLING_PACKAGE_1, "s3", USER_10,
+            assertStartShortcutThrowsException(CALLING_PACKAGE_1, "s3", USER_10,
                     SecurityException.class);
-            assertShortcutNotLaunchable(CALLING_PACKAGE_1, "s4", USER_10,
+            assertStartShortcutThrowsException(CALLING_PACKAGE_1, "s4", USER_10,
                     SecurityException.class);
-            assertShortcutNotLaunchable(CALLING_PACKAGE_1, "s5", USER_10,
+            assertStartShortcutThrowsException(CALLING_PACKAGE_1, "s5", USER_10,
                     SecurityException.class);
-            assertShortcutNotLaunchable(CALLING_PACKAGE_1, "s6", USER_10,
+            assertStartShortcutThrowsException(CALLING_PACKAGE_1, "s6", USER_10,
                     SecurityException.class);
         });
         runWithCaller(LAUNCHER_2, USER_P0, () -> {
@@ -2396,26 +2398,26 @@
                     "s1", "s3");
 
             assertShortcutLaunchable(CALLING_PACKAGE_1, "s1", USER_0);
-            assertShortcutNotLaunchable(CALLING_PACKAGE_1, "s2", USER_0,
+            assertStartShortcutThrowsException(CALLING_PACKAGE_1, "s2", USER_0,
                     ActivityNotFoundException.class);
             assertShortcutLaunchable(CALLING_PACKAGE_1, "s3", USER_0);
 
             assertShortcutLaunchable(CALLING_PACKAGE_2, "s1", USER_0);
-            assertShortcutNotLaunchable(CALLING_PACKAGE_2, "s2", USER_0,
+            assertStartShortcutThrowsException(CALLING_PACKAGE_2, "s2", USER_0,
                     ActivityNotFoundException.class);
             assertShortcutLaunchable(CALLING_PACKAGE_2, "s3", USER_0);
 
-            assertShortcutNotLaunchable(CALLING_PACKAGE_1, "s1", USER_10,
+            assertStartShortcutThrowsException(CALLING_PACKAGE_1, "s1", USER_10,
                     SecurityException.class);
-            assertShortcutNotLaunchable(CALLING_PACKAGE_1, "s2", USER_10,
+            assertStartShortcutThrowsException(CALLING_PACKAGE_1, "s2", USER_10,
                     SecurityException.class);
-            assertShortcutNotLaunchable(CALLING_PACKAGE_1, "s3", USER_10,
+            assertStartShortcutThrowsException(CALLING_PACKAGE_1, "s3", USER_10,
                     SecurityException.class);
-            assertShortcutNotLaunchable(CALLING_PACKAGE_1, "s4", USER_10,
+            assertStartShortcutThrowsException(CALLING_PACKAGE_1, "s4", USER_10,
                     SecurityException.class);
-            assertShortcutNotLaunchable(CALLING_PACKAGE_1, "s5", USER_10,
+            assertStartShortcutThrowsException(CALLING_PACKAGE_1, "s5", USER_10,
                     SecurityException.class);
-            assertShortcutNotLaunchable(CALLING_PACKAGE_1, "s6", USER_10,
+            assertStartShortcutThrowsException(CALLING_PACKAGE_1, "s6", USER_10,
                     SecurityException.class);
         });
         runWithCaller(LAUNCHER_2, USER_10, () -> {
@@ -2432,28 +2434,28 @@
                     /* activity =*/ null, PIN_AND_DYNAMIC), HANDLE_USER_10)),
                     "s1", "s2", "s3");
 
-            assertShortcutNotLaunchable(CALLING_PACKAGE_1, "s1", USER_0,
+            assertStartShortcutThrowsException(CALLING_PACKAGE_1, "s1", USER_0,
                     SecurityException.class);
-            assertShortcutNotLaunchable(CALLING_PACKAGE_1, "s2", USER_0,
+            assertStartShortcutThrowsException(CALLING_PACKAGE_1, "s2", USER_0,
                     SecurityException.class);
-            assertShortcutNotLaunchable(CALLING_PACKAGE_1, "s3", USER_0,
+            assertStartShortcutThrowsException(CALLING_PACKAGE_1, "s3", USER_0,
                     SecurityException.class);
 
-            assertShortcutNotLaunchable(CALLING_PACKAGE_2, "s1", USER_0,
+            assertStartShortcutThrowsException(CALLING_PACKAGE_2, "s1", USER_0,
                     SecurityException.class);
-            assertShortcutNotLaunchable(CALLING_PACKAGE_2, "s2", USER_0,
+            assertStartShortcutThrowsException(CALLING_PACKAGE_2, "s2", USER_0,
                     SecurityException.class);
-            assertShortcutNotLaunchable(CALLING_PACKAGE_2, "s3", USER_0,
+            assertStartShortcutThrowsException(CALLING_PACKAGE_2, "s3", USER_0,
                     SecurityException.class);
 
             assertShortcutLaunchable(CALLING_PACKAGE_1, "s1", USER_10);
             assertShortcutLaunchable(CALLING_PACKAGE_1, "s2", USER_10);
             assertShortcutLaunchable(CALLING_PACKAGE_1, "s3", USER_10);
-            assertShortcutNotLaunchable(CALLING_PACKAGE_1, "s4", USER_10,
+            assertStartShortcutThrowsException(CALLING_PACKAGE_1, "s4", USER_10,
                     ActivityNotFoundException.class);
-            assertShortcutNotLaunchable(CALLING_PACKAGE_1, "s5", USER_10,
+            assertStartShortcutThrowsException(CALLING_PACKAGE_1, "s5", USER_10,
                     ActivityNotFoundException.class);
-            assertShortcutNotLaunchable(CALLING_PACKAGE_1, "s6", USER_10,
+            assertStartShortcutThrowsException(CALLING_PACKAGE_1, "s6", USER_10,
                     ActivityNotFoundException.class);
         });
 
@@ -2490,26 +2492,26 @@
                     "s1", "s2", "s3");
 
             assertShortcutLaunchable(CALLING_PACKAGE_1, "s1", USER_0);
-            assertShortcutNotLaunchable(CALLING_PACKAGE_1, "s2", USER_0,
+            assertStartShortcutThrowsException(CALLING_PACKAGE_1, "s2", USER_0,
                     ActivityNotFoundException.class);
-            assertShortcutNotLaunchable(CALLING_PACKAGE_1, "s3", USER_0,
+            assertStartShortcutThrowsException(CALLING_PACKAGE_1, "s3", USER_0,
                     ActivityNotFoundException.class);
 
             assertShortcutLaunchable(CALLING_PACKAGE_2, "s1", USER_0);
             assertShortcutLaunchable(CALLING_PACKAGE_2, "s2", USER_0);
             assertShortcutLaunchable(CALLING_PACKAGE_2, "s3", USER_0);
 
-            assertShortcutNotLaunchable(CALLING_PACKAGE_1, "s1", USER_10,
+            assertStartShortcutThrowsException(CALLING_PACKAGE_1, "s1", USER_10,
                     SecurityException.class);
-            assertShortcutNotLaunchable(CALLING_PACKAGE_1, "s2", USER_10,
+            assertStartShortcutThrowsException(CALLING_PACKAGE_1, "s2", USER_10,
                     SecurityException.class);
-            assertShortcutNotLaunchable(CALLING_PACKAGE_1, "s3", USER_10,
+            assertStartShortcutThrowsException(CALLING_PACKAGE_1, "s3", USER_10,
                     SecurityException.class);
-            assertShortcutNotLaunchable(CALLING_PACKAGE_1, "s4", USER_10,
+            assertStartShortcutThrowsException(CALLING_PACKAGE_1, "s4", USER_10,
                     SecurityException.class);
-            assertShortcutNotLaunchable(CALLING_PACKAGE_1, "s5", USER_10,
+            assertStartShortcutThrowsException(CALLING_PACKAGE_1, "s5", USER_10,
                     SecurityException.class);
-            assertShortcutNotLaunchable(CALLING_PACKAGE_1, "s6", USER_10,
+            assertStartShortcutThrowsException(CALLING_PACKAGE_1, "s6", USER_10,
                     SecurityException.class);
         });
         runWithCaller(LAUNCHER_1, USER_P0, () -> {
@@ -2541,24 +2543,24 @@
 
             assertShortcutLaunchable(CALLING_PACKAGE_1, "s1", USER_0);
             assertShortcutLaunchable(CALLING_PACKAGE_1, "s2", USER_0);
-            assertShortcutNotLaunchable(CALLING_PACKAGE_1, "s3", USER_0,
+            assertStartShortcutThrowsException(CALLING_PACKAGE_1, "s3", USER_0,
                     ActivityNotFoundException.class);
 
             assertShortcutLaunchable(CALLING_PACKAGE_2, "s1", USER_0);
             assertShortcutLaunchable(CALLING_PACKAGE_2, "s2", USER_0);
             assertShortcutLaunchable(CALLING_PACKAGE_2, "s3", USER_0);
 
-            assertShortcutNotLaunchable(CALLING_PACKAGE_1, "s1", USER_10,
+            assertStartShortcutThrowsException(CALLING_PACKAGE_1, "s1", USER_10,
                     SecurityException.class);
-            assertShortcutNotLaunchable(CALLING_PACKAGE_1, "s2", USER_10,
+            assertStartShortcutThrowsException(CALLING_PACKAGE_1, "s2", USER_10,
                     SecurityException.class);
-            assertShortcutNotLaunchable(CALLING_PACKAGE_1, "s3", USER_10,
+            assertStartShortcutThrowsException(CALLING_PACKAGE_1, "s3", USER_10,
                     SecurityException.class);
-            assertShortcutNotLaunchable(CALLING_PACKAGE_1, "s4", USER_10,
+            assertStartShortcutThrowsException(CALLING_PACKAGE_1, "s4", USER_10,
                     SecurityException.class);
-            assertShortcutNotLaunchable(CALLING_PACKAGE_1, "s5", USER_10,
+            assertStartShortcutThrowsException(CALLING_PACKAGE_1, "s5", USER_10,
                     SecurityException.class);
-            assertShortcutNotLaunchable(CALLING_PACKAGE_1, "s6", USER_10,
+            assertStartShortcutThrowsException(CALLING_PACKAGE_1, "s6", USER_10,
                     SecurityException.class);
         });
         runWithCaller(LAUNCHER_2, USER_P0, () -> {
@@ -2589,26 +2591,26 @@
                     "s1", "s3");
 
             assertShortcutLaunchable(CALLING_PACKAGE_1, "s1", USER_0);
-            assertShortcutNotLaunchable(CALLING_PACKAGE_1, "s2", USER_0,
+            assertStartShortcutThrowsException(CALLING_PACKAGE_1, "s2", USER_0,
                     ActivityNotFoundException.class);
             assertShortcutLaunchable(CALLING_PACKAGE_1, "s3", USER_0);
 
             assertShortcutLaunchable(CALLING_PACKAGE_2, "s1", USER_0);
-            assertShortcutNotLaunchable(CALLING_PACKAGE_2, "s2", USER_0,
+            assertStartShortcutThrowsException(CALLING_PACKAGE_2, "s2", USER_0,
                     ActivityNotFoundException.class);
             assertShortcutLaunchable(CALLING_PACKAGE_2, "s3", USER_0);
 
-            assertShortcutNotLaunchable(CALLING_PACKAGE_1, "s1", USER_10,
+            assertStartShortcutThrowsException(CALLING_PACKAGE_1, "s1", USER_10,
                     SecurityException.class);
-            assertShortcutNotLaunchable(CALLING_PACKAGE_1, "s2", USER_10,
+            assertStartShortcutThrowsException(CALLING_PACKAGE_1, "s2", USER_10,
                     SecurityException.class);
-            assertShortcutNotLaunchable(CALLING_PACKAGE_1, "s3", USER_10,
+            assertStartShortcutThrowsException(CALLING_PACKAGE_1, "s3", USER_10,
                     SecurityException.class);
-            assertShortcutNotLaunchable(CALLING_PACKAGE_1, "s4", USER_10,
+            assertStartShortcutThrowsException(CALLING_PACKAGE_1, "s4", USER_10,
                     SecurityException.class);
-            assertShortcutNotLaunchable(CALLING_PACKAGE_1, "s5", USER_10,
+            assertStartShortcutThrowsException(CALLING_PACKAGE_1, "s5", USER_10,
                     SecurityException.class);
-            assertShortcutNotLaunchable(CALLING_PACKAGE_1, "s6", USER_10,
+            assertStartShortcutThrowsException(CALLING_PACKAGE_1, "s6", USER_10,
                     SecurityException.class);
         });
     }
@@ -2680,10 +2682,8 @@
 
             assertShortcutLaunchable(CALLING_PACKAGE_1, "s3", USER_0);
 
-            assertShortcutNotLaunchable("no-such-package", "s2", USER_0,
-                    ActivityNotFoundException.class);
-            assertShortcutNotLaunchable(CALLING_PACKAGE_1, "xxxx", USER_0,
-                    ActivityNotFoundException.class);
+            assertShortcutNotLaunched("no-such-package", "s2", USER_0);
+            assertShortcutNotLaunched(CALLING_PACKAGE_1, "xxxx", USER_0);
         });
 
         // LAUNCHER_1 is no longer the default launcher
@@ -2710,19 +2710,18 @@
         // Test inner errors.
         runWithCaller(LAUNCHER_1, USER_0, () -> {
             // Not launchable.
-            doAnswer(new AnswerWithSystemCheck<>(inv -> {
-                return ActivityManager.START_CLASS_NOT_FOUND;
-            })).when(mMockActivityManagerInternal).startActivityAsPackage(anyString(), anyInt(),
-                    any(Intent.class), any(Bundle.class));
-            assertShortcutNotLaunchable(CALLING_PACKAGE_1, "s1", USER_0,
+            doReturn(ActivityManager.START_CLASS_NOT_FOUND)
+                    .when(mMockActivityManagerInternal).startActivitiesAsPackage(
+                            anyString(), anyInt(), any(Intent[].class), any(Bundle.class));
+            assertStartShortcutThrowsException(CALLING_PACKAGE_1, "s1", USER_0,
                     ActivityNotFoundException.class);
 
             // Still not launchable.
-            doAnswer(new AnswerWithSystemCheck<>(inv -> {
-                return ActivityManager.START_PERMISSION_DENIED;
-            })).when(mMockActivityManagerInternal).startActivityAsPackage(anyString(), anyInt(),
-                    any(Intent.class), any(Bundle.class));
-            assertShortcutNotLaunchable(CALLING_PACKAGE_1, "s1", USER_0,
+            doReturn(ActivityManager.START_CLASS_NOT_FOUND)
+                    .when(mMockActivityManagerInternal)
+                    .startActivitiesAsPackage(
+                            anyString(), anyInt(), any(Intent[].class), any(Bundle.class));
+            assertStartShortcutThrowsException(CALLING_PACKAGE_1, "s1", USER_0,
                     ActivityNotFoundException.class);
         });
 
@@ -5924,11 +5923,41 @@
                     .areAllEnabled()
                     .forShortcutWithId("ms1", si -> {
                         assertTrue(si.isEnabled());
+                        assertEquals(1, si.getIntents().length);
+
                         assertEquals("action1", si.getIntent().getAction());
+                        assertEquals("value1", si.getIntent().getStringExtra("key1"));
+                        assertEquals(Intent.FLAG_ACTIVITY_NEW_TASK |
+                                Intent.FLAG_ACTIVITY_CLEAR_TASK |
+                                Intent.FLAG_ACTIVITY_TASK_ON_HOME, si.getIntent().getFlags());
+
+                        assertEquals("action1", si.getIntents()[0].getAction());
+                        assertEquals("value1", si.getIntents()[0].getStringExtra("key1"));
+                        assertEquals(Intent.FLAG_ACTIVITY_NEW_TASK |
+                                Intent.FLAG_ACTIVITY_CLEAR_TASK |
+                                Intent.FLAG_ACTIVITY_TASK_ON_HOME, si.getIntents()[0].getFlags());
                     })
                     .forShortcutWithId("ms2", si -> {
                         assertTrue(si.isEnabled());
-                        assertEquals("action2_1", si.getIntent().getAction());
+                        assertEquals(2, si.getIntents().length);
+
+                        // getIntent will return the last one.
+                        assertEquals("action2_2", si.getIntent().getAction());
+                        assertEquals("value2", si.getIntent().getStringExtra("key2"));
+                        assertEquals(0, si.getIntent().getFlags());
+
+                        final Intent i1 = si.getIntents()[0];
+                        final Intent i2 = si.getIntents()[1];
+
+                        assertEquals("action2_1", i1.getAction());
+                        assertEquals("value1", i1.getStringExtra("key1"));
+                        assertEquals(Intent.FLAG_ACTIVITY_NEW_TASK |
+                                        Intent.FLAG_ACTIVITY_CLEAR_TASK |
+                                        Intent.FLAG_ACTIVITY_TASK_ON_HOME, i1.getFlags());
+
+                        assertEquals("action2_2", i2.getAction());
+                        assertEquals("value2", i2.getStringExtra("key2"));
+                        assertEquals(0, i2.getFlags());
                     });
         });
 
@@ -6001,7 +6030,8 @@
                         assertEquals(si.getId(), "action1", si.getIntent().getAction());
                     })
                     .forShortcutWithId("ms2", si -> {
-                        assertEquals(si.getId(), "action2_1", si.getIntent().getAction());
+                        // getIntent returns the last one.
+                        assertEquals(si.getId(), "action2_2", si.getIntent().getAction());
                     })
                     .forShortcutWithId("ms3", si -> {
                         assertEquals(si.getId(), Intent.ACTION_VIEW, si.getIntent().getAction());
diff --git a/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest2.java b/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest2.java
index efd380b..f97355a 100644
--- a/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest2.java
+++ b/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest2.java
@@ -90,7 +90,7 @@
 
         assertExpectException(
                 RuntimeException.class,
-                "intent cannot be null",
+                "intents cannot contain null",
                 () -> new ShortcutInfo.Builder(getTestContext(), "id").setIntent(null));
 
         assertExpectException(
@@ -879,11 +879,16 @@
         final long now = mInjectedCurrentTimeMillis;
         mInjectedCurrentTimeMillis += 1;
 
+        dumpsysOnLogcat("before save");
+
         // Save and load.
         mService.saveDirtyInfo();
         initService();
         mService.handleUnlockUser(USER_10);
 
+        dumpUserFile(USER_10);
+        dumpsysOnLogcat("after load");
+
         ShortcutInfo si;
         si = mService.getPackageShortcutForTest(CALLING_PACKAGE_1, "id", USER_10);
 
@@ -912,6 +917,8 @@
         // to test it.
         si = mService.getPackageShortcutForTest(CALLING_PACKAGE_1, "id2", USER_10);
         assertEquals(1, si.getRank());
+
+        dumpUserFile(USER_10);
     }
 
     public void testShortcutInfoSaveAndLoad_resId() throws InterruptedException {
@@ -1133,7 +1140,30 @@
                     assertEquals(intent.getAction(), si.getIntent().getAction());
                     assertEquals(intent.getData(), si.getIntent().getData());
                     assertEquals(intent.getComponent(), si.getIntent().getComponent());
-                    assertBundlesEqual(intent.getExtras(), si.getExtras());
+                    assertBundlesEqual(intent.getExtras(), si.getIntent().getExtras());
+                });
+    }
+
+    private void checkShortcutInfoSaveAndLoad_intents(Intent... intents) {
+        assertTrue(mManager.setDynamicShortcuts(list(
+                makeShortcutWithIntents("s1", intents))));
+        initService();
+        mService.handleUnlockUser(USER_0);
+
+        assertWith(getCallerShortcuts())
+                .haveIds("s1")
+                .forShortcutWithId("s1", si -> {
+
+                    final Intent[] actual = si.getIntents();
+                    assertEquals(intents.length, actual.length);
+
+                    for (int i = 0; i < intents.length; i++) {
+                        assertEquals(intents[i].getAction(), actual[i].getAction());
+                        assertEquals(intents[i].getData(), actual[i].getData());
+                        assertEquals(intents[i].getComponent(), actual[i].getComponent());
+                        assertEquals(intents[i].getFlags(), actual[i].getFlags());
+                        assertBundlesEqual(intents[i].getExtras(), actual[i].getExtras());
+                    }
                 });
     }
 
@@ -1176,6 +1206,30 @@
                 .putExtras(makeBundle("a", "b")));
 
         mInjectedCurrentTimeMillis += INTERVAL; // reset throttling.
+
+        // Multi-intents
+        checkShortcutInfoSaveAndLoad_intents(
+                new Intent(Intent.ACTION_MAIN).setFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK),
+                new Intent(Intent.ACTION_VIEW).setFlags(Intent.FLAG_ACTIVITY_FORWARD_RESULT)
+        );
+
+        checkShortcutInfoSaveAndLoad_intents(
+                new Intent(Intent.ACTION_MAIN).setFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK)
+                        .setComponent(new ComponentName("a", "b")),
+                new Intent(Intent.ACTION_VIEW)
+                        .setComponent(new ComponentName("a", "b"))
+                );
+
+        checkShortcutInfoSaveAndLoad_intents(
+                new Intent(Intent.ACTION_MAIN)
+                        .setComponent(new ComponentName("a", "b")),
+                new Intent(Intent.ACTION_VIEW).setFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK)
+                        .setComponent(new ComponentName("a", "b")),
+                new Intent("xyz").setFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK
+                        | Intent.FILL_IN_COMPONENT)
+                        .setComponent(new ComponentName("a", "b")).putExtras(
+                        makeBundle("xx", "yy"))
+                );
     }
 
     public void testThrottling() {
diff --git a/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest4.java b/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest4.java
index 54c4b22..583c3d4 100644
--- a/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest4.java
+++ b/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest4.java
@@ -100,7 +100,7 @@
     );
 
     public void testPersistingWeirdCharacters() {
-        final Intent intent = new Intent(Intent.ACTION_VIEW)
+        final Intent intent = new Intent(Intent.ACTION_MAIN)
                 .putExtras(sIntentExtras);
 
         runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
diff --git a/services/tests/shortcutmanagerutils/src/com/android/server/pm/shortcutmanagertest/ShortcutManagerTestUtils.java b/services/tests/shortcutmanagerutils/src/com/android/server/pm/shortcutmanagertest/ShortcutManagerTestUtils.java
index 2f64ad7..ce7adfa 100644
--- a/services/tests/shortcutmanagerutils/src/com/android/server/pm/shortcutmanagertest/ShortcutManagerTestUtils.java
+++ b/services/tests/shortcutmanagerutils/src/com/android/server/pm/shortcutmanagertest/ShortcutManagerTestUtils.java
@@ -861,8 +861,8 @@
         if (b1 == null && b2 == null) {
             return; // pass
         }
-        assertNotNull(b1);
-        assertNotNull(b2);
+        assertNotNull("b1 is null but b2 is not", b1);
+        assertNotNull("b2 is null but b1 is not", b2);
 
         // HashSet makes the error message readable.
         assertEquals(set(b1.keySet()), set(b2.keySet()));
@@ -973,7 +973,8 @@
 
         waitOnMainThread();
 
-        launcherApps.unregisterCallback(asserter.getMockCallback());
+        // TODO unregister doesn't work well during unit tests.  Figure out and fix it.
+        // launcherApps.unregisterCallback(asserter.getMockCallback());
 
         return asserter;
     }