Loading packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java +5 −0 Original line number Diff line number Diff line Loading @@ -40,6 +40,7 @@ import android.app.ActivityManager.RunningTaskInfo; 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; Loading Loading @@ -381,6 +382,10 @@ public class BubbleController implements ConfigurationController.ConfigurationLi * @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); } Loading services/core/java/com/android/server/notification/NotificationManagerService.java +10 −2 Original line number Diff line number Diff line Loading @@ -23,6 +23,7 @@ import static android.app.Notification.FLAG_BUBBLE; 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; Loading Loading @@ -1031,12 +1032,19 @@ public class NotificationManagerService extends SystemService { 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); } } } } Loading Loading @@ -5732,7 +5740,7 @@ public class NotificationManagerService extends SystemService { } // 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 Loading @@ -5751,7 +5759,7 @@ public class NotificationManagerService extends SystemService { 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; } Loading services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java +25 −11 Original line number Diff line number Diff line Loading @@ -22,6 +22,7 @@ import static android.app.ActivityManager.RunningAppProcessInfo.IMPORTANCE_VISIB 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; Loading Loading @@ -119,7 +120,6 @@ import android.provider.Settings; 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; Loading Loading @@ -165,10 +165,8 @@ import java.io.FileOutputStream; 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 Loading Loading @@ -5012,6 +5010,9 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { 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); Loading @@ -5021,10 +5022,13 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { 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 Loading Loading @@ -5054,14 +5058,20 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { 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 Loading @@ -5082,6 +5092,9 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { 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); Loading @@ -5095,6 +5108,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { 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 Loading Loading
packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java +5 −0 Original line number Diff line number Diff line Loading @@ -40,6 +40,7 @@ import android.app.ActivityManager.RunningTaskInfo; 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; Loading Loading @@ -381,6 +382,10 @@ public class BubbleController implements ConfigurationController.ConfigurationLi * @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); } Loading
services/core/java/com/android/server/notification/NotificationManagerService.java +10 −2 Original line number Diff line number Diff line Loading @@ -23,6 +23,7 @@ import static android.app.Notification.FLAG_BUBBLE; 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; Loading Loading @@ -1031,12 +1032,19 @@ public class NotificationManagerService extends SystemService { 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); } } } } Loading Loading @@ -5732,7 +5740,7 @@ public class NotificationManagerService extends SystemService { } // 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 Loading @@ -5751,7 +5759,7 @@ public class NotificationManagerService extends SystemService { 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; } Loading
services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java +25 −11 Original line number Diff line number Diff line Loading @@ -22,6 +22,7 @@ import static android.app.ActivityManager.RunningAppProcessInfo.IMPORTANCE_VISIB 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; Loading Loading @@ -119,7 +120,6 @@ import android.provider.Settings; 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; Loading Loading @@ -165,10 +165,8 @@ import java.io.FileOutputStream; 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 Loading Loading @@ -5012,6 +5010,9 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { 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); Loading @@ -5021,10 +5022,13 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { 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 Loading Loading @@ -5054,14 +5058,20 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { 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 Loading @@ -5082,6 +5092,9 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { 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); Loading @@ -5095,6 +5108,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { 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 Loading