summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author Treehugger Robot <android-test-infra-autosubmit@system.gserviceaccount.com> 2025-03-13 11:52:00 -0700
committer Android (Google) Code Review <android-gerrit@google.com> 2025-03-13 11:52:00 -0700
commit27e388f68cb3ecec1ca598c13efc1d2b97f2e297 (patch)
tree9c7a397fafcb8b873336c55298545aaf00723ff1
parent0ae4f8be4b31a7d088330fc3c977c065cec52c50 (diff)
parent9c4b5334317ec7ed5cad60ec159028dc9dcbc8f6 (diff)
Merge "Move resources loading from Compose to UiBackground thread." into main
-rw-r--r--packages/SystemUI/compose/features/src/com/android/systemui/volume/panel/component/volume/ui/composable/VolumeSlider.kt19
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/volume/panel/component/volume/slider/ui/viewmodel/AudioSharingStreamSliderViewModelTest.kt9
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/volume/panel/component/volume/slider/ui/viewmodel/AudioStreamSliderViewModelTest.kt12
-rw-r--r--packages/SystemUI/src/com/android/systemui/common/shared/model/Icon.kt34
-rw-r--r--packages/SystemUI/src/com/android/systemui/volume/dialog/sliders/ui/VolumeDialogSliderViewBinder.kt11
-rw-r--r--packages/SystemUI/src/com/android/systemui/volume/dialog/sliders/ui/viewmodel/VolumeDialogSliderIconProvider.kt28
-rw-r--r--packages/SystemUI/src/com/android/systemui/volume/dialog/sliders/ui/viewmodel/VolumeDialogSliderStateModel.kt6
-rw-r--r--packages/SystemUI/src/com/android/systemui/volume/dialog/sliders/ui/viewmodel/VolumeDialogSliderViewModel.kt2
-rw-r--r--packages/SystemUI/src/com/android/systemui/volume/panel/component/volume/slider/ui/viewmodel/AudioSharingStreamSliderViewModel.kt40
-rw-r--r--packages/SystemUI/src/com/android/systemui/volume/panel/component/volume/slider/ui/viewmodel/AudioStreamSliderViewModel.kt143
-rw-r--r--packages/SystemUI/src/com/android/systemui/volume/panel/component/volume/slider/ui/viewmodel/CastVolumeSliderViewModel.kt26
-rw-r--r--packages/SystemUI/src/com/android/systemui/volume/panel/component/volume/slider/ui/viewmodel/SliderState.kt16
-rw-r--r--packages/SystemUI/src/com/android/systemui/volume/ui/slider/Slider.kt24
-rw-r--r--packages/SystemUI/tests/utils/src/com/android/systemui/volume/dialog/sliders/ui/viewmodel/VolumeDialogSliderIconProviderKosmos.kt2
-rw-r--r--packages/SystemUI/tests/utils/src/com/android/systemui/volume/panel/component/volume/slider/ui/viewmodel/AudioSharingStreamSliderViewModelKosmos.kt4
-rw-r--r--packages/SystemUI/tests/utils/src/com/android/systemui/volume/panel/component/volume/slider/ui/viewmodel/AudioStreamSliderViewModelKosmos.kt2
-rw-r--r--packages/SystemUI/tests/utils/src/com/android/systemui/volume/panel/component/volume/slider/ui/viewmodel/CastVolumeSliderViewModelKosmos.kt2
17 files changed, 247 insertions, 133 deletions
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 4b3ebc2bd53d..da54cb8e4679 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
@@ -58,6 +58,7 @@ import androidx.compose.ui.semantics.contentDescription
import androidx.compose.ui.semantics.customActions
import androidx.compose.ui.semantics.disabled
import androidx.compose.ui.semantics.progressBarRangeInfo
+import androidx.compose.ui.semantics.semantics
import androidx.compose.ui.semantics.setProgress
import androidx.compose.ui.semantics.stateDescription
import androidx.compose.ui.unit.dp
@@ -106,7 +107,10 @@ fun VolumeSlider(
return
}
- Column(modifier = modifier.animateContentSize(), verticalArrangement = Arrangement.Top) {
+ Column(
+ modifier = modifier.animateContentSize().semantics(true) {},
+ verticalArrangement = Arrangement.Top,
+ ) {
Row(
horizontalArrangement = Arrangement.spacedBy(12.dp),
modifier = Modifier.fillMaxWidth().height(40.dp),
@@ -123,7 +127,7 @@ fun VolumeSlider(
text = state.label,
style = MaterialTheme.typography.titleMedium,
color = MaterialTheme.colorScheme.onSurface,
- modifier = Modifier.weight(1f),
+ modifier = Modifier.weight(1f).clearAndSetSemantics {},
)
button?.invoke()
}
@@ -134,12 +138,11 @@ fun VolumeSlider(
onValueChanged = onValueChange,
onValueChangeFinished = { onValueChangeFinished?.invoke() },
isEnabled = state.isEnabled,
- stepDistance = state.a11yStep,
+ stepDistance = state.step,
accessibilityParams =
AccessibilityParams(
- label = state.label,
- disabledMessage = state.disabledMessage,
- currentStateDescription = state.a11yStateDescription,
+ contentDescription = state.a11yContentDescription,
+ stateDescription = state.a11yStateDescription,
),
haptics =
hapticsViewModelFactory?.let {
@@ -169,7 +172,7 @@ fun VolumeSlider(
text = disabledMessage,
color = MaterialTheme.colorScheme.onSurfaceVariant,
style = MaterialTheme.typography.labelSmall,
- modifier = Modifier.basicMarquee(),
+ modifier = Modifier.basicMarquee().clearAndSetSemantics {},
)
}
}
@@ -229,7 +232,7 @@ private fun LegacyVolumeSlider(
}
val newValue =
- (value + targetDirection * state.a11yStep).coerceIn(
+ (value + targetDirection * state.step).coerceIn(
state.valueRange.start,
state.valueRange.endInclusive,
)
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/volume/panel/component/volume/slider/ui/viewmodel/AudioSharingStreamSliderViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/volume/panel/component/volume/slider/ui/viewmodel/AudioSharingStreamSliderViewModelTest.kt
index 04ab98889755..b1a3caf98f09 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/volume/panel/component/volume/slider/ui/viewmodel/AudioSharingStreamSliderViewModelTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/volume/panel/component/volume/slider/ui/viewmodel/AudioSharingStreamSliderViewModelTest.kt
@@ -17,6 +17,7 @@
package com.android.systemui.volume.panel.component.volume.slider.ui.viewmodel
import android.bluetooth.BluetoothDevice
+import android.graphics.drawable.TestStubDrawable
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.settingslib.bluetooth.CachedBluetoothDevice
@@ -63,6 +64,12 @@ class AudioSharingStreamSliderViewModelTest : SysuiTestCase() {
assertThat(audioSharingSlider!!.label).isEqualTo("my headset 2")
assertThat(audioSharingSlider!!.icon)
- .isEqualTo(Icon.Resource(R.drawable.ic_volume_media_bt, null))
+ .isEqualTo(
+ Icon.Loaded(
+ drawable = TestStubDrawable(),
+ res = R.drawable.ic_volume_media_bt,
+ contentDescription = null,
+ )
+ )
}
}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/volume/panel/component/volume/slider/ui/viewmodel/AudioStreamSliderViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/volume/panel/component/volume/slider/ui/viewmodel/AudioStreamSliderViewModelTest.kt
index 9e8cde3bc936..ffe8e923815f 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/volume/panel/component/volume/slider/ui/viewmodel/AudioStreamSliderViewModelTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/volume/panel/component/volume/slider/ui/viewmodel/AudioStreamSliderViewModelTest.kt
@@ -18,6 +18,7 @@ package com.android.systemui.volume.panel.component.volume.slider.ui.viewmodel
import android.app.Flags
import android.app.NotificationManager.INTERRUPTION_FILTER_NONE
+import android.graphics.drawable.TestStubDrawable
import android.media.AudioManager
import android.platform.test.annotations.EnableFlags
import android.service.notification.ZenPolicy
@@ -28,7 +29,6 @@ import com.android.settingslib.notification.modes.TestModeBuilder
import com.android.settingslib.volume.shared.model.AudioStream
import com.android.systemui.SysuiTestCase
import com.android.systemui.common.shared.model.Icon
-import com.android.systemui.coroutines.collectLastValue
import com.android.systemui.kosmos.Kosmos
import com.android.systemui.kosmos.applicationCoroutineScope
import com.android.systemui.kosmos.collectLastValue
@@ -39,8 +39,6 @@ import com.android.systemui.statusbar.policy.data.repository.fakeZenModeReposito
import com.android.systemui.testKosmos
import com.android.systemui.volume.data.repository.audioSharingRepository
import com.google.common.truth.Truth.assertThat
-import kotlinx.coroutines.test.runCurrent
-import kotlinx.coroutines.test.runTest
import org.junit.Test
import org.junit.runner.RunWith
import org.mockito.kotlin.mock
@@ -173,6 +171,12 @@ class AudioStreamSliderViewModelTest : SysuiTestCase() {
assertThat(mediaSlider!!.label).isEqualTo("my headset 1")
assertThat(mediaSlider!!.icon)
- .isEqualTo(Icon.Resource(R.drawable.ic_volume_media_bt, null))
+ .isEqualTo(
+ Icon.Loaded(
+ drawable = TestStubDrawable(),
+ res = R.drawable.ic_volume_media_bt,
+ contentDescription = null,
+ )
+ )
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/common/shared/model/Icon.kt b/packages/SystemUI/src/com/android/systemui/common/shared/model/Icon.kt
index 2adaec21867f..6792f3188986 100644
--- a/packages/SystemUI/src/com/android/systemui/common/shared/model/Icon.kt
+++ b/packages/SystemUI/src/com/android/systemui/common/shared/model/Icon.kt
@@ -19,6 +19,7 @@ package com.android.systemui.common.shared.model
import android.annotation.DrawableRes
import android.graphics.drawable.Drawable
import androidx.compose.runtime.Stable
+import com.android.systemui.common.shared.model.Icon.Loaded
/**
* Models an icon, that can either be already [loaded][Icon.Loaded] or be a [reference]
@@ -33,8 +34,37 @@ sealed class Icon {
constructor(
val drawable: Drawable,
override val contentDescription: ContentDescription?,
+ /**
+ * Serves as an id to compare two instances. When provided this is used alongside
+ * [contentDescription] to determine equality. This is useful when comparing icons
+ * representing the same UI, but with different [drawable] instances.
+ */
@DrawableRes val res: Int? = null,
- ) : Icon()
+ ) : Icon() {
+
+ override fun equals(other: Any?): Boolean {
+ val that = other as? Loaded ?: return false
+
+ if (this.res != null && that.res != null) {
+ return this.res == that.res && this.contentDescription == that.contentDescription
+ }
+
+ return this.res == that.res &&
+ this.drawable == that.drawable &&
+ this.contentDescription == that.contentDescription
+ }
+
+ override fun hashCode(): Int {
+ var result = contentDescription?.hashCode() ?: 0
+ result =
+ if (res != null) {
+ 31 * result + res.hashCode()
+ } else {
+ 31 * result + drawable.hashCode()
+ }
+ return result
+ }
+ }
data class Resource(
@DrawableRes val res: Int,
@@ -49,4 +79,4 @@ sealed class Icon {
fun Drawable.asIcon(
contentDescription: ContentDescription? = null,
@DrawableRes res: Int? = null,
-): Icon.Loaded = Icon.Loaded(this, contentDescription, res)
+): Loaded = Loaded(this, contentDescription, res)
diff --git a/packages/SystemUI/src/com/android/systemui/volume/dialog/sliders/ui/VolumeDialogSliderViewBinder.kt b/packages/SystemUI/src/com/android/systemui/volume/dialog/sliders/ui/VolumeDialogSliderViewBinder.kt
index 43d1ef478ae1..32f784f17bb7 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/dialog/sliders/ui/VolumeDialogSliderViewBinder.kt
+++ b/packages/SystemUI/src/com/android/systemui/volume/dialog/sliders/ui/VolumeDialogSliderViewBinder.kt
@@ -16,7 +16,6 @@
package com.android.systemui.volume.dialog.sliders.ui
-import android.graphics.drawable.Drawable
import android.view.View
import androidx.compose.animation.AnimatedVisibility
import androidx.compose.animation.core.tween
@@ -29,7 +28,6 @@ import androidx.compose.foundation.layout.BoxScope
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
import androidx.compose.material3.ExperimentalMaterial3Api
-import androidx.compose.material3.Icon
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.SliderDefaults
import androidx.compose.runtime.Composable
@@ -43,7 +41,8 @@ import androidx.compose.ui.platform.ComposeView
import androidx.compose.ui.unit.dp
import androidx.lifecycle.compose.collectAsStateWithLifecycle
import com.android.compose.theme.PlatformTheme
-import com.android.compose.ui.graphics.painter.DrawablePainter
+import com.android.systemui.common.shared.model.Icon
+import com.android.systemui.common.ui.compose.Icon
import com.android.systemui.haptics.slider.SliderHapticFeedbackFilter
import com.android.systemui.haptics.slider.compose.ui.SliderHapticsViewModel
import com.android.systemui.res.R
@@ -155,7 +154,7 @@ private fun VolumeDialogSlider(
},
)
},
- accessibilityParams = AccessibilityParams(label = sliderStateModel.label),
+ accessibilityParams = AccessibilityParams(contentDescription = sliderStateModel.label),
modifier =
modifier.pointerInput(Unit) {
coroutineScope {
@@ -172,7 +171,7 @@ private fun VolumeDialogSlider(
@Composable
private fun BoxScope.VolumeIcon(
- drawable: Drawable,
+ icon: Icon.Loaded,
isVisible: Boolean,
modifier: Modifier = Modifier,
) {
@@ -182,6 +181,6 @@ private fun BoxScope.VolumeIcon(
exit = fadeOut(animationSpec = tween(durationMillis = 50)),
modifier = modifier.align(Alignment.Center).size(40.dp).padding(10.dp),
) {
- Icon(painter = DrawablePainter(drawable), contentDescription = null)
+ Icon(icon)
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/volume/dialog/sliders/ui/viewmodel/VolumeDialogSliderIconProvider.kt b/packages/SystemUI/src/com/android/systemui/volume/dialog/sliders/ui/viewmodel/VolumeDialogSliderIconProvider.kt
index ef147c741bec..3712276488ff 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/dialog/sliders/ui/viewmodel/VolumeDialogSliderIconProvider.kt
+++ b/packages/SystemUI/src/com/android/systemui/volume/dialog/sliders/ui/viewmodel/VolumeDialogSliderIconProvider.kt
@@ -18,32 +18,36 @@ package com.android.systemui.volume.dialog.sliders.ui.viewmodel
import android.annotation.SuppressLint
import android.content.Context
-import android.graphics.drawable.Drawable
import android.media.AudioManager
import androidx.annotation.DrawableRes
import com.android.settingslib.R as SettingsR
import com.android.settingslib.volume.domain.interactor.AudioVolumeInteractor
import com.android.settingslib.volume.shared.model.AudioStream
import com.android.settingslib.volume.shared.model.RingerMode
+import com.android.systemui.common.shared.model.Icon
+import com.android.systemui.dagger.qualifiers.UiBackground
import com.android.systemui.res.R
import com.android.systemui.statusbar.policy.domain.interactor.ZenModeInteractor
import com.android.systemui.statusbar.policy.domain.model.ActiveZenModes
import javax.inject.Inject
+import kotlin.coroutines.CoroutineContext
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.flow.flow
import kotlinx.coroutines.flow.flowOf
+import kotlinx.coroutines.withContext
@SuppressLint("UseCompatLoadingForDrawables")
class VolumeDialogSliderIconProvider
@Inject
constructor(
private val context: Context,
+ @UiBackground private val uiBackgroundContext: CoroutineContext,
private val zenModeInteractor: ZenModeInteractor,
private val audioVolumeInteractor: AudioVolumeInteractor,
) {
- fun getAudioSharingIcon(isMuted: Boolean): Flow<Drawable> {
+ fun getAudioSharingIcon(isMuted: Boolean): Flow<Icon.Loaded> {
return flow {
val iconRes =
if (isMuted) {
@@ -51,11 +55,12 @@ constructor(
} else {
R.drawable.ic_volume_media_bt
}
- emit(context.getDrawable(iconRes)!!)
+ val drawable = withContext(uiBackgroundContext) { context.getDrawable(iconRes)!! }
+ emit(Icon.Loaded(drawable = drawable, contentDescription = null, res = iconRes))
}
}
- fun getCastIcon(isMuted: Boolean): Flow<Drawable> {
+ fun getCastIcon(isMuted: Boolean): Flow<Icon.Loaded> {
return flow {
val iconRes =
if (isMuted) {
@@ -63,7 +68,8 @@ constructor(
} else {
SettingsR.drawable.ic_volume_remote
}
- emit(context.getDrawable(iconRes)!!)
+ val drawable = withContext(uiBackgroundContext) { context.getDrawable(iconRes)!! }
+ emit(Icon.Loaded(drawable = drawable, contentDescription = null, res = iconRes))
}
}
@@ -74,15 +80,18 @@ constructor(
levelMax: Int,
isMuted: Boolean,
isRoutedToBluetooth: Boolean,
- ): Flow<Drawable> {
+ ): Flow<Icon.Loaded> {
return combine(
zenModeInteractor.activeModesBlockingStream(stream),
ringerModeForStream(stream),
) { activeModesBlockingStream, ringerMode ->
if (activeModesBlockingStream?.mainMode?.icon != null) {
- return@combine activeModesBlockingStream.mainMode.icon.drawable
+ Icon.Loaded(
+ drawable = activeModesBlockingStream.mainMode.icon.drawable,
+ contentDescription = null,
+ )
} else {
- context.getDrawable(
+ val iconRes =
getIconRes(
stream,
level,
@@ -92,7 +101,8 @@ constructor(
isRoutedToBluetooth,
ringerMode,
)
- )!!
+ val drawable = withContext(uiBackgroundContext) { context.getDrawable(iconRes)!! }
+ Icon.Loaded(drawable = drawable, contentDescription = null, res = iconRes)
}
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/volume/dialog/sliders/ui/viewmodel/VolumeDialogSliderStateModel.kt b/packages/SystemUI/src/com/android/systemui/volume/dialog/sliders/ui/viewmodel/VolumeDialogSliderStateModel.kt
index 88a061f3813c..ed59598d97d0 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/dialog/sliders/ui/viewmodel/VolumeDialogSliderStateModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/volume/dialog/sliders/ui/viewmodel/VolumeDialogSliderStateModel.kt
@@ -17,7 +17,7 @@
package com.android.systemui.volume.dialog.sliders.ui.viewmodel
import android.content.Context
-import android.graphics.drawable.Drawable
+import com.android.systemui.common.shared.model.Icon
import com.android.systemui.volume.dialog.shared.model.VolumeDialogStreamModel
import com.android.systemui.volume.dialog.shared.model.streamLabel
@@ -25,14 +25,14 @@ data class VolumeDialogSliderStateModel(
val value: Float,
val isDisabled: Boolean,
val valueRange: ClosedFloatingPointRange<Float>,
- val icon: Drawable,
+ val icon: Icon.Loaded,
val label: String,
)
fun VolumeDialogStreamModel.toStateModel(
context: Context,
isDisabled: Boolean,
- icon: Drawable,
+ icon: Icon.Loaded,
): VolumeDialogSliderStateModel {
return VolumeDialogSliderStateModel(
value = level.toFloat(),
diff --git a/packages/SystemUI/src/com/android/systemui/volume/dialog/sliders/ui/viewmodel/VolumeDialogSliderViewModel.kt b/packages/SystemUI/src/com/android/systemui/volume/dialog/sliders/ui/viewmodel/VolumeDialogSliderViewModel.kt
index f6aa189eb571..faf0abd4cabd 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/dialog/sliders/ui/viewmodel/VolumeDialogSliderViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/volume/dialog/sliders/ui/viewmodel/VolumeDialogSliderViewModel.kt
@@ -108,11 +108,9 @@ constructor(
isMuted = isMuted,
isRoutedToBluetooth = routedToBluetooth,
)
-
is VolumeDialogSliderType.RemoteMediaStream -> {
volumeDialogSliderIconProvider.getCastIcon(isMuted)
}
-
is VolumeDialogSliderType.AudioSharingStream -> {
volumeDialogSliderIconProvider.getAudioSharingIcon(isMuted)
}
diff --git a/packages/SystemUI/src/com/android/systemui/volume/panel/component/volume/slider/ui/viewmodel/AudioSharingStreamSliderViewModel.kt b/packages/SystemUI/src/com/android/systemui/volume/panel/component/volume/slider/ui/viewmodel/AudioSharingStreamSliderViewModel.kt
index 3d98ebacc7ca..f6452679cbf4 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/panel/component/volume/slider/ui/viewmodel/AudioSharingStreamSliderViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/volume/panel/component/volume/slider/ui/viewmodel/AudioSharingStreamSliderViewModel.kt
@@ -16,9 +16,11 @@
package com.android.systemui.volume.panel.component.volume.slider.ui.viewmodel
+import android.content.Context
import com.android.internal.logging.UiEventLogger
import com.android.systemui.Flags
import com.android.systemui.common.shared.model.Icon
+import com.android.systemui.dagger.qualifiers.UiBackground
import com.android.systemui.haptics.slider.SliderHapticFeedbackFilter
import com.android.systemui.haptics.slider.compose.ui.SliderHapticsViewModel
import com.android.systemui.res.R
@@ -28,6 +30,7 @@ import com.android.systemui.volume.panel.ui.VolumePanelUiEvent
import dagger.assisted.Assisted
import dagger.assisted.AssistedFactory
import dagger.assisted.AssistedInject
+import kotlin.coroutines.CoroutineContext
import kotlin.math.roundToInt
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.flow.MutableStateFlow
@@ -39,11 +42,14 @@ import kotlinx.coroutines.flow.filterNotNull
import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.onEach
import kotlinx.coroutines.flow.stateIn
+import kotlinx.coroutines.withContext
class AudioSharingStreamSliderViewModel
@AssistedInject
constructor(
+ private val context: Context,
@Assisted private val coroutineScope: CoroutineScope,
+ @UiBackground private val uiBackgroundContext: CoroutineContext,
private val audioSharingInteractor: AudioSharingInteractor,
private val uiEventLogger: UiEventLogger,
private val hapticsViewModelFactory: SliderHapticsViewModel.Factory,
@@ -51,6 +57,12 @@ constructor(
) : SliderViewModel {
private val volumeChanges = MutableStateFlow<Int?>(null)
+ private val audioSharingIcon =
+ Icon.Loaded(
+ drawable = context.getDrawable(R.drawable.ic_volume_media_bt)!!,
+ contentDescription = null,
+ res = R.drawable.ic_volume_media_bt,
+ )
override val slider: StateFlow<SliderState> =
combine(
audioSharingInteractor.volume.distinctUntilChanged().onEach {
@@ -62,16 +74,17 @@ constructor(
if (volume == null) {
SliderState.Empty
} else {
-
- State(
- value = volume.toFloat(),
- valueRange =
- audioSharingInteractor.volumeMin.toFloat()..audioSharingInteractor
- .volumeMax
- .toFloat(),
- icon = Icon.Resource(R.drawable.ic_volume_media_bt, null),
- label = deviceName,
- )
+ withContext(uiBackgroundContext) {
+ State(
+ value = volume.toFloat(),
+ valueRange =
+ audioSharingInteractor.volumeMin.toFloat()..audioSharingInteractor
+ .volumeMax
+ .toFloat(),
+ icon = audioSharingIcon,
+ label = deviceName,
+ )
+ }
}
}
.stateIn(coroutineScope, SharingStarted.Eagerly, SliderState.Empty)
@@ -107,7 +120,7 @@ constructor(
private data class State(
override val value: Float,
override val valueRange: ClosedFloatingPointRange<Float>,
- override val icon: Icon,
+ override val icon: Icon.Loaded?,
override val label: String,
) : SliderState {
override val hapticFilter: SliderHapticFeedbackFilter
@@ -116,7 +129,7 @@ constructor(
override val isEnabled: Boolean
get() = true
- override val a11yStep: Float
+ override val step: Float
get() = 1f
override val disabledMessage: String?
@@ -125,6 +138,9 @@ constructor(
override val isMutable: Boolean
get() = false
+ override val a11yContentDescription: String
+ get() = label
+
override val a11yClickDescription: String?
get() = null
diff --git a/packages/SystemUI/src/com/android/systemui/volume/panel/component/volume/slider/ui/viewmodel/AudioStreamSliderViewModel.kt b/packages/SystemUI/src/com/android/systemui/volume/panel/component/volume/slider/ui/viewmodel/AudioStreamSliderViewModel.kt
index 9d32285fecb3..9fe0ad42cdba 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/panel/component/volume/slider/ui/viewmodel/AudioStreamSliderViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/volume/panel/component/volume/slider/ui/viewmodel/AudioStreamSliderViewModel.kt
@@ -19,6 +19,7 @@ package com.android.systemui.volume.panel.component.volume.slider.ui.viewmodel
import android.content.Context
import android.media.AudioManager
import android.util.Log
+import androidx.annotation.DrawableRes
import com.android.app.tracing.coroutines.launchTraced as launch
import com.android.internal.logging.UiEventLogger
import com.android.settingslib.bluetooth.CachedBluetoothDevice
@@ -28,6 +29,7 @@ import com.android.settingslib.volume.shared.model.AudioStreamModel
import com.android.settingslib.volume.shared.model.RingerMode
import com.android.systemui.Flags
import com.android.systemui.common.shared.model.Icon
+import com.android.systemui.dagger.qualifiers.UiBackground
import com.android.systemui.haptics.slider.SliderHapticFeedbackFilter
import com.android.systemui.haptics.slider.compose.ui.SliderHapticsViewModel
import com.android.systemui.modes.shared.ModesUiIcons
@@ -40,18 +42,21 @@ import com.android.systemui.volume.panel.ui.VolumePanelUiEvent
import dagger.assisted.Assisted
import dagger.assisted.AssistedFactory
import dagger.assisted.AssistedInject
+import kotlin.coroutines.CoroutineContext
import kotlin.math.roundToInt
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.SharingStarted
import kotlinx.coroutines.flow.StateFlow
+import kotlinx.coroutines.flow.distinctUntilChanged
import kotlinx.coroutines.flow.filterNotNull
import kotlinx.coroutines.flow.flowOf
import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.onEach
import kotlinx.coroutines.flow.stateIn
+import kotlinx.coroutines.withContext
/** Models a particular slider state. */
class AudioStreamSliderViewModel
@@ -59,10 +64,11 @@ class AudioStreamSliderViewModel
constructor(
@Assisted private val audioStreamWrapper: FactoryAudioStreamWrapper,
@Assisted private val coroutineScope: CoroutineScope,
+ @UiBackground private val uiBackgroundContext: CoroutineContext,
private val context: Context,
private val audioVolumeInteractor: AudioVolumeInteractor,
private val zenModeInteractor: ZenModeInteractor,
- private val audioSharingInteractor: AudioSharingInteractor,
+ audioSharingInteractor: AudioSharingInteractor,
private val uiEventLogger: UiEventLogger,
private val volumePanelLogger: VolumePanelLogger,
private val hapticsViewModelFactory: SliderHapticsViewModel.Factory,
@@ -148,57 +154,69 @@ constructor(
null
}
- private fun AudioStreamModel.toState(
+ private suspend fun AudioStreamModel.toState(
isEnabled: Boolean,
ringerMode: RingerMode,
disabledMessage: String?,
inAudioSharing: Boolean,
primaryDevice: CachedBluetoothDevice?,
- ): State {
- val label = getLabel(inAudioSharing, primaryDevice)
- val icon = getIcon(ringerMode, inAudioSharing)
- return State(
- value = volume.toFloat(),
- valueRange = volumeRange.first.toFloat()..volumeRange.last.toFloat(),
- hapticFilter = createHapticFilter(ringerMode),
- icon = icon,
- label = label,
- disabledMessage = disabledMessage,
- isEnabled = isEnabled,
- a11yStep = volumeRange.step.toFloat(),
- a11yClickDescription =
- if (isAffectedByMute) {
- context.getString(
- if (isMuted) {
- R.string.volume_panel_hint_unmute
- } else {
- R.string.volume_panel_hint_mute
- },
- label,
- )
- } else {
- null
- },
- a11yStateDescription =
- if (isMuted) {
- context.getString(
- if (isAffectedByRingerMode) {
- if (ringerMode.value == AudioManager.RINGER_MODE_VIBRATE) {
- R.string.volume_panel_hint_vibrate
+ ): State =
+ withContext(uiBackgroundContext) {
+ val label = getLabel(inAudioSharing, primaryDevice)
+ State(
+ value = volume.toFloat(),
+ valueRange = volumeRange.first.toFloat()..volumeRange.last.toFloat(),
+ hapticFilter = createHapticFilter(ringerMode),
+ icon = getIcon(ringerMode, inAudioSharing),
+ label = label,
+ disabledMessage = disabledMessage,
+ isEnabled = isEnabled,
+ step = volumeRange.step.toFloat(),
+ a11yContentDescription =
+ if (isEnabled) {
+ label
+ } else {
+ disabledMessage?.let {
+ context.getString(
+ R.string.volume_slider_disabled_message_template,
+ label,
+ disabledMessage,
+ )
+ } ?: label
+ },
+ a11yClickDescription =
+ if (isAffectedByMute) {
+ context.getString(
+ if (isMuted) {
+ R.string.volume_panel_hint_unmute
+ } else {
+ R.string.volume_panel_hint_mute
+ },
+ label,
+ )
+ } else {
+ null
+ },
+ a11yStateDescription =
+ if (isMuted) {
+ context.getString(
+ if (isAffectedByRingerMode) {
+ if (ringerMode.value == AudioManager.RINGER_MODE_VIBRATE) {
+ R.string.volume_panel_hint_vibrate
+ } else {
+ R.string.volume_panel_hint_muted
+ }
} else {
R.string.volume_panel_hint_muted
}
- } else {
- R.string.volume_panel_hint_muted
- }
- )
- } else {
- null
- },
- audioStreamModel = this,
- isMutable = isAffectedByMute,
- )
- }
+ )
+ } else {
+ null
+ },
+ audioStreamModel = this@toState,
+ isMutable = isAffectedByMute,
+ )
+ }
private fun AudioStreamModel.createHapticFilter(
ringerMode: RingerMode
@@ -220,12 +238,14 @@ constructor(
flowOf(context.getString(R.string.stream_notification_unavailable))
} else {
if (zenModeInteractor.canBeBlockedByZenMode(audioStream)) {
- zenModeInteractor.activeModesBlockingStream(audioStream).map { blockingZenModes
- ->
- blockingZenModes.mainMode?.name?.let {
- context.getString(R.string.stream_unavailable_by_modes, it)
- } ?: context.getString(R.string.stream_unavailable_by_unknown)
- }
+ zenModeInteractor
+ .activeModesBlockingStream(audioStream)
+ .map { blockingZenModes ->
+ blockingZenModes.mainMode?.name?.let {
+ context.getString(R.string.stream_unavailable_by_modes, it)
+ } ?: context.getString(R.string.stream_unavailable_by_unknown)
+ }
+ .distinctUntilChanged()
} else {
flowOf(context.getString(R.string.stream_unavailable_by_unknown))
}
@@ -256,8 +276,11 @@ constructor(
?: error("No label for the stream: $audioStream")
}
- private fun AudioStreamModel.getIcon(ringerMode: RingerMode, inAudioSharing: Boolean): Icon {
- val iconRes =
+ private fun AudioStreamModel.getIcon(
+ ringerMode: RingerMode,
+ inAudioSharing: Boolean,
+ ): Icon.Loaded {
+ val iconResource: Int =
if (isMuted) {
if (isAffectedByRingerMode) {
if (ringerMode.value == AudioManager.RINGER_MODE_VIBRATE) {
@@ -272,14 +295,21 @@ constructor(
inAudioSharing
) {
R.drawable.ic_volume_media_bt_mute
- } else R.drawable.ic_volume_off
+ } else {
+ R.drawable.ic_volume_off
+ }
}
} else {
getIconByStream(audioStream, inAudioSharing)
}
- return Icon.Resource(iconRes, null)
+ return Icon.Loaded(
+ drawable = context.getDrawable(iconResource)!!,
+ contentDescription = null,
+ res = iconResource,
+ )
}
+ @DrawableRes
private fun getIconByStream(audioStream: AudioStream, inAudioSharing: Boolean): Int =
when (audioStream.value) {
AudioManager.STREAM_MUSIC ->
@@ -302,14 +332,15 @@ constructor(
private data class State(
override val value: Float,
override val valueRange: ClosedFloatingPointRange<Float>,
+ override val step: Float,
override val hapticFilter: SliderHapticFeedbackFilter,
- override val icon: Icon,
+ override val icon: Icon.Loaded?,
override val label: String,
override val disabledMessage: String?,
override val isEnabled: Boolean,
- override val a11yStep: Float,
override val a11yClickDescription: String?,
override val a11yStateDescription: String?,
+ override val a11yContentDescription: String,
override val isMutable: Boolean,
val audioStreamModel: AudioStreamModel,
) : SliderState
diff --git a/packages/SystemUI/src/com/android/systemui/volume/panel/component/volume/slider/ui/viewmodel/CastVolumeSliderViewModel.kt b/packages/SystemUI/src/com/android/systemui/volume/panel/component/volume/slider/ui/viewmodel/CastVolumeSliderViewModel.kt
index a6c809186ca5..01810f9aafc3 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/panel/component/volume/slider/ui/viewmodel/CastVolumeSliderViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/volume/panel/component/volume/slider/ui/viewmodel/CastVolumeSliderViewModel.kt
@@ -21,6 +21,7 @@ import android.media.session.MediaController.PlaybackInfo
import com.android.app.tracing.coroutines.launchTraced as launch
import com.android.systemui.Flags
import com.android.systemui.common.shared.model.Icon
+import com.android.systemui.dagger.qualifiers.UiBackground
import com.android.systemui.haptics.slider.SliderHapticFeedbackFilter
import com.android.systemui.haptics.slider.compose.ui.SliderHapticsViewModel
import com.android.systemui.res.R
@@ -30,30 +31,40 @@ import com.android.systemui.volume.panel.shared.VolumePanelLogger
import dagger.assisted.Assisted
import dagger.assisted.AssistedFactory
import dagger.assisted.AssistedInject
+import kotlin.coroutines.CoroutineContext
import kotlin.math.roundToInt
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.flow.SharingStarted
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.mapNotNull
import kotlinx.coroutines.flow.stateIn
+import kotlinx.coroutines.withContext
class CastVolumeSliderViewModel
@AssistedInject
constructor(
@Assisted private val session: MediaDeviceSession,
@Assisted private val coroutineScope: CoroutineScope,
+ @UiBackground private val uiBackgroundContext: CoroutineContext,
private val context: Context,
private val mediaDeviceSessionInteractor: MediaDeviceSessionInteractor,
private val hapticsViewModelFactory: SliderHapticsViewModel.Factory,
private val volumePanelLogger: VolumePanelLogger,
) : SliderViewModel {
+ private val castLabel = context.getString(R.string.media_device_cast)
+ private val castIcon =
+ Icon.Loaded(
+ drawable = context.getDrawable(R.drawable.ic_cast)!!,
+ contentDescription = null,
+ res = R.drawable.ic_cast,
+ )
override val slider: StateFlow<SliderState> =
mediaDeviceSessionInteractor
.playbackInfo(session)
.mapNotNull {
volumePanelLogger.onVolumeUpdateReceived(session.sessionToken, it.currentVolume)
- it.getCurrentState()
+ withContext(uiBackgroundContext) { it.getCurrentState() }
}
.stateIn(coroutineScope, SharingStarted.Eagerly, SliderState.Empty)
@@ -83,20 +94,20 @@ constructor(
return State(
value = currentVolume.toFloat(),
valueRange = volumeRange.first.toFloat()..volumeRange.last.toFloat(),
- icon = Icon.Resource(R.drawable.ic_cast, null),
- label = context.getString(R.string.media_device_cast),
+ icon = castIcon,
+ label = castLabel,
isEnabled = true,
- a11yStep = 1f,
+ step = 1f,
)
}
private data class State(
override val value: Float,
override val valueRange: ClosedFloatingPointRange<Float>,
- override val icon: Icon,
+ override val icon: Icon.Loaded?,
override val label: String,
override val isEnabled: Boolean,
- override val a11yStep: Float,
+ override val step: Float,
) : SliderState {
override val hapticFilter: SliderHapticFeedbackFilter
get() = SliderHapticFeedbackFilter()
@@ -107,6 +118,9 @@ constructor(
override val isMutable: Boolean
get() = false
+ override val a11yContentDescription: String
+ get() = label
+
override val a11yClickDescription: String?
get() = null
diff --git a/packages/SystemUI/src/com/android/systemui/volume/panel/component/volume/slider/ui/viewmodel/SliderState.kt b/packages/SystemUI/src/com/android/systemui/volume/panel/component/volume/slider/ui/viewmodel/SliderState.kt
index 4bc237bd36f5..b1d183404a9f 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/panel/component/volume/slider/ui/viewmodel/SliderState.kt
+++ b/packages/SystemUI/src/com/android/systemui/volume/panel/component/volume/slider/ui/viewmodel/SliderState.kt
@@ -27,18 +27,17 @@ import com.android.systemui.haptics.slider.SliderHapticFeedbackFilter
sealed interface SliderState {
val value: Float
val valueRange: ClosedFloatingPointRange<Float>
+ val step: Float
val hapticFilter: SliderHapticFeedbackFilter
- val icon: Icon?
+ // Force preloaded icon
+ val icon: Icon.Loaded?
val isEnabled: Boolean
val label: String
- /**
- * A11y slider controls works by adjusting one step up or down. The default slider step isn't
- * enough to trigger rounding to the correct value.
- */
- val a11yStep: Float
+
val a11yClickDescription: String?
val a11yStateDescription: String?
+ val a11yContentDescription: String
val disabledMessage: String?
val isMutable: Boolean
@@ -46,12 +45,13 @@ sealed interface SliderState {
override val value: Float = 0f
override val valueRange: ClosedFloatingPointRange<Float> = 0f..1f
override val hapticFilter = SliderHapticFeedbackFilter()
- override val icon: Icon? = null
+ override val icon: Icon.Loaded? = null
override val label: String = ""
override val disabledMessage: String? = null
- override val a11yStep: Float = 0f
+ override val step: Float = 0f
override val a11yClickDescription: String? = null
override val a11yStateDescription: String? = null
+ override val a11yContentDescription: String = label
override val isEnabled: Boolean = true
override val isMutable: Boolean = false
}
diff --git a/packages/SystemUI/src/com/android/systemui/volume/ui/slider/Slider.kt b/packages/SystemUI/src/com/android/systemui/volume/ui/slider/Slider.kt
index f6582a005035..502b311f7b40 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/ui/slider/Slider.kt
+++ b/packages/SystemUI/src/com/android/systemui/volume/ui/slider/Slider.kt
@@ -40,7 +40,6 @@ import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.runtime.setValue
import androidx.compose.runtime.snapshotFlow
import androidx.compose.ui.Modifier
-import androidx.compose.ui.res.stringResource
import androidx.compose.ui.semantics.ProgressBarRangeInfo
import androidx.compose.ui.semantics.SemanticsPropertyReceiver
import androidx.compose.ui.semantics.clearAndSetSemantics
@@ -52,7 +51,6 @@ import androidx.compose.ui.semantics.stateDescription
import com.android.systemui.haptics.slider.SliderHapticFeedbackFilter
import com.android.systemui.haptics.slider.compose.ui.SliderHapticsViewModel
import com.android.systemui.lifecycle.rememberViewModel
-import com.android.systemui.res.R
import com.android.systemui.volume.haptics.ui.VolumeHapticsConfigsProvider
import kotlin.math.round
import kotlinx.coroutines.Job
@@ -108,7 +106,8 @@ fun Slider(
}
}
val semantics =
- accessibilityParams.createSemantics(
+ createSemantics(
+ accessibilityParams,
animatable.targetValue,
valueRange,
valueChange,
@@ -167,24 +166,18 @@ private fun snapValue(
return Math.round(coercedValue / stepDistance) * stepDistance
}
-@Composable
-private fun AccessibilityParams.createSemantics(
+private fun createSemantics(
+ params: AccessibilityParams,
value: Float,
valueRange: ClosedFloatingPointRange<Float>,
onValueChanged: (Float) -> Unit,
isEnabled: Boolean,
stepDistance: Float,
): SemanticsPropertyReceiver.() -> Unit {
- val semanticsContentDescription =
- disabledMessage
- ?.takeIf { !isEnabled }
- ?.let { message ->
- stringResource(R.string.volume_slider_disabled_message_template, label, message)
- } ?: label
return {
- contentDescription = semanticsContentDescription
+ contentDescription = params.contentDescription
if (isEnabled) {
- currentStateDescription?.let { stateDescription = it }
+ params.stateDescription?.let { stateDescription = it }
progressBarRangeInfo = ProgressBarRangeInfo(value, valueRange)
} else {
disabled()
@@ -253,9 +246,8 @@ private fun Haptics.createViewModel(
}
data class AccessibilityParams(
- val label: String,
- val currentStateDescription: String? = null,
- val disabledMessage: String? = null,
+ val contentDescription: String,
+ val stateDescription: String? = null,
)
sealed interface Haptics {
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/volume/dialog/sliders/ui/viewmodel/VolumeDialogSliderIconProviderKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/volume/dialog/sliders/ui/viewmodel/VolumeDialogSliderIconProviderKosmos.kt
index 09f9f1c6362e..44d7a22b6258 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/volume/dialog/sliders/ui/viewmodel/VolumeDialogSliderIconProviderKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/volume/dialog/sliders/ui/viewmodel/VolumeDialogSliderIconProviderKosmos.kt
@@ -18,6 +18,7 @@ package com.android.systemui.volume.dialog.sliders.ui.viewmodel
import android.content.applicationContext
import com.android.systemui.kosmos.Kosmos
+import com.android.systemui.kosmos.backgroundCoroutineContext
import com.android.systemui.statusbar.policy.domain.interactor.zenModeInteractor
import com.android.systemui.volume.domain.interactor.audioVolumeInteractor
@@ -25,6 +26,7 @@ val Kosmos.volumeDialogSliderIconProvider by
Kosmos.Fixture {
VolumeDialogSliderIconProvider(
context = applicationContext,
+ uiBackgroundContext = backgroundCoroutineContext,
audioVolumeInteractor = audioVolumeInteractor,
zenModeInteractor = zenModeInteractor,
)
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/volume/panel/component/volume/slider/ui/viewmodel/AudioSharingStreamSliderViewModelKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/volume/panel/component/volume/slider/ui/viewmodel/AudioSharingStreamSliderViewModelKosmos.kt
index 8c8d0240f572..6e43d79295ff 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/volume/panel/component/volume/slider/ui/viewmodel/AudioSharingStreamSliderViewModelKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/volume/panel/component/volume/slider/ui/viewmodel/AudioSharingStreamSliderViewModelKosmos.kt
@@ -16,9 +16,11 @@
package com.android.systemui.volume.panel.component.volume.slider.ui.viewmodel
+import android.content.applicationContext
import com.android.internal.logging.uiEventLogger
import com.android.systemui.haptics.slider.sliderHapticsViewModelFactory
import com.android.systemui.kosmos.Kosmos
+import com.android.systemui.kosmos.backgroundCoroutineContext
import com.android.systemui.volume.domain.interactor.audioSharingInteractor
import com.android.systemui.volume.shared.volumePanelLogger
import kotlinx.coroutines.CoroutineScope
@@ -28,7 +30,9 @@ val Kosmos.audioSharingStreamSliderViewModelFactory by
object : AudioSharingStreamSliderViewModel.Factory {
override fun create(coroutineScope: CoroutineScope): AudioSharingStreamSliderViewModel {
return AudioSharingStreamSliderViewModel(
+ applicationContext,
coroutineScope,
+ backgroundCoroutineContext,
audioSharingInteractor,
uiEventLogger,
sliderHapticsViewModelFactory,
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/volume/panel/component/volume/slider/ui/viewmodel/AudioStreamSliderViewModelKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/volume/panel/component/volume/slider/ui/viewmodel/AudioStreamSliderViewModelKosmos.kt
index 88c716e0ab10..47016e535ea4 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/volume/panel/component/volume/slider/ui/viewmodel/AudioStreamSliderViewModelKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/volume/panel/component/volume/slider/ui/viewmodel/AudioStreamSliderViewModelKosmos.kt
@@ -20,6 +20,7 @@ import android.content.applicationContext
import com.android.internal.logging.uiEventLogger
import com.android.systemui.haptics.slider.sliderHapticsViewModelFactory
import com.android.systemui.kosmos.Kosmos
+import com.android.systemui.kosmos.backgroundCoroutineContext
import com.android.systemui.statusbar.policy.domain.interactor.zenModeInteractor
import com.android.systemui.volume.domain.interactor.audioSharingInteractor
import com.android.systemui.volume.domain.interactor.audioVolumeInteractor
@@ -37,6 +38,7 @@ val Kosmos.audioStreamSliderViewModelFactory by
return AudioStreamSliderViewModel(
audioStream,
coroutineScope,
+ backgroundCoroutineContext,
applicationContext,
audioVolumeInteractor,
zenModeInteractor,
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/volume/panel/component/volume/slider/ui/viewmodel/CastVolumeSliderViewModelKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/volume/panel/component/volume/slider/ui/viewmodel/CastVolumeSliderViewModelKosmos.kt
index 6875619d45fc..ed51e054e50c 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/volume/panel/component/volume/slider/ui/viewmodel/CastVolumeSliderViewModelKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/volume/panel/component/volume/slider/ui/viewmodel/CastVolumeSliderViewModelKosmos.kt
@@ -19,6 +19,7 @@ package com.android.systemui.volume.panel.component.volume.slider.ui.viewmodel
import android.content.applicationContext
import com.android.systemui.haptics.slider.sliderHapticsViewModelFactory
import com.android.systemui.kosmos.Kosmos
+import com.android.systemui.kosmos.backgroundCoroutineContext
import com.android.systemui.volume.mediaDeviceSessionInteractor
import com.android.systemui.volume.panel.component.mediaoutput.shared.model.MediaDeviceSession
import com.android.systemui.volume.shared.volumePanelLogger
@@ -34,6 +35,7 @@ val Kosmos.castVolumeSliderViewModelFactory by
return CastVolumeSliderViewModel(
session,
coroutineScope,
+ backgroundCoroutineContext,
applicationContext,
mediaDeviceSessionInteractor,
sliderHapticsViewModelFactory,