Loading services/core/java/com/android/server/EventLogTags.logtags +1 −1 Original line number Diff line number Diff line Loading @@ -87,7 +87,7 @@ option java_package com.android.server # replaces 27510 with a row per notification 27531 notification_visibility (key|3),(visibile|1),(lifespan|1),(freshness|1),(exposure|1),(rank|1) # a notification emited noise, vibration, or light 27532 notification_alert (key|3),(buzz|1),(beep|1),(blink|1),(politeness|1) 27532 notification_alert (key|3),(buzz|1),(beep|1),(blink|1),(politeness|1),(mute_reason|1) # a notification was added to a autogroup 27533 notification_autogrouped (key|3) # notification was removed from an autogroup Loading services/core/java/com/android/server/notification/NotificationAttentionHelper.java +66 −32 Original line number Diff line number Diff line Loading @@ -118,6 +118,37 @@ public final class NotificationAttentionHelper { Intent.ACTION_MANAGED_PROFILE_AVAILABLE, new Pair<>(Intent.EXTRA_QUIET_MODE, false) ); // Bits 1, 2, 3, 4 are already taken by: beep|buzz|blink|cooldown static final int MUTE_REASON_NOT_MUTED = 0; static final int MUTE_REASON_NOT_AUDIBLE = 1 << 5; static final int MUTE_REASON_SILENT_UPDATE = 1 << 6; static final int MUTE_REASON_POST_SILENTLY = 1 << 7; static final int MUTE_REASON_LISTENER_HINT = 1 << 8; static final int MUTE_REASON_DND = 1 << 9; static final int MUTE_REASON_GROUP_ALERT = 1 << 10; static final int MUTE_REASON_FLAG_SILENT = 1 << 11; static final int MUTE_REASON_RATE_LIMIT = 1 << 12; static final int MUTE_REASON_OTHER_INSISTENT_PLAYING = 1 << 13; static final int MUTE_REASON_SUPPRESSED_BUBBLE = 1 << 14; static final int MUTE_REASON_COOLDOWN = 1 << 15; @IntDef(prefix = { "MUTE_REASON_" }, value = { MUTE_REASON_NOT_MUTED, MUTE_REASON_NOT_AUDIBLE, MUTE_REASON_SILENT_UPDATE, MUTE_REASON_POST_SILENTLY, MUTE_REASON_LISTENER_HINT, MUTE_REASON_DND, MUTE_REASON_GROUP_ALERT, MUTE_REASON_FLAG_SILENT, MUTE_REASON_RATE_LIMIT, MUTE_REASON_OTHER_INSISTENT_PLAYING, MUTE_REASON_SUPPRESSED_BUBBLE, MUTE_REASON_COOLDOWN, }) @Retention(RetentionPolicy.SOURCE) @interface MuteReason {} private final Context mContext; private final PackageManager mPackageManager; private final TelephonyManager mTelephonyManager; Loading Loading @@ -388,6 +419,7 @@ public final class NotificationAttentionHelper { boolean buzz = false; boolean beep = false; boolean blink = false; @MuteReason int shouldMuteReason = MUTE_REASON_NOT_MUTED; final String key = record.getKey(); Loading @@ -395,10 +427,6 @@ public final class NotificationAttentionHelper { Log.d(TAG, "buzzBeepBlinkLocked " + record); } if (isPoliteNotificationFeatureEnabled(record)) { mStrategy.onNotificationPosted(record); } // Should this notification make noise, vibe, or use the LED? final boolean aboveThreshold = mIsAutomotive Loading Loading @@ -443,7 +471,8 @@ public final class NotificationAttentionHelper { boolean vibrateOnly = hasValidVibrate && mNotificationCooldownVibrateUnlocked && mUserPresent; boolean hasAudibleAlert = hasValidSound || hasValidVibrate; if (hasAudibleAlert && !shouldMuteNotificationLocked(record, signals)) { shouldMuteReason = shouldMuteNotificationLocked(record, signals, hasAudibleAlert); if (shouldMuteReason == MUTE_REASON_NOT_MUTED) { if (!sentAccessibilityEvent) { sendAccessibilityEvent(record); sentAccessibilityEvent = true; Loading Loading @@ -541,15 +570,17 @@ public final class NotificationAttentionHelper { } } final int buzzBeepBlinkLoggingCode = (buzz ? 1 : 0) | (beep ? 2 : 0) | (blink ? 4 : 0) | getPoliteBit(record); (buzz ? 1 : 0) | (beep ? 2 : 0) | (blink ? 4 : 0) | getPoliteBit(record) | shouldMuteReason; if (buzzBeepBlinkLoggingCode > 0) { MetricsLogger.action(record.getLogMaker() .setCategory(MetricsEvent.NOTIFICATION_ALERT) .setType(MetricsEvent.TYPE_OPEN) .setSubtype(buzzBeepBlinkLoggingCode)); EventLogTags.writeNotificationAlert(key, buzz ? 1 : 0, beep ? 1 : 0, blink ? 1 : 0, getPolitenessState(record)); getPolitenessState(record), shouldMuteReason); } if (Flags.politeNotifications()) { // Update last alert time if (buzz || beep) { Loading Loading @@ -594,41 +625,46 @@ public final class NotificationAttentionHelper { mNMP.getNotificationByKey(mVibrateNotificationKey)); } boolean shouldMuteNotificationLocked(final NotificationRecord record, final Signals signals) { @MuteReason int shouldMuteNotificationLocked(final NotificationRecord record, final Signals signals, boolean hasAudibleAlert) { // Suppressed because no audible alert if (!hasAudibleAlert) { return MUTE_REASON_NOT_AUDIBLE; } // Suppressed because it's a silent update final Notification notification = record.getNotification(); if (record.isUpdate && (notification.flags & FLAG_ONLY_ALERT_ONCE) != 0) { return true; return MUTE_REASON_SILENT_UPDATE; } // Suppressed because a user manually unsnoozed something (or similar) if (record.shouldPostSilently()) { return true; return MUTE_REASON_POST_SILENTLY; } // muted by listener final String disableEffects = disableNotificationEffects(record, signals.listenerHints); if (disableEffects != null) { ZenLog.traceDisableEffects(record, disableEffects); return true; return MUTE_REASON_LISTENER_HINT; } // suppressed due to DND if (record.isIntercepted()) { return true; return MUTE_REASON_DND; } // Suppressed because another notification in its group handles alerting if (record.getSbn().isGroup()) { if (notification.suppressAlertingDueToGrouping()) { return true; return MUTE_REASON_GROUP_ALERT; } } // Suppressed because notification was explicitly flagged as silent if (android.service.notification.Flags.notificationSilentFlag()) { if (notification.isSilent()) { return true; return MUTE_REASON_FLAG_SILENT; } } Loading @@ -636,12 +672,12 @@ public final class NotificationAttentionHelper { final String pkg = record.getSbn().getPackageName(); if (mUsageStats.isAlertRateLimited(pkg)) { Slog.e(TAG, "Muting recently noisy " + record.getKey()); return true; return MUTE_REASON_RATE_LIMIT; } // A different looping ringtone, such as an incoming call is playing if (isCurrentlyInsistent() && !isInsistentUpdate(record)) { return true; return MUTE_REASON_OTHER_INSISTENT_PLAYING; } // Suppressed since it's a non-interruptive update to a bubble-suppressed notification Loading @@ -650,11 +686,23 @@ public final class NotificationAttentionHelper { if (record.isUpdate && !record.isInterruptive() && isBubbleOrOverflowed && record.getNotification().getBubbleMetadata() != null) { if (record.getNotification().getBubbleMetadata().isNotificationSuppressed()) { return true; return MUTE_REASON_SUPPRESSED_BUBBLE; } } return false; if (isPoliteNotificationFeatureEnabled(record)) { // Notify the politeness strategy that an alerting notification is posted if (!isInsistentUpdate(record)) { mStrategy.onNotificationPosted(record); } // Suppress if politeness is muted and it's not an update for insistent if (getPolitenessState(record) == PolitenessStrategy.POLITE_STATE_MUTED) { return MUTE_REASON_COOLDOWN; } } return MUTE_REASON_NOT_MUTED; } private boolean isLoopingRingtoneNotification(final NotificationRecord playingRecord) { Loading Loading @@ -1201,12 +1249,6 @@ public final class NotificationAttentionHelper { mApplyPerPackage = applyPerPackage; } boolean shouldIgnoreNotification(final NotificationRecord record) { // Ignore auto-group summaries => don't count them as app-posted notifications // for the cooldown budget return (record.getSbn().isGroup() && GroupHelper.isAggregatedGroup(record)); } /** * Get the key that determines the grouping for the cooldown behavior. * Loading Loading @@ -1358,10 +1400,6 @@ public final class NotificationAttentionHelper { @Override public void onNotificationPosted(final NotificationRecord record) { if (shouldIgnoreNotification(record)) { return; } long timeSinceLastNotif = System.currentTimeMillis() - getLastNotificationUpdateTimeMs(record); Loading Loading @@ -1434,10 +1472,6 @@ public final class NotificationAttentionHelper { @Override void onNotificationPosted(NotificationRecord record) { if (isAvalancheActive()) { if (shouldIgnoreNotification(record)) { return; } long timeSinceLastNotif = System.currentTimeMillis() - getLastNotificationUpdateTimeMs(record); Loading services/tests/uiservicestests/src/com/android/server/notification/NotificationAttentionHelperTest.java +148 −36 Original line number Diff line number Diff line Loading @@ -31,6 +31,12 @@ import static android.content.pm.PackageManager.PERMISSION_GRANTED; import static android.media.AudioAttributes.USAGE_NOTIFICATION; import static android.media.AudioAttributes.USAGE_NOTIFICATION_RINGTONE; import static com.android.server.notification.NotificationAttentionHelper.MUTE_REASON_COOLDOWN; import static com.android.server.notification.NotificationAttentionHelper.MUTE_REASON_FLAG_SILENT; import static com.android.server.notification.NotificationAttentionHelper.MUTE_REASON_GROUP_ALERT; import static com.android.server.notification.NotificationAttentionHelper.MUTE_REASON_NOT_MUTED; import static com.android.server.notification.NotificationAttentionHelper.MUTE_REASON_OTHER_INSISTENT_PLAYING; import static com.google.common.truth.Truth.assertThat; import static org.junit.Assert.assertEquals; Loading Loading @@ -106,6 +112,7 @@ import com.android.internal.config.sysui.SystemUiSystemPropertiesFlags.Notificat import com.android.internal.config.sysui.TestableFlagResolver; import com.android.internal.logging.InstanceIdSequence; import com.android.internal.logging.InstanceIdSequenceFake; import com.android.internal.logging.nano.MetricsProto.MetricsEvent; import com.android.internal.util.IntPair; import com.android.server.UiServiceTestCase; import com.android.server.lights.LightsManager; Loading Loading @@ -1276,7 +1283,8 @@ public class NotificationAttentionHelperTest extends UiServiceTestCase { verifyNeverBeep(); assertFalse(r.isInterruptive()); assertEquals(-1, r.getLastAudiblyAlertedMs()); assertTrue(mAttentionHelper.shouldMuteNotificationLocked(r, DEFAULT_SIGNALS)); assertThat(mAttentionHelper.shouldMuteNotificationLocked(r, DEFAULT_SIGNALS, true)).isEqualTo(MUTE_REASON_FLAG_SILENT); } @Test Loading @@ -1295,7 +1303,8 @@ public class NotificationAttentionHelperTest extends UiServiceTestCase { verifyNeverBeep(); assertFalse(r.isInterruptive()); assertEquals(-1, r.getLastAudiblyAlertedMs()); assertTrue(mAttentionHelper.shouldMuteNotificationLocked(r, DEFAULT_SIGNALS)); assertThat(mAttentionHelper.shouldMuteNotificationLocked(r, DEFAULT_SIGNALS, true)).isEqualTo(MUTE_REASON_GROUP_ALERT); } @Test Loading Loading @@ -1861,7 +1870,9 @@ public class NotificationAttentionHelperTest extends UiServiceTestCase { verifyBeepLooped(); NotificationRecord interrupter = getBeepyOtherNotification(); assertTrue(mAttentionHelper.shouldMuteNotificationLocked(interrupter, DEFAULT_SIGNALS)); assertThat( mAttentionHelper.shouldMuteNotificationLocked(interrupter, DEFAULT_SIGNALS, true)).isEqualTo(MUTE_REASON_OTHER_INSISTENT_PLAYING); mAttentionHelper.buzzBeepBlinkLocked(interrupter, DEFAULT_SIGNALS); verifyBeep(1); Loading @@ -1879,16 +1890,16 @@ public class NotificationAttentionHelperTest extends UiServiceTestCase { ringtoneChannel.enableVibration(true); NotificationRecord ringtoneNotification = getCallRecord(1, ringtoneChannel, true); mService.addNotification(ringtoneNotification); assertFalse(mAttentionHelper.shouldMuteNotificationLocked(ringtoneNotification, DEFAULT_SIGNALS)); assertThat(mAttentionHelper.shouldMuteNotificationLocked(ringtoneNotification, DEFAULT_SIGNALS, true)).isEqualTo(MUTE_REASON_NOT_MUTED); mAttentionHelper.buzzBeepBlinkLocked(ringtoneNotification, DEFAULT_SIGNALS); verifyBeepLooped(); verifyDelayedVibrateLooped(); Mockito.reset(mVibrator); Mockito.reset(mRingtonePlayer); assertFalse(mAttentionHelper.shouldMuteNotificationLocked(ringtoneNotification, DEFAULT_SIGNALS)); assertThat(mAttentionHelper.shouldMuteNotificationLocked(ringtoneNotification, DEFAULT_SIGNALS, true)).isEqualTo(MUTE_REASON_NOT_MUTED); mAttentionHelper.buzzBeepBlinkLocked(ringtoneNotification, DEFAULT_SIGNALS); // beep wasn't reset Loading @@ -1907,8 +1918,8 @@ public class NotificationAttentionHelperTest extends UiServiceTestCase { ringtoneChannel.enableVibration(true); NotificationRecord ringtoneNotification = getCallRecord(1, ringtoneChannel, true); mService.addNotification(ringtoneNotification); assertFalse(mAttentionHelper.shouldMuteNotificationLocked(ringtoneNotification, DEFAULT_SIGNALS)); assertThat(mAttentionHelper.shouldMuteNotificationLocked(ringtoneNotification, DEFAULT_SIGNALS, true)).isEqualTo(MUTE_REASON_NOT_MUTED); mAttentionHelper.buzzBeepBlinkLocked(ringtoneNotification, DEFAULT_SIGNALS); verifyBeepLooped(); verifyDelayedVibrateLooped(); Loading @@ -1930,8 +1941,8 @@ public class NotificationAttentionHelperTest extends UiServiceTestCase { ringtoneChannel.enableVibration(true); NotificationRecord ringtoneNotification = getCallRecord(1, ringtoneChannel, true); mService.addNotification(ringtoneNotification); assertFalse(mAttentionHelper.shouldMuteNotificationLocked(ringtoneNotification, DEFAULT_SIGNALS)); assertThat(mAttentionHelper.shouldMuteNotificationLocked(ringtoneNotification, DEFAULT_SIGNALS, true)).isEqualTo(MUTE_REASON_NOT_MUTED); mAttentionHelper.buzzBeepBlinkLocked(ringtoneNotification, DEFAULT_SIGNALS); verifyBeepLooped(); verifyNeverVibrate(); Loading @@ -1951,14 +1962,15 @@ public class NotificationAttentionHelperTest extends UiServiceTestCase { new AudioAttributes.Builder().setUsage(USAGE_NOTIFICATION_RINGTONE).build()); ringtoneChannel.enableVibration(true); NotificationRecord ringtoneNotification = getCallRecord(1, ringtoneChannel, true); assertFalse(mAttentionHelper.shouldMuteNotificationLocked(ringtoneNotification, DEFAULT_SIGNALS)); assertThat(mAttentionHelper.shouldMuteNotificationLocked(ringtoneNotification, DEFAULT_SIGNALS, true)).isEqualTo(MUTE_REASON_NOT_MUTED); mAttentionHelper.buzzBeepBlinkLocked(ringtoneNotification, DEFAULT_SIGNALS); verifyVibrateLooped(); NotificationRecord interrupter = getBuzzyOtherNotification(); assertTrue(mAttentionHelper.shouldMuteNotificationLocked(interrupter, DEFAULT_SIGNALS)); assertThat(mAttentionHelper.shouldMuteNotificationLocked(interrupter, DEFAULT_SIGNALS, true)).isEqualTo(MUTE_REASON_OTHER_INSISTENT_PLAYING); mAttentionHelper.buzzBeepBlinkLocked(interrupter, DEFAULT_SIGNALS); verifyVibrate(1); Loading Loading @@ -2260,10 +2272,13 @@ public class NotificationAttentionHelperTest extends UiServiceTestCase { // 2nd update should beep at 0% volume Mockito.reset(mRingtonePlayer); mAttentionHelper.buzzBeepBlinkLocked(r, DEFAULT_SIGNALS); verifyBeepVolume(0.0f); int buzzBeepBlink = mAttentionHelper.buzzBeepBlinkLocked(r, DEFAULT_SIGNALS); verifyNeverBeep(); assertThat(buzzBeepBlink).isEqualTo(MetricsEvent.ALERT_MUTED | MUTE_REASON_COOLDOWN); assertThat(mAttentionHelper.shouldMuteNotificationLocked(r, DEFAULT_SIGNALS, true)) .isEqualTo(MUTE_REASON_COOLDOWN); verify(mAccessibilityService, times(3)).sendAccessibilityEvent(any(), anyInt()); verify(mAccessibilityService, times(2)).sendAccessibilityEvent(any(), anyInt()); assertEquals(-1, r.getLastAudiblyAlertedMs()); } Loading Loading @@ -2305,8 +2320,9 @@ public class NotificationAttentionHelperTest extends UiServiceTestCase { // 2nd update should beep at 0% volume Mockito.reset(mRingtonePlayer); mAttentionHelper.buzzBeepBlinkLocked(r3, DEFAULT_SIGNALS); verifyBeepVolume(0.0f); int buzzBeepBlink = mAttentionHelper.buzzBeepBlinkLocked(r3, DEFAULT_SIGNALS); verifyNeverBeep(); assertThat(buzzBeepBlink).isEqualTo(MetricsEvent.ALERT_MUTED | MUTE_REASON_COOLDOWN); verify(mAccessibilityService, times(3)).sendAccessibilityEvent(any(), anyInt()); assertEquals(-1, r3.getLastAudiblyAlertedMs()); Loading Loading @@ -2381,9 +2397,10 @@ public class NotificationAttentionHelperTest extends UiServiceTestCase { false, null, Notification.GROUP_ALERT_ALL, false, mUser, "anotherPkg"); // update should beep at 0% volume mAttentionHelper.buzzBeepBlinkLocked(r2, DEFAULT_SIGNALS); int buzzBeepBlink = mAttentionHelper.buzzBeepBlinkLocked(r2, DEFAULT_SIGNALS); assertEquals(-1, r2.getLastAudiblyAlertedMs()); verifyBeepVolume(0.0f); verifyNeverBeep(); assertThat(buzzBeepBlink).isEqualTo(MetricsEvent.ALERT_MUTED | MUTE_REASON_COOLDOWN); // Use different package for next notifications NotificationRecord r3 = getNotificationRecord(mId, false /* insistent */, false /* once */, Loading @@ -2392,8 +2409,9 @@ public class NotificationAttentionHelperTest extends UiServiceTestCase { // 2nd update should beep at 0% volume Mockito.reset(mRingtonePlayer); mAttentionHelper.buzzBeepBlinkLocked(r3, DEFAULT_SIGNALS); verifyBeepVolume(0.0f); buzzBeepBlink = mAttentionHelper.buzzBeepBlinkLocked(r3, DEFAULT_SIGNALS); verifyNeverBeep(); assertThat(buzzBeepBlink).isEqualTo(MetricsEvent.ALERT_MUTED | MUTE_REASON_COOLDOWN); verify(mAccessibilityService, times(3)).sendAccessibilityEvent(any(), anyInt()); assertEquals(-1, r3.getLastAudiblyAlertedMs()); Loading Loading @@ -2493,8 +2511,9 @@ public class NotificationAttentionHelperTest extends UiServiceTestCase { // Regular notification: should beep at 0% volume NotificationRecord r = getBeepyNotification(); mAttentionHelper.buzzBeepBlinkLocked(r, DEFAULT_SIGNALS); verifyBeepVolume(0.0f); int buzzBeepBlink = mAttentionHelper.buzzBeepBlinkLocked(r, DEFAULT_SIGNALS); verifyNeverBeep(); assertThat(buzzBeepBlink).isEqualTo(MetricsEvent.ALERT_MUTED | MUTE_REASON_COOLDOWN); assertEquals(-1, r.getLastAudiblyAlertedMs()); Mockito.reset(mRingtonePlayer); Loading Loading @@ -2525,8 +2544,9 @@ public class NotificationAttentionHelperTest extends UiServiceTestCase { // 2nd update should beep at 0% volume Mockito.reset(mRingtonePlayer); mAttentionHelper.buzzBeepBlinkLocked(r3, DEFAULT_SIGNALS); verifyBeepVolume(0.0f); buzzBeepBlink = mAttentionHelper.buzzBeepBlinkLocked(r3, DEFAULT_SIGNALS); verifyNeverBeep(); assertThat(buzzBeepBlink).isEqualTo(MetricsEvent.ALERT_MUTED | MUTE_REASON_COOLDOWN); // Set important conversation mChannel.setImportantConversation(true); Loading Loading @@ -2751,9 +2771,10 @@ public class NotificationAttentionHelperTest extends UiServiceTestCase { Mockito.reset(mRingtonePlayer); // next update at 0% volume mAttentionHelper.buzzBeepBlinkLocked(summary, DEFAULT_SIGNALS); int buzzBeepBlink = mAttentionHelper.buzzBeepBlinkLocked(summary, DEFAULT_SIGNALS); assertEquals(-1, summary.getLastAudiblyAlertedMs()); verifyBeepVolume(0.0f); verifyNeverBeep(); assertThat(buzzBeepBlink).isEqualTo(MetricsEvent.ALERT_MUTED | MUTE_REASON_COOLDOWN); verify(mAccessibilityService, times(3)).sendAccessibilityEvent(any(), anyInt()); } Loading Loading @@ -2823,9 +2844,10 @@ public class NotificationAttentionHelperTest extends UiServiceTestCase { // 2nd update should beep at 0% volume Mockito.reset(mRingtonePlayer); mAttentionHelper.buzzBeepBlinkLocked(r2, DEFAULT_SIGNALS); int buzzBeepBlink = mAttentionHelper.buzzBeepBlinkLocked(r2, DEFAULT_SIGNALS); assertEquals(-1, r2.getLastAudiblyAlertedMs()); verifyBeepVolume(0.0f); verifyNeverBeep(); assertThat(buzzBeepBlink).isEqualTo(MetricsEvent.ALERT_MUTED | MUTE_REASON_COOLDOWN); // Use different package for next notifications NotificationRecord r3 = getNotificationRecord(mId, false /* insistent */, false /* once */, Loading Loading @@ -2890,6 +2912,94 @@ public class NotificationAttentionHelperTest extends UiServiceTestCase { assertNotEquals(-1, r3.getLastAudiblyAlertedMs()); } @Test public void testBeepVolume_politeNotif_groupAlertSummary() throws Exception { mSetFlagsRule.enableFlags(Flags.FLAG_POLITE_NOTIFICATIONS); mSetFlagsRule.disableFlags(Flags.FLAG_CROSS_APP_POLITE_NOTIFICATIONS); TestableFlagResolver flagResolver = new TestableFlagResolver(); flagResolver.setFlagOverride(NotificationFlags.NOTIF_VOLUME1, 50); flagResolver.setFlagOverride(NotificationFlags.NOTIF_VOLUME2, 0); // NOTIFICATION_COOLDOWN_ALL setting is enabled Settings.System.putInt(getContext().getContentResolver(), Settings.System.NOTIFICATION_COOLDOWN_ALL, 1); initAttentionHelper(flagResolver); // child should beep at 0% volume NotificationRecord child = getBeepyNotificationRecord("a", GROUP_ALERT_SUMMARY); mAttentionHelper.buzzBeepBlinkLocked(child, DEFAULT_SIGNALS); verifyNeverBeep(); assertFalse(child.isInterruptive()); assertEquals(-1, child.getLastAudiblyAlertedMs()); Mockito.reset(mRingtonePlayer); // child should beep at 0% volume child = getBeepyNotificationRecord("a", GROUP_ALERT_SUMMARY); mAttentionHelper.buzzBeepBlinkLocked(child, DEFAULT_SIGNALS); verifyNeverBeep(); assertFalse(child.isInterruptive()); assertEquals(-1, child.getLastAudiblyAlertedMs()); Mockito.reset(mRingtonePlayer); // summary 100% volume (GROUP_ALERT_SUMMARY) NotificationRecord summary = getBeepyNotificationRecord("a", GROUP_ALERT_SUMMARY); summary.getNotification().flags |= Notification.FLAG_GROUP_SUMMARY; mAttentionHelper.buzzBeepBlinkLocked(summary, DEFAULT_SIGNALS); assertNotEquals(-1, summary.getLastAudiblyAlertedMs()); verifyBeepVolume(1.0f); Mockito.reset(mRingtonePlayer); // next update at 50% volume because only summary was tracked as alerting mAttentionHelper.buzzBeepBlinkLocked(summary, DEFAULT_SIGNALS); assertNotEquals(-1, summary.getLastAudiblyAlertedMs()); verifyBeepVolume(0.5f); verify(mAccessibilityService, times(4)).sendAccessibilityEvent(any(), anyInt()); } @Test public void testBeepVolume_politeNotif_groupAlertChildren() throws Exception { mSetFlagsRule.enableFlags(Flags.FLAG_POLITE_NOTIFICATIONS); mSetFlagsRule.disableFlags(Flags.FLAG_CROSS_APP_POLITE_NOTIFICATIONS); TestableFlagResolver flagResolver = new TestableFlagResolver(); flagResolver.setFlagOverride(NotificationFlags.NOTIF_VOLUME1, 50); flagResolver.setFlagOverride(NotificationFlags.NOTIF_VOLUME2, 0); // NOTIFICATION_COOLDOWN_ALL setting is enabled Settings.System.putInt(getContext().getContentResolver(), Settings.System.NOTIFICATION_COOLDOWN_ALL, 1); initAttentionHelper(flagResolver); // summary 0% volume (GROUP_ALERT_CHILDREN) NotificationRecord summary = getBeepyNotificationRecord("a", GROUP_ALERT_CHILDREN); summary.getNotification().flags |= Notification.FLAG_GROUP_SUMMARY; mAttentionHelper.buzzBeepBlinkLocked(summary, DEFAULT_SIGNALS); verifyNeverBeep(); assertFalse(summary.isInterruptive()); assertEquals(-1, summary.getLastAudiblyAlertedMs()); Mockito.reset(mRingtonePlayer); // child should beep at 100% volume NotificationRecord child = getBeepyNotificationRecord("a", GROUP_ALERT_CHILDREN); mAttentionHelper.buzzBeepBlinkLocked(child, DEFAULT_SIGNALS); assertNotEquals(-1, child.getLastAudiblyAlertedMs()); verifyBeepVolume(1.0f); Mockito.reset(mRingtonePlayer); // child should beep at 50% volume child = getBeepyNotificationRecord("a", GROUP_ALERT_CHILDREN); mAttentionHelper.buzzBeepBlinkLocked(child, DEFAULT_SIGNALS); assertNotEquals(-1, child.getLastAudiblyAlertedMs()); verifyBeepVolume(0.5f); Mockito.reset(mRingtonePlayer); // child should beep at 0% volume mAttentionHelper.buzzBeepBlinkLocked(child, DEFAULT_SIGNALS); verifyNeverBeep(); assertTrue(child.isInterruptive()); assertEquals(-1, child.getLastAudiblyAlertedMs()); verify(mAccessibilityService, times(4)).sendAccessibilityEvent(any(), anyInt()); } @Test public void testVibrationIntensity_politeNotif() throws Exception { mSetFlagsRule.enableFlags(Flags.FLAG_POLITE_NOTIFICATIONS); Loading @@ -2914,8 +3024,9 @@ public class NotificationAttentionHelperTest extends UiServiceTestCase { Mockito.reset(vibratorHelper); // 2nd update should buzz at 0% intensity mAttentionHelper.buzzBeepBlinkLocked(r, DEFAULT_SIGNALS); verify(vibratorHelper, times(1)).scale(any(), eq(0.0f)); int buzzBeepBlink = mAttentionHelper.buzzBeepBlinkLocked(r, DEFAULT_SIGNALS); verifyNeverVibrate(); assertThat(buzzBeepBlink).isEqualTo(MetricsEvent.ALERT_MUTED | MUTE_REASON_COOLDOWN); } @Test Loading Loading @@ -3007,10 +3118,11 @@ public class NotificationAttentionHelperTest extends UiServiceTestCase { // 2nd update should beep at 0% volume Mockito.reset(mRingtonePlayer); mAttentionHelper.buzzBeepBlinkLocked(r, WORK_PROFILE_SIGNALS); verifyBeepVolume(0.0f); int buzzBeepBlink = mAttentionHelper.buzzBeepBlinkLocked(r, WORK_PROFILE_SIGNALS); verifyNeverBeep(); assertThat(buzzBeepBlink).isEqualTo(MetricsEvent.ALERT_MUTED | MUTE_REASON_COOLDOWN); verify(mAccessibilityService, times(3)).sendAccessibilityEvent(any(), anyInt()); verify(mAccessibilityService, times(2)).sendAccessibilityEvent(any(), anyInt()); assertEquals(-1, r.getLastAudiblyAlertedMs()); } Loading Loading
services/core/java/com/android/server/EventLogTags.logtags +1 −1 Original line number Diff line number Diff line Loading @@ -87,7 +87,7 @@ option java_package com.android.server # replaces 27510 with a row per notification 27531 notification_visibility (key|3),(visibile|1),(lifespan|1),(freshness|1),(exposure|1),(rank|1) # a notification emited noise, vibration, or light 27532 notification_alert (key|3),(buzz|1),(beep|1),(blink|1),(politeness|1) 27532 notification_alert (key|3),(buzz|1),(beep|1),(blink|1),(politeness|1),(mute_reason|1) # a notification was added to a autogroup 27533 notification_autogrouped (key|3) # notification was removed from an autogroup Loading
services/core/java/com/android/server/notification/NotificationAttentionHelper.java +66 −32 Original line number Diff line number Diff line Loading @@ -118,6 +118,37 @@ public final class NotificationAttentionHelper { Intent.ACTION_MANAGED_PROFILE_AVAILABLE, new Pair<>(Intent.EXTRA_QUIET_MODE, false) ); // Bits 1, 2, 3, 4 are already taken by: beep|buzz|blink|cooldown static final int MUTE_REASON_NOT_MUTED = 0; static final int MUTE_REASON_NOT_AUDIBLE = 1 << 5; static final int MUTE_REASON_SILENT_UPDATE = 1 << 6; static final int MUTE_REASON_POST_SILENTLY = 1 << 7; static final int MUTE_REASON_LISTENER_HINT = 1 << 8; static final int MUTE_REASON_DND = 1 << 9; static final int MUTE_REASON_GROUP_ALERT = 1 << 10; static final int MUTE_REASON_FLAG_SILENT = 1 << 11; static final int MUTE_REASON_RATE_LIMIT = 1 << 12; static final int MUTE_REASON_OTHER_INSISTENT_PLAYING = 1 << 13; static final int MUTE_REASON_SUPPRESSED_BUBBLE = 1 << 14; static final int MUTE_REASON_COOLDOWN = 1 << 15; @IntDef(prefix = { "MUTE_REASON_" }, value = { MUTE_REASON_NOT_MUTED, MUTE_REASON_NOT_AUDIBLE, MUTE_REASON_SILENT_UPDATE, MUTE_REASON_POST_SILENTLY, MUTE_REASON_LISTENER_HINT, MUTE_REASON_DND, MUTE_REASON_GROUP_ALERT, MUTE_REASON_FLAG_SILENT, MUTE_REASON_RATE_LIMIT, MUTE_REASON_OTHER_INSISTENT_PLAYING, MUTE_REASON_SUPPRESSED_BUBBLE, MUTE_REASON_COOLDOWN, }) @Retention(RetentionPolicy.SOURCE) @interface MuteReason {} private final Context mContext; private final PackageManager mPackageManager; private final TelephonyManager mTelephonyManager; Loading Loading @@ -388,6 +419,7 @@ public final class NotificationAttentionHelper { boolean buzz = false; boolean beep = false; boolean blink = false; @MuteReason int shouldMuteReason = MUTE_REASON_NOT_MUTED; final String key = record.getKey(); Loading @@ -395,10 +427,6 @@ public final class NotificationAttentionHelper { Log.d(TAG, "buzzBeepBlinkLocked " + record); } if (isPoliteNotificationFeatureEnabled(record)) { mStrategy.onNotificationPosted(record); } // Should this notification make noise, vibe, or use the LED? final boolean aboveThreshold = mIsAutomotive Loading Loading @@ -443,7 +471,8 @@ public final class NotificationAttentionHelper { boolean vibrateOnly = hasValidVibrate && mNotificationCooldownVibrateUnlocked && mUserPresent; boolean hasAudibleAlert = hasValidSound || hasValidVibrate; if (hasAudibleAlert && !shouldMuteNotificationLocked(record, signals)) { shouldMuteReason = shouldMuteNotificationLocked(record, signals, hasAudibleAlert); if (shouldMuteReason == MUTE_REASON_NOT_MUTED) { if (!sentAccessibilityEvent) { sendAccessibilityEvent(record); sentAccessibilityEvent = true; Loading Loading @@ -541,15 +570,17 @@ public final class NotificationAttentionHelper { } } final int buzzBeepBlinkLoggingCode = (buzz ? 1 : 0) | (beep ? 2 : 0) | (blink ? 4 : 0) | getPoliteBit(record); (buzz ? 1 : 0) | (beep ? 2 : 0) | (blink ? 4 : 0) | getPoliteBit(record) | shouldMuteReason; if (buzzBeepBlinkLoggingCode > 0) { MetricsLogger.action(record.getLogMaker() .setCategory(MetricsEvent.NOTIFICATION_ALERT) .setType(MetricsEvent.TYPE_OPEN) .setSubtype(buzzBeepBlinkLoggingCode)); EventLogTags.writeNotificationAlert(key, buzz ? 1 : 0, beep ? 1 : 0, blink ? 1 : 0, getPolitenessState(record)); getPolitenessState(record), shouldMuteReason); } if (Flags.politeNotifications()) { // Update last alert time if (buzz || beep) { Loading Loading @@ -594,41 +625,46 @@ public final class NotificationAttentionHelper { mNMP.getNotificationByKey(mVibrateNotificationKey)); } boolean shouldMuteNotificationLocked(final NotificationRecord record, final Signals signals) { @MuteReason int shouldMuteNotificationLocked(final NotificationRecord record, final Signals signals, boolean hasAudibleAlert) { // Suppressed because no audible alert if (!hasAudibleAlert) { return MUTE_REASON_NOT_AUDIBLE; } // Suppressed because it's a silent update final Notification notification = record.getNotification(); if (record.isUpdate && (notification.flags & FLAG_ONLY_ALERT_ONCE) != 0) { return true; return MUTE_REASON_SILENT_UPDATE; } // Suppressed because a user manually unsnoozed something (or similar) if (record.shouldPostSilently()) { return true; return MUTE_REASON_POST_SILENTLY; } // muted by listener final String disableEffects = disableNotificationEffects(record, signals.listenerHints); if (disableEffects != null) { ZenLog.traceDisableEffects(record, disableEffects); return true; return MUTE_REASON_LISTENER_HINT; } // suppressed due to DND if (record.isIntercepted()) { return true; return MUTE_REASON_DND; } // Suppressed because another notification in its group handles alerting if (record.getSbn().isGroup()) { if (notification.suppressAlertingDueToGrouping()) { return true; return MUTE_REASON_GROUP_ALERT; } } // Suppressed because notification was explicitly flagged as silent if (android.service.notification.Flags.notificationSilentFlag()) { if (notification.isSilent()) { return true; return MUTE_REASON_FLAG_SILENT; } } Loading @@ -636,12 +672,12 @@ public final class NotificationAttentionHelper { final String pkg = record.getSbn().getPackageName(); if (mUsageStats.isAlertRateLimited(pkg)) { Slog.e(TAG, "Muting recently noisy " + record.getKey()); return true; return MUTE_REASON_RATE_LIMIT; } // A different looping ringtone, such as an incoming call is playing if (isCurrentlyInsistent() && !isInsistentUpdate(record)) { return true; return MUTE_REASON_OTHER_INSISTENT_PLAYING; } // Suppressed since it's a non-interruptive update to a bubble-suppressed notification Loading @@ -650,11 +686,23 @@ public final class NotificationAttentionHelper { if (record.isUpdate && !record.isInterruptive() && isBubbleOrOverflowed && record.getNotification().getBubbleMetadata() != null) { if (record.getNotification().getBubbleMetadata().isNotificationSuppressed()) { return true; return MUTE_REASON_SUPPRESSED_BUBBLE; } } return false; if (isPoliteNotificationFeatureEnabled(record)) { // Notify the politeness strategy that an alerting notification is posted if (!isInsistentUpdate(record)) { mStrategy.onNotificationPosted(record); } // Suppress if politeness is muted and it's not an update for insistent if (getPolitenessState(record) == PolitenessStrategy.POLITE_STATE_MUTED) { return MUTE_REASON_COOLDOWN; } } return MUTE_REASON_NOT_MUTED; } private boolean isLoopingRingtoneNotification(final NotificationRecord playingRecord) { Loading Loading @@ -1201,12 +1249,6 @@ public final class NotificationAttentionHelper { mApplyPerPackage = applyPerPackage; } boolean shouldIgnoreNotification(final NotificationRecord record) { // Ignore auto-group summaries => don't count them as app-posted notifications // for the cooldown budget return (record.getSbn().isGroup() && GroupHelper.isAggregatedGroup(record)); } /** * Get the key that determines the grouping for the cooldown behavior. * Loading Loading @@ -1358,10 +1400,6 @@ public final class NotificationAttentionHelper { @Override public void onNotificationPosted(final NotificationRecord record) { if (shouldIgnoreNotification(record)) { return; } long timeSinceLastNotif = System.currentTimeMillis() - getLastNotificationUpdateTimeMs(record); Loading Loading @@ -1434,10 +1472,6 @@ public final class NotificationAttentionHelper { @Override void onNotificationPosted(NotificationRecord record) { if (isAvalancheActive()) { if (shouldIgnoreNotification(record)) { return; } long timeSinceLastNotif = System.currentTimeMillis() - getLastNotificationUpdateTimeMs(record); Loading
services/tests/uiservicestests/src/com/android/server/notification/NotificationAttentionHelperTest.java +148 −36 Original line number Diff line number Diff line Loading @@ -31,6 +31,12 @@ import static android.content.pm.PackageManager.PERMISSION_GRANTED; import static android.media.AudioAttributes.USAGE_NOTIFICATION; import static android.media.AudioAttributes.USAGE_NOTIFICATION_RINGTONE; import static com.android.server.notification.NotificationAttentionHelper.MUTE_REASON_COOLDOWN; import static com.android.server.notification.NotificationAttentionHelper.MUTE_REASON_FLAG_SILENT; import static com.android.server.notification.NotificationAttentionHelper.MUTE_REASON_GROUP_ALERT; import static com.android.server.notification.NotificationAttentionHelper.MUTE_REASON_NOT_MUTED; import static com.android.server.notification.NotificationAttentionHelper.MUTE_REASON_OTHER_INSISTENT_PLAYING; import static com.google.common.truth.Truth.assertThat; import static org.junit.Assert.assertEquals; Loading Loading @@ -106,6 +112,7 @@ import com.android.internal.config.sysui.SystemUiSystemPropertiesFlags.Notificat import com.android.internal.config.sysui.TestableFlagResolver; import com.android.internal.logging.InstanceIdSequence; import com.android.internal.logging.InstanceIdSequenceFake; import com.android.internal.logging.nano.MetricsProto.MetricsEvent; import com.android.internal.util.IntPair; import com.android.server.UiServiceTestCase; import com.android.server.lights.LightsManager; Loading Loading @@ -1276,7 +1283,8 @@ public class NotificationAttentionHelperTest extends UiServiceTestCase { verifyNeverBeep(); assertFalse(r.isInterruptive()); assertEquals(-1, r.getLastAudiblyAlertedMs()); assertTrue(mAttentionHelper.shouldMuteNotificationLocked(r, DEFAULT_SIGNALS)); assertThat(mAttentionHelper.shouldMuteNotificationLocked(r, DEFAULT_SIGNALS, true)).isEqualTo(MUTE_REASON_FLAG_SILENT); } @Test Loading @@ -1295,7 +1303,8 @@ public class NotificationAttentionHelperTest extends UiServiceTestCase { verifyNeverBeep(); assertFalse(r.isInterruptive()); assertEquals(-1, r.getLastAudiblyAlertedMs()); assertTrue(mAttentionHelper.shouldMuteNotificationLocked(r, DEFAULT_SIGNALS)); assertThat(mAttentionHelper.shouldMuteNotificationLocked(r, DEFAULT_SIGNALS, true)).isEqualTo(MUTE_REASON_GROUP_ALERT); } @Test Loading Loading @@ -1861,7 +1870,9 @@ public class NotificationAttentionHelperTest extends UiServiceTestCase { verifyBeepLooped(); NotificationRecord interrupter = getBeepyOtherNotification(); assertTrue(mAttentionHelper.shouldMuteNotificationLocked(interrupter, DEFAULT_SIGNALS)); assertThat( mAttentionHelper.shouldMuteNotificationLocked(interrupter, DEFAULT_SIGNALS, true)).isEqualTo(MUTE_REASON_OTHER_INSISTENT_PLAYING); mAttentionHelper.buzzBeepBlinkLocked(interrupter, DEFAULT_SIGNALS); verifyBeep(1); Loading @@ -1879,16 +1890,16 @@ public class NotificationAttentionHelperTest extends UiServiceTestCase { ringtoneChannel.enableVibration(true); NotificationRecord ringtoneNotification = getCallRecord(1, ringtoneChannel, true); mService.addNotification(ringtoneNotification); assertFalse(mAttentionHelper.shouldMuteNotificationLocked(ringtoneNotification, DEFAULT_SIGNALS)); assertThat(mAttentionHelper.shouldMuteNotificationLocked(ringtoneNotification, DEFAULT_SIGNALS, true)).isEqualTo(MUTE_REASON_NOT_MUTED); mAttentionHelper.buzzBeepBlinkLocked(ringtoneNotification, DEFAULT_SIGNALS); verifyBeepLooped(); verifyDelayedVibrateLooped(); Mockito.reset(mVibrator); Mockito.reset(mRingtonePlayer); assertFalse(mAttentionHelper.shouldMuteNotificationLocked(ringtoneNotification, DEFAULT_SIGNALS)); assertThat(mAttentionHelper.shouldMuteNotificationLocked(ringtoneNotification, DEFAULT_SIGNALS, true)).isEqualTo(MUTE_REASON_NOT_MUTED); mAttentionHelper.buzzBeepBlinkLocked(ringtoneNotification, DEFAULT_SIGNALS); // beep wasn't reset Loading @@ -1907,8 +1918,8 @@ public class NotificationAttentionHelperTest extends UiServiceTestCase { ringtoneChannel.enableVibration(true); NotificationRecord ringtoneNotification = getCallRecord(1, ringtoneChannel, true); mService.addNotification(ringtoneNotification); assertFalse(mAttentionHelper.shouldMuteNotificationLocked(ringtoneNotification, DEFAULT_SIGNALS)); assertThat(mAttentionHelper.shouldMuteNotificationLocked(ringtoneNotification, DEFAULT_SIGNALS, true)).isEqualTo(MUTE_REASON_NOT_MUTED); mAttentionHelper.buzzBeepBlinkLocked(ringtoneNotification, DEFAULT_SIGNALS); verifyBeepLooped(); verifyDelayedVibrateLooped(); Loading @@ -1930,8 +1941,8 @@ public class NotificationAttentionHelperTest extends UiServiceTestCase { ringtoneChannel.enableVibration(true); NotificationRecord ringtoneNotification = getCallRecord(1, ringtoneChannel, true); mService.addNotification(ringtoneNotification); assertFalse(mAttentionHelper.shouldMuteNotificationLocked(ringtoneNotification, DEFAULT_SIGNALS)); assertThat(mAttentionHelper.shouldMuteNotificationLocked(ringtoneNotification, DEFAULT_SIGNALS, true)).isEqualTo(MUTE_REASON_NOT_MUTED); mAttentionHelper.buzzBeepBlinkLocked(ringtoneNotification, DEFAULT_SIGNALS); verifyBeepLooped(); verifyNeverVibrate(); Loading @@ -1951,14 +1962,15 @@ public class NotificationAttentionHelperTest extends UiServiceTestCase { new AudioAttributes.Builder().setUsage(USAGE_NOTIFICATION_RINGTONE).build()); ringtoneChannel.enableVibration(true); NotificationRecord ringtoneNotification = getCallRecord(1, ringtoneChannel, true); assertFalse(mAttentionHelper.shouldMuteNotificationLocked(ringtoneNotification, DEFAULT_SIGNALS)); assertThat(mAttentionHelper.shouldMuteNotificationLocked(ringtoneNotification, DEFAULT_SIGNALS, true)).isEqualTo(MUTE_REASON_NOT_MUTED); mAttentionHelper.buzzBeepBlinkLocked(ringtoneNotification, DEFAULT_SIGNALS); verifyVibrateLooped(); NotificationRecord interrupter = getBuzzyOtherNotification(); assertTrue(mAttentionHelper.shouldMuteNotificationLocked(interrupter, DEFAULT_SIGNALS)); assertThat(mAttentionHelper.shouldMuteNotificationLocked(interrupter, DEFAULT_SIGNALS, true)).isEqualTo(MUTE_REASON_OTHER_INSISTENT_PLAYING); mAttentionHelper.buzzBeepBlinkLocked(interrupter, DEFAULT_SIGNALS); verifyVibrate(1); Loading Loading @@ -2260,10 +2272,13 @@ public class NotificationAttentionHelperTest extends UiServiceTestCase { // 2nd update should beep at 0% volume Mockito.reset(mRingtonePlayer); mAttentionHelper.buzzBeepBlinkLocked(r, DEFAULT_SIGNALS); verifyBeepVolume(0.0f); int buzzBeepBlink = mAttentionHelper.buzzBeepBlinkLocked(r, DEFAULT_SIGNALS); verifyNeverBeep(); assertThat(buzzBeepBlink).isEqualTo(MetricsEvent.ALERT_MUTED | MUTE_REASON_COOLDOWN); assertThat(mAttentionHelper.shouldMuteNotificationLocked(r, DEFAULT_SIGNALS, true)) .isEqualTo(MUTE_REASON_COOLDOWN); verify(mAccessibilityService, times(3)).sendAccessibilityEvent(any(), anyInt()); verify(mAccessibilityService, times(2)).sendAccessibilityEvent(any(), anyInt()); assertEquals(-1, r.getLastAudiblyAlertedMs()); } Loading Loading @@ -2305,8 +2320,9 @@ public class NotificationAttentionHelperTest extends UiServiceTestCase { // 2nd update should beep at 0% volume Mockito.reset(mRingtonePlayer); mAttentionHelper.buzzBeepBlinkLocked(r3, DEFAULT_SIGNALS); verifyBeepVolume(0.0f); int buzzBeepBlink = mAttentionHelper.buzzBeepBlinkLocked(r3, DEFAULT_SIGNALS); verifyNeverBeep(); assertThat(buzzBeepBlink).isEqualTo(MetricsEvent.ALERT_MUTED | MUTE_REASON_COOLDOWN); verify(mAccessibilityService, times(3)).sendAccessibilityEvent(any(), anyInt()); assertEquals(-1, r3.getLastAudiblyAlertedMs()); Loading Loading @@ -2381,9 +2397,10 @@ public class NotificationAttentionHelperTest extends UiServiceTestCase { false, null, Notification.GROUP_ALERT_ALL, false, mUser, "anotherPkg"); // update should beep at 0% volume mAttentionHelper.buzzBeepBlinkLocked(r2, DEFAULT_SIGNALS); int buzzBeepBlink = mAttentionHelper.buzzBeepBlinkLocked(r2, DEFAULT_SIGNALS); assertEquals(-1, r2.getLastAudiblyAlertedMs()); verifyBeepVolume(0.0f); verifyNeverBeep(); assertThat(buzzBeepBlink).isEqualTo(MetricsEvent.ALERT_MUTED | MUTE_REASON_COOLDOWN); // Use different package for next notifications NotificationRecord r3 = getNotificationRecord(mId, false /* insistent */, false /* once */, Loading @@ -2392,8 +2409,9 @@ public class NotificationAttentionHelperTest extends UiServiceTestCase { // 2nd update should beep at 0% volume Mockito.reset(mRingtonePlayer); mAttentionHelper.buzzBeepBlinkLocked(r3, DEFAULT_SIGNALS); verifyBeepVolume(0.0f); buzzBeepBlink = mAttentionHelper.buzzBeepBlinkLocked(r3, DEFAULT_SIGNALS); verifyNeverBeep(); assertThat(buzzBeepBlink).isEqualTo(MetricsEvent.ALERT_MUTED | MUTE_REASON_COOLDOWN); verify(mAccessibilityService, times(3)).sendAccessibilityEvent(any(), anyInt()); assertEquals(-1, r3.getLastAudiblyAlertedMs()); Loading Loading @@ -2493,8 +2511,9 @@ public class NotificationAttentionHelperTest extends UiServiceTestCase { // Regular notification: should beep at 0% volume NotificationRecord r = getBeepyNotification(); mAttentionHelper.buzzBeepBlinkLocked(r, DEFAULT_SIGNALS); verifyBeepVolume(0.0f); int buzzBeepBlink = mAttentionHelper.buzzBeepBlinkLocked(r, DEFAULT_SIGNALS); verifyNeverBeep(); assertThat(buzzBeepBlink).isEqualTo(MetricsEvent.ALERT_MUTED | MUTE_REASON_COOLDOWN); assertEquals(-1, r.getLastAudiblyAlertedMs()); Mockito.reset(mRingtonePlayer); Loading Loading @@ -2525,8 +2544,9 @@ public class NotificationAttentionHelperTest extends UiServiceTestCase { // 2nd update should beep at 0% volume Mockito.reset(mRingtonePlayer); mAttentionHelper.buzzBeepBlinkLocked(r3, DEFAULT_SIGNALS); verifyBeepVolume(0.0f); buzzBeepBlink = mAttentionHelper.buzzBeepBlinkLocked(r3, DEFAULT_SIGNALS); verifyNeverBeep(); assertThat(buzzBeepBlink).isEqualTo(MetricsEvent.ALERT_MUTED | MUTE_REASON_COOLDOWN); // Set important conversation mChannel.setImportantConversation(true); Loading Loading @@ -2751,9 +2771,10 @@ public class NotificationAttentionHelperTest extends UiServiceTestCase { Mockito.reset(mRingtonePlayer); // next update at 0% volume mAttentionHelper.buzzBeepBlinkLocked(summary, DEFAULT_SIGNALS); int buzzBeepBlink = mAttentionHelper.buzzBeepBlinkLocked(summary, DEFAULT_SIGNALS); assertEquals(-1, summary.getLastAudiblyAlertedMs()); verifyBeepVolume(0.0f); verifyNeverBeep(); assertThat(buzzBeepBlink).isEqualTo(MetricsEvent.ALERT_MUTED | MUTE_REASON_COOLDOWN); verify(mAccessibilityService, times(3)).sendAccessibilityEvent(any(), anyInt()); } Loading Loading @@ -2823,9 +2844,10 @@ public class NotificationAttentionHelperTest extends UiServiceTestCase { // 2nd update should beep at 0% volume Mockito.reset(mRingtonePlayer); mAttentionHelper.buzzBeepBlinkLocked(r2, DEFAULT_SIGNALS); int buzzBeepBlink = mAttentionHelper.buzzBeepBlinkLocked(r2, DEFAULT_SIGNALS); assertEquals(-1, r2.getLastAudiblyAlertedMs()); verifyBeepVolume(0.0f); verifyNeverBeep(); assertThat(buzzBeepBlink).isEqualTo(MetricsEvent.ALERT_MUTED | MUTE_REASON_COOLDOWN); // Use different package for next notifications NotificationRecord r3 = getNotificationRecord(mId, false /* insistent */, false /* once */, Loading Loading @@ -2890,6 +2912,94 @@ public class NotificationAttentionHelperTest extends UiServiceTestCase { assertNotEquals(-1, r3.getLastAudiblyAlertedMs()); } @Test public void testBeepVolume_politeNotif_groupAlertSummary() throws Exception { mSetFlagsRule.enableFlags(Flags.FLAG_POLITE_NOTIFICATIONS); mSetFlagsRule.disableFlags(Flags.FLAG_CROSS_APP_POLITE_NOTIFICATIONS); TestableFlagResolver flagResolver = new TestableFlagResolver(); flagResolver.setFlagOverride(NotificationFlags.NOTIF_VOLUME1, 50); flagResolver.setFlagOverride(NotificationFlags.NOTIF_VOLUME2, 0); // NOTIFICATION_COOLDOWN_ALL setting is enabled Settings.System.putInt(getContext().getContentResolver(), Settings.System.NOTIFICATION_COOLDOWN_ALL, 1); initAttentionHelper(flagResolver); // child should beep at 0% volume NotificationRecord child = getBeepyNotificationRecord("a", GROUP_ALERT_SUMMARY); mAttentionHelper.buzzBeepBlinkLocked(child, DEFAULT_SIGNALS); verifyNeverBeep(); assertFalse(child.isInterruptive()); assertEquals(-1, child.getLastAudiblyAlertedMs()); Mockito.reset(mRingtonePlayer); // child should beep at 0% volume child = getBeepyNotificationRecord("a", GROUP_ALERT_SUMMARY); mAttentionHelper.buzzBeepBlinkLocked(child, DEFAULT_SIGNALS); verifyNeverBeep(); assertFalse(child.isInterruptive()); assertEquals(-1, child.getLastAudiblyAlertedMs()); Mockito.reset(mRingtonePlayer); // summary 100% volume (GROUP_ALERT_SUMMARY) NotificationRecord summary = getBeepyNotificationRecord("a", GROUP_ALERT_SUMMARY); summary.getNotification().flags |= Notification.FLAG_GROUP_SUMMARY; mAttentionHelper.buzzBeepBlinkLocked(summary, DEFAULT_SIGNALS); assertNotEquals(-1, summary.getLastAudiblyAlertedMs()); verifyBeepVolume(1.0f); Mockito.reset(mRingtonePlayer); // next update at 50% volume because only summary was tracked as alerting mAttentionHelper.buzzBeepBlinkLocked(summary, DEFAULT_SIGNALS); assertNotEquals(-1, summary.getLastAudiblyAlertedMs()); verifyBeepVolume(0.5f); verify(mAccessibilityService, times(4)).sendAccessibilityEvent(any(), anyInt()); } @Test public void testBeepVolume_politeNotif_groupAlertChildren() throws Exception { mSetFlagsRule.enableFlags(Flags.FLAG_POLITE_NOTIFICATIONS); mSetFlagsRule.disableFlags(Flags.FLAG_CROSS_APP_POLITE_NOTIFICATIONS); TestableFlagResolver flagResolver = new TestableFlagResolver(); flagResolver.setFlagOverride(NotificationFlags.NOTIF_VOLUME1, 50); flagResolver.setFlagOverride(NotificationFlags.NOTIF_VOLUME2, 0); // NOTIFICATION_COOLDOWN_ALL setting is enabled Settings.System.putInt(getContext().getContentResolver(), Settings.System.NOTIFICATION_COOLDOWN_ALL, 1); initAttentionHelper(flagResolver); // summary 0% volume (GROUP_ALERT_CHILDREN) NotificationRecord summary = getBeepyNotificationRecord("a", GROUP_ALERT_CHILDREN); summary.getNotification().flags |= Notification.FLAG_GROUP_SUMMARY; mAttentionHelper.buzzBeepBlinkLocked(summary, DEFAULT_SIGNALS); verifyNeverBeep(); assertFalse(summary.isInterruptive()); assertEquals(-1, summary.getLastAudiblyAlertedMs()); Mockito.reset(mRingtonePlayer); // child should beep at 100% volume NotificationRecord child = getBeepyNotificationRecord("a", GROUP_ALERT_CHILDREN); mAttentionHelper.buzzBeepBlinkLocked(child, DEFAULT_SIGNALS); assertNotEquals(-1, child.getLastAudiblyAlertedMs()); verifyBeepVolume(1.0f); Mockito.reset(mRingtonePlayer); // child should beep at 50% volume child = getBeepyNotificationRecord("a", GROUP_ALERT_CHILDREN); mAttentionHelper.buzzBeepBlinkLocked(child, DEFAULT_SIGNALS); assertNotEquals(-1, child.getLastAudiblyAlertedMs()); verifyBeepVolume(0.5f); Mockito.reset(mRingtonePlayer); // child should beep at 0% volume mAttentionHelper.buzzBeepBlinkLocked(child, DEFAULT_SIGNALS); verifyNeverBeep(); assertTrue(child.isInterruptive()); assertEquals(-1, child.getLastAudiblyAlertedMs()); verify(mAccessibilityService, times(4)).sendAccessibilityEvent(any(), anyInt()); } @Test public void testVibrationIntensity_politeNotif() throws Exception { mSetFlagsRule.enableFlags(Flags.FLAG_POLITE_NOTIFICATIONS); Loading @@ -2914,8 +3024,9 @@ public class NotificationAttentionHelperTest extends UiServiceTestCase { Mockito.reset(vibratorHelper); // 2nd update should buzz at 0% intensity mAttentionHelper.buzzBeepBlinkLocked(r, DEFAULT_SIGNALS); verify(vibratorHelper, times(1)).scale(any(), eq(0.0f)); int buzzBeepBlink = mAttentionHelper.buzzBeepBlinkLocked(r, DEFAULT_SIGNALS); verifyNeverVibrate(); assertThat(buzzBeepBlink).isEqualTo(MetricsEvent.ALERT_MUTED | MUTE_REASON_COOLDOWN); } @Test Loading Loading @@ -3007,10 +3118,11 @@ public class NotificationAttentionHelperTest extends UiServiceTestCase { // 2nd update should beep at 0% volume Mockito.reset(mRingtonePlayer); mAttentionHelper.buzzBeepBlinkLocked(r, WORK_PROFILE_SIGNALS); verifyBeepVolume(0.0f); int buzzBeepBlink = mAttentionHelper.buzzBeepBlinkLocked(r, WORK_PROFILE_SIGNALS); verifyNeverBeep(); assertThat(buzzBeepBlink).isEqualTo(MetricsEvent.ALERT_MUTED | MUTE_REASON_COOLDOWN); verify(mAccessibilityService, times(3)).sendAccessibilityEvent(any(), anyInt()); verify(mAccessibilityService, times(2)).sendAccessibilityEvent(any(), anyInt()); assertEquals(-1, r.getLastAudiblyAlertedMs()); } Loading