Throw ActivityNotFoundException when failed to launch shortcut

Originally the code used IIntentSender, but I had to switch to calling
startActivitiesInPackage() directly, because sendIntentSender() does
not support returning errors.

Bug 30035853

Change-Id: I5d7669c96a2f1805373c71aebf45b97ac1d01ff6
diff --git a/core/java/android/app/ActivityManagerInternal.java b/core/java/android/app/ActivityManagerInternal.java
index 6dd14fd..fc3596e 100644
--- a/core/java/android/app/ActivityManagerInternal.java
+++ b/core/java/android/app/ActivityManagerInternal.java
@@ -165,9 +165,10 @@
             int userId);
 
     /**
-     * Create an {@link IIntentSender} to start an activity, as if {@code packageName} on
-     * user {@code userId} created it.
+     * Start an activity {@code intent} as if {@code packageName} on user {@code userId} did it.
+     *
+     * @return error codes used by {@link IActivityManager#startActivity} and its siblings.
      */
-    public abstract IIntentSender getActivityIntentSenderAsPackage(String packageName,
-            int userId, int requestCode, Intent intent, int flags, Bundle bOptions);
+    public abstract int startActivityAsPackage(String packageName,
+            int userId, Intent intent, Bundle bOptions);
 }
diff --git a/core/java/android/content/pm/ILauncherApps.aidl b/core/java/android/content/pm/ILauncherApps.aidl
index c19e638..430c7e7 100644
--- a/core/java/android/content/pm/ILauncherApps.aidl
+++ b/core/java/android/content/pm/ILauncherApps.aidl
@@ -51,7 +51,7 @@
             in List shortcutIds, in ComponentName componentName, int flags, in UserHandle user);
     void pinShortcuts(String callingPackage, String packageName, in List<String> shortcutIds,
             in UserHandle user);
-    void startShortcut(String callingPackage, String packageName, String id,
+    boolean startShortcut(String callingPackage, String packageName, String id,
             in Rect sourceBounds, in Bundle startActivityOptions, int userId);
 
     int getShortcutIconResId(String callingPackage, String packageName, String id,
diff --git a/core/java/android/content/pm/LauncherApps.java b/core/java/android/content/pm/LauncherApps.java
index 2133222..29b2230 100644
--- a/core/java/android/content/pm/LauncherApps.java
+++ b/core/java/android/content/pm/LauncherApps.java
@@ -20,6 +20,7 @@
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.annotation.TestApi;
+import android.content.ActivityNotFoundException;
 import android.content.ComponentName;
 import android.content.Context;
 import android.content.Intent;
@@ -688,6 +689,9 @@
      * @param sourceBounds The Rect containing the source bounds of the clicked icon.
      * @param startActivityOptions Options to pass to startActivity.
      * @param user The UserHandle of the profile.
+     *
+     * @throws android.content.ActivityNotFoundException failed to start shortcut. (e.g.
+     * the shortcut no longer exists, is disabled, the intent receiver activity doesn't exist, etc)
      */
     public void startShortcut(@NonNull String packageName, @NonNull String shortcutId,
             @Nullable Rect sourceBounds, @Nullable Bundle startActivityOptions,
@@ -705,6 +709,9 @@
      * @param shortcut The target shortcut.
      * @param sourceBounds The Rect containing the source bounds of the clicked icon.
      * @param startActivityOptions Options to pass to startActivity.
+     *
+     * @throws android.content.ActivityNotFoundException failed to start shortcut. (e.g.
+     * the shortcut no longer exists, is disabled, the intent receiver activity doesn't exist, etc)
      */
     public void startShortcut(@NonNull ShortcutInfo shortcut,
             @Nullable Rect sourceBounds, @Nullable Bundle startActivityOptions) {
@@ -717,8 +724,12 @@
             @Nullable Rect sourceBounds, @Nullable Bundle startActivityOptions,
             int userId) {
         try {
-            mService.startShortcut(mContext.getPackageName(), packageName, shortcutId,
+            final boolean success =
+                    mService.startShortcut(mContext.getPackageName(), packageName, shortcutId,
                     sourceBounds, startActivityOptions, userId);
+            if (!success) {
+                throw new ActivityNotFoundException("Shortcut could not be started");
+            }
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         }
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 5bfb90f..cac1f41 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -21788,11 +21788,10 @@
         }
 
         @Override
-        public IIntentSender getActivityIntentSenderAsPackage(
-                String packageName, int userId, int requestCode, Intent intent,
-                int flags, Bundle bOptions) {
-            String resolvedType = intent != null ? intent.resolveTypeIfNeeded(
-                    mContext.getContentResolver()) : null;
+        public int startActivityAsPackage(String packageName, int userId, Intent intent,
+                Bundle bOptions) {
+            Preconditions.checkNotNull(intent, "intent");
+            final String resolvedType = intent.resolveTypeIfNeeded(mContext.getContentResolver());
 
             // UID of the package on user userId.
             // "= 0" is needed because otherwise catch(RemoteException) would make it look like
@@ -21806,11 +21805,9 @@
             }
 
             synchronized (ActivityManagerService.this) {
-                return getIntentSenderLocked(
-                        ActivityManager.INTENT_SENDER_ACTIVITY, packageName, packageUid,
-                        UserHandle.getUserId(packageUid), /*token*/ null, /*resultWho*/ null,
-                        requestCode, new Intent[] {intent}, new String[]{resolvedType},
-                        flags, bOptions);
+                return startActivityInPackage(packageUid, packageName, intent, resolvedType,
+                        /*resultTo*/ null, /*resultWho*/ null, /*requestCode*/ 0, /*startFlags*/ 0,
+                        bOptions, userId, /*container*/ null, /*inTask*/ null);
             }
         }
     }
diff --git a/services/core/java/com/android/server/pm/LauncherAppsService.java b/services/core/java/com/android/server/pm/LauncherAppsService.java
index 03d5645..cff2da9 100644
--- a/services/core/java/com/android/server/pm/LauncherAppsService.java
+++ b/services/core/java/com/android/server/pm/LauncherAppsService.java
@@ -19,19 +19,18 @@
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.annotation.UserIdInt;
+import android.app.ActivityManager;
 import android.app.ActivityManagerInternal;
-import android.app.ActivityManagerNative;
 import android.app.AppGlobals;
-import android.app.PendingIntent;
 import android.content.ComponentName;
 import android.content.Context;
-import android.content.IIntentSender;
 import android.content.Intent;
 import android.content.pm.ActivityInfo;
 import android.content.pm.ApplicationInfo;
 import android.content.pm.ILauncherApps;
 import android.content.pm.IOnAppsChangedListener;
 import android.content.pm.IPackageManager;
+import android.content.pm.LauncherApps;
 import android.content.pm.LauncherApps.ShortcutQuery;
 import android.content.pm.PackageInfo;
 import android.content.pm.PackageManager;
@@ -439,7 +438,7 @@
         }
 
         @Override
-        public void startShortcut(String callingPackage, String packageName, String shortcutId,
+        public boolean startShortcut(String callingPackage, String packageName, String shortcutId,
                 Rect sourceBounds, Bundle startActivityOptions, int userId) {
             verifyCallingPackage(callingPackage);
             ensureInUserProfiles(userId, "Cannot start activity for unrelated profile " + userId);
@@ -458,39 +457,36 @@
             final Intent intent = mShortcutServiceInternal.createShortcutIntent(getCallingUserId(),
                     callingPackage, packageName, shortcutId, userId);
             if (intent == null) {
-                return;
+                return false;
             }
             // Note the target activity doesn't have to be exported.
 
             prepareIntentForLaunch(intent, sourceBounds);
 
-            startShortcutIntentAsPublisher(
+            return startShortcutIntentAsPublisher(
                     intent, packageName, startActivityOptions, userId);
         }
 
-        @VisibleForTesting
-        protected void startShortcutIntentAsPublisher(@NonNull Intent intent,
+        private boolean startShortcutIntentAsPublisher(@NonNull Intent intent,
                 @NonNull String publisherPackage, Bundle startActivityOptions, int userId) {
-
+            final int code;
+            final long ident = injectClearCallingIdentity();
             try {
-                final IIntentSender intentSender;
-
-                final long ident = Binder.clearCallingIdentity();
-                try {
-                    intentSender = mActivityManagerInternal.getActivityIntentSenderAsPackage(
-                            publisherPackage, userId, /* requestCode= */ 0,
-                            intent, PendingIntent.FLAG_ONE_SHOT,
-                            /* options= */ startActivityOptions);
-                } finally {
-                    Binder.restoreCallingIdentity(ident);
+                code = mActivityManagerInternal.startActivityAsPackage(publisherPackage,
+                        userId, intent, startActivityOptions);
+                if (code >= ActivityManager.START_SUCCESS) {
+                    return true; // Success
+                } else {
+                    Log.e(TAG, "Couldn't start activity, code=" + code);
                 }
-
-                // Negative result means a failure.
-                ActivityManagerNative.getDefault().sendIntentSender(
-                        intentSender, 0, null, null, null, null, null);
-
-            } catch (RemoteException e) {
-                return;
+                return code >= ActivityManager.START_SUCCESS;
+            } catch (SecurityException e) {
+                if (DEBUG) {
+                    Slog.d(TAG, "SecurityException while launching intent", e);
+                }
+                return false;
+            } finally {
+                injectRestoreCallingIdentity(ident);
             }
         }
 
diff --git a/services/core/java/com/android/server/pm/ShortcutService.java b/services/core/java/com/android/server/pm/ShortcutService.java
index dda9a5d..a9018b3 100644
--- a/services/core/java/com/android/server/pm/ShortcutService.java
+++ b/services/core/java/com/android/server/pm/ShortcutService.java
@@ -2271,6 +2271,7 @@
                         launcherUserId, callingPackage, packageName, shortcutId, userId);
                 // "si == null" should suffice here, but check the flags too just to make sure.
                 if (si == null || !si.isEnabled() || !si.isAlive()) {
+                    Log.e(TAG, "Shortcut " + shortcutId + " does not exist or disabled");
                     return null;
                 }
                 return si.getIntent();
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 d853f91..3d68b59 100644
--- a/services/tests/servicestests/src/com/android/server/pm/BaseShortcutManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/BaseShortcutManagerTest.java
@@ -38,6 +38,7 @@
 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;
@@ -475,13 +476,6 @@
         void injectRestoreCallingIdentity(long token) {
             mInjectedCallingUid = (int) token;
         }
-
-        @Override
-        protected void startShortcutIntentAsPublisher(@NonNull Intent intent,
-                @NonNull String publisherPackage, Bundle startActivityOptions, int userId) {
-            // Just forward to startActivityAsUser() during unit tests.
-            mContext.startActivityAsUser(intent, startActivityOptions, UserHandle.of(userId));
-        }
     }
 
     protected class LauncherAppsTestable extends LauncherApps {
@@ -709,6 +703,17 @@
         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();
 
@@ -1414,20 +1419,22 @@
     }
 
     protected void assertShortcutNotLaunchable(@NonNull String packageName,
-            @NonNull String shortcutId, int userId) {
+            @NonNull String shortcutId, int userId, Class<?> expectedException) {
         reset(mServiceContext);
+        Exception thrown = null;
         try {
             mLauncherApps.startShortcut(packageName, shortcutId, null, null,
                     UserHandle.of(userId));
-        } catch (SecurityException expected) {
-            // security exception is okay.
-            return;
+        } 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());
     }
 
     protected void assertBitmapDirectories(int userId, String... expectedDirectories) {
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 f5ae706..aa1072e 100644
--- a/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest1.java
+++ b/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest1.java
@@ -54,13 +54,19 @@
 import static com.android.server.pm.shortcutmanagertest.ShortcutManagerTestUtils.waitOnMainThread;
 
 import static org.mockito.Matchers.any;
+import static org.mockito.Matchers.anyInt;
+import static org.mockito.Matchers.anyString;
 import static org.mockito.Matchers.eq;
+import static org.mockito.Mockito.doAnswer;
 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;
+import android.content.ActivityNotFoundException;
 import android.content.ComponentName;
 import android.content.Intent;
 import android.content.pm.ApplicationInfo;
@@ -72,6 +78,7 @@
 import android.graphics.BitmapFactory;
 import android.graphics.drawable.Icon;
 import android.net.Uri;
+import android.os.Bundle;
 import android.os.Handler;
 import android.os.Looper;
 import android.os.UserHandle;
@@ -1666,18 +1673,32 @@
 
         // Get pinned shortcuts from launcher
         runWithCaller(LAUNCHER_1, USER_0, () -> {
-            // CALLING_PACKAGE_1 deleted s2, but it's pinned, so it still exists.
-            assertShortcutIds(assertAllPinned(assertAllNotKeyFieldsOnly(assertAllDisabled(
-                    mLauncherApps.getShortcuts(buildQuery(/* time =*/ 0, CALLING_PACKAGE_1,
-                    /* activity =*/ null, ShortcutQuery.FLAG_GET_PINNED), getCallingUser())))),
-                    "s2");
-            assertShortcutNotLaunchable(CALLING_PACKAGE_1, "s2", USER_0);
+            // CALLING_PACKAGE_1 deleted s2, but it's pinned, so it still exists, and disabled.
+            assertWith(mLauncherApps.getShortcuts(buildQuery(/* time =*/ 0, CALLING_PACKAGE_1,
+                    /* activity =*/ null, ShortcutQuery.FLAG_GET_PINNED), getCallingUser()))
+                    .haveIds("s2")
+                    .areAllPinned()
+                    .areAllNotWithKeyFieldsOnly()
+                    .areAllDisabled();
+            assertShortcutNotLaunchable(CALLING_PACKAGE_1, "s2", USER_0,
+                    ActivityNotFoundException.class);
 
-            assertShortcutIds(assertAllPinned(assertAllNotKeyFieldsOnly(
-                    mLauncherApps.getShortcuts(buildQuery(/* time =*/ 0, CALLING_PACKAGE_2,
-                    /* activity =*/ null, ShortcutQuery.FLAG_GET_PINNED), getCallingUser()))),
-                    "s3", "s4");
-            assertShortcutNotLaunchable(CALLING_PACKAGE_2, "s3", USER_0);
+            // Here, s4 is still enabled and launchable, but s3 is disabled.
+            assertWith(mLauncherApps.getShortcuts(buildQuery(/* time =*/ 0, CALLING_PACKAGE_2,
+                    /* activity =*/ null, ShortcutQuery.FLAG_GET_PINNED), getCallingUser()))
+                    .haveIds("s3", "s4")
+                    .areAllPinned()
+                    .areAllNotWithKeyFieldsOnly()
+
+                    .selectByIds("s3")
+                    .areAllDisabled()
+
+                    .revertToOriginalList()
+                    .selectByIds("s4")
+                    .areAllEnabled();
+
+            assertShortcutNotLaunchable(CALLING_PACKAGE_2, "s3", USER_0,
+                    ActivityNotFoundException.class);
             assertShortcutLaunchable(CALLING_PACKAGE_2, "s4", USER_0);
 
             assertShortcutIds(assertAllPinned(assertAllNotKeyFieldsOnly(assertAllEnabled(
@@ -2108,12 +2129,18 @@
             assertShortcutLaunchable(CALLING_PACKAGE_2, "s2", USER_0);
             assertShortcutLaunchable(CALLING_PACKAGE_2, "s3", USER_0);
 
-            assertShortcutNotLaunchable(CALLING_PACKAGE_1, "s1", USER_10);
-            assertShortcutNotLaunchable(CALLING_PACKAGE_1, "s2", USER_10);
-            assertShortcutNotLaunchable(CALLING_PACKAGE_1, "s3", USER_10);
-            assertShortcutNotLaunchable(CALLING_PACKAGE_1, "s4", USER_10);
-            assertShortcutNotLaunchable(CALLING_PACKAGE_1, "s5", USER_10);
-            assertShortcutNotLaunchable(CALLING_PACKAGE_1, "s6", USER_10);
+            assertShortcutNotLaunchable(CALLING_PACKAGE_1, "s1", USER_10,
+                    SecurityException.class);
+            assertShortcutNotLaunchable(CALLING_PACKAGE_1, "s2", USER_10,
+                    SecurityException.class);
+            assertShortcutNotLaunchable(CALLING_PACKAGE_1, "s3", USER_10,
+                    SecurityException.class);
+            assertShortcutNotLaunchable(CALLING_PACKAGE_1, "s4", USER_10,
+                    SecurityException.class);
+            assertShortcutNotLaunchable(CALLING_PACKAGE_1, "s5", USER_10,
+                    SecurityException.class);
+            assertShortcutNotLaunchable(CALLING_PACKAGE_1, "s6", USER_10,
+                    SecurityException.class);
         });
         runWithCaller(LAUNCHER_1, USER_P0, () -> {
             assertShortcutIds(assertAllPinned(
@@ -2150,12 +2177,18 @@
             assertShortcutLaunchable(CALLING_PACKAGE_2, "s2", USER_0);
             assertShortcutLaunchable(CALLING_PACKAGE_2, "s3", USER_0);
 
-            assertShortcutNotLaunchable(CALLING_PACKAGE_1, "s1", USER_10);
-            assertShortcutNotLaunchable(CALLING_PACKAGE_1, "s2", USER_10);
-            assertShortcutNotLaunchable(CALLING_PACKAGE_1, "s3", USER_10);
-            assertShortcutNotLaunchable(CALLING_PACKAGE_1, "s4", USER_10);
-            assertShortcutNotLaunchable(CALLING_PACKAGE_1, "s5", USER_10);
-            assertShortcutNotLaunchable(CALLING_PACKAGE_1, "s6", USER_10);
+            assertShortcutNotLaunchable(CALLING_PACKAGE_1, "s1", USER_10,
+                    SecurityException.class);
+            assertShortcutNotLaunchable(CALLING_PACKAGE_1, "s2", USER_10,
+                    SecurityException.class);
+            assertShortcutNotLaunchable(CALLING_PACKAGE_1, "s3", USER_10,
+                    SecurityException.class);
+            assertShortcutNotLaunchable(CALLING_PACKAGE_1, "s4", USER_10,
+                    SecurityException.class);
+            assertShortcutNotLaunchable(CALLING_PACKAGE_1, "s5", USER_10,
+                    SecurityException.class);
+            assertShortcutNotLaunchable(CALLING_PACKAGE_1, "s6", USER_10,
+                    SecurityException.class);
         });
         runWithCaller(LAUNCHER_2, USER_P0, () -> {
             assertShortcutIds(assertAllPinned(
@@ -2192,12 +2225,18 @@
             assertShortcutLaunchable(CALLING_PACKAGE_2, "s2", USER_0);
             assertShortcutLaunchable(CALLING_PACKAGE_2, "s3", USER_0);
 
-            assertShortcutNotLaunchable(CALLING_PACKAGE_1, "s1", USER_10);
-            assertShortcutNotLaunchable(CALLING_PACKAGE_1, "s2", USER_10);
-            assertShortcutNotLaunchable(CALLING_PACKAGE_1, "s3", USER_10);
-            assertShortcutNotLaunchable(CALLING_PACKAGE_1, "s4", USER_10);
-            assertShortcutNotLaunchable(CALLING_PACKAGE_1, "s5", USER_10);
-            assertShortcutNotLaunchable(CALLING_PACKAGE_1, "s6", USER_10);
+            assertShortcutNotLaunchable(CALLING_PACKAGE_1, "s1", USER_10,
+                    SecurityException.class);
+            assertShortcutNotLaunchable(CALLING_PACKAGE_1, "s2", USER_10,
+                    SecurityException.class);
+            assertShortcutNotLaunchable(CALLING_PACKAGE_1, "s3", USER_10,
+                    SecurityException.class);
+            assertShortcutNotLaunchable(CALLING_PACKAGE_1, "s4", USER_10,
+                    SecurityException.class);
+            assertShortcutNotLaunchable(CALLING_PACKAGE_1, "s5", USER_10,
+                    SecurityException.class);
+            assertShortcutNotLaunchable(CALLING_PACKAGE_1, "s6", USER_10,
+                    SecurityException.class);
         });
         runWithCaller(LAUNCHER_2, USER_10, () -> {
             assertShortcutIds(assertAllPinned(
@@ -2257,19 +2296,27 @@
                     "s1", "s2", "s3");
 
             assertShortcutLaunchable(CALLING_PACKAGE_1, "s1", USER_0);
-            assertShortcutNotLaunchable(CALLING_PACKAGE_1, "s2", USER_0);
-            assertShortcutNotLaunchable(CALLING_PACKAGE_1, "s3", USER_0);
+            assertShortcutNotLaunchable(CALLING_PACKAGE_1, "s2", USER_0,
+                    ActivityNotFoundException.class);
+            assertShortcutNotLaunchable(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);
-            assertShortcutNotLaunchable(CALLING_PACKAGE_1, "s2", USER_10);
-            assertShortcutNotLaunchable(CALLING_PACKAGE_1, "s3", USER_10);
-            assertShortcutNotLaunchable(CALLING_PACKAGE_1, "s4", USER_10);
-            assertShortcutNotLaunchable(CALLING_PACKAGE_1, "s5", USER_10);
-            assertShortcutNotLaunchable(CALLING_PACKAGE_1, "s6", USER_10);
+            assertShortcutNotLaunchable(CALLING_PACKAGE_1, "s1", USER_10,
+                    SecurityException.class);
+            assertShortcutNotLaunchable(CALLING_PACKAGE_1, "s2", USER_10,
+                    SecurityException.class);
+            assertShortcutNotLaunchable(CALLING_PACKAGE_1, "s3", USER_10,
+                    SecurityException.class);
+            assertShortcutNotLaunchable(CALLING_PACKAGE_1, "s4", USER_10,
+                    SecurityException.class);
+            assertShortcutNotLaunchable(CALLING_PACKAGE_1, "s5", USER_10,
+                    SecurityException.class);
+            assertShortcutNotLaunchable(CALLING_PACKAGE_1, "s6", USER_10,
+                    SecurityException.class);
         });
         runWithCaller(LAUNCHER_1, USER_P0, () -> {
             assertShortcutIds(assertAllPinned(
@@ -2300,18 +2347,25 @@
 
             assertShortcutLaunchable(CALLING_PACKAGE_1, "s1", USER_0);
             assertShortcutLaunchable(CALLING_PACKAGE_1, "s2", USER_0);
-            assertShortcutNotLaunchable(CALLING_PACKAGE_1, "s3", USER_0);
+            assertShortcutNotLaunchable(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);
-            assertShortcutNotLaunchable(CALLING_PACKAGE_1, "s2", USER_10);
-            assertShortcutNotLaunchable(CALLING_PACKAGE_1, "s3", USER_10);
-            assertShortcutNotLaunchable(CALLING_PACKAGE_1, "s4", USER_10);
-            assertShortcutNotLaunchable(CALLING_PACKAGE_1, "s5", USER_10);
-            assertShortcutNotLaunchable(CALLING_PACKAGE_1, "s6", USER_10);
+            assertShortcutNotLaunchable(CALLING_PACKAGE_1, "s1", USER_10,
+                    SecurityException.class);
+            assertShortcutNotLaunchable(CALLING_PACKAGE_1, "s2", USER_10,
+                    SecurityException.class);
+            assertShortcutNotLaunchable(CALLING_PACKAGE_1, "s3", USER_10,
+                    SecurityException.class);
+            assertShortcutNotLaunchable(CALLING_PACKAGE_1, "s4", USER_10,
+                    SecurityException.class);
+            assertShortcutNotLaunchable(CALLING_PACKAGE_1, "s5", USER_10,
+                    SecurityException.class);
+            assertShortcutNotLaunchable(CALLING_PACKAGE_1, "s6", USER_10,
+                    SecurityException.class);
         });
         runWithCaller(LAUNCHER_2, USER_P0, () -> {
             assertShortcutIds(assertAllPinned(
@@ -2341,19 +2395,27 @@
                     "s1", "s3");
 
             assertShortcutLaunchable(CALLING_PACKAGE_1, "s1", USER_0);
-            assertShortcutNotLaunchable(CALLING_PACKAGE_1, "s2", USER_0);
+            assertShortcutNotLaunchable(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);
+            assertShortcutNotLaunchable(CALLING_PACKAGE_2, "s2", USER_0,
+                    ActivityNotFoundException.class);
             assertShortcutLaunchable(CALLING_PACKAGE_2, "s3", USER_0);
 
-            assertShortcutNotLaunchable(CALLING_PACKAGE_1, "s1", USER_10);
-            assertShortcutNotLaunchable(CALLING_PACKAGE_1, "s2", USER_10);
-            assertShortcutNotLaunchable(CALLING_PACKAGE_1, "s3", USER_10);
-            assertShortcutNotLaunchable(CALLING_PACKAGE_1, "s4", USER_10);
-            assertShortcutNotLaunchable(CALLING_PACKAGE_1, "s5", USER_10);
-            assertShortcutNotLaunchable(CALLING_PACKAGE_1, "s6", USER_10);
+            assertShortcutNotLaunchable(CALLING_PACKAGE_1, "s1", USER_10,
+                    SecurityException.class);
+            assertShortcutNotLaunchable(CALLING_PACKAGE_1, "s2", USER_10,
+                    SecurityException.class);
+            assertShortcutNotLaunchable(CALLING_PACKAGE_1, "s3", USER_10,
+                    SecurityException.class);
+            assertShortcutNotLaunchable(CALLING_PACKAGE_1, "s4", USER_10,
+                    SecurityException.class);
+            assertShortcutNotLaunchable(CALLING_PACKAGE_1, "s5", USER_10,
+                    SecurityException.class);
+            assertShortcutNotLaunchable(CALLING_PACKAGE_1, "s6", USER_10,
+                    SecurityException.class);
         });
         runWithCaller(LAUNCHER_2, USER_10, () -> {
             assertShortcutIds(assertAllPinned(
@@ -2369,20 +2431,29 @@
                     /* activity =*/ null, PIN_AND_DYNAMIC), HANDLE_USER_10)),
                     "s1", "s2", "s3");
 
-            assertShortcutNotLaunchable(CALLING_PACKAGE_1, "s1", USER_0);
-            assertShortcutNotLaunchable(CALLING_PACKAGE_1, "s2", USER_0);
-            assertShortcutNotLaunchable(CALLING_PACKAGE_1, "s3", USER_0);
+            assertShortcutNotLaunchable(CALLING_PACKAGE_1, "s1", USER_0,
+                    SecurityException.class);
+            assertShortcutNotLaunchable(CALLING_PACKAGE_1, "s2", USER_0,
+                    SecurityException.class);
+            assertShortcutNotLaunchable(CALLING_PACKAGE_1, "s3", USER_0,
+                    SecurityException.class);
 
-            assertShortcutNotLaunchable(CALLING_PACKAGE_2, "s1", USER_0);
-            assertShortcutNotLaunchable(CALLING_PACKAGE_2, "s2", USER_0);
-            assertShortcutNotLaunchable(CALLING_PACKAGE_2, "s3", USER_0);
+            assertShortcutNotLaunchable(CALLING_PACKAGE_2, "s1", USER_0,
+                    SecurityException.class);
+            assertShortcutNotLaunchable(CALLING_PACKAGE_2, "s2", USER_0,
+                    SecurityException.class);
+            assertShortcutNotLaunchable(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);
-            assertShortcutNotLaunchable(CALLING_PACKAGE_1, "s5", USER_10);
-            assertShortcutNotLaunchable(CALLING_PACKAGE_1, "s6", USER_10);
+            assertShortcutNotLaunchable(CALLING_PACKAGE_1, "s4", USER_10,
+                    ActivityNotFoundException.class);
+            assertShortcutNotLaunchable(CALLING_PACKAGE_1, "s5", USER_10,
+                    ActivityNotFoundException.class);
+            assertShortcutNotLaunchable(CALLING_PACKAGE_1, "s6", USER_10,
+                    ActivityNotFoundException.class);
         });
 
         // Save & load and make sure we still have the same information.
@@ -2418,19 +2489,27 @@
                     "s1", "s2", "s3");
 
             assertShortcutLaunchable(CALLING_PACKAGE_1, "s1", USER_0);
-            assertShortcutNotLaunchable(CALLING_PACKAGE_1, "s2", USER_0);
-            assertShortcutNotLaunchable(CALLING_PACKAGE_1, "s3", USER_0);
+            assertShortcutNotLaunchable(CALLING_PACKAGE_1, "s2", USER_0,
+                    ActivityNotFoundException.class);
+            assertShortcutNotLaunchable(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);
-            assertShortcutNotLaunchable(CALLING_PACKAGE_1, "s2", USER_10);
-            assertShortcutNotLaunchable(CALLING_PACKAGE_1, "s3", USER_10);
-            assertShortcutNotLaunchable(CALLING_PACKAGE_1, "s4", USER_10);
-            assertShortcutNotLaunchable(CALLING_PACKAGE_1, "s5", USER_10);
-            assertShortcutNotLaunchable(CALLING_PACKAGE_1, "s6", USER_10);
+            assertShortcutNotLaunchable(CALLING_PACKAGE_1, "s1", USER_10,
+                    SecurityException.class);
+            assertShortcutNotLaunchable(CALLING_PACKAGE_1, "s2", USER_10,
+                    SecurityException.class);
+            assertShortcutNotLaunchable(CALLING_PACKAGE_1, "s3", USER_10,
+                    SecurityException.class);
+            assertShortcutNotLaunchable(CALLING_PACKAGE_1, "s4", USER_10,
+                    SecurityException.class);
+            assertShortcutNotLaunchable(CALLING_PACKAGE_1, "s5", USER_10,
+                    SecurityException.class);
+            assertShortcutNotLaunchable(CALLING_PACKAGE_1, "s6", USER_10,
+                    SecurityException.class);
         });
         runWithCaller(LAUNCHER_1, USER_P0, () -> {
             assertShortcutIds(assertAllPinned(
@@ -2461,18 +2540,25 @@
 
             assertShortcutLaunchable(CALLING_PACKAGE_1, "s1", USER_0);
             assertShortcutLaunchable(CALLING_PACKAGE_1, "s2", USER_0);
-            assertShortcutNotLaunchable(CALLING_PACKAGE_1, "s3", USER_0);
+            assertShortcutNotLaunchable(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);
-            assertShortcutNotLaunchable(CALLING_PACKAGE_1, "s2", USER_10);
-            assertShortcutNotLaunchable(CALLING_PACKAGE_1, "s3", USER_10);
-            assertShortcutNotLaunchable(CALLING_PACKAGE_1, "s4", USER_10);
-            assertShortcutNotLaunchable(CALLING_PACKAGE_1, "s5", USER_10);
-            assertShortcutNotLaunchable(CALLING_PACKAGE_1, "s6", USER_10);
+            assertShortcutNotLaunchable(CALLING_PACKAGE_1, "s1", USER_10,
+                    SecurityException.class);
+            assertShortcutNotLaunchable(CALLING_PACKAGE_1, "s2", USER_10,
+                    SecurityException.class);
+            assertShortcutNotLaunchable(CALLING_PACKAGE_1, "s3", USER_10,
+                    SecurityException.class);
+            assertShortcutNotLaunchable(CALLING_PACKAGE_1, "s4", USER_10,
+                    SecurityException.class);
+            assertShortcutNotLaunchable(CALLING_PACKAGE_1, "s5", USER_10,
+                    SecurityException.class);
+            assertShortcutNotLaunchable(CALLING_PACKAGE_1, "s6", USER_10,
+                    SecurityException.class);
         });
         runWithCaller(LAUNCHER_2, USER_P0, () -> {
             assertShortcutIds(assertAllPinned(
@@ -2502,80 +2588,143 @@
                     "s1", "s3");
 
             assertShortcutLaunchable(CALLING_PACKAGE_1, "s1", USER_0);
-            assertShortcutNotLaunchable(CALLING_PACKAGE_1, "s2", USER_0);
+            assertShortcutNotLaunchable(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);
+            assertShortcutNotLaunchable(CALLING_PACKAGE_2, "s2", USER_0,
+                    ActivityNotFoundException.class);
             assertShortcutLaunchable(CALLING_PACKAGE_2, "s3", USER_0);
 
-            assertShortcutNotLaunchable(CALLING_PACKAGE_1, "s1", USER_10);
-            assertShortcutNotLaunchable(CALLING_PACKAGE_1, "s2", USER_10);
-            assertShortcutNotLaunchable(CALLING_PACKAGE_1, "s3", USER_10);
-            assertShortcutNotLaunchable(CALLING_PACKAGE_1, "s4", USER_10);
-            assertShortcutNotLaunchable(CALLING_PACKAGE_1, "s5", USER_10);
-            assertShortcutNotLaunchable(CALLING_PACKAGE_1, "s6", USER_10);
+            assertShortcutNotLaunchable(CALLING_PACKAGE_1, "s1", USER_10,
+                    SecurityException.class);
+            assertShortcutNotLaunchable(CALLING_PACKAGE_1, "s2", USER_10,
+                    SecurityException.class);
+            assertShortcutNotLaunchable(CALLING_PACKAGE_1, "s3", USER_10,
+                    SecurityException.class);
+            assertShortcutNotLaunchable(CALLING_PACKAGE_1, "s4", USER_10,
+                    SecurityException.class);
+            assertShortcutNotLaunchable(CALLING_PACKAGE_1, "s5", USER_10,
+                    SecurityException.class);
+            assertShortcutNotLaunchable(CALLING_PACKAGE_1, "s6", USER_10,
+                    SecurityException.class);
         });
     }
 
     public void testStartShortcut() {
         // Create some shortcuts.
-        setCaller(CALLING_PACKAGE_1);
-        final ShortcutInfo s1_1 = makeShortcut(
-                "s1",
-                "Title 1",
-                makeComponent(ShortcutActivity.class),
-                /* icon =*/ null,
-                makeIntent(Intent.ACTION_ASSIST, ShortcutActivity2.class,
-                        "key1", "val1", "nest", makeBundle("key", 123)),
-                /* weight */ 10);
+        runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
+            final ShortcutInfo s1_1 = makeShortcut(
+                    "s1",
+                    "Title 1",
+                    makeComponent(ShortcutActivity.class),
+            /* icon =*/ null,
+                    makeIntent(Intent.ACTION_ASSIST, ShortcutActivity2.class,
+                            "key1", "val1", "nest", makeBundle("key", 123)),
+            /* rank */ 10);
 
-        final ShortcutInfo s1_2 = makeShortcut(
-                "s2",
-                "Title 2",
-                /* activity */ null,
-                /* icon =*/ null,
-                makeIntent(Intent.ACTION_ASSIST, ShortcutActivity3.class),
-                /* weight */ 12);
+            final ShortcutInfo s1_2 = makeShortcut(
+                    "s2",
+                    "Title 2",
+            /* activity */ null,
+            /* icon =*/ null,
+                    makeIntent(Intent.ACTION_ASSIST, ShortcutActivity3.class),
+            /* rank */ 12);
 
-        assertTrue(mManager.setDynamicShortcuts(list(s1_1, s1_2)));
+            final ShortcutInfo s1_3 = makeShortcut("s3");
 
-        setCaller(CALLING_PACKAGE_2);
-        final ShortcutInfo s2_1 = makeShortcut(
-                "s1",
-                "ABC",
-                makeComponent(ShortcutActivity.class),
-                /* icon =*/ null,
-                makeIntent(Intent.ACTION_ANSWER, ShortcutActivity.class,
-                        "key1", "val1", "nest", makeBundle("key", 123)),
-                /* weight */ 10);
-        assertTrue(mManager.setDynamicShortcuts(list(s2_1)));
+            assertTrue(mManager.setDynamicShortcuts(list(s1_1, s1_2, s1_3)));
+        });
 
-        // Pin all.
-        setCaller(LAUNCHER_1);
-        mLauncherApps.pinShortcuts(CALLING_PACKAGE_1,
-                list("s1", "s2"), getCallingUser());
+        runWithCaller(CALLING_PACKAGE_2, USER_0, () -> {
+            final ShortcutInfo s2_1 = makeShortcut(
+                    "s1",
+                    "ABC",
+                    makeComponent(ShortcutActivity.class),
+                    /* icon =*/ null,
+                    makeIntent(Intent.ACTION_ANSWER, ShortcutActivity.class,
+                            "key1", "val1", "nest", makeBundle("key", 123)),
+                    /* weight */ 10);
+            assertTrue(mManager.setDynamicShortcuts(list(s2_1)));
+        });
 
-        mLauncherApps.pinShortcuts(CALLING_PACKAGE_2,
-                list("s1"), getCallingUser());
+        // Pin some.
+        runWithCaller(LAUNCHER_1, USER_0, () -> {
+            mLauncherApps.pinShortcuts(CALLING_PACKAGE_1,
+                    list("s1", "s2"), getCallingUser());
+
+            mLauncherApps.pinShortcuts(CALLING_PACKAGE_2,
+                    list("s1"), getCallingUser());
+        });
 
         // Just to make it complicated, delete some.
-        setCaller(CALLING_PACKAGE_1);
-        mManager.removeDynamicShortcuts(list("s2"));
+        runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
+            mManager.removeDynamicShortcuts(list("s2"));
+        });
 
-        // intent and check.
-        setCaller(LAUNCHER_1);
+        runWithCaller(LAUNCHER_1, USER_0, () -> {
+            assertEquals(
+                    ShortcutActivity2.class.getName(),
+                    launchShortcutAndGetIntent(CALLING_PACKAGE_1, "s1", USER_0)
+                            .getComponent().getClassName());
+            assertEquals(
+                    ShortcutActivity3.class.getName(),
+                    launchShortcutAndGetIntent(CALLING_PACKAGE_1, "s2", USER_0)
+                            .getComponent().getClassName());
+            assertEquals(
+                    ShortcutActivity.class.getName(),
+                    launchShortcutAndGetIntent(CALLING_PACKAGE_2, "s1", USER_0)
+                            .getComponent().getClassName());
 
-        Intent intent;
-        intent = launchShortcutAndGetIntent(CALLING_PACKAGE_1, "s1", USER_0);
-        assertEquals(ShortcutActivity2.class.getName(), intent.getComponent().getClassName());
+            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);
+        });
 
-        intent = launchShortcutAndGetIntent(CALLING_PACKAGE_1, "s2", USER_0);
-        assertEquals(ShortcutActivity3.class.getName(), intent.getComponent().getClassName());
+        // LAUNCHER_1 is no longer the default launcher
+        setDefaultLauncherChecker((pkg, userId) -> false);
 
-        intent = launchShortcutAndGetIntent(CALLING_PACKAGE_2, "s1", USER_0);
-        assertEquals(ShortcutActivity.class.getName(), intent.getComponent().getClassName());
+        runWithCaller(LAUNCHER_1, USER_0, () -> {
+            // Not the default launcher, but pinned shortcuts are still lauchable.
+            assertEquals(
+                    ShortcutActivity2.class.getName(),
+                    launchShortcutAndGetIntent(CALLING_PACKAGE_1, "s1", USER_0)
+                            .getComponent().getClassName());
+            assertEquals(
+                    ShortcutActivity3.class.getName(),
+                    launchShortcutAndGetIntent(CALLING_PACKAGE_1, "s2", USER_0)
+                            .getComponent().getClassName());
+            assertEquals(
+                    ShortcutActivity.class.getName(),
+                    launchShortcutAndGetIntent(CALLING_PACKAGE_2, "s1", USER_0)
+                            .getComponent().getClassName());
+
+            // Not pinned, so not lauchable.
+        });
+
+        // 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,
+                    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,
+                    ActivityNotFoundException.class);
+        });
+
 
         // TODO Check extra, etc
     }