Bypass HUN snooze for notifs with FSI
If an app posts a time-sensitive (alarm, call, etc.) notification that can either HUN or FSI, it's possible for *neither* alerting behavior to happen if the user has snoozed HUNs for the package and System UI has suppressed FSIs because the screen is on and unlocked and the FSI_REQUIRES_KEYGUARD flag is set. In this case, assume any notification with an FSI is time-sensitive (like an alarm or incoming call) and ignore whether HUNs have been snoozed for the package. Bug: 245356701 Test: atest NotificationInterruptStateProviderImplTest Test: manual tests of relevant FSI/HUN snooze scenarios Change-Id: Idee76ef9fc9d303903617ffd5bc79aad0756b2a0
This commit is contained in:
@@ -70,7 +70,15 @@ class NotificationInterruptLogger @Inject constructor(
|
||||
buffer.log(TAG, DEBUG, {
|
||||
str1 = entry.logKey
|
||||
}, {
|
||||
"No alerting: snoozed package: $str1"
|
||||
"No heads up: snoozed package: $str1"
|
||||
})
|
||||
}
|
||||
|
||||
fun logHeadsUpPackageSnoozeBypassedHasFsi(entry: NotificationEntry) {
|
||||
buffer.log(TAG, DEBUG, {
|
||||
str1 = entry.logKey
|
||||
}, {
|
||||
"Heads up: package snooze bypassed because notification has full-screen intent: $str1"
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
@@ -19,6 +19,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_GROUP_ALERT_BEHAVIOR;
|
||||
import static com.android.systemui.statusbar.notification.interruption.NotificationInterruptStateProviderImpl.NotificationInterruptEvent.HUN_SNOOZE_BYPASSED_POTENTIALLY_SUPPRESSED_FSI;
|
||||
|
||||
import android.app.Notification;
|
||||
import android.app.NotificationManager;
|
||||
@@ -87,7 +88,10 @@ public class NotificationInterruptStateProviderImpl implements NotificationInter
|
||||
FSI_SUPPRESSED_NO_HUN_OR_KEYGUARD(1236),
|
||||
|
||||
@UiEvent(doc = "HUN suppressed for old when")
|
||||
HUN_SUPPRESSED_OLD_WHEN(1237);
|
||||
HUN_SUPPRESSED_OLD_WHEN(1237),
|
||||
|
||||
@UiEvent(doc = "HUN snooze bypassed for potentially suppressed FSI")
|
||||
HUN_SNOOZE_BYPASSED_POTENTIALLY_SUPPRESSED_FSI(1269);
|
||||
|
||||
private final int mId;
|
||||
|
||||
@@ -409,7 +413,15 @@ public class NotificationInterruptStateProviderImpl implements NotificationInter
|
||||
return false;
|
||||
}
|
||||
|
||||
if (isSnoozedPackage(sbn)) {
|
||||
final boolean isSnoozedPackage = isSnoozedPackage(sbn);
|
||||
final boolean fsiRequiresKeyguard = mFlags.fullScreenIntentRequiresKeyguard();
|
||||
final boolean hasFsi = sbn.getNotification().fullScreenIntent != null;
|
||||
|
||||
// Assume any notification with an FSI is time-sensitive (like an alarm or incoming call)
|
||||
// and ignore whether HUNs have been snoozed for the package.
|
||||
final boolean shouldBypassSnooze = fsiRequiresKeyguard && hasFsi;
|
||||
|
||||
if (isSnoozedPackage && !shouldBypassSnooze) {
|
||||
if (log) mLogger.logNoHeadsUpPackageSnoozed(entry);
|
||||
return false;
|
||||
}
|
||||
@@ -447,6 +459,19 @@ public class NotificationInterruptStateProviderImpl implements NotificationInter
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (isSnoozedPackage) {
|
||||
if (log) {
|
||||
mLogger.logHeadsUpPackageSnoozeBypassedHasFsi(entry);
|
||||
final int uid = entry.getSbn().getUid();
|
||||
final String packageName = entry.getSbn().getPackageName();
|
||||
mUiEventLogger.log(HUN_SNOOZE_BYPASSED_POTENTIALLY_SUPPRESSED_FSI, uid,
|
||||
packageName);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
if (log) mLogger.logHeadsUp(entry);
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -741,7 +741,7 @@ public class NotificationInterruptStateProviderImplTest extends SysuiTestCase {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testShouldFullScreen_snoozed_occluding_withStrictRules() throws Exception {
|
||||
public void testShouldNotFullScreen_snoozed_occluding_withStrictRules() throws Exception {
|
||||
when(mFlags.fullScreenIntentRequiresKeyguard()).thenReturn(true);
|
||||
NotificationEntry entry = createFsiNotification(IMPORTANCE_HIGH, /* silenced */ false);
|
||||
when(mPowerManager.isInteractive()).thenReturn(true);
|
||||
@@ -753,16 +753,41 @@ public class NotificationInterruptStateProviderImplTest extends SysuiTestCase {
|
||||
when(mKeyguardStateController.isOccluded()).thenReturn(true);
|
||||
|
||||
assertThat(mNotifInterruptionStateProvider.getFullScreenIntentDecision(entry))
|
||||
.isEqualTo(FullScreenIntentDecision.FSI_KEYGUARD_OCCLUDED);
|
||||
.isEqualTo(FullScreenIntentDecision.NO_FSI_EXPECTED_TO_HUN);
|
||||
assertThat(mNotifInterruptionStateProvider.shouldLaunchFullScreenIntentWhenAdded(entry))
|
||||
.isTrue();
|
||||
verify(mLogger, never()).logNoFullscreen(any(), any());
|
||||
.isFalse();
|
||||
verify(mLogger).logNoFullscreen(entry, "Expected to HUN");
|
||||
verify(mLogger, never()).logNoFullscreenWarning(any(), any());
|
||||
verify(mLogger).logFullscreen(entry, "Expected not to HUN while keyguard occluded");
|
||||
verify(mLogger, never()).logFullscreen(any(), any());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testShouldFullScreen_snoozed_lockedShade_withStrictRules() throws Exception {
|
||||
public void testShouldHeadsUp_snoozed_occluding_withStrictRules() throws Exception {
|
||||
when(mFlags.fullScreenIntentRequiresKeyguard()).thenReturn(true);
|
||||
NotificationEntry entry = createFsiNotification(IMPORTANCE_HIGH, /* silenced */ false);
|
||||
when(mPowerManager.isInteractive()).thenReturn(true);
|
||||
when(mPowerManager.isScreenOn()).thenReturn(true);
|
||||
when(mDreamManager.isDreaming()).thenReturn(false);
|
||||
when(mStatusBarStateController.getState()).thenReturn(SHADE);
|
||||
when(mHeadsUpManager.isSnoozed("a")).thenReturn(true);
|
||||
when(mKeyguardStateController.isShowing()).thenReturn(true);
|
||||
when(mKeyguardStateController.isOccluded()).thenReturn(true);
|
||||
|
||||
assertThat(mNotifInterruptionStateProvider.shouldHeadsUp(entry)).isTrue();
|
||||
|
||||
verify(mLogger).logHeadsUpPackageSnoozeBypassedHasFsi(entry);
|
||||
verify(mLogger, never()).logHeadsUp(any());
|
||||
|
||||
assertThat(mUiEventLoggerFake.numLogs()).isEqualTo(1);
|
||||
UiEventLoggerFake.FakeUiEvent fakeUiEvent = mUiEventLoggerFake.get(0);
|
||||
assertThat(fakeUiEvent.eventId).isEqualTo(
|
||||
NotificationInterruptEvent.HUN_SNOOZE_BYPASSED_POTENTIALLY_SUPPRESSED_FSI.getId());
|
||||
assertThat(fakeUiEvent.uid).isEqualTo(entry.getSbn().getUid());
|
||||
assertThat(fakeUiEvent.packageName).isEqualTo(entry.getSbn().getPackageName());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testShouldNotFullScreen_snoozed_lockedShade_withStrictRules() throws Exception {
|
||||
when(mFlags.fullScreenIntentRequiresKeyguard()).thenReturn(true);
|
||||
NotificationEntry entry = createFsiNotification(IMPORTANCE_HIGH, /* silenced */ false);
|
||||
when(mPowerManager.isInteractive()).thenReturn(true);
|
||||
@@ -774,12 +799,37 @@ public class NotificationInterruptStateProviderImplTest extends SysuiTestCase {
|
||||
when(mKeyguardStateController.isOccluded()).thenReturn(false);
|
||||
|
||||
assertThat(mNotifInterruptionStateProvider.getFullScreenIntentDecision(entry))
|
||||
.isEqualTo(FullScreenIntentDecision.FSI_LOCKED_SHADE);
|
||||
.isEqualTo(FullScreenIntentDecision.NO_FSI_EXPECTED_TO_HUN);
|
||||
assertThat(mNotifInterruptionStateProvider.shouldLaunchFullScreenIntentWhenAdded(entry))
|
||||
.isTrue();
|
||||
verify(mLogger, never()).logNoFullscreen(any(), any());
|
||||
.isFalse();
|
||||
verify(mLogger).logNoFullscreen(entry, "Expected to HUN");
|
||||
verify(mLogger, never()).logNoFullscreenWarning(any(), any());
|
||||
verify(mLogger).logFullscreen(entry, "Keyguard is showing and not occluded");
|
||||
verify(mLogger, never()).logFullscreen(any(), any());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testShouldHeadsUp_snoozed_lockedShade_withStrictRules() throws Exception {
|
||||
when(mFlags.fullScreenIntentRequiresKeyguard()).thenReturn(true);
|
||||
NotificationEntry entry = createFsiNotification(IMPORTANCE_HIGH, /* silenced */ false);
|
||||
when(mPowerManager.isInteractive()).thenReturn(true);
|
||||
when(mPowerManager.isScreenOn()).thenReturn(true);
|
||||
when(mDreamManager.isDreaming()).thenReturn(false);
|
||||
when(mStatusBarStateController.getState()).thenReturn(SHADE_LOCKED);
|
||||
when(mHeadsUpManager.isSnoozed("a")).thenReturn(true);
|
||||
when(mKeyguardStateController.isShowing()).thenReturn(true);
|
||||
when(mKeyguardStateController.isOccluded()).thenReturn(false);
|
||||
|
||||
assertThat(mNotifInterruptionStateProvider.shouldHeadsUp(entry)).isTrue();
|
||||
|
||||
verify(mLogger).logHeadsUpPackageSnoozeBypassedHasFsi(entry);
|
||||
verify(mLogger, never()).logHeadsUp(any());
|
||||
|
||||
assertThat(mUiEventLoggerFake.numLogs()).isEqualTo(1);
|
||||
UiEventLoggerFake.FakeUiEvent fakeUiEvent = mUiEventLoggerFake.get(0);
|
||||
assertThat(fakeUiEvent.eventId).isEqualTo(
|
||||
NotificationInterruptEvent.HUN_SNOOZE_BYPASSED_POTENTIALLY_SUPPRESSED_FSI.getId());
|
||||
assertThat(fakeUiEvent.uid).isEqualTo(entry.getSbn().getUid());
|
||||
assertThat(fakeUiEvent.packageName).isEqualTo(entry.getSbn().getPackageName());
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -795,21 +845,41 @@ public class NotificationInterruptStateProviderImplTest extends SysuiTestCase {
|
||||
when(mKeyguardStateController.isOccluded()).thenReturn(false);
|
||||
|
||||
assertThat(mNotifInterruptionStateProvider.getFullScreenIntentDecision(entry))
|
||||
.isEqualTo(FullScreenIntentDecision.NO_FSI_NO_HUN_OR_KEYGUARD);
|
||||
.isEqualTo(FullScreenIntentDecision.NO_FSI_EXPECTED_TO_HUN);
|
||||
assertThat(mNotifInterruptionStateProvider.shouldLaunchFullScreenIntentWhenAdded(entry))
|
||||
.isFalse();
|
||||
verify(mLogger, never()).logNoFullscreen(any(), any());
|
||||
verify(mLogger).logNoFullscreenWarning(entry, "Expected not to HUN while not on keyguard");
|
||||
verify(mLogger).logNoFullscreen(entry, "Expected to HUN");
|
||||
verify(mLogger, never()).logNoFullscreenWarning(any(), any());
|
||||
verify(mLogger, never()).logFullscreen(any(), any());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testShouldHeadsUp_snoozed_unlocked_withStrictRules() throws Exception {
|
||||
when(mFlags.fullScreenIntentRequiresKeyguard()).thenReturn(true);
|
||||
NotificationEntry entry = createFsiNotification(IMPORTANCE_HIGH, /* silenced */ false);
|
||||
when(mPowerManager.isInteractive()).thenReturn(true);
|
||||
when(mPowerManager.isScreenOn()).thenReturn(true);
|
||||
when(mDreamManager.isDreaming()).thenReturn(false);
|
||||
when(mStatusBarStateController.getState()).thenReturn(SHADE);
|
||||
when(mHeadsUpManager.isSnoozed("a")).thenReturn(true);
|
||||
when(mKeyguardStateController.isShowing()).thenReturn(false);
|
||||
when(mKeyguardStateController.isOccluded()).thenReturn(false);
|
||||
|
||||
assertThat(mNotifInterruptionStateProvider.shouldHeadsUp(entry)).isTrue();
|
||||
|
||||
verify(mLogger).logHeadsUpPackageSnoozeBypassedHasFsi(entry);
|
||||
verify(mLogger, never()).logHeadsUp(any());
|
||||
|
||||
assertThat(mUiEventLoggerFake.numLogs()).isEqualTo(1);
|
||||
UiEventLoggerFake.FakeUiEvent fakeUiEvent = mUiEventLoggerFake.get(0);
|
||||
assertThat(fakeUiEvent.eventId).isEqualTo(
|
||||
NotificationInterruptEvent.FSI_SUPPRESSED_NO_HUN_OR_KEYGUARD.getId());
|
||||
NotificationInterruptEvent.HUN_SNOOZE_BYPASSED_POTENTIALLY_SUPPRESSED_FSI.getId());
|
||||
assertThat(fakeUiEvent.uid).isEqualTo(entry.getSbn().getUid());
|
||||
assertThat(fakeUiEvent.packageName).isEqualTo(entry.getSbn().getPackageName());
|
||||
}
|
||||
|
||||
/* TODO: Verify the FSI_SUPPRESSED_NO_HUN_OR_KEYGUARD UiEvent some other way. */
|
||||
|
||||
/**
|
||||
* Bubbles can happen.
|
||||
*/
|
||||
|
||||
Reference in New Issue
Block a user