Loading core/api/test-current.txt +1 −0 Original line number Diff line number Diff line Loading @@ -1882,6 +1882,7 @@ package android.media { 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 { Loading media/java/android/media/AudioManager.java +23 −0 Original line number Diff line number Diff line Loading @@ -21,6 +21,7 @@ import static android.companion.virtual.VirtualDeviceParams.POLICY_TYPE_AUDIO; 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; Loading Loading @@ -10081,6 +10082,28 @@ public class AudioManager { } } /** * @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 Loading media/java/android/media/IAudioService.aidl +4 −0 Original line number Diff line number Diff line Loading @@ -775,4 +775,8 @@ interface IAudioService { @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); } services/core/java/com/android/server/audio/AudioService.java +40 −0 Original line number Diff line number Diff line Loading @@ -13591,6 +13591,46 @@ public class AudioService extends IAudioService.Stub } } /** * @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 //====================== services/core/java/com/android/server/audio/MediaFocusControl.java +17 −0 Original line number Diff line number Diff line Loading @@ -296,6 +296,23 @@ public class MediaFocusControl implements PlayerFocusEnforcer { } } /** * 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 Loading Loading
core/api/test-current.txt +1 −0 Original line number Diff line number Diff line Loading @@ -1882,6 +1882,7 @@ package android.media { 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 { Loading
media/java/android/media/AudioManager.java +23 −0 Original line number Diff line number Diff line Loading @@ -21,6 +21,7 @@ import static android.companion.virtual.VirtualDeviceParams.POLICY_TYPE_AUDIO; 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; Loading Loading @@ -10081,6 +10082,28 @@ public class AudioManager { } } /** * @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 Loading
media/java/android/media/IAudioService.aidl +4 −0 Original line number Diff line number Diff line Loading @@ -775,4 +775,8 @@ interface IAudioService { @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); }
services/core/java/com/android/server/audio/AudioService.java +40 −0 Original line number Diff line number Diff line Loading @@ -13591,6 +13591,46 @@ public class AudioService extends IAudioService.Stub } } /** * @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 //======================
services/core/java/com/android/server/audio/MediaFocusControl.java +17 −0 Original line number Diff line number Diff line Loading @@ -296,6 +296,23 @@ public class MediaFocusControl implements PlayerFocusEnforcer { } } /** * 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 Loading