Shortcut: Reset throttling upon inline reply

When the user does an "inline reply", we consider the notification
publisher app is "activated" and reset the shortcut throttling.

Bug 28705275

Change-Id: Ic9ffa13635274ead7e9d1e832cd31dea997830aa
diff --git a/core/java/android/content/pm/ShortcutManager.java b/core/java/android/content/pm/ShortcutManager.java
index eaccb3a..36ab804 100644
--- a/core/java/android/content/pm/ShortcutManager.java
+++ b/core/java/android/content/pm/ShortcutManager.java
@@ -17,6 +17,7 @@
 
 import android.annotation.NonNull;
 import android.annotation.TestApi;
+import android.annotation.UserIdInt;
 import android.app.usage.UsageStatsManager;
 import android.content.Context;
 import android.os.RemoteException;
@@ -379,6 +380,22 @@
         }
     }
 
+    /**
+     * Called internally when an application is considered to have come to foreground
+     * even when technically it's not.  This method resets the throttling for this package.
+     * For example, when the user sends an "inline reply" on an notification, the system UI will
+     * call it.
+     *
+     * @hide
+     */
+    public void onApplicationActive(@NonNull String packageName, @UserIdInt int userId) {
+        try {
+            mService.onApplicationActive(packageName, userId);
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
     /** @hide injection point */
     @VisibleForTesting
     protected int injectMyUserId() {
diff --git a/packages/SystemUI/AndroidManifest.xml b/packages/SystemUI/AndroidManifest.xml
index 25dc357..809774b 100644
--- a/packages/SystemUI/AndroidManifest.xml
+++ b/packages/SystemUI/AndroidManifest.xml
@@ -165,6 +165,9 @@
     <!-- the ability to rename notifications posted by other apps -->
     <uses-permission android:name="android.permission.SUBSTITUTE_NOTIFICATION_APP_NAME" />
 
+    <!-- shortcut manager -->
+    <uses-permission android:name="android.permission.RESET_SHORTCUT_MANAGER_THROTTLING" />
+
     <application
         android:name=".SystemUIApplication"
         android:persistent="true"
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/RemoteInputView.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/RemoteInputView.java
index 7704a07..a2289c8 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/RemoteInputView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/RemoteInputView.java
@@ -21,6 +21,7 @@
 import android.app.RemoteInput;
 import android.content.Context;
 import android.content.Intent;
+import android.content.pm.ShortcutManager;
 import android.graphics.Rect;
 import android.graphics.drawable.Drawable;
 import android.os.Bundle;
@@ -132,6 +133,15 @@
         mEditText.mShowImeOnInputConnection = false;
         mController.remoteInputSent(mEntry);
 
+        // Tell ShortcutManager that this package has been "activated".  ShortcutManager
+        // will reset the throttling for this package.
+        // Strictly speaking, the intent receiver may be different from the notification publisher,
+        // but that's an edge case, and also because we can't always know which package will receive
+        // an intent, so we just reset for the publisher.
+        getContext().getSystemService(ShortcutManager.class).onApplicationActive(
+                mEntry.notification.getPackageName(),
+                mEntry.notification.getUser().getIdentifier());
+
         MetricsLogger.action(mContext, MetricsProto.MetricsEvent.ACTION_REMOTE_INPUT_SEND,
                 mEntry.notification.getPackageName());
         try {
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 fe2d1ec..6a0ca11 100644
--- a/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest1.java
+++ b/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest1.java
@@ -4384,11 +4384,11 @@
 
     public void testOnApplicationActive_permission() {
         assertExpectException(SecurityException.class, "Missing permission", () ->
-                mService.onApplicationActive(CALLING_PACKAGE_1, USER_0));
+                mManager.onApplicationActive(CALLING_PACKAGE_1, USER_0));
 
         // Has permission, now it should pass.
         mCallerPermissions.add(permission.RESET_SHORTCUT_MANAGER_THROTTLING);
-        mService.onApplicationActive(CALLING_PACKAGE_1, USER_0);
+        mManager.onApplicationActive(CALLING_PACKAGE_1, USER_0);
     }
 
     public void testDumpsys_crossProfile() {
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 399fddf..45a06eb 100644
--- a/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest2.java
+++ b/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest2.java
@@ -1414,7 +1414,7 @@
 
         // Simulate a call from sys UI.
         mCallerPermissions.add(permission.RESET_SHORTCUT_MANAGER_THROTTLING);
-        mService.onApplicationActive(CALLING_PACKAGE_1, USER_0);
+        mManager.onApplicationActive(CALLING_PACKAGE_1, USER_0);
 
         runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
             assertEquals(3, mManager.getRemainingCallCount());
@@ -1435,7 +1435,7 @@
             MoreAsserts.assertNotEqual(3, mManager.getRemainingCallCount());
         });
 
-        mService.onApplicationActive(CALLING_PACKAGE_3, USER_0);
+        mManager.onApplicationActive(CALLING_PACKAGE_3, USER_0);
 
         runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
             assertEquals(3, mManager.getRemainingCallCount());
@@ -1456,7 +1456,7 @@
             MoreAsserts.assertNotEqual(3, mManager.getRemainingCallCount());
         });
 
-        mService.onApplicationActive(CALLING_PACKAGE_1, USER_10);
+        mManager.onApplicationActive(CALLING_PACKAGE_1, USER_10);
 
         runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
             assertEquals(3, mManager.getRemainingCallCount());