Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 63ff0454 authored by Treehugger Robot's avatar Treehugger Robot Committed by Android (Google) Code Review
Browse files

Merge "Skip playing notification sound or vibration when cooldown is muted" into main

parents 58f9bdf0 216db747
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -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
+66 −32
Original line number Diff line number Diff line
@@ -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;
@@ -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();

@@ -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
@@ -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;
@@ -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) {
@@ -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;
            }
        }

@@ -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
@@ -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) {
@@ -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.
         *
@@ -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);

@@ -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);

+148 −36
Original line number Diff line number Diff line
@@ -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;
@@ -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;
@@ -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
@@ -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
@@ -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);
@@ -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
@@ -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();
@@ -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();
@@ -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);
@@ -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());
    }

@@ -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());
@@ -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 */,
@@ -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());
@@ -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);

@@ -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);
@@ -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());
    }
@@ -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 */,
@@ -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);
@@ -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
@@ -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());
    }