Loading services/core/java/com/android/server/notification/NotificationAttentionHelper.java +40 −10 Original line number Diff line number Diff line Loading @@ -22,12 +22,14 @@ import static android.app.Notification.FLAG_ONLY_ALERT_ONCE; import static android.app.NotificationManager.IMPORTANCE_MIN; import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_LIGHTS; import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_STATUS_BAR; import static android.content.pm.PackageManager.PERMISSION_GRANTED; import static android.media.AudioAttributes.USAGE_NOTIFICATION_RINGTONE; import static android.media.audio.Flags.focusExclusiveWithRecording; import static android.service.notification.NotificationListenerService.HINT_HOST_DISABLE_CALL_EFFECTS; import static android.service.notification.NotificationListenerService.HINT_HOST_DISABLE_EFFECTS; import static android.service.notification.NotificationListenerService.HINT_HOST_DISABLE_NOTIFICATION_EFFECTS; import android.Manifest.permission; import android.annotation.IntDef; import android.app.ActivityManager; import android.app.KeyguardManager; Loading Loading @@ -223,7 +225,10 @@ public final class NotificationAttentionHelper { mFlagResolver.getIntValue(NotificationFlags.NOTIF_COOLDOWN_T2), mFlagResolver.getIntValue(NotificationFlags.NOTIF_VOLUME1), mFlagResolver.getIntValue(NotificationFlags.NOTIF_VOLUME2), mFlagResolver.getIntValue(NotificationFlags.NOTIF_COOLDOWN_COUNTER_RESET)); mFlagResolver.getIntValue(NotificationFlags.NOTIF_COOLDOWN_COUNTER_RESET), record -> mPackageManager.checkPermission( permission.RECEIVE_EMERGENCY_BROADCAST, record.getSbn().getPackageName()) == PERMISSION_GRANTED); return new StrategyAvalanche( mFlagResolver.getIntValue(NotificationFlags.NOTIF_COOLDOWN_T1), Loading @@ -231,14 +236,17 @@ public final class NotificationAttentionHelper { mFlagResolver.getIntValue(NotificationFlags.NOTIF_VOLUME1), mFlagResolver.getIntValue(NotificationFlags.NOTIF_VOLUME2), mFlagResolver.getIntValue(NotificationFlags.NOTIF_AVALANCHE_TIMEOUT), appStrategy); appStrategy, appStrategy.mExemptionProvider); } else { return new StrategyPerApp( mFlagResolver.getIntValue(NotificationFlags.NOTIF_COOLDOWN_T1), mFlagResolver.getIntValue(NotificationFlags.NOTIF_COOLDOWN_T2), mFlagResolver.getIntValue(NotificationFlags.NOTIF_VOLUME1), mFlagResolver.getIntValue(NotificationFlags.NOTIF_VOLUME2), mFlagResolver.getIntValue(NotificationFlags.NOTIF_COOLDOWN_COUNTER_RESET)); mFlagResolver.getIntValue(NotificationFlags.NOTIF_COOLDOWN_COUNTER_RESET), record -> mPackageManager.checkPermission( permission.RECEIVE_EMERGENCY_BROADCAST, record.getSbn().getPackageName()) == PERMISSION_GRANTED); } } Loading Loading @@ -1098,6 +1106,11 @@ public final class NotificationAttentionHelper { } } // Returns true if a notification should be exempted from attenuation private interface ExemptionProvider { boolean isExempted(NotificationRecord record); } @VisibleForTesting abstract static class PolitenessStrategy { static final int POLITE_STATE_DEFAULT = 0; Loading Loading @@ -1128,8 +1141,10 @@ public final class NotificationAttentionHelper { protected boolean mIsActive = true; protected final ExemptionProvider mExemptionProvider; public PolitenessStrategy(int timeoutPolite, int timeoutMuted, int volumePolite, int volumeMuted) { int volumeMuted, ExemptionProvider exemptionProvider) { mVolumeStates = new HashMap<>(); mLastUpdatedTimestampByPackage = new HashMap<>(); Loading @@ -1137,6 +1152,7 @@ public final class NotificationAttentionHelper { this.mTimeoutMuted = timeoutMuted; this.mVolumePolite = volumePolite / 100.0f; this.mVolumeMuted = volumeMuted / 100.0f; this.mExemptionProvider = exemptionProvider; } abstract void onNotificationPosted(NotificationRecord record); Loading Loading @@ -1294,8 +1310,8 @@ public final class NotificationAttentionHelper { private final int mMaxPostedForReset; public StrategyPerApp(int timeoutPolite, int timeoutMuted, int volumePolite, int volumeMuted, int maxPosted) { super(timeoutPolite, timeoutMuted, volumePolite, volumeMuted); int volumeMuted, int maxPosted, ExemptionProvider exemptionProvider) { super(timeoutPolite, timeoutMuted, volumePolite, volumeMuted, exemptionProvider); mNumPosted = new HashMap<>(); mMaxPostedForReset = maxPosted; Loading @@ -1316,7 +1332,12 @@ public final class NotificationAttentionHelper { final String key = getChannelKey(record); @PolitenessState final int currState = getPolitenessState(record); @PolitenessState int nextState = getNextState(currState, timeSinceLastNotif); @PolitenessState int nextState; if (Flags.politeNotificationsAttnUpdate()) { nextState = getNextState(currState, timeSinceLastNotif, record); } else { nextState = getNextState(currState, timeSinceLastNotif); } // Reset to default state if number of posted notifications exceed this value when muted int numPosted = mNumPosted.getOrDefault(key, 0) + 1; Loading @@ -1334,6 +1355,14 @@ public final class NotificationAttentionHelper { mVolumeStates.put(key, nextState); } @PolitenessState int getNextState(@PolitenessState final int currState, final long timeSinceLastNotif, final NotificationRecord record) { if (mExemptionProvider.isExempted(record)) { return POLITE_STATE_DEFAULT; } return getNextState(currState, timeSinceLastNotif); } @Override public void onUserInteraction(final NotificationRecord record) { super.onUserInteraction(record); Loading @@ -1354,8 +1383,9 @@ public final class NotificationAttentionHelper { private long mLastAvalancheTriggerTimestamp = 0; StrategyAvalanche(int timeoutPolite, int timeoutMuted, int volumePolite, int volumeMuted, int timeoutAvalanche, PolitenessStrategy appStrategy) { super(timeoutPolite, timeoutMuted, volumePolite, volumeMuted); int volumeMuted, int timeoutAvalanche, PolitenessStrategy appStrategy, ExemptionProvider exemptionProvider) { super(timeoutPolite, timeoutMuted, volumePolite, volumeMuted, exemptionProvider); mTimeoutAvalanche = timeoutAvalanche; mAppStrategy = appStrategy; Loading Loading @@ -1528,7 +1558,7 @@ public final class NotificationAttentionHelper { return true; } return false; return mExemptionProvider.isExempted(record); } private boolean isAvalancheExempted(final NotificationRecord record) { Loading services/tests/uiservicestests/src/com/android/server/notification/NotificationAttentionHelperTest.java +71 −0 Original line number Diff line number Diff line Loading @@ -24,6 +24,8 @@ import static android.app.NotificationManager.IMPORTANCE_HIGH; import static android.app.NotificationManager.IMPORTANCE_LOW; import static android.app.NotificationManager.IMPORTANCE_MIN; import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_LIGHTS; import static android.content.pm.PackageManager.PERMISSION_DENIED; import static android.content.pm.PackageManager.PERMISSION_GRANTED; import static android.media.AudioAttributes.USAGE_NOTIFICATION; import static android.media.AudioAttributes.USAGE_NOTIFICATION_RINGTONE; Loading Loading @@ -52,6 +54,7 @@ import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; import android.Manifest.permission; import android.annotation.SuppressLint; import android.app.ActivityManager; import android.app.KeyguardManager; Loading Loading @@ -190,6 +193,8 @@ public class NotificationAttentionHelperTest extends UiServiceTestCase { getContext().addMockSystemService(Vibrator.class, mVibrator); getContext().addMockSystemService(PackageManager.class, mPackageManager); when(mPackageManager.hasSystemFeature(PackageManager.FEATURE_TELEPHONY)).thenReturn(false); when(mPackageManager.checkPermission(eq(permission.RECEIVE_EMERGENCY_BROADCAST), anyString())).thenReturn(PERMISSION_DENIED); when(mAudioManager.isAudioFocusExclusive()).thenReturn(false); when(mAudioManager.getRingtonePlayer()).thenReturn(mRingtonePlayer); Loading Loading @@ -2362,6 +2367,72 @@ public class NotificationAttentionHelperTest extends UiServiceTestCase { assertNotEquals(-1, r4.getLastAudiblyAlertedMs()); } @Test public void testBeepVolume_politeNotif_Avalanche_exemptEmergency() throws Exception { mSetFlagsRule.enableFlags(Flags.FLAG_POLITE_NOTIFICATIONS); mSetFlagsRule.enableFlags(Flags.FLAG_CROSS_APP_POLITE_NOTIFICATIONS); mSetFlagsRule.enableFlags(Flags.FLAG_POLITE_NOTIFICATIONS_ATTN_UPDATE); TestableFlagResolver flagResolver = new TestableFlagResolver(); flagResolver.setFlagOverride(NotificationFlags.NOTIF_VOLUME1, 50); flagResolver.setFlagOverride(NotificationFlags.NOTIF_VOLUME2, 0); initAttentionHelper(flagResolver); // Trigger avalanche trigger intent final Intent intent = new Intent(Intent.ACTION_AIRPLANE_MODE_CHANGED); intent.putExtra("state", false); mAvalancheBroadcastReceiver.onReceive(getContext(), intent); NotificationRecord r = getBeepyNotification(); // Grant RECEIVE_EMERGENCY_BROADCAST to notification's package when(mPackageManager.checkPermission(eq(permission.RECEIVE_EMERGENCY_BROADCAST), eq(r.getSbn().getPackageName()))).thenReturn(PERMISSION_GRANTED); // Should beep at 100% volume mAttentionHelper.buzzBeepBlinkLocked(r, DEFAULT_SIGNALS); verifyBeepVolume(1.0f); assertNotEquals(-1, r.getLastAudiblyAlertedMs()); verify(mAccessibilityService, times(1)).sendAccessibilityEvent(any(), anyInt()); } @Test public void testBeepVolume_politeNotif_exemptEmergency() throws Exception { mSetFlagsRule.enableFlags(Flags.FLAG_POLITE_NOTIFICATIONS); mSetFlagsRule.disableFlags(Flags.FLAG_CROSS_APP_POLITE_NOTIFICATIONS); mSetFlagsRule.enableFlags(Flags.FLAG_POLITE_NOTIFICATIONS_ATTN_UPDATE); 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); NotificationRecord r = getBeepyNotification(); // Grant RECEIVE_EMERGENCY_BROADCAST to notification's package when(mPackageManager.checkPermission(eq(permission.RECEIVE_EMERGENCY_BROADCAST), eq(r.getSbn().getPackageName()))).thenReturn(PERMISSION_GRANTED); // set up internal state mAttentionHelper.buzzBeepBlinkLocked(r, DEFAULT_SIGNALS); Mockito.reset(mRingtonePlayer); // update should beep at 100% volume NotificationRecord r2 = getBeepyNotification(); mAttentionHelper.buzzBeepBlinkLocked(r2, DEFAULT_SIGNALS); assertNotEquals(-1, r2.getLastAudiblyAlertedMs()); verifyBeepVolume(1.0f); // 2nd update should beep at 100% volume Mockito.reset(mRingtonePlayer); mAttentionHelper.buzzBeepBlinkLocked(r2, DEFAULT_SIGNALS); assertNotEquals(-1, r2.getLastAudiblyAlertedMs()); verifyBeepVolume(1.0f); verify(mAccessibilityService, times(3)).sendAccessibilityEvent(any(), anyInt()); } @Test public void testBeepVolume_politeNotif_applyPerApp() throws Exception { mSetFlagsRule.enableFlags(Flags.FLAG_POLITE_NOTIFICATIONS); Loading Loading
services/core/java/com/android/server/notification/NotificationAttentionHelper.java +40 −10 Original line number Diff line number Diff line Loading @@ -22,12 +22,14 @@ import static android.app.Notification.FLAG_ONLY_ALERT_ONCE; import static android.app.NotificationManager.IMPORTANCE_MIN; import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_LIGHTS; import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_STATUS_BAR; import static android.content.pm.PackageManager.PERMISSION_GRANTED; import static android.media.AudioAttributes.USAGE_NOTIFICATION_RINGTONE; import static android.media.audio.Flags.focusExclusiveWithRecording; import static android.service.notification.NotificationListenerService.HINT_HOST_DISABLE_CALL_EFFECTS; import static android.service.notification.NotificationListenerService.HINT_HOST_DISABLE_EFFECTS; import static android.service.notification.NotificationListenerService.HINT_HOST_DISABLE_NOTIFICATION_EFFECTS; import android.Manifest.permission; import android.annotation.IntDef; import android.app.ActivityManager; import android.app.KeyguardManager; Loading Loading @@ -223,7 +225,10 @@ public final class NotificationAttentionHelper { mFlagResolver.getIntValue(NotificationFlags.NOTIF_COOLDOWN_T2), mFlagResolver.getIntValue(NotificationFlags.NOTIF_VOLUME1), mFlagResolver.getIntValue(NotificationFlags.NOTIF_VOLUME2), mFlagResolver.getIntValue(NotificationFlags.NOTIF_COOLDOWN_COUNTER_RESET)); mFlagResolver.getIntValue(NotificationFlags.NOTIF_COOLDOWN_COUNTER_RESET), record -> mPackageManager.checkPermission( permission.RECEIVE_EMERGENCY_BROADCAST, record.getSbn().getPackageName()) == PERMISSION_GRANTED); return new StrategyAvalanche( mFlagResolver.getIntValue(NotificationFlags.NOTIF_COOLDOWN_T1), Loading @@ -231,14 +236,17 @@ public final class NotificationAttentionHelper { mFlagResolver.getIntValue(NotificationFlags.NOTIF_VOLUME1), mFlagResolver.getIntValue(NotificationFlags.NOTIF_VOLUME2), mFlagResolver.getIntValue(NotificationFlags.NOTIF_AVALANCHE_TIMEOUT), appStrategy); appStrategy, appStrategy.mExemptionProvider); } else { return new StrategyPerApp( mFlagResolver.getIntValue(NotificationFlags.NOTIF_COOLDOWN_T1), mFlagResolver.getIntValue(NotificationFlags.NOTIF_COOLDOWN_T2), mFlagResolver.getIntValue(NotificationFlags.NOTIF_VOLUME1), mFlagResolver.getIntValue(NotificationFlags.NOTIF_VOLUME2), mFlagResolver.getIntValue(NotificationFlags.NOTIF_COOLDOWN_COUNTER_RESET)); mFlagResolver.getIntValue(NotificationFlags.NOTIF_COOLDOWN_COUNTER_RESET), record -> mPackageManager.checkPermission( permission.RECEIVE_EMERGENCY_BROADCAST, record.getSbn().getPackageName()) == PERMISSION_GRANTED); } } Loading Loading @@ -1098,6 +1106,11 @@ public final class NotificationAttentionHelper { } } // Returns true if a notification should be exempted from attenuation private interface ExemptionProvider { boolean isExempted(NotificationRecord record); } @VisibleForTesting abstract static class PolitenessStrategy { static final int POLITE_STATE_DEFAULT = 0; Loading Loading @@ -1128,8 +1141,10 @@ public final class NotificationAttentionHelper { protected boolean mIsActive = true; protected final ExemptionProvider mExemptionProvider; public PolitenessStrategy(int timeoutPolite, int timeoutMuted, int volumePolite, int volumeMuted) { int volumeMuted, ExemptionProvider exemptionProvider) { mVolumeStates = new HashMap<>(); mLastUpdatedTimestampByPackage = new HashMap<>(); Loading @@ -1137,6 +1152,7 @@ public final class NotificationAttentionHelper { this.mTimeoutMuted = timeoutMuted; this.mVolumePolite = volumePolite / 100.0f; this.mVolumeMuted = volumeMuted / 100.0f; this.mExemptionProvider = exemptionProvider; } abstract void onNotificationPosted(NotificationRecord record); Loading Loading @@ -1294,8 +1310,8 @@ public final class NotificationAttentionHelper { private final int mMaxPostedForReset; public StrategyPerApp(int timeoutPolite, int timeoutMuted, int volumePolite, int volumeMuted, int maxPosted) { super(timeoutPolite, timeoutMuted, volumePolite, volumeMuted); int volumeMuted, int maxPosted, ExemptionProvider exemptionProvider) { super(timeoutPolite, timeoutMuted, volumePolite, volumeMuted, exemptionProvider); mNumPosted = new HashMap<>(); mMaxPostedForReset = maxPosted; Loading @@ -1316,7 +1332,12 @@ public final class NotificationAttentionHelper { final String key = getChannelKey(record); @PolitenessState final int currState = getPolitenessState(record); @PolitenessState int nextState = getNextState(currState, timeSinceLastNotif); @PolitenessState int nextState; if (Flags.politeNotificationsAttnUpdate()) { nextState = getNextState(currState, timeSinceLastNotif, record); } else { nextState = getNextState(currState, timeSinceLastNotif); } // Reset to default state if number of posted notifications exceed this value when muted int numPosted = mNumPosted.getOrDefault(key, 0) + 1; Loading @@ -1334,6 +1355,14 @@ public final class NotificationAttentionHelper { mVolumeStates.put(key, nextState); } @PolitenessState int getNextState(@PolitenessState final int currState, final long timeSinceLastNotif, final NotificationRecord record) { if (mExemptionProvider.isExempted(record)) { return POLITE_STATE_DEFAULT; } return getNextState(currState, timeSinceLastNotif); } @Override public void onUserInteraction(final NotificationRecord record) { super.onUserInteraction(record); Loading @@ -1354,8 +1383,9 @@ public final class NotificationAttentionHelper { private long mLastAvalancheTriggerTimestamp = 0; StrategyAvalanche(int timeoutPolite, int timeoutMuted, int volumePolite, int volumeMuted, int timeoutAvalanche, PolitenessStrategy appStrategy) { super(timeoutPolite, timeoutMuted, volumePolite, volumeMuted); int volumeMuted, int timeoutAvalanche, PolitenessStrategy appStrategy, ExemptionProvider exemptionProvider) { super(timeoutPolite, timeoutMuted, volumePolite, volumeMuted, exemptionProvider); mTimeoutAvalanche = timeoutAvalanche; mAppStrategy = appStrategy; Loading Loading @@ -1528,7 +1558,7 @@ public final class NotificationAttentionHelper { return true; } return false; return mExemptionProvider.isExempted(record); } private boolean isAvalancheExempted(final NotificationRecord record) { Loading
services/tests/uiservicestests/src/com/android/server/notification/NotificationAttentionHelperTest.java +71 −0 Original line number Diff line number Diff line Loading @@ -24,6 +24,8 @@ import static android.app.NotificationManager.IMPORTANCE_HIGH; import static android.app.NotificationManager.IMPORTANCE_LOW; import static android.app.NotificationManager.IMPORTANCE_MIN; import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_LIGHTS; import static android.content.pm.PackageManager.PERMISSION_DENIED; import static android.content.pm.PackageManager.PERMISSION_GRANTED; import static android.media.AudioAttributes.USAGE_NOTIFICATION; import static android.media.AudioAttributes.USAGE_NOTIFICATION_RINGTONE; Loading Loading @@ -52,6 +54,7 @@ import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; import android.Manifest.permission; import android.annotation.SuppressLint; import android.app.ActivityManager; import android.app.KeyguardManager; Loading Loading @@ -190,6 +193,8 @@ public class NotificationAttentionHelperTest extends UiServiceTestCase { getContext().addMockSystemService(Vibrator.class, mVibrator); getContext().addMockSystemService(PackageManager.class, mPackageManager); when(mPackageManager.hasSystemFeature(PackageManager.FEATURE_TELEPHONY)).thenReturn(false); when(mPackageManager.checkPermission(eq(permission.RECEIVE_EMERGENCY_BROADCAST), anyString())).thenReturn(PERMISSION_DENIED); when(mAudioManager.isAudioFocusExclusive()).thenReturn(false); when(mAudioManager.getRingtonePlayer()).thenReturn(mRingtonePlayer); Loading Loading @@ -2362,6 +2367,72 @@ public class NotificationAttentionHelperTest extends UiServiceTestCase { assertNotEquals(-1, r4.getLastAudiblyAlertedMs()); } @Test public void testBeepVolume_politeNotif_Avalanche_exemptEmergency() throws Exception { mSetFlagsRule.enableFlags(Flags.FLAG_POLITE_NOTIFICATIONS); mSetFlagsRule.enableFlags(Flags.FLAG_CROSS_APP_POLITE_NOTIFICATIONS); mSetFlagsRule.enableFlags(Flags.FLAG_POLITE_NOTIFICATIONS_ATTN_UPDATE); TestableFlagResolver flagResolver = new TestableFlagResolver(); flagResolver.setFlagOverride(NotificationFlags.NOTIF_VOLUME1, 50); flagResolver.setFlagOverride(NotificationFlags.NOTIF_VOLUME2, 0); initAttentionHelper(flagResolver); // Trigger avalanche trigger intent final Intent intent = new Intent(Intent.ACTION_AIRPLANE_MODE_CHANGED); intent.putExtra("state", false); mAvalancheBroadcastReceiver.onReceive(getContext(), intent); NotificationRecord r = getBeepyNotification(); // Grant RECEIVE_EMERGENCY_BROADCAST to notification's package when(mPackageManager.checkPermission(eq(permission.RECEIVE_EMERGENCY_BROADCAST), eq(r.getSbn().getPackageName()))).thenReturn(PERMISSION_GRANTED); // Should beep at 100% volume mAttentionHelper.buzzBeepBlinkLocked(r, DEFAULT_SIGNALS); verifyBeepVolume(1.0f); assertNotEquals(-1, r.getLastAudiblyAlertedMs()); verify(mAccessibilityService, times(1)).sendAccessibilityEvent(any(), anyInt()); } @Test public void testBeepVolume_politeNotif_exemptEmergency() throws Exception { mSetFlagsRule.enableFlags(Flags.FLAG_POLITE_NOTIFICATIONS); mSetFlagsRule.disableFlags(Flags.FLAG_CROSS_APP_POLITE_NOTIFICATIONS); mSetFlagsRule.enableFlags(Flags.FLAG_POLITE_NOTIFICATIONS_ATTN_UPDATE); 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); NotificationRecord r = getBeepyNotification(); // Grant RECEIVE_EMERGENCY_BROADCAST to notification's package when(mPackageManager.checkPermission(eq(permission.RECEIVE_EMERGENCY_BROADCAST), eq(r.getSbn().getPackageName()))).thenReturn(PERMISSION_GRANTED); // set up internal state mAttentionHelper.buzzBeepBlinkLocked(r, DEFAULT_SIGNALS); Mockito.reset(mRingtonePlayer); // update should beep at 100% volume NotificationRecord r2 = getBeepyNotification(); mAttentionHelper.buzzBeepBlinkLocked(r2, DEFAULT_SIGNALS); assertNotEquals(-1, r2.getLastAudiblyAlertedMs()); verifyBeepVolume(1.0f); // 2nd update should beep at 100% volume Mockito.reset(mRingtonePlayer); mAttentionHelper.buzzBeepBlinkLocked(r2, DEFAULT_SIGNALS); assertNotEquals(-1, r2.getLastAudiblyAlertedMs()); verifyBeepVolume(1.0f); verify(mAccessibilityService, times(3)).sendAccessibilityEvent(any(), anyInt()); } @Test public void testBeepVolume_politeNotif_applyPerApp() throws Exception { mSetFlagsRule.enableFlags(Flags.FLAG_POLITE_NOTIFICATIONS); Loading