Bubbles policy: require remote input for messaging
Test: atest NotificationManagerServiceTest (& see cts CL)
Bug: 130894746
Change-Id: I196cfaa8f89ee328f96c426ff64f76f937495486
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index 21a862a..3f93a81 100644
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -111,6 +111,7 @@
import android.app.NotificationManager.Policy;
import android.app.PendingIntent;
import android.app.Person;
+import android.app.RemoteInput;
import android.app.StatusBarManager;
import android.app.UriGrantsManager;
import android.app.admin.DeviceAdminInfo;
@@ -4833,17 +4834,35 @@
: null;
boolean isForegroundCall = CATEGORY_CALL.equals(notification.category)
&& (notification.flags & FLAG_FOREGROUND_SERVICE) != 0;
- // OR message style (which always has a person)
+ // OR message style (which always has a person) with any remote input
Class<? extends Notification.Style> style = notification.getNotificationStyle();
boolean isMessageStyle = Notification.MessagingStyle.class.equals(style);
- boolean notificationAppropriateToBubble = isMessageStyle
+ boolean notificationAppropriateToBubble =
+ (isMessageStyle && hasValidRemoteInput(notification))
|| (peopleList != null && !peopleList.isEmpty() && isForegroundCall);
+
// OR something that was previously a bubble & still exists
boolean bubbleUpdate = oldRecord != null
&& (oldRecord.getNotification().flags & FLAG_BUBBLE) != 0;
return canBubble && (notificationAppropriateToBubble || appIsForeground || bubbleUpdate);
}
+ private boolean hasValidRemoteInput(Notification n) {
+ // Also check for inline reply
+ Notification.Action[] actions = n.actions;
+ if (actions != null) {
+ // Get the remote inputs
+ for (int i = 0; i < actions.length; i++) {
+ Notification.Action action = actions[i];
+ RemoteInput[] inputs = action.getRemoteInputs();
+ if (inputs != null && inputs.length > 0) {
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+
private void doChannelWarningToast(CharSequence toastText) {
Binder.withCleanCallingIdentity(() -> {
final int defaultWarningEnabled = Build.IS_DEBUGGABLE ? 1 : 0;
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
index cbca087..1203546d 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
@@ -85,6 +85,7 @@
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.app.Person;
+import android.app.RemoteInput;
import android.app.admin.DevicePolicyManagerInternal;
import android.app.usage.UsageStatsManagerInternal;
import android.companion.ICompanionDeviceManager;
@@ -4492,6 +4493,13 @@
Person person = new Person.Builder()
.setName("bubblebot")
.build();
+ // It needs remote input to be bubble-able
+ RemoteInput remoteInput = new RemoteInput.Builder("reply_key").setLabel("reply").build();
+ PendingIntent inputIntent = PendingIntent.getActivity(mContext, 0, new Intent(), 0);
+ Icon icon = Icon.createWithResource(mContext, android.R.drawable.sym_def_app_icon);
+ Notification.Action replyAction = new Notification.Action.Builder(icon, "Reply",
+ inputIntent).addRemoteInput(remoteInput)
+ .build();
// Make it messaging style
Notification.Builder nb = new Notification.Builder(mContext,
mTestNotificationChannel.getId())
@@ -4504,6 +4512,7 @@
.addMessage("Is it me you're looking for?",
SystemClock.currentThreadTimeMillis(), person)
)
+ .setActions(replyAction)
.setSmallIcon(android.R.drawable.sym_def_app_icon);
StatusBarNotification sbn = new StatusBarNotification(PKG, PKG, 1, null, mUid, 0,