From 213e2ad4758d3e91bde646267ded95b0d38d7996 Mon Sep 17 00:00:00 2001 From: Alejandro Nijamkin Date: Tue, 9 May 2023 09:49:13 -0700 Subject: [PATCH] [flexiglass] Container config - UI layer. The container configuration portion of the Flexiglass framework allows OEMs to configure one or more Flexiglass containers with scenes. Each scene is a distinct bit of UI content that the user can navigate to (for example by swiping in a direction) or that can be navigated to automatically through the SceneInteractor methods. Bug: 279501596 Test: Included unit tests. Manually tested through a testbed app that uses Jetpack Compose to implement a simple UI to traverse all scenes. Change-Id: I2c925707b0709e4aaf26bca8f94e5e2b3cf6bbcc --- .../ui/viewmodel/SceneContainerViewModel.kt | 64 ++++++++++++++++ .../viewmodel/SceneContainerViewModelTest.kt | 74 +++++++++++++++++++ 2 files changed, 138 insertions(+) create mode 100644 packages/SystemUI/src/com/android/systemui/scene/ui/viewmodel/SceneContainerViewModel.kt create mode 100644 packages/SystemUI/tests/src/com/android/systemui/scene/ui/viewmodel/SceneContainerViewModelTest.kt diff --git a/packages/SystemUI/src/com/android/systemui/scene/ui/viewmodel/SceneContainerViewModel.kt b/packages/SystemUI/src/com/android/systemui/scene/ui/viewmodel/SceneContainerViewModel.kt new file mode 100644 index 0000000000000..afc053151ab5a --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/scene/ui/viewmodel/SceneContainerViewModel.kt @@ -0,0 +1,64 @@ +/* + * Copyright (C) 2023 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.scene.ui.viewmodel + +import com.android.systemui.scene.domain.interactor.SceneInteractor +import com.android.systemui.scene.shared.model.SceneKey +import com.android.systemui.scene.shared.model.SceneModel +import dagger.assisted.Assisted +import dagger.assisted.AssistedFactory +import dagger.assisted.AssistedInject +import kotlinx.coroutines.flow.StateFlow + +/** Models UI state for a single scene container. */ +class SceneContainerViewModel +@AssistedInject +constructor( + private val interactor: SceneInteractor, + @Assisted private val containerName: String, +) { + /** + * Keys of all scenes in the container. + * + * The scenes will be sorted in z-order such that the last one is the one that should be + * rendered on top of all previous ones. + */ + val allSceneKeys: List = interactor.allSceneKeys(containerName) + + /** The current scene. */ + val currentScene: StateFlow = interactor.currentScene(containerName) + + /** Whether the container is visible. */ + val isVisible: StateFlow = interactor.isVisible(containerName) + + /** Requests a transition to the scene with the given key. */ + fun setCurrentScene(scene: SceneModel) { + interactor.setCurrentScene(containerName, scene) + } + + /** Notifies of the progress of a scene transition. */ + fun setSceneTransitionProgress(progress: Float) { + interactor.setSceneTransitionProgress(containerName, progress) + } + + @AssistedFactory + interface Factory { + fun create( + containerName: String, + ): SceneContainerViewModel + } +} diff --git a/packages/SystemUI/tests/src/com/android/systemui/scene/ui/viewmodel/SceneContainerViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/scene/ui/viewmodel/SceneContainerViewModelTest.kt new file mode 100644 index 0000000000000..ab61ddddaeab5 --- /dev/null +++ b/packages/SystemUI/tests/src/com/android/systemui/scene/ui/viewmodel/SceneContainerViewModelTest.kt @@ -0,0 +1,74 @@ +/* + * Copyright (C) 2023 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. + */ + +@file:OptIn(ExperimentalCoroutinesApi::class) + +package com.android.systemui.scene.ui.viewmodel + +import androidx.test.filters.SmallTest +import com.android.systemui.SysuiTestCase +import com.android.systemui.coroutines.collectLastValue +import com.android.systemui.scene.data.repository.fakeSceneContainerRepository +import com.android.systemui.scene.data.repository.fakeSceneKeys +import com.android.systemui.scene.domain.interactor.SceneInteractor +import com.android.systemui.scene.shared.model.SceneKey +import com.android.systemui.scene.shared.model.SceneModel +import com.google.common.truth.Truth.assertThat +import kotlinx.coroutines.ExperimentalCoroutinesApi +import kotlinx.coroutines.test.runTest +import org.junit.Test +import org.junit.runner.RunWith +import org.junit.runners.JUnit4 + +@SmallTest +@RunWith(JUnit4::class) +class SceneContainerViewModelTest : SysuiTestCase() { + private val interactor = + SceneInteractor( + repository = fakeSceneContainerRepository(), + ) + private val underTest = + SceneContainerViewModel( + interactor = interactor, + containerName = "container1", + ) + + @Test + fun isVisible() = runTest { + val isVisible by collectLastValue(underTest.isVisible) + assertThat(isVisible).isTrue() + + interactor.setVisible("container1", false) + assertThat(isVisible).isFalse() + + interactor.setVisible("container1", true) + assertThat(isVisible).isTrue() + } + + @Test + fun allSceneKeys() { + assertThat(underTest.allSceneKeys).isEqualTo(fakeSceneKeys()) + } + + @Test + fun sceneTransition() = runTest { + val currentScene by collectLastValue(underTest.currentScene) + assertThat(currentScene).isEqualTo(SceneModel(SceneKey.LockScreen)) + + underTest.setCurrentScene(SceneModel(SceneKey.Shade)) + assertThat(currentScene).isEqualTo(SceneModel(SceneKey.Shade)) + } +}