Loading packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/NotificationInterruptStateProvider.java +6 −0 Original line number Diff line number Diff line Loading @@ -60,6 +60,12 @@ public interface NotificationInterruptStateProvider { * FSI even while the device was unlocked. */ NO_FSI_SUPPRESSIVE_GROUP_ALERT_BEHAVIOR(false), /** * Notification should not FSI due to having suppressive BubbleMetadata. This blocks a * potentially malicious use of flags that previously allowed apps to escalate a HUN to an * FSI even while the device was unlocked. */ NO_FSI_SUPPRESSIVE_BUBBLE_METADATA(false), /** * Device screen is off, so the FSI should launch. */ Loading packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/NotificationInterruptStateProviderImpl.java +22 −0 Original line number Diff line number Diff line Loading @@ -18,6 +18,7 @@ package com.android.systemui.statusbar.notification.interruption; import static com.android.systemui.statusbar.StatusBarState.SHADE; import static com.android.systemui.statusbar.notification.interruption.NotificationInterruptStateProviderImpl.NotificationInterruptEvent.FSI_SUPPRESSED_NO_HUN_OR_KEYGUARD; import static com.android.systemui.statusbar.notification.interruption.NotificationInterruptStateProviderImpl.NotificationInterruptEvent.FSI_SUPPRESSED_SUPPRESSIVE_BUBBLE_METADATA; import static com.android.systemui.statusbar.notification.interruption.NotificationInterruptStateProviderImpl.NotificationInterruptEvent.FSI_SUPPRESSED_SUPPRESSIVE_GROUP_ALERT_BEHAVIOR; import static com.android.systemui.statusbar.notification.interruption.NotificationInterruptStateProviderImpl.NotificationInterruptEvent.HUN_SNOOZE_BYPASSED_POTENTIALLY_SUPPRESSED_FSI; Loading Loading @@ -82,6 +83,9 @@ public class NotificationInterruptStateProviderImpl implements NotificationInter @UiEvent(doc = "FSI suppressed for suppressive GroupAlertBehavior") FSI_SUPPRESSED_SUPPRESSIVE_GROUP_ALERT_BEHAVIOR(1235), @UiEvent(doc = "FSI suppressed for suppressive BubbleMetadata") FSI_SUPPRESSED_SUPPRESSIVE_BUBBLE_METADATA(1353), @UiEvent(doc = "FSI suppressed for requiring neither HUN nor keyguard") FSI_SUPPRESSED_NO_HUN_OR_KEYGUARD(1236), Loading Loading @@ -273,6 +277,16 @@ public class NotificationInterruptStateProviderImpl implements NotificationInter suppressedByDND); } // If the notification has suppressive BubbleMetadata, block FSI and warn. Notification.BubbleMetadata bubbleMetadata = sbn.getNotification().getBubbleMetadata(); if (bubbleMetadata != null && bubbleMetadata.isNotificationSuppressed()) { // b/274759612: Detect and report an event when a notification has both an FSI and a // suppressive BubbleMetadata, and now correctly block the FSI from firing. return getDecisionGivenSuppression( FullScreenIntentDecision.NO_FSI_SUPPRESSIVE_BUBBLE_METADATA, suppressedByDND); } // Notification is coming from a suspended package, block FSI if (entry.getRanking().isSuspended()) { return getDecisionGivenSuppression(FullScreenIntentDecision.NO_FSI_SUSPENDED, Loading Loading @@ -351,6 +365,14 @@ public class NotificationInterruptStateProviderImpl implements NotificationInter mLogger.logNoFullscreenWarning(entry, decision + ": GroupAlertBehavior will prevent HUN"); return; case NO_FSI_SUPPRESSIVE_BUBBLE_METADATA: android.util.EventLog.writeEvent(0x534e4554, "274759612", uid, "bubbleMetadata"); mUiEventLogger.log(FSI_SUPPRESSED_SUPPRESSIVE_BUBBLE_METADATA, uid, packageName); mLogger.logNoFullscreenWarning(entry, decision + ": BubbleMetadata may prevent HUN"); return; case NO_FSI_NO_HUN_OR_KEYGUARD: android.util.EventLog.writeEvent(0x534e4554, "231322873", uid, "no hun or keyguard"); Loading packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/interruption/NotificationInterruptStateProviderImplTest.java +37 −0 Original line number Diff line number Diff line Loading @@ -655,6 +655,39 @@ public class NotificationInterruptStateProviderImplTest extends SysuiTestCase { assertThat(fakeUiEvent.packageName).isEqualTo(entry.getSbn().getPackageName()); } @Test public void testShouldNotFullScreen_isSuppressedByBubbleMetadata_withStrictFlag() { when(mFlags.fullScreenIntentRequiresKeyguard()).thenReturn(true); testShouldNotFullScreen_isSuppressedByBubbleMetadata(); } @Test public void testShouldNotFullScreen_isSuppressedByBubbleMetadata() { NotificationEntry entry = createFsiNotification(IMPORTANCE_HIGH, /* silenced */ false); Notification.BubbleMetadata bubbleMetadata = new Notification.BubbleMetadata.Builder("foo") .setSuppressNotification(true).build(); entry.getSbn().getNotification().setBubbleMetadata(bubbleMetadata); when(mPowerManager.isInteractive()).thenReturn(false); when(mStatusBarStateController.isDreaming()).thenReturn(true); when(mStatusBarStateController.getState()).thenReturn(KEYGUARD); assertThat(mNotifInterruptionStateProvider.getFullScreenIntentDecision(entry)) .isEqualTo(FullScreenIntentDecision.NO_FSI_SUPPRESSIVE_BUBBLE_METADATA); assertThat(mNotifInterruptionStateProvider.shouldLaunchFullScreenIntentWhenAdded(entry)) .isFalse(); verify(mLogger, never()).logNoFullscreen(any(), any()); verify(mLogger).logNoFullscreenWarning(entry, "NO_FSI_SUPPRESSIVE_BUBBLE_METADATA: BubbleMetadata may prevent HUN"); verify(mLogger, never()).logFullscreen(any(), any()); assertThat(mUiEventLoggerFake.numLogs()).isEqualTo(1); UiEventLoggerFake.FakeUiEvent fakeUiEvent = mUiEventLoggerFake.get(0); assertThat(fakeUiEvent.eventId).isEqualTo( NotificationInterruptEvent.FSI_SUPPRESSED_SUPPRESSIVE_BUBBLE_METADATA.getId()); assertThat(fakeUiEvent.uid).isEqualTo(entry.getSbn().getUid()); assertThat(fakeUiEvent.packageName).isEqualTo(entry.getSbn().getPackageName()); } @Test public void testShouldFullScreen_notInteractive_withStrictFlag() throws Exception { when(mFlags.fullScreenIntentRequiresKeyguard()).thenReturn(true); Loading @@ -664,6 +697,9 @@ public class NotificationInterruptStateProviderImplTest extends SysuiTestCase { @Test public void testShouldFullScreen_notInteractive() throws RemoteException { NotificationEntry entry = createFsiNotification(IMPORTANCE_HIGH, /* silenced */ false); Notification.BubbleMetadata bubbleMetadata = new Notification.BubbleMetadata.Builder("foo") .setSuppressNotification(false).build(); entry.getSbn().getNotification().setBubbleMetadata(bubbleMetadata); when(mPowerManager.isInteractive()).thenReturn(false); when(mStatusBarStateController.isDreaming()).thenReturn(false); when(mStatusBarStateController.getState()).thenReturn(SHADE); Loading Loading @@ -897,6 +933,7 @@ public class NotificationInterruptStateProviderImplTest extends SysuiTestCase { NotificationEntry entry = createFsiNotification(IMPORTANCE_HIGH, /* silenced */ false); Set<FullScreenIntentDecision> warnings = new HashSet<>(Arrays.asList( FullScreenIntentDecision.NO_FSI_SUPPRESSIVE_GROUP_ALERT_BEHAVIOR, FullScreenIntentDecision.NO_FSI_SUPPRESSIVE_BUBBLE_METADATA, FullScreenIntentDecision.NO_FSI_NO_HUN_OR_KEYGUARD )); for (FullScreenIntentDecision decision : FullScreenIntentDecision.values()) { Loading Loading
packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/NotificationInterruptStateProvider.java +6 −0 Original line number Diff line number Diff line Loading @@ -60,6 +60,12 @@ public interface NotificationInterruptStateProvider { * FSI even while the device was unlocked. */ NO_FSI_SUPPRESSIVE_GROUP_ALERT_BEHAVIOR(false), /** * Notification should not FSI due to having suppressive BubbleMetadata. This blocks a * potentially malicious use of flags that previously allowed apps to escalate a HUN to an * FSI even while the device was unlocked. */ NO_FSI_SUPPRESSIVE_BUBBLE_METADATA(false), /** * Device screen is off, so the FSI should launch. */ Loading
packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/NotificationInterruptStateProviderImpl.java +22 −0 Original line number Diff line number Diff line Loading @@ -18,6 +18,7 @@ package com.android.systemui.statusbar.notification.interruption; import static com.android.systemui.statusbar.StatusBarState.SHADE; import static com.android.systemui.statusbar.notification.interruption.NotificationInterruptStateProviderImpl.NotificationInterruptEvent.FSI_SUPPRESSED_NO_HUN_OR_KEYGUARD; import static com.android.systemui.statusbar.notification.interruption.NotificationInterruptStateProviderImpl.NotificationInterruptEvent.FSI_SUPPRESSED_SUPPRESSIVE_BUBBLE_METADATA; import static com.android.systemui.statusbar.notification.interruption.NotificationInterruptStateProviderImpl.NotificationInterruptEvent.FSI_SUPPRESSED_SUPPRESSIVE_GROUP_ALERT_BEHAVIOR; import static com.android.systemui.statusbar.notification.interruption.NotificationInterruptStateProviderImpl.NotificationInterruptEvent.HUN_SNOOZE_BYPASSED_POTENTIALLY_SUPPRESSED_FSI; Loading Loading @@ -82,6 +83,9 @@ public class NotificationInterruptStateProviderImpl implements NotificationInter @UiEvent(doc = "FSI suppressed for suppressive GroupAlertBehavior") FSI_SUPPRESSED_SUPPRESSIVE_GROUP_ALERT_BEHAVIOR(1235), @UiEvent(doc = "FSI suppressed for suppressive BubbleMetadata") FSI_SUPPRESSED_SUPPRESSIVE_BUBBLE_METADATA(1353), @UiEvent(doc = "FSI suppressed for requiring neither HUN nor keyguard") FSI_SUPPRESSED_NO_HUN_OR_KEYGUARD(1236), Loading Loading @@ -273,6 +277,16 @@ public class NotificationInterruptStateProviderImpl implements NotificationInter suppressedByDND); } // If the notification has suppressive BubbleMetadata, block FSI and warn. Notification.BubbleMetadata bubbleMetadata = sbn.getNotification().getBubbleMetadata(); if (bubbleMetadata != null && bubbleMetadata.isNotificationSuppressed()) { // b/274759612: Detect and report an event when a notification has both an FSI and a // suppressive BubbleMetadata, and now correctly block the FSI from firing. return getDecisionGivenSuppression( FullScreenIntentDecision.NO_FSI_SUPPRESSIVE_BUBBLE_METADATA, suppressedByDND); } // Notification is coming from a suspended package, block FSI if (entry.getRanking().isSuspended()) { return getDecisionGivenSuppression(FullScreenIntentDecision.NO_FSI_SUSPENDED, Loading Loading @@ -351,6 +365,14 @@ public class NotificationInterruptStateProviderImpl implements NotificationInter mLogger.logNoFullscreenWarning(entry, decision + ": GroupAlertBehavior will prevent HUN"); return; case NO_FSI_SUPPRESSIVE_BUBBLE_METADATA: android.util.EventLog.writeEvent(0x534e4554, "274759612", uid, "bubbleMetadata"); mUiEventLogger.log(FSI_SUPPRESSED_SUPPRESSIVE_BUBBLE_METADATA, uid, packageName); mLogger.logNoFullscreenWarning(entry, decision + ": BubbleMetadata may prevent HUN"); return; case NO_FSI_NO_HUN_OR_KEYGUARD: android.util.EventLog.writeEvent(0x534e4554, "231322873", uid, "no hun or keyguard"); Loading
packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/interruption/NotificationInterruptStateProviderImplTest.java +37 −0 Original line number Diff line number Diff line Loading @@ -655,6 +655,39 @@ public class NotificationInterruptStateProviderImplTest extends SysuiTestCase { assertThat(fakeUiEvent.packageName).isEqualTo(entry.getSbn().getPackageName()); } @Test public void testShouldNotFullScreen_isSuppressedByBubbleMetadata_withStrictFlag() { when(mFlags.fullScreenIntentRequiresKeyguard()).thenReturn(true); testShouldNotFullScreen_isSuppressedByBubbleMetadata(); } @Test public void testShouldNotFullScreen_isSuppressedByBubbleMetadata() { NotificationEntry entry = createFsiNotification(IMPORTANCE_HIGH, /* silenced */ false); Notification.BubbleMetadata bubbleMetadata = new Notification.BubbleMetadata.Builder("foo") .setSuppressNotification(true).build(); entry.getSbn().getNotification().setBubbleMetadata(bubbleMetadata); when(mPowerManager.isInteractive()).thenReturn(false); when(mStatusBarStateController.isDreaming()).thenReturn(true); when(mStatusBarStateController.getState()).thenReturn(KEYGUARD); assertThat(mNotifInterruptionStateProvider.getFullScreenIntentDecision(entry)) .isEqualTo(FullScreenIntentDecision.NO_FSI_SUPPRESSIVE_BUBBLE_METADATA); assertThat(mNotifInterruptionStateProvider.shouldLaunchFullScreenIntentWhenAdded(entry)) .isFalse(); verify(mLogger, never()).logNoFullscreen(any(), any()); verify(mLogger).logNoFullscreenWarning(entry, "NO_FSI_SUPPRESSIVE_BUBBLE_METADATA: BubbleMetadata may prevent HUN"); verify(mLogger, never()).logFullscreen(any(), any()); assertThat(mUiEventLoggerFake.numLogs()).isEqualTo(1); UiEventLoggerFake.FakeUiEvent fakeUiEvent = mUiEventLoggerFake.get(0); assertThat(fakeUiEvent.eventId).isEqualTo( NotificationInterruptEvent.FSI_SUPPRESSED_SUPPRESSIVE_BUBBLE_METADATA.getId()); assertThat(fakeUiEvent.uid).isEqualTo(entry.getSbn().getUid()); assertThat(fakeUiEvent.packageName).isEqualTo(entry.getSbn().getPackageName()); } @Test public void testShouldFullScreen_notInteractive_withStrictFlag() throws Exception { when(mFlags.fullScreenIntentRequiresKeyguard()).thenReturn(true); Loading @@ -664,6 +697,9 @@ public class NotificationInterruptStateProviderImplTest extends SysuiTestCase { @Test public void testShouldFullScreen_notInteractive() throws RemoteException { NotificationEntry entry = createFsiNotification(IMPORTANCE_HIGH, /* silenced */ false); Notification.BubbleMetadata bubbleMetadata = new Notification.BubbleMetadata.Builder("foo") .setSuppressNotification(false).build(); entry.getSbn().getNotification().setBubbleMetadata(bubbleMetadata); when(mPowerManager.isInteractive()).thenReturn(false); when(mStatusBarStateController.isDreaming()).thenReturn(false); when(mStatusBarStateController.getState()).thenReturn(SHADE); Loading Loading @@ -897,6 +933,7 @@ public class NotificationInterruptStateProviderImplTest extends SysuiTestCase { NotificationEntry entry = createFsiNotification(IMPORTANCE_HIGH, /* silenced */ false); Set<FullScreenIntentDecision> warnings = new HashSet<>(Arrays.asList( FullScreenIntentDecision.NO_FSI_SUPPRESSIVE_GROUP_ALERT_BEHAVIOR, FullScreenIntentDecision.NO_FSI_SUPPRESSIVE_BUBBLE_METADATA, FullScreenIntentDecision.NO_FSI_NO_HUN_OR_KEYGUARD )); for (FullScreenIntentDecision decision : FullScreenIntentDecision.values()) { Loading