Muting notifications due to focus is conditional on recording
Legacy behavior is to mute notification while an app has
requested audio focus with GAIN_TRANSIENT_EXCLUSIVE.
The new behavior under flag is to enforce that the muting
happens only when the focus requester is also recording audio.
Implementation uses a new AudioManager method that contains
all audio framework-side evaluation of whether the notification
should play, and avoid code duplication in
NotificationManagerService and NotificationAttentionHelper.
Annotated AudioAttributes field in NotificationRecord
to document that they are never null (so always available
to be consumed by AudioManager.shouldNotificationSoundPlay).
Updated unit tests to also mock AudioManager's response
for shouldNotificationPlaySound such that it's compliant
with the ringer mode and volume set on the mock in the
existing test. This way the test is independent of the flag
state.
Flag: android.media.audio.focus_exclusive_with_recording
Test: atest android.media.audio.cts.AudioFocusTest
Test: atest BuzzBeepBlinkTest NotificationAttentionHelperTest
Bug: 316414750
Change-Id: I54147c0dcccd7785589f4c9882582f42cf1a2d65
diff --git a/core/api/test-current.txt b/core/api/test-current.txt
index 812ba6d..59f0345b 100644
--- a/core/api/test-current.txt
+++ b/core/api/test-current.txt
@@ -1871,6 +1871,7 @@
method public void setRampingRingerEnabled(boolean);
method @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_SETTINGS_PRIVILEGED) public void setRs2Value(float);
method @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public void setTestDeviceConnectionState(@NonNull android.media.AudioDeviceAttributes, boolean);
+ method @FlaggedApi("android.media.audio.focus_exclusive_with_recording") @RequiresPermission(android.Manifest.permission.QUERY_AUDIO_STATE) public boolean shouldNotificationSoundPlay(@NonNull android.media.AudioAttributes);
}
public static final class AudioRecord.MetricsConstants {
diff --git a/media/java/android/media/AudioManager.java b/media/java/android/media/AudioManager.java
index a5a69f9..4918289 100644
--- a/media/java/android/media/AudioManager.java
+++ b/media/java/android/media/AudioManager.java
@@ -21,6 +21,7 @@
import static android.content.Context.DEVICE_ID_DEFAULT;
import static android.media.audio.Flags.autoPublicVolumeApiHardening;
import static android.media.audio.Flags.automaticBtDeviceType;
+import static android.media.audio.Flags.FLAG_FOCUS_EXCLUSIVE_WITH_RECORDING;
import static android.media.audio.Flags.FLAG_FOCUS_FREEZE_TEST_API;
import static android.media.audiopolicy.Flags.FLAG_ENABLE_FADE_MANAGER_CONFIGURATION;
@@ -10081,6 +10082,28 @@
}
}
+ /**
+ * @hide
+ * Checks whether a notification sound should be played or not, as reported by the state
+ * of the audio framework. Querying whether playback should proceed is favored over
+ * playing and letting the sound be muted or not.
+ * @param aa the {@link AudioAttributes} of the notification about to maybe play
+ * @return true if the audio framework state is such that the notification should be played
+ * because at time of checking, and the notification will be heard,
+ * false otherwise
+ */
+ @TestApi
+ @FlaggedApi(FLAG_FOCUS_EXCLUSIVE_WITH_RECORDING)
+ @RequiresPermission(android.Manifest.permission.QUERY_AUDIO_STATE)
+ public boolean shouldNotificationSoundPlay(@NonNull final AudioAttributes aa) {
+ final IAudioService service = getService();
+ try {
+ return service.shouldNotificationSoundPlay(Objects.requireNonNull(aa));
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
//====================================================================
// Mute await connection
diff --git a/media/java/android/media/IAudioService.aidl b/media/java/android/media/IAudioService.aidl
index 5c268d4..2eec9b3 100644
--- a/media/java/android/media/IAudioService.aidl
+++ b/media/java/android/media/IAudioService.aidl
@@ -775,4 +775,8 @@
@EnforcePermission("MODIFY_AUDIO_SETTINGS_PRIVILEGED")
@JavaPassthrough(annotation="@android.annotation.RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_SETTINGS_PRIVILEGED)")
FadeManagerConfiguration getFadeManagerConfigurationForFocusLoss();
+
+ @EnforcePermission("QUERY_AUDIO_STATE")
+ @JavaPassthrough(annotation="@android.annotation.RequiresPermission(android.Manifest.permission.QUERY_AUDIO_STATE)")
+ boolean shouldNotificationSoundPlay(in AudioAttributes aa);
}
diff --git a/services/core/java/com/android/server/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java
index 37fe389..2036ce2 100644
--- a/services/core/java/com/android/server/audio/AudioService.java
+++ b/services/core/java/com/android/server/audio/AudioService.java
@@ -13588,6 +13588,46 @@
}
}
+
+ /**
+ * @see AudioManager#shouldNotificationSoundPlay(AudioAttributes)
+ */
+ @android.annotation.EnforcePermission(
+ android.Manifest.permission.QUERY_AUDIO_STATE)
+ public boolean shouldNotificationSoundPlay(@NonNull final AudioAttributes aa) {
+ super.shouldNotificationSoundPlay_enforcePermission();
+ Objects.requireNonNull(aa);
+
+ // don't play notifications if the stream volume associated with the
+ // AudioAttributes of the notification record is 0 (non-zero volume implies
+ // not silenced by SILENT or VIBRATE ringer mode)
+ final int stream = AudioAttributes.toLegacyStreamType(aa);
+ final boolean mutingFromVolume = getStreamVolume(stream) == 0;
+ if (mutingFromVolume) {
+ if (DEBUG_VOL) {
+ Slog.d(TAG, "notification should not play due to muted stream " + stream);
+ }
+ return false;
+ }
+
+ // don't play notifications if there is a user of GAIN_TRANSIENT_EXCLUSIVE audio focus
+ // and the focus owner is recording
+ final int uid = mMediaFocusControl.getExclusiveFocusOwnerUid();
+ if (uid == -1) { // return value is -1 if focus isn't GAIN_TRANSIENT_EXCLUSIVE
+ return true;
+ }
+ // is the owner of GAIN_TRANSIENT_EXCLUSIVE focus also recording?
+ final boolean mutingFromFocusAndRecording = mRecordMonitor.isRecordingActiveForUid(uid);
+ if (mutingFromFocusAndRecording) {
+ if (DEBUG_VOL) {
+ Slog.d(TAG, "notification should not play due to exclusive focus owner recording "
+ + " uid:" + uid);
+ }
+ return false;
+ }
+ return true;
+ }
+
//======================
// Audioserver state dispatch
//======================
diff --git a/services/core/java/com/android/server/audio/MediaFocusControl.java b/services/core/java/com/android/server/audio/MediaFocusControl.java
index 0df0006..1376bde 100644
--- a/services/core/java/com/android/server/audio/MediaFocusControl.java
+++ b/services/core/java/com/android/server/audio/MediaFocusControl.java
@@ -297,6 +297,23 @@
}
/**
+ * Return the UID of the focus owner that has focus with exclusive focus gain
+ * @return -1 if nobody has exclusive focus, the UID of the owner otherwise
+ */
+ protected int getExclusiveFocusOwnerUid() {
+ synchronized (mAudioFocusLock) {
+ if (mFocusStack.empty()) {
+ return -1;
+ }
+ final FocusRequester owner = mFocusStack.peek();
+ if (owner.getGainRequest() != AudioManager.AUDIOFOCUS_GAIN_TRANSIENT_EXCLUSIVE) {
+ return -1;
+ }
+ return owner.getClientUid();
+ }
+ }
+
+ /**
* Send AUDIOFOCUS_LOSS to a specific stack entry.
* Note this method is supporting an external API, and is restricted to LOSS in order to
* prevent allowing the stack to be in an invalid state (e.g. entry inside stack has focus)
diff --git a/services/core/java/com/android/server/notification/NotificationAttentionHelper.java b/services/core/java/com/android/server/notification/NotificationAttentionHelper.java
index 6b7db2d..db7be21 100644
--- a/services/core/java/com/android/server/notification/NotificationAttentionHelper.java
+++ b/services/core/java/com/android/server/notification/NotificationAttentionHelper.java
@@ -22,6 +22,7 @@
import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_LIGHTS;
import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_STATUS_BAR;
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;
@@ -588,30 +589,41 @@
}
private boolean playSound(final NotificationRecord record, Uri soundUri) {
+ final boolean shouldPlay;
+ if (focusExclusiveWithRecording()) {
+ // flagged path
+ shouldPlay = mAudioManager.shouldNotificationSoundPlay(record.getAudioAttributes());
+ } else {
+ // legacy path
+ // play notifications if there is no user of exclusive audio focus
+ // and the stream volume is not 0 (non-zero volume implies not silenced by SILENT or
+ // VIBRATE ringer mode)
+ shouldPlay = !mAudioManager.isAudioFocusExclusive()
+ && (mAudioManager.getStreamVolume(
+ AudioAttributes.toLegacyStreamType(record.getAudioAttributes())) != 0);
+ }
+ if (!shouldPlay) {
+ if (DEBUG) Slog.v(TAG, "Not playing sound " + soundUri + " due to focus/volume");
+ return false;
+ }
+
boolean looping = (record.getNotification().flags & FLAG_INSISTENT) != 0;
- // play notifications if there is no user of exclusive audio focus
- // and the stream volume is not 0 (non-zero volume implies not silenced by SILENT or
- // VIBRATE ringer mode)
- if (!mAudioManager.isAudioFocusExclusive()
- && (mAudioManager.getStreamVolume(
- AudioAttributes.toLegacyStreamType(record.getAudioAttributes())) != 0)) {
- final long identity = Binder.clearCallingIdentity();
- try {
- final IRingtonePlayer player = mAudioManager.getRingtonePlayer();
- if (player != null) {
- if (DEBUG) {
- Slog.v(TAG, "Playing sound " + soundUri + " with attributes "
- + record.getAudioAttributes());
- }
- player.playAsync(soundUri, record.getSbn().getUser(), looping,
- record.getAudioAttributes(), getSoundVolume(record));
- return true;
+ final long identity = Binder.clearCallingIdentity();
+ try {
+ final IRingtonePlayer player = mAudioManager.getRingtonePlayer();
+ if (player != null) {
+ if (DEBUG) {
+ Slog.v(TAG, "Playing sound " + soundUri + " with attributes "
+ + record.getAudioAttributes());
}
- } catch (RemoteException e) {
- Log.e(TAG, "Failed playSound: " + e);
- } finally {
- Binder.restoreCallingIdentity(identity);
+ player.playAsync(soundUri, record.getSbn().getUser(), looping,
+ record.getAudioAttributes(), getSoundVolume(record));
+ return true;
}
+ } catch (RemoteException e) {
+ Log.e(TAG, "Failed playSound: " + e);
+ } finally {
+ Binder.restoreCallingIdentity(identity);
}
return false;
}
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index ff415c1..c2cdcb0 100755
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -79,6 +79,7 @@
import static android.content.pm.PackageManager.MATCH_DIRECT_BOOT_AWARE;
import static android.content.pm.PackageManager.MATCH_DIRECT_BOOT_UNAWARE;
import static android.content.pm.PackageManager.PERMISSION_GRANTED;
+import static android.media.audio.Flags.focusExclusiveWithRecording;
import static android.media.AudioAttributes.USAGE_NOTIFICATION_RINGTONE;
import static android.os.Flags.allowPrivateProfile;
import static android.os.IServiceManager.DUMP_FLAG_PRIORITY_CRITICAL;
@@ -9052,27 +9053,40 @@
}
private boolean playSound(final NotificationRecord record, Uri soundUri) {
+ final boolean shouldPlay;
+ if (focusExclusiveWithRecording()) {
+ // flagged path
+ shouldPlay = mAudioManager.shouldNotificationSoundPlay(record.getAudioAttributes());
+ } else {
+ // legacy path
+ // play notifications if there is no user of exclusive audio focus
+ // and the stream volume is not 0 (non-zero volume implies not silenced by SILENT or
+ // VIBRATE ringer mode)
+ shouldPlay = !mAudioManager.isAudioFocusExclusive()
+ && (mAudioManager.getStreamVolume(
+ AudioAttributes.toLegacyStreamType(record.getAudioAttributes())) != 0);
+ }
+ if (!shouldPlay) {
+ if (DBG) Slog.v(TAG, "Not playing sound " + soundUri + " due to focus/volume");
+ return false;
+ }
+
boolean looping = (record.getNotification().flags & FLAG_INSISTENT) != 0;
- // play notifications if there is no user of exclusive audio focus
- // and the stream volume is not 0 (non-zero volume implies not silenced by SILENT or
- // VIBRATE ringer mode)
- if (!mAudioManager.isAudioFocusExclusive()
- && (mAudioManager.getStreamVolume(
- AudioAttributes.toLegacyStreamType(record.getAudioAttributes())) != 0)) {
- final long identity = Binder.clearCallingIdentity();
- try {
- final IRingtonePlayer player = mAudioManager.getRingtonePlayer();
- if (player != null) {
- if (DBG) Slog.v(TAG, "Playing sound " + soundUri
+ final long identity = Binder.clearCallingIdentity();
+ try {
+ final IRingtonePlayer player = mAudioManager.getRingtonePlayer();
+ if (player != null) {
+ if (DBG) {
+ Slog.v(TAG, "Playing sound " + soundUri
+ " with attributes " + record.getAudioAttributes());
- player.playAsync(soundUri, record.getSbn().getUser(), looping,
- record.getAudioAttributes(), 1.0f);
- return true;
}
- } catch (RemoteException e) {
- } finally {
- Binder.restoreCallingIdentity(identity);
+ player.playAsync(soundUri, record.getSbn().getUser(), looping,
+ record.getAudioAttributes(), 1.0f);
+ return true;
}
+ } catch (RemoteException e) {
+ } finally {
+ Binder.restoreCallingIdentity(identity);
}
return false;
}
diff --git a/services/core/java/com/android/server/notification/NotificationRecord.java b/services/core/java/com/android/server/notification/NotificationRecord.java
index 64d3a20..1786ac5 100644
--- a/services/core/java/com/android/server/notification/NotificationRecord.java
+++ b/services/core/java/com/android/server/notification/NotificationRecord.java
@@ -25,6 +25,7 @@
import static android.service.notification.NotificationListenerService.Ranking.USER_SENTIMENT_POSITIVE;
import android.annotation.FlaggedApi;
+import android.annotation.NonNull;
import android.annotation.Nullable;
import android.app.Flags;
import android.app.KeyguardManager;
@@ -167,7 +168,7 @@
private boolean mPreChannelsNotification = true;
private Uri mSound;
private VibrationEffect mVibration;
- private AudioAttributes mAttributes;
+ private @NonNull AudioAttributes mAttributes;
private NotificationChannel mChannel;
private ArrayList<String> mPeopleOverride;
private ArrayList<SnoozeCriterion> mSnoozeCriteria;
@@ -334,7 +335,7 @@
return vibration;
}
- private AudioAttributes calculateAttributes() {
+ private @NonNull AudioAttributes calculateAttributes() {
final Notification n = getSbn().getNotification();
AudioAttributes attributes = getChannel().getAudioAttributes();
if (attributes == null) {
@@ -1003,7 +1004,7 @@
}
public boolean isAudioAttributesUsage(int usage) {
- return mAttributes != null && mAttributes.getUsage() == usage;
+ return mAttributes.getUsage() == usage;
}
/**
@@ -1172,7 +1173,7 @@
return mVibration;
}
- public AudioAttributes getAudioAttributes() {
+ public @NonNull AudioAttributes getAudioAttributes() {
return mAttributes;
}
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/BuzzBeepBlinkTest.java b/services/tests/uiservicestests/src/com/android/server/notification/BuzzBeepBlinkTest.java
index 42ad73a..8622488 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/BuzzBeepBlinkTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/BuzzBeepBlinkTest.java
@@ -158,6 +158,9 @@
when(mAudioManager.isAudioFocusExclusive()).thenReturn(false);
when(mAudioManager.getRingtonePlayer()).thenReturn(mRingtonePlayer);
when(mAudioManager.getStreamVolume(anyInt())).thenReturn(10);
+ // consistent with focus not exclusive and volume not muted
+ when(mAudioManager.shouldNotificationSoundPlay(any(AudioAttributes.class)))
+ .thenReturn(true);
when(mAudioManager.getRingerModeInternal()).thenReturn(AudioManager.RINGER_MODE_NORMAL);
when(mAudioManager.getFocusRampTimeMs(anyInt(), any(AudioAttributes.class))).thenReturn(50);
when(mUsageStats.isAlertRateLimited(any())).thenReturn(false);
@@ -869,6 +872,7 @@
// the phone is quiet
when(mAudioManager.getRingerModeInternal()).thenReturn(AudioManager.RINGER_MODE_VIBRATE);
when(mAudioManager.getStreamVolume(anyInt())).thenReturn(0);
+ when(mAudioManager.shouldNotificationSoundPlay(any())).thenReturn(false);
mService.buzzBeepBlinkLocked(r);
@@ -886,6 +890,8 @@
// the phone is quiet
when(mAudioManager.getRingerModeInternal()).thenReturn(AudioManager.RINGER_MODE_VIBRATE);
when(mAudioManager.getStreamVolume(anyInt())).thenReturn(1);
+ // all streams at 1 means no muting from audio framework
+ when(mAudioManager.shouldNotificationSoundPlay(any())).thenReturn(true);
mService.buzzBeepBlinkLocked(r);
@@ -904,6 +910,7 @@
// the phone is quiet
when(mAudioManager.getRingerModeInternal()).thenReturn(AudioManager.RINGER_MODE_VIBRATE);
when(mAudioManager.getStreamVolume(anyInt())).thenReturn(0);
+ when(mAudioManager.shouldNotificationSoundPlay(any())).thenReturn(false);
mService.buzzBeepBlinkLocked(r);
@@ -924,6 +931,7 @@
// the phone is quiet
when(mAudioManager.getStreamVolume(anyInt())).thenReturn(0);
when(mAudioManager.getRingerModeInternal()).thenReturn(AudioManager.RINGER_MODE_VIBRATE);
+ when(mAudioManager.shouldNotificationSoundPlay(any())).thenReturn(false);
mService.buzzBeepBlinkLocked(r);
@@ -1195,6 +1203,7 @@
// the phone is quiet
when(mAudioManager.getStreamVolume(anyInt())).thenReturn(0);
when(mAudioManager.getRingerModeInternal()).thenReturn(AudioManager.RINGER_MODE_VIBRATE);
+ when(mAudioManager.shouldNotificationSoundPlay(any())).thenReturn(false);
mService.buzzBeepBlinkLocked(r);
verifyDelayedVibrate(mService.getVibratorHelper().createFallbackVibration(false));
@@ -1923,6 +1932,7 @@
NotificationRecord r = getBuzzyBeepyNotification();
when(mAudioManager.getRingerModeInternal()).thenReturn(AudioManager.RINGER_MODE_SILENT);
when(mAudioManager.getStreamVolume(anyInt())).thenReturn(0);
+ when(mAudioManager.shouldNotificationSoundPlay(any())).thenReturn(false);
mService.buzzBeepBlinkLocked(r);
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/NotificationAttentionHelperTest.java b/services/tests/uiservicestests/src/com/android/server/notification/NotificationAttentionHelperTest.java
index cf8548c..f0f97ac 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationAttentionHelperTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationAttentionHelperTest.java
@@ -25,9 +25,11 @@
import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_LIGHTS;
import static android.media.AudioAttributes.USAGE_NOTIFICATION;
import static android.media.AudioAttributes.USAGE_NOTIFICATION_RINGTONE;
+
import static junit.framework.Assert.assertFalse;
import static junit.framework.Assert.assertNull;
import static junit.framework.Assert.assertTrue;
+
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotEquals;
import static org.mockito.ArgumentMatchers.anyFloat;
@@ -178,6 +180,8 @@
when(mAudioManager.getStreamVolume(anyInt())).thenReturn(10);
when(mAudioManager.getRingerModeInternal()).thenReturn(AudioManager.RINGER_MODE_NORMAL);
when(mAudioManager.getFocusRampTimeMs(anyInt(), any(AudioAttributes.class))).thenReturn(50);
+ when(mAudioManager.shouldNotificationSoundPlay(any(AudioAttributes.class)))
+ .thenReturn(true);
when(mUsageStats.isAlertRateLimited(any())).thenReturn(false);
when(mVibrator.hasFrequencyControl()).thenReturn(false);
when(mKeyguardManager.isDeviceLocked(anyInt())).thenReturn(false);
@@ -915,6 +919,8 @@
// the phone is quiet
when(mAudioManager.getRingerModeInternal()).thenReturn(AudioManager.RINGER_MODE_VIBRATE);
when(mAudioManager.getStreamVolume(anyInt())).thenReturn(0);
+ when(mAudioManager.shouldNotificationSoundPlay(any(AudioAttributes.class)))
+ .thenReturn(false);
mAttentionHelper.buzzBeepBlinkLocked(r, DEFAULT_SIGNALS);
@@ -932,6 +938,8 @@
// the phone is quiet
when(mAudioManager.getRingerModeInternal()).thenReturn(AudioManager.RINGER_MODE_VIBRATE);
when(mAudioManager.getStreamVolume(anyInt())).thenReturn(1);
+ // all streams at 1 means no muting from audio framework
+ when(mAudioManager.shouldNotificationSoundPlay(any())).thenReturn(true);
mAttentionHelper.buzzBeepBlinkLocked(r, DEFAULT_SIGNALS);
@@ -950,6 +958,7 @@
// the phone is quiet
when(mAudioManager.getRingerModeInternal()).thenReturn(AudioManager.RINGER_MODE_VIBRATE);
when(mAudioManager.getStreamVolume(anyInt())).thenReturn(0);
+ when(mAudioManager.shouldNotificationSoundPlay(any())).thenReturn(false);
mAttentionHelper.buzzBeepBlinkLocked(r, DEFAULT_SIGNALS);
@@ -971,6 +980,7 @@
// the phone is quiet
when(mAudioManager.getStreamVolume(anyInt())).thenReturn(0);
when(mAudioManager.getRingerModeInternal()).thenReturn(AudioManager.RINGER_MODE_VIBRATE);
+ when(mAudioManager.shouldNotificationSoundPlay(any())).thenReturn(false);
mAttentionHelper.buzzBeepBlinkLocked(r, DEFAULT_SIGNALS);
@@ -1243,6 +1253,7 @@
// the phone is quiet
when(mAudioManager.getStreamVolume(anyInt())).thenReturn(0);
when(mAudioManager.getRingerModeInternal()).thenReturn(AudioManager.RINGER_MODE_VIBRATE);
+ when(mAudioManager.shouldNotificationSoundPlay(any())).thenReturn(false);
mAttentionHelper.buzzBeepBlinkLocked(r, DEFAULT_SIGNALS);
verifyDelayedVibrate(mAttentionHelper.getVibratorHelper().createFallbackVibration(false));
@@ -1973,6 +1984,7 @@
NotificationRecord r = getBuzzyBeepyNotification();
when(mAudioManager.getRingerModeInternal()).thenReturn(AudioManager.RINGER_MODE_SILENT);
when(mAudioManager.getStreamVolume(anyInt())).thenReturn(0);
+ when(mAudioManager.shouldNotificationSoundPlay(any())).thenReturn(false);
mAttentionHelper.buzzBeepBlinkLocked(r, DEFAULT_SIGNALS);