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

Commit b0accc8e authored by William Xiao's avatar William Xiao
Browse files

Fix misc issues for transition to hub when turning screen on

This CL fixes various timing issues when showing the dream when wkaing
from doze, especially when pressing power button quickly:
* Dream doesn't start under the hub sometimes
* Hub transitions to dream or occluded when dream starts underneath
* Device doesn't transition to hub when pressing power quickly and
  skipping the DOZING keyguard state
* Keyguard state goes to OCCLUDED instead of DREAMING when closing hub
  shortly after dream starts underneath hub

Manually verified on device while dreaming with various sleep timings:
adb shell input keyevent POWER && sleep 0.8 && adb shell input keyevent POWER

Bug: 363239820
Test: atest CommunalSceneTransitionInteractorTest FromDreamingTransitionInteractorTest
Flag: com.android.systemui.communal_hub
Change-Id: Ida1ee5880099a060b348e1977a951d04cb73102a
parent 6c9fc4c4
Loading
Loading
Loading
Loading
+6 −14
Original line number Diff line number Diff line
@@ -34,8 +34,6 @@ import com.android.systemui.flags.fakeFeatureFlagsClassic
import com.android.systemui.keyguard.data.repository.fakeKeyguardRepository
import com.android.systemui.keyguard.data.repository.keyguardTransitionRepository
import com.android.systemui.keyguard.data.repository.realKeyguardTransitionRepository
import com.android.systemui.keyguard.shared.model.DozeStateModel
import com.android.systemui.keyguard.shared.model.DozeTransitionModel
import com.android.systemui.keyguard.shared.model.KeyguardState.ALTERNATE_BOUNCER
import com.android.systemui.keyguard.shared.model.KeyguardState.DREAMING
import com.android.systemui.keyguard.shared.model.KeyguardState.GLANCEABLE_HUB
@@ -50,8 +48,6 @@ 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.power.domain.interactor.PowerInteractor.Companion.setAwakeForTest
import com.android.systemui.power.domain.interactor.powerInteractor
import com.android.systemui.testKosmos
import com.google.common.truth.Truth.assertThat
import kotlin.time.Duration.Companion.seconds
@@ -220,15 +216,11 @@ class CommunalSceneTransitionInteractorTest : SysuiTestCase() {
    @Test
    fun transition_from_hub_end_in_dream() =
        testScope.runTest {
            // Device is dreaming and not dozing.
            kosmos.powerInteractor.setAwakeForTest()
            kosmos.fakeKeyguardRepository.setDozeTransitionModel(
                DozeTransitionModel(from = DozeStateModel.DOZE, to = DozeStateModel.FINISH)
            )
            // Device is dreaming and occluded.
            kosmos.fakeKeyguardRepository.setKeyguardOccluded(true)
            kosmos.fakeKeyguardRepository.setDreaming(true)
            kosmos.fakeKeyguardRepository.setDreamingWithOverlay(true)
            advanceTimeBy(600L)
            runCurrent()

            sceneTransitions.value = hubToBlank

@@ -663,7 +655,7 @@ class CommunalSceneTransitionInteractorTest : SysuiTestCase() {
                    from = LOCKSCREEN,
                    to = OCCLUDED,
                    animator = null,
                    modeOnCanceled = TransitionModeOnCanceled.RESET
                    modeOnCanceled = TransitionModeOnCanceled.RESET,
                )
            )

@@ -750,7 +742,7 @@ class CommunalSceneTransitionInteractorTest : SysuiTestCase() {
                    from = LOCKSCREEN,
                    to = OCCLUDED,
                    animator = null,
                    modeOnCanceled = TransitionModeOnCanceled.RESET
                    modeOnCanceled = TransitionModeOnCanceled.RESET,
                )
            )

@@ -852,8 +844,8 @@ class CommunalSceneTransitionInteractorTest : SysuiTestCase() {
                    to = ALTERNATE_BOUNCER,
                    animator = null,
                    ownerName = "external",
                    modeOnCanceled = TransitionModeOnCanceled.RESET
                ),
                    modeOnCanceled = TransitionModeOnCanceled.RESET,
                )
            )

            val allSteps by collectValues(keyguardTransitionRepository.transitions)
+62 −13
Original line number Diff line number Diff line
@@ -16,12 +16,19 @@

package com.android.systemui.keyguard.domain.interactor

import android.platform.test.annotations.DisableFlags
import android.platform.test.annotations.EnableFlags
import androidx.test.ext.junit.runners.AndroidJUnit4
import android.platform.test.flag.junit.FlagsParameterization
import android.service.dream.dreamManager
import androidx.test.filters.SmallTest
import com.android.systemui.Flags
import com.android.systemui.Flags.FLAG_COMMUNAL_SCENE_KTF_REFACTOR
import com.android.systemui.SysuiTestCase
import com.android.systemui.bouncer.data.repository.fakeKeyguardBouncerRepository
import com.android.systemui.communal.data.repository.communalSceneRepository
import com.android.systemui.communal.domain.interactor.setCommunalAvailable
import com.android.systemui.communal.shared.model.CommunalScenes
import com.android.systemui.flags.andSceneContainer
import com.android.systemui.keyguard.data.repository.FakeKeyguardTransitionRepository
import com.android.systemui.keyguard.data.repository.fakeKeyguardRepository
import com.android.systemui.keyguard.data.repository.fakeKeyguardTransitionRepository
@@ -36,6 +43,7 @@ import com.android.systemui.statusbar.domain.interactor.keyguardOcclusionInterac
import com.android.systemui.testKosmos
import com.google.common.truth.Truth.assertThat
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.runBlocking
import kotlinx.coroutines.test.advanceTimeBy
import kotlinx.coroutines.test.runCurrent
import kotlinx.coroutines.test.runTest
@@ -43,26 +51,52 @@ import org.junit.Before
import org.junit.Ignore
import org.junit.Test
import org.junit.runner.RunWith
import org.mockito.Mockito.anyBoolean
import org.mockito.Mockito.reset
import org.mockito.Mockito.spy
import org.mockito.kotlin.whenever
import platform.test.runner.parameterized.ParameterizedAndroidJunit4
import platform.test.runner.parameterized.Parameters

@OptIn(ExperimentalCoroutinesApi::class)
@SmallTest
@RunWith(AndroidJUnit4::class)
class FromDreamingTransitionInteractorTest : SysuiTestCase() {
@RunWith(ParameterizedAndroidJunit4::class)
class FromDreamingTransitionInteractorTest(flags: FlagsParameterization?) : SysuiTestCase() {
    companion object {
        @JvmStatic
        @Parameters(name = "{0}")
        fun getParams(): List<FlagsParameterization> {
            return FlagsParameterization.allCombinationsOf(FLAG_COMMUNAL_SCENE_KTF_REFACTOR)
                .andSceneContainer()
        }
    }

    init {
        mSetFlagsRule.setFlagsParameterization(flags!!)
    }

    private val kosmos =
        testKosmos().apply {
            this.fakeKeyguardTransitionRepository = spy(FakeKeyguardTransitionRepository())
        }

    private val testScope = kosmos.testScope
    private val underTest = kosmos.fromDreamingTransitionInteractor
    private val underTest by lazy { kosmos.fromDreamingTransitionInteractor }

    private val powerInteractor = kosmos.powerInteractor
    private val transitionRepository = kosmos.fakeKeyguardTransitionRepository

    @Before
    fun setup() {
        runBlocking {
            transitionRepository.sendTransitionSteps(
                from = KeyguardState.LOCKSCREEN,
                to = KeyguardState.DREAMING,
                testScope,
            )
            reset(transitionRepository)
            kosmos.setCommunalAvailable(true)
        }
        underTest.start()
    }

@@ -86,10 +120,7 @@ class FromDreamingTransitionInteractorTest : SysuiTestCase() {
            runCurrent()

            assertThat(transitionRepository)
                .startedTransition(
                    from = KeyguardState.DREAMING,
                    to = KeyguardState.OCCLUDED,
                )
                .startedTransition(from = KeyguardState.DREAMING, to = KeyguardState.OCCLUDED)
        }

    @Test
@@ -126,7 +157,7 @@ class FromDreamingTransitionInteractorTest : SysuiTestCase() {
            transitionRepository.sendTransitionSteps(
                from = KeyguardState.LOCKSCREEN,
                to = KeyguardState.DREAMING,
                testScope
                testScope,
            )
            kosmos.fakeKeyguardRepository.setBiometricUnlockState(BiometricUnlockMode.NONE)

@@ -139,10 +170,7 @@ class FromDreamingTransitionInteractorTest : SysuiTestCase() {
            advanceTimeBy(60L)

            assertThat(transitionRepository)
                .startedTransition(
                    from = KeyguardState.DREAMING,
                    to = KeyguardState.LOCKSCREEN,
                )
                .startedTransition(from = KeyguardState.DREAMING, to = KeyguardState.LOCKSCREEN)
        }

    @Test
@@ -164,4 +192,25 @@ class FromDreamingTransitionInteractorTest : SysuiTestCase() {
                    to = KeyguardState.ALTERNATE_BOUNCER,
                )
        }

    @Test
    @EnableFlags(FLAG_COMMUNAL_SCENE_KTF_REFACTOR)
    @DisableFlags(Flags.FLAG_SCENE_CONTAINER)
    fun testTransitionToGlanceableHubOnWake() =
        testScope.runTest {
            whenever(kosmos.dreamManager.canStartDreaming(anyBoolean())).thenReturn(true)
            kosmos.setCommunalAvailable(true)
            runCurrent()

            // Device wakes up.
            powerInteractor.setAwakeForTest()
            advanceTimeBy(150L)
            runCurrent()

            // We transition to the hub when waking up.
            assertThat(kosmos.communalSceneRepository.currentScene.value)
                .isEqualTo(CommunalScenes.Communal)
            // No transitions are directly started by this interactor.
            assertThat(transitionRepository).noTransitionsStarted()
        }
}
+3 −8
Original line number Diff line number Diff line
@@ -1465,10 +1465,8 @@ class KeyguardTransitionScenariosTest(flags: FlagsParameterization?) : SysuiTest

            // WHEN the keyguard is occluded and device wakes up and is no longer dreaming
            keyguardRepository.setDreaming(false)
            testScheduler.advanceTimeBy(150) // The dreaming signal is debounced.
            runCurrent()
            keyguardRepository.setKeyguardOccluded(true)
            powerInteractor.setAwakeForTest()
            testScheduler.advanceTimeBy(150) // The dreaming and occluded signals are debounced.
            runCurrent()

            // THEN a transition to OCCLUDED should occur
@@ -2059,12 +2057,7 @@ class KeyguardTransitionScenariosTest(flags: FlagsParameterization?) : SysuiTest
    fun glanceableHubToOccluded_communalKtfRefactor() =
        testScope.runTest {
            // GIVEN device is not dreaming
            powerInteractor.setAwakeForTest()
            keyguardRepository.setDreaming(false)
            keyguardRepository.setDozeTransitionModel(
                DozeTransitionModel(from = DozeStateModel.DOZE, to = DozeStateModel.FINISH)
            )
            advanceTimeBy(600.milliseconds)

            // GIVEN a prior transition has run to GLANCEABLE_HUB
            communalSceneInteractor.changeScene(CommunalScenes.Communal, "test")
@@ -2073,6 +2066,7 @@ class KeyguardTransitionScenariosTest(flags: FlagsParameterization?) : SysuiTest

            // WHEN the keyguard is occluded
            keyguardRepository.setKeyguardOccluded(true)
            advanceTimeBy(200.milliseconds)
            runCurrent()

            assertThat(transitionRepository)
@@ -2218,6 +2212,7 @@ class KeyguardTransitionScenariosTest(flags: FlagsParameterization?) : SysuiTest
            advanceTimeBy(10.milliseconds)
            keyguardRepository.setKeyguardOccluded(true)
            advanceTimeBy(200.milliseconds)
            runCurrent()

            assertThat(transitionRepository)
                .startedTransition(
+3 −1
Original line number Diff line number Diff line
@@ -65,7 +65,9 @@ constructor(
                keyguardTransitionInteractor
                    .transitionValue(Scenes.Communal, KeyguardState.GLANCEABLE_HUB)
                    .map { it == 1f },
                not(keyguardInteractor.isDreaming),
                // Use isDreamingAny because isDreaming is false in doze and doesn't change again
                // when the screen turns on, which causes the dream to not start underneath the hub.
                not(keyguardInteractor.isDreamingAny),
                // TODO(b/362830856): Remove this workaround.
                keyguardInteractor.isKeyguardShowing,
                not(communalSceneInteractor.isLaunchingWidget),
+8 −6
Original line number Diff line number Diff line
@@ -87,7 +87,9 @@ constructor(
     */
    private val nextKeyguardStateInternal =
        combine(
                keyguardInteractor.isAbleToDream,
                // Don't use delayed dreaming signal as otherwise we might go to occluded or lock
                // screen when closing hub if dream just started under the hub.
                keyguardInteractor.isDreamingWithOverlay,
                keyguardInteractor.isKeyguardOccluded,
                keyguardInteractor.isKeyguardGoingAway,
                keyguardInteractor.isKeyguardShowing,
@@ -156,7 +158,7 @@ constructor(

    private suspend fun handleIdle(
        prevTransition: ObservableTransitionState,
        idle: ObservableTransitionState.Idle
        idle: ObservableTransitionState.Idle,
    ) {
        if (
            prevTransition is ObservableTransitionState.Transition &&
@@ -186,7 +188,7 @@ constructor(
        internalTransitionInteractor.updateTransition(
            currentTransitionId!!,
            1f,
            TransitionState.FINISHED
            TransitionState.FINISHED,
        )
        resetTransitionData()
    }
@@ -204,7 +206,7 @@ constructor(
        internalTransitionInteractor.updateTransition(
            currentTransitionId!!,
            1f,
            TransitionState.FINISHED
            TransitionState.FINISHED,
        )
        resetTransitionData()
    }
@@ -217,7 +219,7 @@ constructor(

    private suspend fun handleTransition(
        prevTransition: ObservableTransitionState,
        transition: ObservableTransitionState.Transition
        transition: ObservableTransitionState.Transition,
    ) {
        if (
            prevTransition.isTransitioning(from = transition.fromContent, to = transition.toContent)
@@ -295,7 +297,7 @@ constructor(
        internalTransitionInteractor.updateTransition(
            currentTransitionId!!,
            progress.coerceIn(0f, 1f),
            TransitionState.RUNNING
            TransitionState.RUNNING,
        )
    }
}
Loading