diff options
| author | 2024-05-16 11:36:27 +0100 | |
|---|---|---|
| committer | 2024-05-16 17:37:49 +0100 | |
| commit | 050d56f0ff09397049a1957fd382d0400e5b5d5d (patch) | |
| tree | fdd0613a80afdbc366c7364fd37cf0c6c448cf30 | |
| parent | cdecb49e25430152c7656b287a754c3058c61632 (diff) | |
Add muting/unmuting when volume change to/from min value
Also fix setting a11y description because in the VolumeSlider. We should
always set progressbar info to allow a11y gestures to change the value.
Flag: aconfig new_volume_panel NEXTFOOD
Test: atest AudioVolumeInteractorTest
Test: manual on the device with the voiceover
Fixes: 339162398
Change-Id: I13e0aad3325edd6d16ad5a9b9aaa5dc79db3c21c
6 files changed, 118 insertions, 45 deletions
diff --git a/packages/SettingsLib/src/com/android/settingslib/statusbar/notification/data/repository/FakeNotificationsSoundPolicyRepository.kt b/packages/SettingsLib/src/com/android/settingslib/statusbar/notification/data/repository/FakeNotificationsSoundPolicyRepository.kt index 2a44511599f1..a939ed14b7c1 100644 --- a/packages/SettingsLib/src/com/android/settingslib/statusbar/notification/data/repository/FakeNotificationsSoundPolicyRepository.kt +++ b/packages/SettingsLib/src/com/android/settingslib/statusbar/notification/data/repository/FakeNotificationsSoundPolicyRepository.kt @@ -17,6 +17,7 @@ package com.android.settingslib.statusbar.notification.data.repository import android.app.NotificationManager +import android.provider.Settings import com.android.settingslib.statusbar.notification.data.model.ZenMode import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.StateFlow @@ -28,10 +29,14 @@ class FakeNotificationsSoundPolicyRepository : NotificationsSoundPolicyRepositor override val notificationPolicy: StateFlow<NotificationManager.Policy?> get() = mutableNotificationPolicy.asStateFlow() - private val mutableZenMode = MutableStateFlow<ZenMode?>(null) + private val mutableZenMode = MutableStateFlow<ZenMode?>(ZenMode(Settings.Global.ZEN_MODE_OFF)) override val zenMode: StateFlow<ZenMode?> get() = mutableZenMode.asStateFlow() + init { + updateNotificationPolicy() + } + fun updateNotificationPolicy(policy: NotificationManager.Policy?) { mutableNotificationPolicy.value = policy } @@ -48,13 +53,14 @@ fun FakeNotificationsSoundPolicyRepository.updateNotificationPolicy( suppressedVisualEffects: Int = NotificationManager.Policy.SUPPRESSED_EFFECTS_UNSET, state: Int = NotificationManager.Policy.STATE_UNSET, priorityConversationSenders: Int = NotificationManager.Policy.CONVERSATION_SENDERS_NONE, -) = updateNotificationPolicy( - NotificationManager.Policy( - priorityCategories, - priorityCallSenders, - priorityMessageSenders, - suppressedVisualEffects, - state, - priorityConversationSenders, +) = + updateNotificationPolicy( + NotificationManager.Policy( + priorityCategories, + priorityCallSenders, + priorityMessageSenders, + suppressedVisualEffects, + state, + priorityConversationSenders, + ) ) -)
\ No newline at end of file diff --git a/packages/SettingsLib/src/com/android/settingslib/volume/data/repository/AudioRepository.kt b/packages/SettingsLib/src/com/android/settingslib/volume/data/repository/AudioRepository.kt index 65a5317ed0cb..36e396fb0c4f 100644 --- a/packages/SettingsLib/src/com/android/settingslib/volume/data/repository/AudioRepository.kt +++ b/packages/SettingsLib/src/com/android/settingslib/volume/data/repository/AudioRepository.kt @@ -72,7 +72,11 @@ interface AudioRepository { suspend fun setVolume(audioStream: AudioStream, volume: Int) - suspend fun setMuted(audioStream: AudioStream, isMuted: Boolean) + /** + * Mutes and un-mutes [audioStream]. Returns true when the state changes and false the + * otherwise. + */ + suspend fun setMuted(audioStream: AudioStream, isMuted: Boolean): Boolean suspend fun setRingerMode(audioStream: AudioStream, mode: RingerMode) @@ -164,14 +168,20 @@ class AudioRepositoryImpl( audioManager.setStreamVolume(audioStream.value, volume, 0) } - override suspend fun setMuted(audioStream: AudioStream, isMuted: Boolean) = - withContext(backgroundCoroutineContext) { - audioManager.adjustStreamVolume( - audioStream.value, - if (isMuted) AudioManager.ADJUST_MUTE else AudioManager.ADJUST_UNMUTE, - 0, - ) + override suspend fun setMuted(audioStream: AudioStream, isMuted: Boolean): Boolean { + return withContext(backgroundCoroutineContext) { + if (isMuted == audioManager.isStreamMute(audioStream.value)) { + false + } else { + audioManager.adjustStreamVolume( + audioStream.value, + if (isMuted) AudioManager.ADJUST_MUTE else AudioManager.ADJUST_UNMUTE, + 0, + ) + true + } } + } override suspend fun setRingerMode(audioStream: AudioStream, mode: RingerMode) { withContext(backgroundCoroutineContext) { audioManager.ringerMode = mode.value } diff --git a/packages/SettingsLib/src/com/android/settingslib/volume/domain/interactor/AudioVolumeInteractor.kt b/packages/SettingsLib/src/com/android/settingslib/volume/domain/interactor/AudioVolumeInteractor.kt index 33f917e701c2..0e5ebdae96e4 100644 --- a/packages/SettingsLib/src/com/android/settingslib/volume/domain/interactor/AudioVolumeInteractor.kt +++ b/packages/SettingsLib/src/com/android/settingslib/volume/domain/interactor/AudioVolumeInteractor.kt @@ -25,6 +25,7 @@ import com.android.settingslib.volume.shared.model.RingerMode import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.combine +import kotlinx.coroutines.flow.first import kotlinx.coroutines.flow.map /** Provides audio stream state and an ability to change it */ @@ -46,8 +47,16 @@ class AudioVolumeInteractor( val ringerMode: StateFlow<RingerMode> get() = audioRepository.ringerMode - suspend fun setVolume(audioStream: AudioStream, volume: Int) = + suspend fun setVolume(audioStream: AudioStream, volume: Int) { + val streamModel = getAudioStream(audioStream).first() + val oldVolume = streamModel.volume audioRepository.setVolume(audioStream, volume) + when { + volume == streamModel.minVolume -> setMuted(audioStream, true) + oldVolume == streamModel.minVolume && volume > streamModel.minVolume -> + setMuted(audioStream, false) + } + } suspend fun setMuted(audioStream: AudioStream, isMuted: Boolean) { if (audioStream.value == AudioManager.STREAM_RING) { @@ -55,7 +64,16 @@ class AudioVolumeInteractor( if (isMuted) AudioManager.RINGER_MODE_VIBRATE else AudioManager.RINGER_MODE_NORMAL audioRepository.setRingerMode(audioStream, RingerMode(mode)) } - audioRepository.setMuted(audioStream, isMuted) + val mutedChanged = audioRepository.setMuted(audioStream, isMuted) + if (mutedChanged && !isMuted) { + with(getAudioStream(audioStream).first()) { + if (volume == minVolume) { + // Slightly increase volume when user un-mutes the stream that is lowered + // down to its minimum + setVolume(audioStream, volume + 1) + } + } + } } /** Checks if the volume can be changed via the UI. */ diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/volume/panel/component/volume/ui/composable/VolumeSlider.kt b/packages/SystemUI/compose/features/src/com/android/systemui/volume/panel/component/volume/ui/composable/VolumeSlider.kt index cb3867f209e3..271eb9601dbd 100644 --- a/packages/SystemUI/compose/features/src/com/android/systemui/volume/panel/component/volume/ui/composable/VolumeSlider.kt +++ b/packages/SystemUI/compose/features/src/com/android/systemui/volume/panel/component/volume/ui/composable/VolumeSlider.kt @@ -78,12 +78,7 @@ fun VolumeSlider( } state.a11yStateDescription?.let { stateDescription = it } - ?: run { - // provide a not animated value to the a11y because it fails to announce - // the settled value when it changes rapidly. - progressBarRangeInfo = - ProgressBarRangeInfo(state.value, state.valueRange) - } + progressBarRangeInfo = ProgressBarRangeInfo(state.value, state.valueRange) } else { disabled() contentDescription = diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/volume/domain/interactor/AudioVolumeInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/volume/domain/interactor/AudioVolumeInteractorTest.kt index 675136c7cf26..a163ca08691e 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/volume/domain/interactor/AudioVolumeInteractorTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/volume/domain/interactor/AudioVolumeInteractorTest.kt @@ -36,7 +36,6 @@ import com.google.common.truth.Truth.assertThat import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.test.runCurrent import kotlinx.coroutines.test.runTest -import org.junit.Before import org.junit.Test import org.junit.runner.RunWith @@ -47,19 +46,8 @@ class AudioVolumeInteractorTest : SysuiTestCase() { private val kosmos = testKosmos() - private lateinit var underTest: AudioVolumeInteractor - - @Before - fun setup() { - with(kosmos) { - underTest = AudioVolumeInteractor(audioRepository, notificationsSoundPolicyInteractor) - - audioRepository.setRingerMode(RingerMode(AudioManager.RINGER_MODE_NORMAL)) - - notificationsSoundPolicyRepository.updateNotificationPolicy() - notificationsSoundPolicyRepository.updateZenMode(ZenMode(Settings.Global.ZEN_MODE_OFF)) - } - } + private val underTest: AudioVolumeInteractor = + with(kosmos) { AudioVolumeInteractor(audioRepository, notificationsSoundPolicyInteractor) } @Test fun setMuted_mutesStream() { @@ -236,6 +224,55 @@ class AudioVolumeInteractorTest : SysuiTestCase() { } } + @Test + fun testReducingVolumeToMin_mutes() = + with(kosmos) { + testScope.runTest { + val audioStreamModel by + collectLastValue(audioRepository.getAudioStream(audioStream)) + runCurrent() + + underTest.setVolume(audioStream, audioStreamModel!!.minVolume) + runCurrent() + + assertThat(audioStreamModel!!.isMuted).isTrue() + } + } + + @Test + fun testIncreasingVolumeFromMin_unmutes() = + with(kosmos) { + testScope.runTest { + val audioStreamModel by + collectLastValue(audioRepository.getAudioStream(audioStream)) + audioRepository.setMuted(audioStream, true) + audioRepository.setVolume(audioStream, audioStreamModel!!.minVolume) + runCurrent() + + underTest.setVolume(audioStream, audioStreamModel!!.maxVolume) + runCurrent() + + assertThat(audioStreamModel!!.isMuted).isFalse() + } + } + + @Test + fun testUnmutingMinVolume_increasesVolume() = + with(kosmos) { + testScope.runTest { + val audioStreamModel by + collectLastValue(audioRepository.getAudioStream(audioStream)) + audioRepository.setMuted(audioStream, true) + audioRepository.setVolume(audioStream, audioStreamModel!!.minVolume) + runCurrent() + + underTest.setMuted(audioStream, false) + runCurrent() + + assertThat(audioStreamModel!!.volume).isGreaterThan(audioStreamModel!!.minVolume) + } + } + private companion object { val audioStream = AudioStream(AudioManager.STREAM_SYSTEM) } diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/volume/data/repository/FakeAudioRepository.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/volume/data/repository/FakeAudioRepository.kt index 617fc5258ec7..6b27079cb648 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/volume/data/repository/FakeAudioRepository.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/volume/data/repository/FakeAudioRepository.kt @@ -17,6 +17,7 @@ package com.android.systemui.volume.data.repository import android.media.AudioDeviceInfo +import android.media.AudioManager import com.android.settingslib.volume.data.repository.AudioRepository import com.android.settingslib.volume.shared.model.AudioStream import com.android.settingslib.volume.shared.model.AudioStreamModel @@ -29,10 +30,10 @@ import kotlinx.coroutines.flow.update class FakeAudioRepository : AudioRepository { - private val mutableMode = MutableStateFlow(0) + private val mutableMode = MutableStateFlow(AudioManager.MODE_NORMAL) override val mode: StateFlow<Int> = mutableMode.asStateFlow() - private val mutableRingerMode = MutableStateFlow(RingerMode(0)) + private val mutableRingerMode = MutableStateFlow(RingerMode(AudioManager.RINGER_MODE_NORMAL)) override val ringerMode: StateFlow<RingerMode> = mutableRingerMode.asStateFlow() private val mutableCommunicationDevice = MutableStateFlow<AudioDeviceInfo?>(null) @@ -53,7 +54,7 @@ class FakeAudioRepository : AudioRepository { audioStream = audioStream, volume = 0, minVolume = 0, - maxVolume = 0, + maxVolume = 10, isAffectedByRingerMode = false, isMuted = false, ) @@ -67,8 +68,14 @@ class FakeAudioRepository : AudioRepository { getAudioStreamModelState(audioStream).update { it.copy(volume = volume) } } - override suspend fun setMuted(audioStream: AudioStream, isMuted: Boolean) { - getAudioStreamModelState(audioStream).update { it.copy(isMuted = isMuted) } + override suspend fun setMuted(audioStream: AudioStream, isMuted: Boolean): Boolean { + val modelState = getAudioStreamModelState(audioStream) + return if (modelState.value.isMuted == isMuted) { + false + } else { + modelState.update { it.copy(isMuted = isMuted) } + true + } } override suspend fun getLastAudibleVolume(audioStream: AudioStream): Int = |