Add captioning button to the Volume Panel
Plus a few changes to the infra:
- fix volume panel styling;
- rework ComponentsLayout to accomodate a separated buttons collection;
- move FakeCaptioningRepository from SettingsLib to SystemUI to use it
in the tests;
Flag: aconfig new_volume_panel DISABLED
Test: atest CaptioningViewModelTest
Test: atest DefaultComponentsLayoutManagerTest
Test: atest VolumePanelViewModelTest
Fixes: 324241246
Change-Id: I5277e92fe01b9e0ee65755e19f3c65ff7a710ed2
diff --git a/packages/SettingsLib/tests/integ/src/com/android/settingslib/view/accessibility/data/repository/FakeCaptioningRepository.kt b/packages/SettingsLib/tests/integ/src/com/android/settingslib/view/accessibility/data/repository/FakeCaptioningRepository.kt
deleted file mode 100644
index fd253c6..0000000
--- a/packages/SettingsLib/tests/integ/src/com/android/settingslib/view/accessibility/data/repository/FakeCaptioningRepository.kt
+++ /dev/null
@@ -1,40 +0,0 @@
-/*
- * Copyright (C) 2024 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.settingslib.view.accessibility.data.repository
-
-import kotlinx.coroutines.flow.MutableStateFlow
-import kotlinx.coroutines.flow.StateFlow
-import kotlinx.coroutines.flow.asStateFlow
-
-class FakeCaptioningRepository : CaptioningRepository {
-
- private val mutableIsSystemAudioCaptioningEnabled = MutableStateFlow(false)
- override val isSystemAudioCaptioningEnabled: StateFlow<Boolean>
- get() = mutableIsSystemAudioCaptioningEnabled.asStateFlow()
-
- private val mutableIsSystemAudioCaptioningUiEnabled = MutableStateFlow(false)
- override val isSystemAudioCaptioningUiEnabled: StateFlow<Boolean>
- get() = mutableIsSystemAudioCaptioningUiEnabled.asStateFlow()
-
- override suspend fun setIsSystemAudioCaptioningEnabled(isEnabled: Boolean) {
- mutableIsSystemAudioCaptioningEnabled.value = isEnabled
- }
-
- fun setIsSystemAudioCaptioningUiEnabled(isSystemAudioCaptioningUiEnabled: Boolean) {
- mutableIsSystemAudioCaptioningUiEnabled.value = isSystemAudioCaptioningUiEnabled
- }
-}
diff --git a/packages/SystemUI/compose/facade/disabled/src/com/android/systemui/volume/panel/component/captioning/CaptioningModule.kt b/packages/SystemUI/compose/facade/disabled/src/com/android/systemui/volume/panel/component/captioning/CaptioningModule.kt
new file mode 100644
index 0000000..aeb5c5d
--- /dev/null
+++ b/packages/SystemUI/compose/facade/disabled/src/com/android/systemui/volume/panel/component/captioning/CaptioningModule.kt
@@ -0,0 +1,21 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.volume.panel.component.captioning
+
+import dagger.Module
+
+@Module interface CaptioningModule
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/volume/panel/component/button/ui/composable/ToggleButtonComponent.kt b/packages/SystemUI/compose/features/src/com/android/systemui/volume/panel/component/button/ui/composable/ToggleButtonComponent.kt
new file mode 100644
index 0000000..228111d
--- /dev/null
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/volume/panel/component/button/ui/composable/ToggleButtonComponent.kt
@@ -0,0 +1,79 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.volume.panel.component.button.ui.composable
+
+import androidx.compose.foundation.BorderStroke
+import androidx.compose.foundation.layout.Arrangement
+import androidx.compose.foundation.layout.Column
+import androidx.compose.foundation.layout.fillMaxWidth
+import androidx.compose.foundation.layout.height
+import androidx.compose.foundation.layout.size
+import androidx.compose.material3.IconButtonDefaults
+import androidx.compose.material3.MaterialTheme
+import androidx.compose.material3.OutlinedIconToggleButton
+import androidx.compose.material3.Text
+import androidx.compose.runtime.Composable
+import androidx.compose.runtime.collectAsState
+import androidx.compose.runtime.getValue
+import androidx.compose.ui.Alignment
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.text.style.TextOverflow
+import androidx.compose.ui.unit.dp
+import com.android.systemui.common.ui.compose.Icon
+import com.android.systemui.volume.panel.component.button.ui.viewmodel.ToggleButtonViewModel
+import com.android.systemui.volume.panel.ui.composable.ComposeVolumePanelUiComponent
+import com.android.systemui.volume.panel.ui.composable.VolumePanelComposeScope
+import kotlinx.coroutines.flow.StateFlow
+
+class ToggleButtonComponent(
+ private val viewModelFlow: StateFlow<ToggleButtonViewModel?>,
+ private val onCheckedChange: (isChecked: Boolean) -> Unit
+) : ComposeVolumePanelUiComponent {
+
+ @Composable
+ override fun VolumePanelComposeScope.Content(modifier: Modifier) {
+ val viewModelByState by viewModelFlow.collectAsState()
+ val viewModel = viewModelByState ?: return
+ Column(
+ modifier = modifier,
+ verticalArrangement = Arrangement.spacedBy(12.dp),
+ horizontalAlignment = Alignment.CenterHorizontally,
+ ) {
+ OutlinedIconToggleButton(
+ modifier = Modifier.height(64.dp).fillMaxWidth(),
+ checked = viewModel.isChecked,
+ onCheckedChange = onCheckedChange,
+ colors =
+ IconButtonDefaults.outlinedIconToggleButtonColors(
+ containerColor = MaterialTheme.colorScheme.surface,
+ contentColor = MaterialTheme.colorScheme.onSurfaceVariant,
+ checkedContainerColor = MaterialTheme.colorScheme.primaryContainer,
+ checkedContentColor = MaterialTheme.colorScheme.onPrimaryContainer,
+ ),
+ border = BorderStroke(8.dp, MaterialTheme.colorScheme.surface),
+ ) {
+ Icon(modifier = Modifier.size(24.dp), icon = viewModel.icon)
+ }
+ Text(
+ text = viewModel.label.toString(),
+ style = MaterialTheme.typography.labelMedium,
+ maxLines = 1,
+ overflow = TextOverflow.Ellipsis,
+ )
+ }
+ }
+}
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/volume/panel/component/captioning/CaptioningModule.kt b/packages/SystemUI/compose/features/src/com/android/systemui/volume/panel/component/captioning/CaptioningModule.kt
new file mode 100644
index 0000000..7d431d9
--- /dev/null
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/volume/panel/component/captioning/CaptioningModule.kt
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.volume.panel.component.captioning
+
+import com.android.systemui.volume.panel.component.button.ui.composable.ToggleButtonComponent
+import com.android.systemui.volume.panel.component.captioning.domain.CaptioningAvailabilityCriteria
+import com.android.systemui.volume.panel.component.captioning.ui.viewmodel.CaptioningViewModel
+import com.android.systemui.volume.panel.component.shared.model.VolumePanelComponents
+import com.android.systemui.volume.panel.domain.ComponentAvailabilityCriteria
+import com.android.systemui.volume.panel.shared.model.VolumePanelUiComponent
+import dagger.Binds
+import dagger.Module
+import dagger.Provides
+import dagger.multibindings.IntoMap
+import dagger.multibindings.StringKey
+
+/** Dagger module, that provides Captioning Volume Panel UI functionality. */
+@Module
+interface CaptioningModule {
+
+ @Binds
+ @IntoMap
+ @StringKey(VolumePanelComponents.CAPTIONING)
+ fun bindComponentAvailabilityCriteria(
+ criteria: CaptioningAvailabilityCriteria
+ ): ComponentAvailabilityCriteria
+
+ companion object {
+
+ @Provides
+ @IntoMap
+ @StringKey(VolumePanelComponents.CAPTIONING)
+ fun provideVolumePanelUiComponent(viewModel: CaptioningViewModel): VolumePanelUiComponent =
+ ToggleButtonComponent(
+ viewModel.buttonViewModel,
+ viewModel::setIsSystemAudioCaptioningEnabled,
+ )
+ }
+}
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/volume/panel/ui/composable/VerticalVolumePanelContent.kt b/packages/SystemUI/compose/features/src/com/android/systemui/volume/panel/ui/composable/VerticalVolumePanelContent.kt
index a7ec93f..e8d5966 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/volume/panel/ui/composable/VerticalVolumePanelContent.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/volume/panel/ui/composable/VerticalVolumePanelContent.kt
@@ -19,26 +19,39 @@
import androidx.compose.animation.AnimatedVisibility
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
-import androidx.compose.material3.Slider
+import androidx.compose.foundation.layout.Row
+import androidx.compose.foundation.layout.fillMaxWidth
+import androidx.compose.foundation.layout.wrapContentHeight
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.dp
-import com.android.systemui.volume.panel.ui.viewmodel.ComponentState
+import com.android.systemui.volume.panel.ui.layout.ComponentsLayout
@Composable
fun VolumePanelComposeScope.VerticalVolumePanelContent(
- components: List<ComponentState>,
+ layout: ComponentsLayout,
modifier: Modifier = Modifier,
) {
Column(
modifier = modifier,
verticalArrangement = Arrangement.spacedBy(20.dp),
) {
- Slider(0.5f, {})
- for (component in components) {
+ for (component in layout.contentComponents) {
AnimatedVisibility(component.isVisible) {
with(component.component as ComposeVolumePanelUiComponent) { Content(Modifier) }
}
}
+ if (layout.footerComponents.isNotEmpty()) {
+ Row(
+ modifier = Modifier.fillMaxWidth().wrapContentHeight(),
+ horizontalArrangement = Arrangement.spacedBy(20.dp)
+ ) {
+ for (component in layout.footerComponents) {
+ with(component.component as ComposeVolumePanelUiComponent) {
+ Content(Modifier.weight(1f))
+ }
+ }
+ }
+ }
}
}
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/volume/panel/ui/composable/VolumePanelRoot.kt b/packages/SystemUI/compose/features/src/com/android/systemui/volume/panel/ui/composable/VolumePanelRoot.kt
index 3487184..60d03fc 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/volume/panel/ui/composable/VolumePanelRoot.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/volume/panel/ui/composable/VolumePanelRoot.kt
@@ -21,14 +21,15 @@
import androidx.compose.animation.core.MutableTransitionState
import androidx.compose.animation.slideInVertically
import androidx.compose.animation.slideOutVertically
+import androidx.compose.foundation.background
import androidx.compose.foundation.clickable
import androidx.compose.foundation.isSystemInDarkTheme
-import androidx.compose.foundation.layout.Arrangement
+import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
+import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.navigationBarsPadding
import androidx.compose.foundation.layout.padding
-import androidx.compose.foundation.layout.statusBarsPadding
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Surface
@@ -37,7 +38,9 @@
import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue
import androidx.compose.runtime.remember
+import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
+import androidx.compose.ui.draw.alpha
import androidx.compose.ui.res.dimensionResource
import com.android.compose.theme.PlatformTheme
import com.android.systemui.res.R
@@ -64,14 +67,17 @@
}
}
- Column(
- modifier =
- modifier
- .fillMaxSize()
- .statusBarsPadding()
- .clickable(onClick = { viewModel.dismissPanel() }),
- verticalArrangement = Arrangement.Bottom,
+ Box(
+ modifier = modifier.fillMaxSize(),
+ contentAlignment = Alignment.BottomCenter,
) {
+ Spacer(
+ modifier =
+ Modifier.fillMaxSize()
+ .alpha(0.32f)
+ .background(MaterialTheme.colorScheme.scrim)
+ .clickable(onClick = { viewModel.dismissPanel() })
+ )
AnimatedVisibility(
visibleState = transitionState,
enter = slideInVertically { it },
@@ -80,7 +86,7 @@
val radius = dimensionResource(R.dimen.volume_panel_corner_radius)
Surface(
shape = RoundedCornerShape(topStart = radius, topEnd = radius),
- color = MaterialTheme.colorScheme.surfaceBright,
+ color = MaterialTheme.colorScheme.surfaceContainer,
) {
Column {
components?.let { componentsState ->
@@ -97,7 +103,7 @@
private fun VolumePanelComposeScope.Components(state: ComponentsLayout) {
if (orientation == Configuration.ORIENTATION_PORTRAIT) {
VerticalVolumePanelContent(
- components = state.contentComponents,
+ state,
modifier = Modifier.padding(dimensionResource(R.dimen.volume_panel_content_padding)),
)
} else {
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/volume/panel/component/captioning/ui/viewmodel/CaptioningViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/volume/panel/component/captioning/ui/viewmodel/CaptioningViewModelTest.kt
new file mode 100644
index 0000000..610195f
--- /dev/null
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/volume/panel/component/captioning/ui/viewmodel/CaptioningViewModelTest.kt
@@ -0,0 +1,79 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.volume.panel.component.captioning.ui.viewmodel
+
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.coroutines.collectLastValue
+import com.android.systemui.kosmos.testScope
+import com.android.systemui.testKosmos
+import com.android.systemui.view.accessibility.data.repository.captioningInteractor
+import com.android.systemui.view.accessibility.data.repository.captioningRepository
+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
+
+@OptIn(ExperimentalCoroutinesApi::class)
+@SmallTest
+@RunWith(AndroidJUnit4::class)
+class CaptioningViewModelTest : SysuiTestCase() {
+
+ private val kosmos = testKosmos()
+
+ private lateinit var underTest: CaptioningViewModel
+
+ @Before
+ fun setup() {
+ underTest =
+ with(kosmos) {
+ CaptioningViewModel(context, captioningInteractor, testScope.backgroundScope)
+ }
+ }
+
+ @Test
+ fun captioningDisabled_buttonViewModel_notChecked() {
+ with(kosmos) {
+ testScope.runTest {
+ captioningRepository.setIsSystemAudioCaptioningEnabled(false)
+
+ val buttonViewModel by collectLastValue(underTest.buttonViewModel)
+ runCurrent()
+
+ assertThat(buttonViewModel!!.isChecked).isFalse()
+ }
+ }
+ }
+
+ @Test
+ fun captioningDisabled_buttonViewModel_checked() {
+ with(kosmos) {
+ testScope.runTest {
+ captioningRepository.setIsSystemAudioCaptioningEnabled(true)
+
+ val buttonViewModel by collectLastValue(underTest.buttonViewModel)
+ runCurrent()
+
+ assertThat(buttonViewModel!!.isChecked).isTrue()
+ }
+ }
+ }
+}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/volume/panel/ui/viewmodel/DefaultComponentsLayoutManagerTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/volume/panel/ui/viewmodel/DefaultComponentsLayoutManagerTest.kt
index 35d9698..7c99360 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/volume/panel/ui/viewmodel/DefaultComponentsLayoutManagerTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/volume/panel/ui/viewmodel/DefaultComponentsLayoutManagerTest.kt
@@ -33,43 +33,37 @@
class DefaultComponentsLayoutManagerTest : SysuiTestCase() {
private val kosmos = testKosmos()
- private val underTest: ComponentsLayoutManager = DefaultComponentsLayoutManager()
+ private val underTest: ComponentsLayoutManager =
+ DefaultComponentsLayoutManager(
+ BOTTOM_BAR,
+ headerComponents = listOf(COMPONENT_1),
+ footerComponents = listOf(COMPONENT_2),
+ )
@Test
- fun bottomBar_isSet() {
+ fun correspondingComponents_areSet() {
val bottomBarComponentState =
ComponentState(BOTTOM_BAR, kosmos.mockVolumePanelUiComponent, false)
+ val component1 = ComponentState(COMPONENT_1, kosmos.mockVolumePanelUiComponent, false)
+ val component2 = ComponentState(COMPONENT_2, kosmos.mockVolumePanelUiComponent, false)
+ val component3 = ComponentState(COMPONENT_3, kosmos.mockVolumePanelUiComponent, false)
+ val component4 = ComponentState(COMPONENT_4, kosmos.mockVolumePanelUiComponent, false)
val layout =
underTest.layout(
VolumePanelState(0, false),
- setOf(
- bottomBarComponentState,
- ComponentState(COMPONENT_1, kosmos.mockVolumePanelUiComponent, false),
- ComponentState(COMPONENT_2, kosmos.mockVolumePanelUiComponent, false),
- )
+ setOf(bottomBarComponentState, component1, component2, component3, component4)
)
Truth.assertThat(layout.bottomBarComponent).isEqualTo(bottomBarComponentState)
- }
-
- @Test
- fun componentsAreInOrder() {
- val bottomBarComponentState =
- ComponentState(BOTTOM_BAR, kosmos.mockVolumePanelUiComponent, false)
- val component1State = ComponentState(COMPONENT_1, kosmos.mockVolumePanelUiComponent, false)
- val component2State = ComponentState(COMPONENT_2, kosmos.mockVolumePanelUiComponent, false)
- val layout =
- underTest.layout(
- VolumePanelState(0, false),
- setOf(
- bottomBarComponentState,
- component1State,
- component2State,
- )
- )
-
- Truth.assertThat(layout.contentComponents[0]).isEqualTo(component1State)
- Truth.assertThat(layout.contentComponents[1]).isEqualTo(component2State)
+ Truth.assertThat(layout.headerComponents)
+ .containsExactlyElementsIn(listOf(component1))
+ .inOrder()
+ Truth.assertThat(layout.footerComponents)
+ .containsExactlyElementsIn(listOf(component2))
+ .inOrder()
+ Truth.assertThat(layout.contentComponents)
+ .containsExactlyElementsIn(listOf(component3, component4))
+ .inOrder()
}
@Test(expected = IllegalStateException::class)
@@ -89,5 +83,7 @@
const val BOTTOM_BAR: VolumePanelComponentKey = "bottom_bar"
const val COMPONENT_1: VolumePanelComponentKey = "test_component:1"
const val COMPONENT_2: VolumePanelComponentKey = "test_component:2"
+ const val COMPONENT_3: VolumePanelComponentKey = "test_component:3"
+ const val COMPONENT_4: VolumePanelComponentKey = "test_component:4"
}
}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/volume/panel/ui/viewmodel/VolumePanelViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/volume/panel/ui/viewmodel/VolumePanelViewModelTest.kt
index c4c9cc6..910f71e 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/volume/panel/ui/viewmodel/VolumePanelViewModelTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/volume/panel/ui/viewmodel/VolumePanelViewModelTest.kt
@@ -30,7 +30,7 @@
import com.android.systemui.volume.panel.dagger.factory.KosmosVolumePanelComponentFactory
import com.android.systemui.volume.panel.mockVolumePanelUiComponentProvider
import com.android.systemui.volume.panel.shared.model.VolumePanelComponentKey
-import com.android.systemui.volume.panel.ui.layout.FakeComponentsLayoutManager
+import com.android.systemui.volume.panel.ui.layout.DefaultComponentsLayoutManager
import com.android.systemui.volume.panel.unavailableCriteria
import com.google.common.truth.Truth.assertThat
import kotlinx.coroutines.ExperimentalCoroutinesApi
@@ -45,9 +45,7 @@
class VolumePanelViewModelTest : SysuiTestCase() {
private val kosmos =
- testKosmos().apply {
- componentsLayoutManager = FakeComponentsLayoutManager { it.key == BOTTOM_BAR }
- }
+ testKosmos().apply { componentsLayoutManager = DefaultComponentsLayoutManager(BOTTOM_BAR) }
private val testableResources = context.orCreateTestableResources
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index 15688c5..6d765f4 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -1437,6 +1437,8 @@
<!-- Label for button to go to sound settings screen [CHAR_LIMIT=30] -->
<string name="volume_panel_dialog_settings_button">Settings</string>
+ <string name="volume_panel_captioning_title">Live Caption</string>
+
<!-- Title for notification after audio lowers -->
<string name="csd_lowered_title" product="default">Volume lowered to safer level</string>
<!-- Message shown in notification after system lowers audio -->
diff --git a/packages/SystemUI/src/com/android/systemui/volume/panel/component/button/ui/viewmodel/ToggleButtonViewModel.kt b/packages/SystemUI/src/com/android/systemui/volume/panel/component/button/ui/viewmodel/ToggleButtonViewModel.kt
new file mode 100644
index 0000000..8ab563a
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/volume/panel/component/button/ui/viewmodel/ToggleButtonViewModel.kt
@@ -0,0 +1,25 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.volume.panel.component.button.ui.viewmodel
+
+import com.android.systemui.common.shared.model.Icon
+
+data class ToggleButtonViewModel(
+ val isChecked: Boolean,
+ val icon: Icon,
+ val label: CharSequence,
+)
diff --git a/packages/SystemUI/src/com/android/systemui/volume/panel/component/captioning/domain/CaptioningAvailabilityCriteria.kt b/packages/SystemUI/src/com/android/systemui/volume/panel/component/captioning/domain/CaptioningAvailabilityCriteria.kt
new file mode 100644
index 0000000..aab825f
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/volume/panel/component/captioning/domain/CaptioningAvailabilityCriteria.kt
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.volume.panel.component.captioning.domain
+
+import com.android.settingslib.view.accessibility.domain.interactor.CaptioningInteractor
+import com.android.systemui.volume.panel.dagger.scope.VolumePanelScope
+import com.android.systemui.volume.panel.domain.ComponentAvailabilityCriteria
+import javax.inject.Inject
+import kotlinx.coroutines.flow.Flow
+
+@VolumePanelScope
+class CaptioningAvailabilityCriteria
+@Inject
+constructor(private val captioningInteractor: CaptioningInteractor) :
+ ComponentAvailabilityCriteria {
+
+ override fun isAvailable(): Flow<Boolean> =
+ captioningInteractor.isSystemAudioCaptioningUiEnabled
+}
diff --git a/packages/SystemUI/src/com/android/systemui/volume/panel/component/captioning/ui/viewmodel/CaptioningViewModel.kt b/packages/SystemUI/src/com/android/systemui/volume/panel/component/captioning/ui/viewmodel/CaptioningViewModel.kt
new file mode 100644
index 0000000..92f8f22
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/volume/panel/component/captioning/ui/viewmodel/CaptioningViewModel.kt
@@ -0,0 +1,62 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.volume.panel.component.captioning.ui.viewmodel
+
+import android.content.Context
+import com.android.settingslib.view.accessibility.domain.interactor.CaptioningInteractor
+import com.android.systemui.common.shared.model.Icon
+import com.android.systemui.res.R
+import com.android.systemui.volume.panel.component.button.ui.viewmodel.ToggleButtonViewModel
+import com.android.systemui.volume.panel.dagger.scope.VolumePanelScope
+import javax.inject.Inject
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.flow.SharingStarted
+import kotlinx.coroutines.flow.StateFlow
+import kotlinx.coroutines.flow.map
+import kotlinx.coroutines.flow.stateIn
+import kotlinx.coroutines.launch
+
+/** Volume Panel captioning UI model. */
+@VolumePanelScope
+class CaptioningViewModel
+@Inject
+constructor(
+ private val context: Context,
+ private val captioningInteractor: CaptioningInteractor,
+ @VolumePanelScope private val coroutineScope: CoroutineScope,
+) {
+
+ val buttonViewModel: StateFlow<ToggleButtonViewModel?> =
+ captioningInteractor.isSystemAudioCaptioningEnabled
+ .map { isEnabled ->
+ ToggleButtonViewModel(
+ isChecked = isEnabled,
+ icon =
+ Icon.Resource(
+ if (isEnabled) R.drawable.ic_volume_odi_captions
+ else R.drawable.ic_volume_odi_captions_disabled,
+ null
+ ),
+ label = context.getString(R.string.volume_panel_captioning_title),
+ )
+ }
+ .stateIn(coroutineScope, SharingStarted.Eagerly, null)
+
+ fun setIsSystemAudioCaptioningEnabled(enabled: Boolean) {
+ coroutineScope.launch { captioningInteractor.setIsSystemAudioCaptioningEnabled(enabled) }
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/volume/panel/component/shared/model/VolumePanelComponents.kt b/packages/SystemUI/src/com/android/systemui/volume/panel/component/shared/model/VolumePanelComponents.kt
index 1a4174a..842c323 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/panel/component/shared/model/VolumePanelComponents.kt
+++ b/packages/SystemUI/src/com/android/systemui/volume/panel/component/shared/model/VolumePanelComponents.kt
@@ -21,4 +21,5 @@
object VolumePanelComponents {
const val BOTTOM_BAR: VolumePanelComponentKey = "bottom_bar"
+ const val CAPTIONING: VolumePanelComponentKey = "captioning"
}
diff --git a/packages/SystemUI/src/com/android/systemui/volume/panel/dagger/VolumePanelComponent.kt b/packages/SystemUI/src/com/android/systemui/volume/panel/dagger/VolumePanelComponent.kt
index 0f19e9f..841daf8 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/panel/dagger/VolumePanelComponent.kt
+++ b/packages/SystemUI/src/com/android/systemui/volume/panel/dagger/VolumePanelComponent.kt
@@ -17,6 +17,7 @@
package com.android.systemui.volume.panel.dagger
import com.android.systemui.volume.panel.component.bottombar.BottomBarModule
+import com.android.systemui.volume.panel.component.captioning.CaptioningModule
import com.android.systemui.volume.panel.dagger.factory.VolumePanelComponentFactory
import com.android.systemui.volume.panel.dagger.scope.VolumePanelScope
import com.android.systemui.volume.panel.domain.DomainModule
@@ -44,6 +45,7 @@
UiModule::class,
// Components modules
BottomBarModule::class,
+ CaptioningModule::class,
]
)
interface VolumePanelComponent {
diff --git a/packages/SystemUI/src/com/android/systemui/volume/panel/domain/DomainModule.kt b/packages/SystemUI/src/com/android/systemui/volume/panel/domain/DomainModule.kt
index f785eb7..defa92d 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/panel/domain/DomainModule.kt
+++ b/packages/SystemUI/src/com/android/systemui/volume/panel/domain/DomainModule.kt
@@ -50,6 +50,7 @@
@VolumePanelScope
fun provideEnabledComponents(): Collection<VolumePanelComponentKey> {
return setOf(
+ VolumePanelComponents.CAPTIONING,
VolumePanelComponents.BOTTOM_BAR,
)
}
diff --git a/packages/SystemUI/src/com/android/systemui/volume/panel/ui/BottomBar.kt b/packages/SystemUI/src/com/android/systemui/volume/panel/ui/BottomBar.kt
new file mode 100644
index 0000000..3ea0eac
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/volume/panel/ui/BottomBar.kt
@@ -0,0 +1,26 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.volume.panel.ui
+
+import javax.inject.Qualifier
+
+/**
+ * Bottom bar component key.
+ *
+ * @see com.android.systemui.volume.panel.ui.layout.ComponentsLayoutManager
+ */
+@Qualifier @Retention(AnnotationRetention.RUNTIME) annotation class BottomBar()
diff --git a/packages/SystemUI/src/com/android/systemui/volume/panel/ui/FooterComponents.kt b/packages/SystemUI/src/com/android/systemui/volume/panel/ui/FooterComponents.kt
new file mode 100644
index 0000000..12a505d
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/volume/panel/ui/FooterComponents.kt
@@ -0,0 +1,27 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.volume.panel.ui
+
+import javax.inject.Qualifier
+
+/**
+ * [com.android.systemui.volume.panel.shared.model.VolumePanelUiComponent] collection to be shown
+ * below the content.
+ *
+ * @see com.android.systemui.volume.panel.ui.layout.ComponentsLayoutManager
+ */
+@Qualifier @Retention(AnnotationRetention.RUNTIME) annotation class FooterComponents()
diff --git a/packages/SystemUI/src/com/android/systemui/volume/panel/ui/HeaderComponents.kt b/packages/SystemUI/src/com/android/systemui/volume/panel/ui/HeaderComponents.kt
new file mode 100644
index 0000000..95be84a
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/volume/panel/ui/HeaderComponents.kt
@@ -0,0 +1,27 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.volume.panel.ui
+
+import javax.inject.Qualifier
+
+/**
+ * [com.android.systemui.volume.panel.shared.model.VolumePanelUiComponent] collection to be shown
+ * above the content.
+ *
+ * @see com.android.systemui.volume.panel.ui.layout.ComponentsLayoutManager
+ */
+@Qualifier @Retention(AnnotationRetention.RUNTIME) annotation class HeaderComponents()
diff --git a/packages/SystemUI/src/com/android/systemui/volume/panel/ui/UiModule.kt b/packages/SystemUI/src/com/android/systemui/volume/panel/ui/UiModule.kt
index 1346c54..a3f052d 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/panel/ui/UiModule.kt
+++ b/packages/SystemUI/src/com/android/systemui/volume/panel/ui/UiModule.kt
@@ -16,10 +16,14 @@
package com.android.systemui.volume.panel.ui
+import com.android.systemui.volume.panel.component.shared.model.VolumePanelComponents
+import com.android.systemui.volume.panel.dagger.scope.VolumePanelScope
+import com.android.systemui.volume.panel.shared.model.VolumePanelComponentKey
import com.android.systemui.volume.panel.ui.layout.ComponentsLayoutManager
import com.android.systemui.volume.panel.ui.layout.DefaultComponentsLayoutManager
import dagger.Binds
import dagger.Module
+import dagger.Provides
/** UI layer bindings module. */
@Module
@@ -27,4 +31,26 @@
@Binds
fun bindComponentsLayoutManager(impl: DefaultComponentsLayoutManager): ComponentsLayoutManager
+
+ companion object {
+
+ @Provides
+ @VolumePanelScope
+ @HeaderComponents
+ fun provideHeaderComponents(): Collection<VolumePanelComponentKey> = setOf()
+
+ @Provides
+ @VolumePanelScope
+ @FooterComponents
+ fun provideFooterComponents(): Collection<VolumePanelComponentKey> {
+ return setOf(
+ VolumePanelComponents.CAPTIONING,
+ )
+ }
+
+ @Provides
+ @VolumePanelScope
+ @BottomBar
+ fun provideBottomBarKey(): VolumePanelComponentKey = VolumePanelComponents.BOTTOM_BAR
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/volume/panel/ui/layout/ComponentsLayout.kt b/packages/SystemUI/src/com/android/systemui/volume/panel/ui/layout/ComponentsLayout.kt
index 25a95d8..1c51236 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/panel/ui/layout/ComponentsLayout.kt
+++ b/packages/SystemUI/src/com/android/systemui/volume/panel/ui/layout/ComponentsLayout.kt
@@ -20,6 +20,12 @@
/** Represents components grouping into the layout. */
data class ComponentsLayout(
+ /** Top section of the Volume Panel. It's typically shown above the [contentComponents]. */
+ val headerComponents: List<ComponentState>,
+ /** Main Volume Panel content. */
val contentComponents: List<ComponentState>,
+ /** Bottom section of the Volume Panel. It's typically shown below the [contentComponents]. */
+ val footerComponents: List<ComponentState>,
+ /** This is a separated entity that is always visible on the bottom of the Volume Panel. */
val bottomBarComponent: ComponentState,
)
diff --git a/packages/SystemUI/src/com/android/systemui/volume/panel/ui/layout/DefaultComponentsLayoutManager.kt b/packages/SystemUI/src/com/android/systemui/volume/panel/ui/layout/DefaultComponentsLayoutManager.kt
index ff485c2..7fd9c8a 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/panel/ui/layout/DefaultComponentsLayoutManager.kt
+++ b/packages/SystemUI/src/com/android/systemui/volume/panel/ui/layout/DefaultComponentsLayoutManager.kt
@@ -16,27 +16,47 @@
package com.android.systemui.volume.panel.ui.layout
-import com.android.systemui.volume.panel.component.shared.model.VolumePanelComponents
import com.android.systemui.volume.panel.dagger.scope.VolumePanelScope
+import com.android.systemui.volume.panel.shared.model.VolumePanelComponentKey
+import com.android.systemui.volume.panel.ui.BottomBar
+import com.android.systemui.volume.panel.ui.FooterComponents
+import com.android.systemui.volume.panel.ui.HeaderComponents
import com.android.systemui.volume.panel.ui.viewmodel.ComponentState
import com.android.systemui.volume.panel.ui.viewmodel.VolumePanelState
import javax.inject.Inject
@VolumePanelScope
-class DefaultComponentsLayoutManager @Inject constructor() : ComponentsLayoutManager {
+class DefaultComponentsLayoutManager
+@Inject
+constructor(
+ @BottomBar private val bottomBar: VolumePanelComponentKey,
+ @HeaderComponents
+ private val headerComponents: Collection<VolumePanelComponentKey> = emptyList(),
+ @FooterComponents
+ private val footerComponents: Collection<VolumePanelComponentKey> = emptyList(),
+) : ComponentsLayoutManager {
override fun layout(
volumePanelState: VolumePanelState,
components: Collection<ComponentState>
): ComponentsLayout {
- val bottomBarKey = VolumePanelComponents.BOTTOM_BAR
+ val contentComponents =
+ components.filter {
+ !headerComponents.contains(it.key) &&
+ !footerComponents.contains(it.key) &&
+ it.key != bottomBar
+ }
+ val headerComponents = components.filter { headerComponents.contains(it.key) }
+ val footerComponents = components.filter { footerComponents.contains(it.key) }
return ComponentsLayout(
- components.filter { it.key != bottomBarKey }.sortedBy { it.key },
- components.find { it.key == bottomBarKey }
- ?: error(
- "VolumePanelComponents.BOTTOM_BAR must be present in the default " +
- "components layout."
- )
+ headerComponents = headerComponents.sortedBy { it.key },
+ contentComponents = contentComponents.sortedBy { it.key },
+ footerComponents = footerComponents.sortedBy { it.key },
+ bottomBarComponent = components.find { it.key == bottomBar }
+ ?: error(
+ "VolumePanelComponents.BOTTOM_BAR must be present in the default " +
+ "components layout."
+ )
)
}
}
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/view/accessibility/data/repository/CaptioningKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/view/accessibility/data/repository/CaptioningKosmos.kt
new file mode 100644
index 0000000..0e978f2
--- /dev/null
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/view/accessibility/data/repository/CaptioningKosmos.kt
@@ -0,0 +1,23 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.view.accessibility.data.repository
+
+import com.android.settingslib.view.accessibility.domain.interactor.CaptioningInteractor
+import com.android.systemui.kosmos.Kosmos
+
+val Kosmos.captioningRepository by Kosmos.Fixture { FakeCaptioningRepository() }
+val Kosmos.captioningInteractor by Kosmos.Fixture { CaptioningInteractor(captioningRepository) }
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/view/accessibility/data/repository/FakeCaptioningRepository.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/view/accessibility/data/repository/FakeCaptioningRepository.kt
new file mode 100644
index 0000000..663aaf2
--- /dev/null
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/view/accessibility/data/repository/FakeCaptioningRepository.kt
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.view.accessibility.data.repository
+
+import com.android.settingslib.view.accessibility.data.repository.CaptioningRepository
+import kotlinx.coroutines.flow.MutableStateFlow
+import kotlinx.coroutines.flow.StateFlow
+import kotlinx.coroutines.flow.asStateFlow
+
+class FakeCaptioningRepository : CaptioningRepository {
+
+ private val mutableIsSystemAudioCaptioningEnabled = MutableStateFlow(false)
+ override val isSystemAudioCaptioningEnabled: StateFlow<Boolean>
+ get() = mutableIsSystemAudioCaptioningEnabled.asStateFlow()
+
+ private val mutableIsSystemAudioCaptioningUiEnabled = MutableStateFlow(false)
+ override val isSystemAudioCaptioningUiEnabled: StateFlow<Boolean>
+ get() = mutableIsSystemAudioCaptioningUiEnabled.asStateFlow()
+
+ override suspend fun setIsSystemAudioCaptioningEnabled(isEnabled: Boolean) {
+ mutableIsSystemAudioCaptioningEnabled.value = isEnabled
+ }
+
+ fun setIsSystemAudioCaptioningUiEnabled(isSystemAudioCaptioningUiEnabled: Boolean) {
+ mutableIsSystemAudioCaptioningUiEnabled.value = isSystemAudioCaptioningUiEnabled
+ }
+}
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/volume/panel/ui/layout/FakeComponentsLayoutManager.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/volume/panel/ui/layout/FakeComponentsLayoutManager.kt
deleted file mode 100644
index 655d8f7..0000000
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/volume/panel/ui/layout/FakeComponentsLayoutManager.kt
+++ /dev/null
@@ -1,37 +0,0 @@
-/*
- * Copyright (C) 2024 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.systemui.volume.panel.ui.layout
-
-import com.android.systemui.volume.panel.ui.viewmodel.ComponentState
-import com.android.systemui.volume.panel.ui.viewmodel.VolumePanelState
-
-class FakeComponentsLayoutManager(
- private val isBottomBar: (components: ComponentState) -> Boolean
-) : ComponentsLayoutManager {
-
- override fun layout(
- volumePanelState: VolumePanelState,
- components: Collection<ComponentState>
- ): ComponentsLayout {
- return ComponentsLayout(
- components
- .filter { componentState -> !isBottomBar(componentState) }
- .sortedBy { it.key },
- components.find(isBottomBar)!!,
- )
- }
-}