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

Commit 7e404fb2 authored by Andreas Miko's avatar Andreas Miko
Browse files

Enable and auto-convert old KTF transitions to scene container

When a collector of a transition with old KTF states listened to e.g.
AOD -> GONE in the past, the KTF state GONE won't exist in the future.
This now requires two things to happen to be able to listen to the same
transition:
1. GONE needs to be converted to UNDEFINED (AOD -> UNDEFINED)
2. Because AOD -> UNDEFINED is not conclusive (it could be also a AOD ->
Bouncer transition) you need to additionally listen/filter to scene
container and make sure Lockscreen -> Gone is in progress.

The auto-convert aspect is a convenience function to make todays
viewmodels work easily while migrating to scene container.

Test: KeyguardTransitionInteractorTest
Bug: b/330311871
Flag: ACONFIG com.android.systemui.scene_container DEVELOPMENT
Change-Id: If6032d6cb3eec498a124c204317bb96971ac74c2
parent 19db0f80
Loading
Loading
Loading
Loading
+186 −9
Original line number Diff line number Diff line
@@ -19,9 +19,13 @@ package com.android.systemui.keyguard.domain.interactor

import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.compose.animation.scene.ObservableTransitionState
import com.android.systemui.SysuiTestCase
import com.android.systemui.coroutines.collectValues
import com.android.systemui.flags.DisableSceneContainer
import com.android.systemui.flags.EnableSceneContainer
import com.android.systemui.keyguard.data.repository.fakeKeyguardTransitionRepository
import com.android.systemui.keyguard.shared.model.Edge
import com.android.systemui.keyguard.shared.model.KeyguardState
import com.android.systemui.keyguard.shared.model.KeyguardState.AOD
import com.android.systemui.keyguard.shared.model.KeyguardState.DOZING
@@ -29,31 +33,67 @@ import com.android.systemui.keyguard.shared.model.KeyguardState.GONE
import com.android.systemui.keyguard.shared.model.KeyguardState.LOCKSCREEN
import com.android.systemui.keyguard.shared.model.KeyguardState.OFF
import com.android.systemui.keyguard.shared.model.KeyguardState.PRIMARY_BOUNCER
import com.android.systemui.keyguard.shared.model.KeyguardState.UNDEFINED
import com.android.systemui.keyguard.shared.model.TransitionState.CANCELED
import com.android.systemui.keyguard.shared.model.TransitionState.FINISHED
import com.android.systemui.keyguard.shared.model.TransitionState.RUNNING
import com.android.systemui.keyguard.shared.model.TransitionState.STARTED
import com.android.systemui.keyguard.shared.model.TransitionStep
import com.android.systemui.kosmos.testScope
import com.android.systemui.scene.data.repository.sceneContainerRepository
import com.android.systemui.scene.shared.model.Scenes
import com.android.systemui.testKosmos
import com.google.common.truth.Truth.assertThat
import junit.framework.Assert.assertEquals
import kotlinx.coroutines.flow.MutableSharedFlow
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.flowOf
import kotlinx.coroutines.test.runCurrent
import kotlinx.coroutines.test.runTest
import org.junit.Assert.assertThrows
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith

@SmallTest
@RunWith(AndroidJUnit4::class)
@kotlinx.coroutines.ExperimentalCoroutinesApi
@android.platform.test.annotations.EnabledOnRavenwood
class KeyguardTransitionInteractorTest : SysuiTestCase() {
    val kosmos = testKosmos()
    val underTest = kosmos.keyguardTransitionInteractor
    val repository = kosmos.fakeKeyguardTransitionRepository
    val testScope = kosmos.testScope

    private val sceneTransitions =
        MutableStateFlow<ObservableTransitionState>(
            ObservableTransitionState.Idle(Scenes.Lockscreen)
        )

    private val lsToGone =
        ObservableTransitionState.Transition(
            Scenes.Lockscreen,
            Scenes.Gone,
            flowOf(Scenes.Lockscreen),
            flowOf(0f),
            false,
            flowOf(false)
        )

    private val goneToLs =
        ObservableTransitionState.Transition(
            Scenes.Gone,
            Scenes.Lockscreen,
            flowOf(Scenes.Lockscreen),
            flowOf(0f),
            false,
            flowOf(false)
        )

    @Before
    fun setUp() {
        kosmos.sceneContainerRepository.setTransitionState(sceneTransitions)
    }

    @Test
    fun transitionCollectorsReceivesOnlyAppropriateEvents() =
        testScope.runTest {
@@ -482,6 +522,7 @@ class KeyguardTransitionInteractorTest : SysuiTestCase() {
        }

    @Test
    @DisableSceneContainer
    fun isInTransitionToState() =
        testScope.runTest {
            val results by collectValues(underTest.isInTransitionToState(GONE))
@@ -586,7 +627,7 @@ class KeyguardTransitionInteractorTest : SysuiTestCase() {
                )

            sendSteps(
                TransitionStep(DOZING, GONE, 0f, STARTED),
                TransitionStep(DOZING, LOCKSCREEN, 0f, STARTED),
            )

            assertThat(results)
@@ -598,7 +639,7 @@ class KeyguardTransitionInteractorTest : SysuiTestCase() {
                )

            sendSteps(
                TransitionStep(DOZING, GONE, 0f, RUNNING),
                TransitionStep(DOZING, LOCKSCREEN, 0f, RUNNING),
            )

            assertThat(results)
@@ -610,7 +651,7 @@ class KeyguardTransitionInteractorTest : SysuiTestCase() {
                )

            sendSteps(
                TransitionStep(DOZING, GONE, 0f, FINISHED),
                TransitionStep(DOZING, LOCKSCREEN, 0f, FINISHED),
            )

            assertThat(results)
@@ -623,9 +664,9 @@ class KeyguardTransitionInteractorTest : SysuiTestCase() {
                )

            sendSteps(
                TransitionStep(GONE, DOZING, 0f, STARTED),
                TransitionStep(GONE, DOZING, 0f, RUNNING),
                TransitionStep(GONE, DOZING, 1f, FINISHED),
                TransitionStep(LOCKSCREEN, DOZING, 0f, STARTED),
                TransitionStep(LOCKSCREEN, DOZING, 0f, RUNNING),
                TransitionStep(LOCKSCREEN, DOZING, 1f, FINISHED),
            )

            assertThat(results)
@@ -638,8 +679,8 @@ class KeyguardTransitionInteractorTest : SysuiTestCase() {
                )

            sendSteps(
                TransitionStep(DOZING, GONE, 0f, STARTED),
                TransitionStep(DOZING, GONE, 0f, RUNNING),
                TransitionStep(DOZING, LOCKSCREEN, 0f, STARTED),
                TransitionStep(DOZING, LOCKSCREEN, 0f, RUNNING),
            )

            assertThat(results)
@@ -1404,6 +1445,142 @@ class KeyguardTransitionInteractorTest : SysuiTestCase() {
            )
        }

    @Test
    @DisableSceneContainer
    fun getOrCreateFlow_no_conversion_with_flag_off() =
        testScope.runTest {
            val currentStates by
                collectValues(underTest.getOrCreateFlow(Edge(PRIMARY_BOUNCER, GONE)))

            val sendStep1 = TransitionStep(PRIMARY_BOUNCER, GONE, 0f, STARTED)
            sendSteps(sendStep1)

            assertEquals(listOf(sendStep1), currentStates)
        }

    @Test
    @EnableSceneContainer
    fun getOrCreateFlow_conversion_with_flag_on() =
        testScope.runTest {
            val currentStates by
                collectValues(underTest.getOrCreateFlow(Edge(PRIMARY_BOUNCER, GONE)))

            val sendStep1 = TransitionStep(PRIMARY_BOUNCER, GONE, 0f, STARTED)
            sendSteps(sendStep1)

            assertEquals(listOf<TransitionStep>(), currentStates)
        }

    @Test
    @EnableSceneContainer
    fun getOrCreateFlow_conversion_emits_values_with_sceneContainer_in_correct_state() =
        testScope.runTest {
            val currentStates by collectValues(underTest.getOrCreateFlow(Edge(LOCKSCREEN, GONE)))
            val currentStatesConverted by
                collectValues(underTest.getOrCreateFlow(Edge(LOCKSCREEN, UNDEFINED)))

            sceneTransitions.value = lsToGone
            val sendStep1 = TransitionStep(LOCKSCREEN, UNDEFINED, 0f, STARTED)
            val sendStep2 = TransitionStep(LOCKSCREEN, UNDEFINED, 1f, FINISHED)
            val sendStep3 = TransitionStep(LOCKSCREEN, AOD, 0f, STARTED)
            sendSteps(sendStep1, sendStep2, sendStep3)

            assertEquals(listOf(sendStep1, sendStep2), currentStates)
            assertEquals(listOf(sendStep1, sendStep2), currentStatesConverted)
        }

    @Test
    @EnableSceneContainer
    fun getOrCreateFlow_conversion_emits_nothing_with_sceneContainer_in_wrong_state() =
        testScope.runTest {
            val currentStates by collectValues(underTest.getOrCreateFlow(Edge(LOCKSCREEN, GONE)))

            sceneTransitions.value = goneToLs
            val sendStep1 = TransitionStep(LOCKSCREEN, UNDEFINED, 0f, STARTED)
            val sendStep2 = TransitionStep(LOCKSCREEN, UNDEFINED, 1f, FINISHED)
            val sendStep3 = TransitionStep(LOCKSCREEN, AOD, 0f, STARTED)
            sendSteps(sendStep1, sendStep2, sendStep3)

            assertEquals(listOf<TransitionStep>(), currentStates)
        }

    @Test
    @EnableSceneContainer
    fun getOrCreateFlow_conversion_emits_values_when_edge_within_lockscreen_scene() =
        testScope.runTest {
            val currentStates by collectValues(underTest.getOrCreateFlow(Edge(LOCKSCREEN, DOZING)))

            sceneTransitions.value = goneToLs
            val sendStep1 = TransitionStep(LOCKSCREEN, DOZING, 0f, STARTED)
            val sendStep2 = TransitionStep(LOCKSCREEN, DOZING, 1f, FINISHED)
            val sendStep3 = TransitionStep(LOCKSCREEN, AOD, 0f, STARTED)
            sendSteps(sendStep1, sendStep2, sendStep3)

            assertEquals(listOf(sendStep1, sendStep2), currentStates)
        }

    @Test
    @EnableSceneContainer
    fun getOrCreateFlow_conversion_emits_values_with_null_edge_within_lockscreen_scene() =
        testScope.runTest {
            val currentStates by collectValues(underTest.getOrCreateFlow(Edge(LOCKSCREEN, null)))
            val currentStatesReversed by
                collectValues(underTest.getOrCreateFlow(Edge(null, LOCKSCREEN)))

            sceneTransitions.value = goneToLs
            val sendStep1 = TransitionStep(LOCKSCREEN, DOZING, 0f, STARTED)
            val sendStep2 = TransitionStep(LOCKSCREEN, DOZING, 1f, FINISHED)
            val sendStep3 = TransitionStep(LOCKSCREEN, AOD, 0f, STARTED)
            val sendStep4 = TransitionStep(AOD, LOCKSCREEN, 0f, STARTED)
            sendSteps(sendStep1, sendStep2, sendStep3, sendStep4)

            assertEquals(listOf(sendStep1, sendStep2, sendStep3), currentStates)
            assertEquals(listOf(sendStep4), currentStatesReversed)
        }

    @Test
    @EnableSceneContainer
    fun getOrCreateFlow_conversion_emits_values_with_null_edge_out_of_lockscreen_scene() =
        testScope.runTest {
            val currentStates by collectValues(underTest.getOrCreateFlow(Edge(null, UNDEFINED)))
            val currentStatesMapped by collectValues(underTest.getOrCreateFlow(Edge(null, GONE)))

            sceneTransitions.value = lsToGone
            val sendStep1 = TransitionStep(LOCKSCREEN, UNDEFINED, 0f, STARTED)
            val sendStep2 = TransitionStep(LOCKSCREEN, UNDEFINED, 1f, FINISHED)
            val sendStep3 = TransitionStep(UNDEFINED, AOD, 0f, STARTED)
            val sendStep4 = TransitionStep(AOD, LOCKSCREEN, 0f, STARTED)
            sendSteps(sendStep1, sendStep2, sendStep3, sendStep4)

            assertEquals(listOf(sendStep1, sendStep2), currentStates)
            assertEquals(listOf(sendStep1, sendStep2), currentStatesMapped)
        }

    @Test
    @EnableSceneContainer
    fun getOrCreateFlow_conversion_does_not_emit_with_null_edge_with_wrong_stl_state() =
        testScope.runTest {
            val currentStatesMapped by collectValues(underTest.getOrCreateFlow(Edge(null, GONE)))

            sceneTransitions.value = goneToLs
            val sendStep1 = TransitionStep(LOCKSCREEN, UNDEFINED, 0f, STARTED)
            val sendStep2 = TransitionStep(LOCKSCREEN, UNDEFINED, 1f, FINISHED)
            val sendStep3 = TransitionStep(UNDEFINED, AOD, 0f, STARTED)
            val sendStep4 = TransitionStep(AOD, LOCKSCREEN, 0f, STARTED)
            sendSteps(sendStep1, sendStep2, sendStep3, sendStep4)

            assertEquals(listOf<TransitionStep>(), currentStatesMapped)
        }

    @Test
    @EnableSceneContainer
    fun getOrCreateFlow_null_edges_throw() =
        testScope.runTest {
            assertThrows(IllegalStateException::class.java) {
                underTest.getOrCreateFlow(Edge(null, null))
            }
        }

    private suspend fun sendSteps(vararg steps: TransitionStep) {
        steps.forEach {
            repository.sendTransitionStep(it)
+5 −0
Original line number Diff line number Diff line
@@ -87,6 +87,7 @@ class BouncerToGoneFlowsTest(flags: FlagsParameterization) : SysuiTestCase() {
    }

    @Test
    @BrokenWithSceneContainer(339465026)
    fun scrimAlpha_runDimissFromKeyguard_shadeExpanded() =
        testScope.runTest {
            val values by collectValues(underTest.scrimAlpha(500.milliseconds, PRIMARY_BOUNCER))
@@ -137,6 +138,7 @@ class BouncerToGoneFlowsTest(flags: FlagsParameterization) : SysuiTestCase() {
        }

    @Test
    @BrokenWithSceneContainer(339465026)
    fun scrimBehindAlpha_leaveShadeOpen() =
        testScope.runTest {
            val values by collectValues(underTest.scrimAlpha(500.milliseconds, PRIMARY_BOUNCER))
@@ -161,6 +163,7 @@ class BouncerToGoneFlowsTest(flags: FlagsParameterization) : SysuiTestCase() {
        }

    @Test
    @BrokenWithSceneContainer(339465026)
    fun showAllNotifications_isTrue_whenLeaveShadeOpen() =
        testScope.runTest {
            val showAllNotifications by
@@ -177,6 +180,7 @@ class BouncerToGoneFlowsTest(flags: FlagsParameterization) : SysuiTestCase() {
        }

    @Test
    @BrokenWithSceneContainer(339465026)
    fun showAllNotifications_isFalse_whenLeaveShadeIsNotOpen() =
        testScope.runTest {
            val showAllNotifications by
@@ -193,6 +197,7 @@ class BouncerToGoneFlowsTest(flags: FlagsParameterization) : SysuiTestCase() {
        }

    @Test
    @BrokenWithSceneContainer(330311871)
    fun scrimBehindAlpha_doNotLeaveShadeOpen() =
        testScope.runTest {
            val values by collectValues(underTest.scrimAlpha(500.milliseconds, PRIMARY_BOUNCER))
+38 −0
Original line number Diff line number Diff line
@@ -30,6 +30,8 @@ import com.android.systemui.communal.data.repository.communalRepository
import com.android.systemui.communal.shared.model.CommunalScenes
import com.android.systemui.coroutines.collectLastValue
import com.android.systemui.deviceentry.data.repository.fakeDeviceEntryRepository
import com.android.systemui.flags.DisableSceneContainer
import com.android.systemui.flags.EnableSceneContainer
import com.android.systemui.flags.parameterizeSceneContainerFlag
import com.android.systemui.keyguard.data.repository.fakeKeyguardRepository
import com.android.systemui.keyguard.data.repository.fakeKeyguardTransitionRepository
@@ -37,7 +39,9 @@ import com.android.systemui.keyguard.shared.model.KeyguardState
import com.android.systemui.keyguard.shared.model.TransitionState
import com.android.systemui.keyguard.shared.model.TransitionStep
import com.android.systemui.kosmos.testScope
import com.android.systemui.scene.data.repository.sceneContainerRepository
import com.android.systemui.scene.shared.flag.SceneContainerFlag
import com.android.systemui.scene.shared.model.Scenes
import com.android.systemui.shade.shadeTestUtil
import com.android.systemui.statusbar.notification.stack.domain.interactor.notificationsKeyguardInteractor
import com.android.systemui.statusbar.phone.dozeParameters
@@ -49,6 +53,8 @@ import com.android.systemui.util.ui.stopAnimating
import com.android.systemui.util.ui.value
import com.google.common.truth.Truth.assertThat
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.emptyFlow
import kotlinx.coroutines.flow.flowOf
import kotlinx.coroutines.test.runCurrent
import kotlinx.coroutines.test.runTest
@@ -75,6 +81,11 @@ class KeyguardRootViewModelTest(flags: FlagsParameterization) : SysuiTestCase()

    private val viewState = ViewStateAccessor()

    private val transitionState =
        MutableStateFlow<ObservableTransitionState>(
            ObservableTransitionState.Idle(Scenes.Lockscreen)
        )

    companion object {
        @JvmStatic
        @Parameters(name = "{0}")
@@ -96,6 +107,7 @@ class KeyguardRootViewModelTest(flags: FlagsParameterization) : SysuiTestCase()
                AConfigFlags.FLAG_MIGRATE_CLOCKS_TO_BLUEPRINT,
            )
        }
        kosmos.sceneContainerRepository.setTransitionState(transitionState)
    }

    @Test
@@ -309,6 +321,32 @@ class KeyguardRootViewModelTest(flags: FlagsParameterization) : SysuiTestCase()
        }

    @Test
    @EnableSceneContainer
    fun alpha_transitionToHub_isZero_scene_container() =
        testScope.runTest {
            val alpha by collectLastValue(underTest.alpha(viewState))

            transitionState.value =
                ObservableTransitionState.Transition(
                    fromScene = Scenes.Lockscreen,
                    toScene = Scenes.Communal,
                    emptyFlow(),
                    emptyFlow(),
                    false,
                    emptyFlow()
                )

            keyguardTransitionRepository.sendTransitionSteps(
                from = KeyguardState.LOCKSCREEN,
                to = KeyguardState.UNDEFINED,
                testScope,
            )

            assertThat(alpha).isEqualTo(0f)
        }

    @Test
    @DisableSceneContainer
    fun alpha_transitionToHub_isZero() =
        testScope.runTest {
            val alpha by collectLastValue(underTest.alpha(viewState))
+27 −1
Original line number Diff line number Diff line
@@ -18,8 +18,10 @@ package com.android.systemui.keyguard.ui.viewmodel

import android.platform.test.flag.junit.FlagsParameterization
import androidx.test.filters.SmallTest
import com.android.compose.animation.scene.ObservableTransitionState
import com.android.systemui.SysuiTestCase
import com.android.systemui.coroutines.collectLastValue
import com.android.systemui.flags.BrokenWithSceneContainer
import com.android.systemui.flags.Flags
import com.android.systemui.flags.andSceneContainer
import com.android.systemui.flags.fakeFeatureFlagsClassic
@@ -30,11 +32,16 @@ import com.android.systemui.keyguard.shared.model.StatusBarState
import com.android.systemui.keyguard.shared.model.TransitionState
import com.android.systemui.keyguard.shared.model.TransitionStep
import com.android.systemui.kosmos.testScope
import com.android.systemui.scene.data.repository.sceneContainerRepository
import com.android.systemui.scene.shared.flag.SceneContainerFlag
import com.android.systemui.scene.shared.model.Scenes
import com.android.systemui.shade.shadeTestUtil
import com.android.systemui.testKosmos
import com.google.common.collect.Range
import com.google.common.truth.Truth
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.emptyFlow
import kotlinx.coroutines.test.runCurrent
import kotlinx.coroutines.test.runTest
import org.junit.Before
@@ -58,6 +65,11 @@ class LockscreenToPrimaryBouncerTransitionViewModelTest(flags: FlagsParameteriza
    private val keyguardRepository = kosmos.fakeKeyguardRepository
    private lateinit var underTest: LockscreenToPrimaryBouncerTransitionViewModel

    private val transitionState =
        MutableStateFlow<ObservableTransitionState>(
            ObservableTransitionState.Idle(Scenes.Lockscreen)
        )

    companion object {
        @JvmStatic
        @Parameters(name = "{0}")
@@ -76,6 +88,7 @@ class LockscreenToPrimaryBouncerTransitionViewModelTest(flags: FlagsParameteriza
    }

    @Test
    @BrokenWithSceneContainer(330311871)
    fun deviceEntryParentViewAlpha_shadeExpanded() =
        testScope.runTest {
            val actual by collectLastValue(underTest.deviceEntryParentViewAlpha)
@@ -107,6 +120,17 @@ class LockscreenToPrimaryBouncerTransitionViewModelTest(flags: FlagsParameteriza
            shadeExpanded(false)
            runCurrent()

            kosmos.sceneContainerRepository.setTransitionState(transitionState)
            transitionState.value =
                ObservableTransitionState.Transition(
                    fromScene = Scenes.Lockscreen,
                    toScene = Scenes.Bouncer,
                    emptyFlow(),
                    emptyFlow(),
                    false,
                    emptyFlow()
                )
            runCurrent()
            // fade out
            repository.sendTransitionStep(step(0f, TransitionState.STARTED))
            runCurrent()
@@ -132,7 +156,9 @@ class LockscreenToPrimaryBouncerTransitionViewModelTest(flags: FlagsParameteriza
    ): TransitionStep {
        return TransitionStep(
            from = KeyguardState.LOCKSCREEN,
            to = KeyguardState.PRIMARY_BOUNCER,
            to =
                if (SceneContainerFlag.isEnabled) KeyguardState.UNDEFINED
                else KeyguardState.PRIMARY_BOUNCER,
            value = value,
            transitionState = state,
            ownerName = "LockscreenToPrimaryBouncerTransitionViewModelTest"
+9 −0
Original line number Diff line number Diff line
@@ -30,6 +30,7 @@ import com.android.systemui.common.shared.model.NotificationContainerBounds
import com.android.systemui.common.ui.data.repository.fakeConfigurationRepository
import com.android.systemui.coroutines.collectLastValue
import com.android.systemui.coroutines.collectValues
import com.android.systemui.flags.BrokenWithSceneContainer
import com.android.systemui.flags.DisableSceneContainer
import com.android.systemui.flags.EnableSceneContainer
import com.android.systemui.flags.Flags
@@ -107,18 +108,25 @@ class SharedNotificationContainerViewModelTest(flags: FlagsParameterization) : S
    val testScope = kosmos.testScope
    val configurationRepository
        get() = kosmos.fakeConfigurationRepository

    val keyguardRepository
        get() = kosmos.fakeKeyguardRepository

    val keyguardInteractor
        get() = kosmos.keyguardInteractor

    val keyguardRootViewModel
        get() = kosmos.keyguardRootViewModel

    val keyguardTransitionRepository
        get() = kosmos.fakeKeyguardTransitionRepository

    val shadeTestUtil
        get() = kosmos.shadeTestUtil

    val sharedNotificationContainerInteractor
        get() = kosmos.sharedNotificationContainerInteractor

    val largeScreenHeaderHelper
        get() = kosmos.mockLargeScreenHeaderHelper

@@ -814,6 +822,7 @@ class SharedNotificationContainerViewModelTest(flags: FlagsParameterization) : S
        }

    @Test
    @BrokenWithSceneContainer(330311871)
    fun alphaDoesNotUpdateWhileGoneTransitionIsRunning() =
        testScope.runTest {
            val viewState = ViewStateAccessor()
Loading