Ensure that SysUI & listeners get the newly updated bubble state
This CL fixes two issues:
1) When bubbles are posted we should note that the notification has
interrupted
2) When the bubble flag state changes it gets propagated to any listeners
Fixes: 131187135
Test: atest NotificationManagerServiceTest
Change-Id: I003a36b9938a4d1f4a69efea463a39fd0df1abda
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java
index 48edf67..e8b054e 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java
@@ -40,6 +40,7 @@
import android.app.ActivityTaskManager;
import android.app.IActivityTaskManager;
import android.app.Notification;
+import android.app.NotificationManager;
import android.content.Context;
import android.content.pm.ParceledListSlice;
import android.content.res.Configuration;
@@ -381,6 +382,10 @@
* @param notif the notification associated with this bubble.
*/
void updateBubble(NotificationEntry notif) {
+ // If this is an interruptive notif, mark that it's interrupted
+ if (notif.importance >= NotificationManager.IMPORTANCE_HIGH) {
+ notif.setInterruption();
+ }
mBubbleData.notificationEntryUpdated(notif);
}
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index 4f85941..13b4ab9 100644
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -23,6 +23,7 @@
import static android.app.Notification.FLAG_FOREGROUND_SERVICE;
import static android.app.Notification.FLAG_NO_CLEAR;
import static android.app.Notification.FLAG_ONGOING_EVENT;
+import static android.app.Notification.FLAG_ONLY_ALERT_ONCE;
import static android.app.NotificationManager.ACTION_APP_BLOCK_STATE_CHANGED;
import static android.app.NotificationManager.ACTION_NOTIFICATION_CHANNEL_BLOCK_STATE_CHANGED;
import static android.app.NotificationManager.ACTION_NOTIFICATION_CHANNEL_GROUP_BLOCK_STATE_CHANGED;
@@ -1031,12 +1032,19 @@
final StatusBarNotification n = r.sbn;
final int callingUid = n.getUid();
final String pkg = n.getPackageName();
+ final boolean wasBubble = r.getNotification().isBubbleNotification();
if (isBubble && isNotificationAppropriateToBubble(r, pkg, callingUid,
null /* oldEntry */)) {
r.getNotification().flags |= FLAG_BUBBLE;
} else {
r.getNotification().flags &= ~FLAG_BUBBLE;
}
+ if (wasBubble != r.getNotification().isBubbleNotification()) {
+ // Add the "alert only once" flag so that the notification won't HUN
+ // unnecessarily just because the bubble flag was changed.
+ r.getNotification().flags |= FLAG_ONLY_ALERT_ONCE;
+ mListeners.notifyPostedLocked(r, r);
+ }
}
}
}
@@ -5732,7 +5740,7 @@
}
// Suppressed because it's a silent update
final Notification notification = record.getNotification();
- if (record.isUpdate && (notification.flags & Notification.FLAG_ONLY_ALERT_ONCE) != 0) {
+ if (record.isUpdate && (notification.flags & FLAG_ONLY_ALERT_ONCE) != 0) {
return false;
}
// Suppressed because another notification in its group handles alerting
@@ -5751,7 +5759,7 @@
boolean shouldMuteNotificationLocked(final NotificationRecord record) {
// Suppressed because it's a silent update
final Notification notification = record.getNotification();
- if (record.isUpdate && (notification.flags & Notification.FLAG_ONLY_ALERT_ONCE) != 0) {
+ if (record.isUpdate && (notification.flags & FLAG_ONLY_ALERT_ONCE) != 0) {
return true;
}
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 d2332bf..3661e89 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
@@ -22,6 +22,7 @@
import static android.app.Notification.CATEGORY_CALL;
import static android.app.Notification.FLAG_BUBBLE;
import static android.app.Notification.FLAG_FOREGROUND_SERVICE;
+import static android.app.Notification.FLAG_ONLY_ALERT_ONCE;
import static android.app.NotificationManager.EXTRA_BLOCKED_STATE;
import static android.app.NotificationManager.IMPORTANCE_DEFAULT;
import static android.app.NotificationManager.IMPORTANCE_HIGH;
@@ -119,7 +120,6 @@
import android.service.notification.Adjustment;
import android.service.notification.NotificationListenerService;
import android.service.notification.NotificationStats;
-import android.service.notification.NotifyingApp;
import android.service.notification.StatusBarNotification;
import android.service.notification.ZenPolicy;
import android.test.suitebuilder.annotation.SmallTest;
@@ -165,10 +165,8 @@
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
-import java.util.HashSet;
import java.util.List;
import java.util.Map;
-import java.util.Set;
import java.util.function.Consumer;
@SmallTest
@@ -5012,6 +5010,9 @@
nr.sbn.getId(), nr.sbn.getNotification(), nr.sbn.getUserId());
waitForIdle();
+ // Reset as this is called when the notif is first sent
+ reset(mListeners);
+
// First we were a bubble
StatusBarNotification[] notifsBefore = mBinderService.getActiveNotifications(PKG);
assertEquals(1, notifsBefore.length);
@@ -5021,10 +5022,13 @@
mService.mNotificationDelegate.onNotificationBubbleChanged(nr.getKey(), false);
waitForIdle();
- // Now we are not a bubble
- StatusBarNotification[] notifsAfter = mBinderService.getActiveNotifications(PKG);
- assertEquals(1, notifsAfter.length);
- assertEquals((notifsAfter[0].getNotification().flags & FLAG_BUBBLE), 0);
+ // Make sure we are not a bubble / reported as such to listeners
+ ArgumentCaptor<NotificationRecord> captor =
+ ArgumentCaptor.forClass(NotificationRecord.class);
+ verify(mListeners, times(1)).notifyPostedLocked(captor.capture(), any());
+
+ assertEquals((captor.getValue().getNotification().flags & FLAG_BUBBLE), 0);
+ assertTrue((captor.getValue().getNotification().flags & FLAG_ONLY_ALERT_ONCE) != 0);
}
@Test
@@ -5054,14 +5058,20 @@
when(mActivityManager.getPackageImportance(nr.sbn.getPackageName())).thenReturn(
IMPORTANCE_FOREGROUND);
+ // Reset as this is called when the notif is first sent
+ reset(mListeners);
+
// Notify we are now a bubble
mService.mNotificationDelegate.onNotificationBubbleChanged(nr.getKey(), true);
waitForIdle();
- // Make sure we are a bubble
- StatusBarNotification[] notifsAfter = mBinderService.getActiveNotifications(PKG);
- assertEquals(1, notifsAfter.length);
- assertTrue((notifsAfter[0].getNotification().flags & FLAG_BUBBLE) != 0);
+ // Make sure we are a bubble / reported as such to listeners
+ ArgumentCaptor<NotificationRecord> captor =
+ ArgumentCaptor.forClass(NotificationRecord.class);
+ verify(mListeners, times(1)).notifyPostedLocked(captor.capture(), any());
+
+ assertTrue((captor.getValue().getNotification().flags & FLAG_BUBBLE) != 0);
+ assertTrue((captor.getValue().getNotification().flags & FLAG_ONLY_ALERT_ONCE) != 0);
}
@Test
@@ -5082,6 +5092,9 @@
nr.sbn.getId(), nr.sbn.getNotification(), nr.sbn.getUserId());
waitForIdle();
+ // Reset as this is called when the notif is first sent
+ reset(mListeners);
+
// Would be a normal notification because wouldn't have met requirements to bubble
StatusBarNotification[] notifsBefore = mBinderService.getActiveNotifications(PKG);
assertEquals(1, notifsBefore.length);
@@ -5095,6 +5108,7 @@
StatusBarNotification[] notifsAfter = mBinderService.getActiveNotifications(PKG);
assertEquals(1, notifsAfter.length);
assertEquals((notifsAfter[0].getNotification().flags & FLAG_BUBBLE), 0);
+ verify(mListeners, times(0)).notifyPostedLocked(any(), any());
}
@Test