summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author Anton Potapov <apotapov@google.com> 2024-05-16 11:36:27 +0100
committer Anton Potapov <apotapov@google.com> 2024-05-16 17:37:49 +0100
commit050d56f0ff09397049a1957fd382d0400e5b5d5d (patch)
treefdd0613a80afdbc366c7364fd37cf0c6c448cf30
parentcdecb49e25430152c7656b287a754c3058c61632 (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
-rw-r--r--packages/SettingsLib/src/com/android/settingslib/statusbar/notification/data/repository/FakeNotificationsSoundPolicyRepository.kt26
-rw-r--r--packages/SettingsLib/src/com/android/settingslib/volume/data/repository/AudioRepository.kt26
-rw-r--r--packages/SettingsLib/src/com/android/settingslib/volume/domain/interactor/AudioVolumeInteractor.kt22
-rw-r--r--packages/SystemUI/compose/features/src/com/android/systemui/volume/panel/component/volume/ui/composable/VolumeSlider.kt7
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/volume/domain/interactor/AudioVolumeInteractorTest.kt65
-rw-r--r--packages/SystemUI/tests/utils/src/com/android/systemui/volume/data/repository/FakeAudioRepository.kt17
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 =