Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit f67efebd authored by Lucas Silva's avatar Lucas Silva Committed by Android (Google) Code Review
Browse files

Merge "Add support for TransitionKey in glanceable hub" into main

parents 33f5eeee baf5bdcf
Loading
Loading
Loading
Loading
+22 −10
Original line number Diff line number Diff line
@@ -8,12 +8,15 @@ import androidx.compose.runtime.Composable
import androidx.compose.runtime.DisposableEffect
import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue
import androidx.compose.runtime.remember
import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.ui.Modifier
import androidx.compose.ui.res.dimensionResource
import com.android.compose.animation.scene.Edge
import com.android.compose.animation.scene.ElementKey
import com.android.compose.animation.scene.FixedSizeEdgeDetector
import com.android.compose.animation.scene.LowestZIndexScenePicker
import com.android.compose.animation.scene.MutableSceneTransitionLayoutState
import com.android.compose.animation.scene.SceneKey
import com.android.compose.animation.scene.SceneScope
import com.android.compose.animation.scene.SceneTransitionLayout
@@ -21,12 +24,13 @@ import com.android.compose.animation.scene.Swipe
import com.android.compose.animation.scene.SwipeDirection
import com.android.compose.animation.scene.observableTransitionState
import com.android.compose.animation.scene.transitions
import com.android.compose.animation.scene.updateSceneTransitionLayoutState
import com.android.compose.theme.LocalAndroidColorScheme
import com.android.systemui.communal.shared.model.CommunalScenes
import com.android.systemui.communal.ui.viewmodel.BaseCommunalViewModel
import com.android.systemui.communal.ui.viewmodel.CommunalViewModel
import com.android.systemui.res.R
import com.android.systemui.scene.shared.model.SceneDataSourceDelegator
import com.android.systemui.scene.ui.composable.SceneTransitionLayoutDataSource
import com.android.systemui.statusbar.phone.SystemUIDialogFactory

object Communal {
@@ -63,27 +67,35 @@ val sceneTransitions = transitions {
fun CommunalContainer(
    modifier: Modifier = Modifier,
    viewModel: CommunalViewModel,
    dataSourceDelegator: SceneDataSourceDelegator,
    dialogFactory: SystemUIDialogFactory,
) {
    val currentScene: SceneKey by viewModel.currentScene.collectAsState(CommunalScenes.Blank)
    val sceneTransitionLayoutState =
        updateSceneTransitionLayoutState(
            currentScene,
            onChangeScene = { viewModel.onSceneChanged(it) },
    val coroutineScope = rememberCoroutineScope()
    val currentSceneKey: SceneKey by viewModel.currentScene.collectAsState(CommunalScenes.Blank)
    val touchesAllowed by viewModel.touchesAllowed.collectAsState(initial = false)
    val state: MutableSceneTransitionLayoutState = remember {
        MutableSceneTransitionLayoutState(
            initialScene = currentSceneKey,
            transitions = sceneTransitions,
            enableInterruptions = false,
        )
    val touchesAllowed by viewModel.touchesAllowed.collectAsState(initial = false)
    }

    DisposableEffect(state) {
        val dataSource = SceneTransitionLayoutDataSource(state, coroutineScope)
        dataSourceDelegator.setDelegate(dataSource)
        onDispose { dataSourceDelegator.setDelegate(null) }
    }

    // This effect exposes the SceneTransitionLayout's observable transition state to the rest of
    // the system, and unsets it when the view is disposed to avoid a memory leak.
    DisposableEffect(viewModel, sceneTransitionLayoutState) {
        viewModel.setTransitionState(sceneTransitionLayoutState.observableTransitionState())
    DisposableEffect(viewModel, state) {
        viewModel.setTransitionState(state.observableTransitionState())
        onDispose { viewModel.setTransitionState(null) }
    }

    SceneTransitionLayout(
        state = sceneTransitionLayoutState,
        state = state,
        modifier = modifier.fillMaxSize(),
        swipeSourceDetector =
            FixedSizeEdgeDetector(
+11 −11
Original line number Diff line number Diff line
@@ -88,7 +88,7 @@ class CommunalSceneStartableTest : SysuiTestCase() {
            testScope.runTest {
                val scene by collectLastValue(communalInteractor.desiredScene)

                communalInteractor.onSceneChanged(CommunalScenes.Communal)
                communalInteractor.changeScene(CommunalScenes.Communal)
                assertThat(scene).isEqualTo(CommunalScenes.Communal)

                fakeKeyguardTransitionRepository.sendTransitionSteps(
@@ -158,7 +158,7 @@ class CommunalSceneStartableTest : SysuiTestCase() {
        with(kosmos) {
            testScope.runTest {
                val scene by collectLastValue(communalInteractor.desiredScene)
                communalInteractor.onSceneChanged(CommunalScenes.Communal)
                communalInteractor.changeScene(CommunalScenes.Communal)
                assertThat(scene).isEqualTo(CommunalScenes.Communal)

                fakeKeyguardTransitionRepository.sendTransitionSteps(
@@ -179,7 +179,7 @@ class CommunalSceneStartableTest : SysuiTestCase() {
        with(kosmos) {
            testScope.runTest {
                val scene by collectLastValue(communalInteractor.desiredScene)
                communalInteractor.onSceneChanged(CommunalScenes.Communal)
                communalInteractor.changeScene(CommunalScenes.Communal)
                assertThat(scene).isEqualTo(CommunalScenes.Communal)

                fakeKeyguardTransitionRepository.sendTransitionSteps(
@@ -207,7 +207,7 @@ class CommunalSceneStartableTest : SysuiTestCase() {
    fun dockingOnLockscreen_forcesCommunal() =
        with(kosmos) {
            testScope.runTest {
                communalInteractor.onSceneChanged(CommunalScenes.Blank)
                communalInteractor.changeScene(CommunalScenes.Blank)
                val scene by collectLastValue(communalInteractor.desiredScene)

                // device is docked while on the lockscreen
@@ -229,7 +229,7 @@ class CommunalSceneStartableTest : SysuiTestCase() {
    fun dockingOnLockscreen_doesNotForceCommunalIfDreamStarts() =
        with(kosmos) {
            testScope.runTest {
                communalInteractor.onSceneChanged(CommunalScenes.Blank)
                communalInteractor.changeScene(CommunalScenes.Blank)
                val scene by collectLastValue(communalInteractor.desiredScene)

                // device is docked while on the lockscreen
@@ -261,7 +261,7 @@ class CommunalSceneStartableTest : SysuiTestCase() {
            testScope.runTest {
                // Device is dreaming and on communal.
                fakeKeyguardRepository.setDreaming(true)
                communalInteractor.onSceneChanged(CommunalScenes.Communal)
                communalInteractor.changeScene(CommunalScenes.Communal)

                val scene by collectLastValue(communalInteractor.desiredScene)
                assertThat(scene).isEqualTo(CommunalScenes.Communal)
@@ -278,7 +278,7 @@ class CommunalSceneStartableTest : SysuiTestCase() {
            testScope.runTest {
                // Device is not dreaming and on communal.
                fakeKeyguardRepository.setDreaming(false)
                communalInteractor.onSceneChanged(CommunalScenes.Communal)
                communalInteractor.changeScene(CommunalScenes.Communal)

                // Scene stays as Communal
                advanceTimeBy(SCREEN_TIMEOUT.milliseconds)
@@ -293,7 +293,7 @@ class CommunalSceneStartableTest : SysuiTestCase() {
            testScope.runTest {
                // Device is dreaming and on communal.
                fakeKeyguardRepository.setDreaming(true)
                communalInteractor.onSceneChanged(CommunalScenes.Communal)
                communalInteractor.changeScene(CommunalScenes.Communal)

                val scene by collectLastValue(communalInteractor.desiredScene)
                assertThat(scene).isEqualTo(CommunalScenes.Communal)
@@ -316,7 +316,7 @@ class CommunalSceneStartableTest : SysuiTestCase() {
            testScope.runTest {
                // Device is on communal, but not dreaming.
                fakeKeyguardRepository.setDreaming(false)
                communalInteractor.onSceneChanged(CommunalScenes.Communal)
                communalInteractor.changeScene(CommunalScenes.Communal)

                val scene by collectLastValue(communalInteractor.desiredScene)
                assertThat(scene).isEqualTo(CommunalScenes.Communal)
@@ -338,7 +338,7 @@ class CommunalSceneStartableTest : SysuiTestCase() {
            testScope.runTest {
                // Device is dreaming and on communal.
                fakeKeyguardRepository.setDreaming(true)
                communalInteractor.onSceneChanged(CommunalScenes.Communal)
                communalInteractor.changeScene(CommunalScenes.Communal)

                val scene by collectLastValue(communalInteractor.desiredScene)
                assertThat(scene).isEqualTo(CommunalScenes.Communal)
@@ -367,7 +367,7 @@ class CommunalSceneStartableTest : SysuiTestCase() {

                // Device is dreaming and on communal.
                fakeKeyguardRepository.setDreaming(true)
                communalInteractor.onSceneChanged(CommunalScenes.Communal)
                communalInteractor.changeScene(CommunalScenes.Communal)

                val scene by collectLastValue(communalInteractor.desiredScene)
                assertThat(scene).isEqualTo(CommunalScenes.Communal)
+6 −16
Original line number Diff line number Diff line
@@ -22,36 +22,26 @@ import com.android.compose.animation.scene.ObservableTransitionState
import com.android.systemui.SysuiTestCase
import com.android.systemui.communal.shared.model.CommunalScenes
import com.android.systemui.coroutines.collectLastValue
import com.android.systemui.kosmos.applicationCoroutineScope
import com.android.systemui.kosmos.testScope
import com.android.systemui.scene.data.repository.sceneContainerRepository
import com.android.systemui.scene.shared.flag.fakeSceneContainerFlags
import com.android.systemui.scene.shared.model.sceneDataSource
import com.android.systemui.testKosmos
import com.google.common.truth.Truth.assertThat
import kotlinx.coroutines.flow.flowOf
import kotlinx.coroutines.test.runTest
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith

@SmallTest
@RunWith(AndroidJUnit4::class)
class CommunalRepositoryImplTest : SysuiTestCase() {
    private lateinit var underTest: CommunalRepositoryImpl

    private val kosmos = testKosmos()
    private val testScope = kosmos.testScope
    private val sceneContainerRepository = kosmos.sceneContainerRepository

    @Before
    fun setUp() {
        underTest = createRepositoryImpl(false)
    }

    private fun createRepositoryImpl(sceneContainerEnabled: Boolean): CommunalRepositoryImpl {
        return CommunalRepositoryImpl(
            testScope.backgroundScope,
            kosmos.fakeSceneContainerFlags.apply { enabled = sceneContainerEnabled },
            sceneContainerRepository,
    private val underTest by lazy {
        CommunalRepositoryImpl(
            kosmos.applicationCoroutineScope,
            kosmos.sceneDataSource,
        )
    }

+8 −8
Original line number Diff line number Diff line
@@ -482,7 +482,7 @@ class CommunalInteractorTest : SysuiTestCase() {
            assertThat(desiredScene()).isEqualTo(CommunalScenes.Blank)

            val targetScene = CommunalScenes.Communal
            communalRepository.setDesiredScene(targetScene)
            communalRepository.changeScene(targetScene)
            desiredScene = collectLastValue(underTest.desiredScene)
            runCurrent()
            assertThat(desiredScene()).isEqualTo(targetScene)
@@ -493,9 +493,9 @@ class CommunalInteractorTest : SysuiTestCase() {
        testScope.runTest {
            val targetScene = CommunalScenes.Communal

            underTest.onSceneChanged(targetScene)
            underTest.changeScene(targetScene)

            val desiredScene = collectLastValue(communalRepository.desiredScene)
            val desiredScene = collectLastValue(communalRepository.currentScene)
            runCurrent()
            assertThat(desiredScene()).isEqualTo(targetScene)
        }
@@ -508,7 +508,7 @@ class CommunalInteractorTest : SysuiTestCase() {

            val desiredScene by collectLastValue(underTest.desiredScene)

            underTest.onSceneChanged(CommunalScenes.Communal)
            underTest.changeScene(CommunalScenes.Communal)
            assertThat(desiredScene).isEqualTo(CommunalScenes.Communal)

            kosmos.setCommunalAvailable(false)
@@ -659,7 +659,7 @@ class CommunalInteractorTest : SysuiTestCase() {
            runCurrent()
            assertThat(isCommunalShowing()).isEqualTo(false)

            underTest.onSceneChanged(CommunalScenes.Communal)
            underTest.changeScene(CommunalScenes.Communal)

            isCommunalShowing = collectLastValue(underTest.isCommunalShowing)
            runCurrent()
@@ -683,12 +683,12 @@ class CommunalInteractorTest : SysuiTestCase() {
            assertThat(isCommunalShowing).isFalse()

            // Verify scene changes (without the flag) to communal sets the value to true
            underTest.onSceneChanged(CommunalScenes.Communal)
            underTest.changeScene(CommunalScenes.Communal)
            runCurrent()
            assertThat(isCommunalShowing).isTrue()

            // Verify scene changes (without the flag) to blank sets the value back to false
            underTest.onSceneChanged(CommunalScenes.Blank)
            underTest.changeScene(CommunalScenes.Blank)
            runCurrent()
            assertThat(isCommunalShowing).isFalse()
        }
@@ -704,7 +704,7 @@ class CommunalInteractorTest : SysuiTestCase() {
            assertThat(isCommunalShowing).isFalse()

            // Verify scene changes without the flag doesn't have any impact
            underTest.onSceneChanged(CommunalScenes.Communal)
            underTest.changeScene(CommunalScenes.Communal)
            runCurrent()
            assertThat(isCommunalShowing).isFalse()

+4 −4
Original line number Diff line number Diff line
@@ -158,7 +158,7 @@ class CommunalTutorialInteractorTest : SysuiTestCase() {
            kosmos.setCommunalAvailable(true)
            communalTutorialRepository.setTutorialSettingState(HUB_MODE_TUTORIAL_NOT_STARTED)

            communalInteractor.onSceneChanged(CommunalScenes.Blank)
            communalInteractor.changeScene(CommunalScenes.Blank)

            assertThat(tutorialSettingState).isEqualTo(HUB_MODE_TUTORIAL_NOT_STARTED)
        }
@@ -171,7 +171,7 @@ class CommunalTutorialInteractorTest : SysuiTestCase() {
            goToCommunal()
            communalTutorialRepository.setTutorialSettingState(HUB_MODE_TUTORIAL_STARTED)

            communalInteractor.onSceneChanged(CommunalScenes.Blank)
            communalInteractor.changeScene(CommunalScenes.Blank)

            assertThat(tutorialSettingState).isEqualTo(HUB_MODE_TUTORIAL_COMPLETED)
        }
@@ -184,13 +184,13 @@ class CommunalTutorialInteractorTest : SysuiTestCase() {
            goToCommunal()
            communalTutorialRepository.setTutorialSettingState(HUB_MODE_TUTORIAL_COMPLETED)

            communalInteractor.onSceneChanged(CommunalScenes.Blank)
            communalInteractor.changeScene(CommunalScenes.Blank)

            assertThat(tutorialSettingState).isEqualTo(HUB_MODE_TUTORIAL_COMPLETED)
        }

    private suspend fun goToCommunal() {
        kosmos.setCommunalAvailable(true)
        communalInteractor.onSceneChanged(CommunalScenes.Communal)
        communalInteractor.changeScene(CommunalScenes.Communal)
    }
}
Loading