Merge "Stop adding FLAG_ACTIVITY_RESET_TASK_IF_NEEDED when..." into nyc-mr1-dev
diff --git a/api/current.txt b/api/current.txt
index c0fd25b..5263c26 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -10066,6 +10066,7 @@
     method public android.os.PersistableBundle getExtras();
     method public java.lang.String getId();
     method public android.content.Intent getIntent();
+    method public android.content.Intent getIntents();
     method public long getLastChangedTimestamp();
     method public java.lang.CharSequence getLongLabel();
     method public java.lang.String getPackage();
@@ -10092,6 +10093,7 @@
     method public android.content.pm.ShortcutInfo.Builder setExtras(android.os.PersistableBundle);
     method public android.content.pm.ShortcutInfo.Builder setIcon(android.graphics.drawable.Icon);
     method public android.content.pm.ShortcutInfo.Builder setIntent(android.content.Intent);
+    method public android.content.pm.ShortcutInfo.Builder setIntents(android.content.Intent[]);
     method public android.content.pm.ShortcutInfo.Builder setLongLabel(java.lang.CharSequence);
     method public android.content.pm.ShortcutInfo.Builder setRank(int);
     method public android.content.pm.ShortcutInfo.Builder setShortLabel(java.lang.CharSequence);
@@ -10108,6 +10110,7 @@
     method public java.util.List<android.content.pm.ShortcutInfo> getManifestShortcuts();
     method public int getMaxShortcutCountPerActivity();
     method public java.util.List<android.content.pm.ShortcutInfo> getPinnedShortcuts();
+    method public boolean isRateLimitingActive();
     method public void removeAllDynamicShortcuts();
     method public void removeDynamicShortcuts(java.util.List<java.lang.String>);
     method public void reportShortcutUsed(java.lang.String);
diff --git a/api/system-current.txt b/api/system-current.txt
index e407eb4..07a8825 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -10491,6 +10491,7 @@
     method public android.os.PersistableBundle getExtras();
     method public java.lang.String getId();
     method public android.content.Intent getIntent();
+    method public android.content.Intent getIntents();
     method public long getLastChangedTimestamp();
     method public java.lang.CharSequence getLongLabel();
     method public java.lang.String getPackage();
@@ -10517,6 +10518,7 @@
     method public android.content.pm.ShortcutInfo.Builder setExtras(android.os.PersistableBundle);
     method public android.content.pm.ShortcutInfo.Builder setIcon(android.graphics.drawable.Icon);
     method public android.content.pm.ShortcutInfo.Builder setIntent(android.content.Intent);
+    method public android.content.pm.ShortcutInfo.Builder setIntents(android.content.Intent[]);
     method public android.content.pm.ShortcutInfo.Builder setLongLabel(java.lang.CharSequence);
     method public android.content.pm.ShortcutInfo.Builder setRank(int);
     method public android.content.pm.ShortcutInfo.Builder setShortLabel(java.lang.CharSequence);
@@ -10533,6 +10535,7 @@
     method public java.util.List<android.content.pm.ShortcutInfo> getManifestShortcuts();
     method public int getMaxShortcutCountPerActivity();
     method public java.util.List<android.content.pm.ShortcutInfo> getPinnedShortcuts();
+    method public boolean isRateLimitingActive();
     method public void removeAllDynamicShortcuts();
     method public void removeDynamicShortcuts(java.util.List<java.lang.String>);
     method public void reportShortcutUsed(java.lang.String);
diff --git a/api/test-current.txt b/api/test-current.txt
index 53f87f4..9256ba4 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -10079,6 +10079,7 @@
     method public android.os.PersistableBundle getExtras();
     method public java.lang.String getId();
     method public android.content.Intent getIntent();
+    method public android.content.Intent getIntents();
     method public long getLastChangedTimestamp();
     method public java.lang.CharSequence getLongLabel();
     method public java.lang.String getPackage();
@@ -10105,6 +10106,7 @@
     method public android.content.pm.ShortcutInfo.Builder setExtras(android.os.PersistableBundle);
     method public android.content.pm.ShortcutInfo.Builder setIcon(android.graphics.drawable.Icon);
     method public android.content.pm.ShortcutInfo.Builder setIntent(android.content.Intent);
+    method public android.content.pm.ShortcutInfo.Builder setIntents(android.content.Intent[]);
     method public android.content.pm.ShortcutInfo.Builder setLongLabel(java.lang.CharSequence);
     method public android.content.pm.ShortcutInfo.Builder setRank(int);
     method public android.content.pm.ShortcutInfo.Builder setShortLabel(java.lang.CharSequence);
@@ -10122,6 +10124,7 @@
     method public java.util.List<android.content.pm.ShortcutInfo> getManifestShortcuts();
     method public int getMaxShortcutCountPerActivity();
     method public java.util.List<android.content.pm.ShortcutInfo> getPinnedShortcuts();
+    method public boolean isRateLimitingActive();
     method public void removeAllDynamicShortcuts();
     method public void removeDynamicShortcuts(java.util.List<java.lang.String>);
     method public void reportShortcutUsed(java.lang.String);
diff --git a/core/java/android/content/pm/ShortcutInfo.java b/core/java/android/content/pm/ShortcutInfo.java
index f66e1f4..54f1b76 100644
--- a/core/java/android/content/pm/ShortcutInfo.java
+++ b/core/java/android/content/pm/ShortcutInfo.java
@@ -19,6 +19,7 @@
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.annotation.UserIdInt;
+import android.app.TaskStackBuilder;
 import android.content.ComponentName;
 import android.content.Context;
 import android.content.Intent;
@@ -920,6 +921,19 @@
         }
 
         /**
+         * Sets multiple intents instead of a single intent.
+         *
+         * @see Builder#setIntent(Intent)
+         * @see ShortcutInfo#getIntents()
+         * @see Context#startActivities(Intent[])
+         * @see TaskStackBuilder
+         */
+        @NonNull
+        public Builder setIntents(@NonNull Intent[] intents) {
+            throw new RuntimeException("NOT SUPPORTED YET");
+        }
+
+        /**
          * "Rank" of a shortcut, which is a non-negative value that's used by the launcher app
          * to sort shortcuts.
          *
@@ -1084,7 +1098,7 @@
     }
 
     /**
-     * Return the intent.
+     * Return the intent.  (Or the last intent set with {@link Builder#setIntents(Intent[])}.
      *
      * <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.
@@ -1104,6 +1118,20 @@
     }
 
     /**
+     * Return the intent set with {@link Builder#setIntents(Intent[])}.
+     *
+     * <p>Launcher applications <b>cannot</b> see the intents.  If a {@link ShortcutInfo} is
+     * obtained via {@link LauncherApps}, then this method will always return null.
+     * Launchers can only start a shortcut intent with {@link LauncherApps#startShortcut}.
+     *
+     * @see Builder#setIntents(Intent[])
+     */
+    @Nullable
+    public Intent getIntents() {
+        throw new RuntimeException("NOT SUPPORTED YET");
+    }
+
+    /**
      * Return "raw" intent, which is the original intent without the extras.
      * @hide
      */
diff --git a/core/java/android/content/pm/ShortcutManager.java b/core/java/android/content/pm/ShortcutManager.java
index f6c0be0..cfd3442 100644
--- a/core/java/android/content/pm/ShortcutManager.java
+++ b/core/java/android/content/pm/ShortcutManager.java
@@ -614,6 +614,20 @@
     }
 
     /**
+     * Return {@code true} when rate-limiting is active for the caller application.
+     *
+     * <p>See the class level javadoc for details.
+     */
+    public boolean isRateLimitingActive() {
+        try {
+            return mService.getRemainingCallCount(mContext.getPackageName(), injectMyUserId())
+                    == 0;
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
+    /**
      * Return the max width for icons, in pixels.
      */
     public int getIconMaxWidth() {
diff --git a/services/core/java/com/android/server/pm/LauncherAppsService.java b/services/core/java/com/android/server/pm/LauncherAppsService.java
index cff2da9..1913b61 100644
--- a/services/core/java/com/android/server/pm/LauncherAppsService.java
+++ b/services/core/java/com/android/server/pm/LauncherAppsService.java
@@ -17,7 +17,6 @@
 package com.android.server.pm;
 
 import android.annotation.NonNull;
-import android.annotation.Nullable;
 import android.annotation.UserIdInt;
 import android.app.ActivityManager;
 import android.app.ActivityManagerInternal;
@@ -30,7 +29,6 @@
 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;
@@ -461,7 +459,8 @@
             }
             // Note the target activity doesn't have to be exported.
 
-            prepareIntentForLaunch(intent, sourceBounds);
+            intent.setSourceBounds(sourceBounds);
+            intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
 
             return startShortcutIntentAsPublisher(
                     intent, packageName, startActivityOptions, userId);
@@ -521,7 +520,9 @@
 
             Intent launchIntent = new Intent(Intent.ACTION_MAIN);
             launchIntent.addCategory(Intent.CATEGORY_LAUNCHER);
-            prepareIntentForLaunch(launchIntent, sourceBounds);
+            launchIntent.setSourceBounds(sourceBounds);
+            launchIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK
+                    | Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED);
             launchIntent.setPackage(component.getPackageName());
 
             long ident = Binder.clearCallingIdentity();
@@ -562,13 +563,6 @@
             }
         }
 
-        private void prepareIntentForLaunch(@NonNull Intent launchIntent,
-                @Nullable Rect sourceBounds) {
-            launchIntent.setSourceBounds(sourceBounds);
-            launchIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK
-                    | Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED);
-        }
-
         @Override
         public void showAppDetailsAsUser(ComponentName component, Rect sourceBounds,
                 Bundle opts, UserHandle user) throws RemoteException {
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 dc70583..efd380b 100644
--- a/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest2.java
+++ b/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest2.java
@@ -1566,12 +1566,22 @@
                 ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE);
         runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
             assertEquals(3, mManager.getRemainingCallCount());
+            assertFalse(mManager.isRateLimitingActive());
 
             mManager.setDynamicShortcuts(list(makeShortcut("s")));
+
+            assertEquals(2, mManager.getRemainingCallCount());
+            assertFalse(mManager.isRateLimitingActive());
+
             mManager.setDynamicShortcuts(list(makeShortcut("s")));
+
+            assertEquals(1, mManager.getRemainingCallCount());
+            assertFalse(mManager.isRateLimitingActive());
+
             mManager.setDynamicShortcuts(list(makeShortcut("s")));
 
             assertEquals(0, mManager.getRemainingCallCount());
+            assertTrue(mManager.isRateLimitingActive());
         });
         runWithCaller(CALLING_PACKAGE_2, USER_0, () -> {
             assertEquals(3, mManager.getRemainingCallCount());
@@ -1581,6 +1591,7 @@
             mManager.setDynamicShortcuts(list(makeShortcut("s")));
 
             assertEquals(0, mManager.getRemainingCallCount());
+            assertTrue(mManager.isRateLimitingActive());
         });
         runWithCaller(CALLING_PACKAGE_3, USER_0, () -> {
             MoreAsserts.assertNotEqual(3, mManager.getRemainingCallCount());
@@ -1590,6 +1601,7 @@
             mManager.setDynamicShortcuts(list(makeShortcut("s")));
 
             assertEquals(0, mManager.getRemainingCallCount());
+            assertTrue(mManager.isRateLimitingActive());
         });
         runWithCaller(CALLING_PACKAGE_4, USER_0, () -> {
             MoreAsserts.assertNotEqual(3, mManager.getRemainingCallCount());
@@ -1599,6 +1611,7 @@
             mManager.setDynamicShortcuts(list(makeShortcut("s")));
 
             assertEquals(0, mManager.getRemainingCallCount());
+            assertTrue(mManager.isRateLimitingActive());
         });
         runWithCaller(CALLING_PACKAGE_1, USER_P0, () -> {
             MoreAsserts.assertNotEqual(3, mManager.getRemainingCallCount());
@@ -1608,6 +1621,7 @@
             mManager.setDynamicShortcuts(list(makeShortcut("s")));
 
             assertEquals(0, mManager.getRemainingCallCount());
+            assertTrue(mManager.isRateLimitingActive());
         });
         runWithCaller(CALLING_PACKAGE_1, USER_10, () -> {
             assertEquals(3, mManager.getRemainingCallCount());
@@ -1617,6 +1631,7 @@
             mManager.setDynamicShortcuts(list(makeShortcut("s")));
 
             assertEquals(3, mManager.getRemainingCallCount()); // Still 3!
+            assertFalse(mManager.isRateLimitingActive());
         });
     }