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

Commit 67d0f996 authored by William Xiao's avatar William Xiao
Browse files

Add transitions between glanceable hub and dozing

No animations needed at the moment, this just ensures KeyguardState
remains accurate.

Bug: 319721010
Flag: ACONFIG com.android.systemui.communal_hub DEVELOPMENT
Test: atest KeyguardTransitionScenariosTest
Change-Id: I33b84f05297540660652ab74a89d59c11889fb7a
parent 90ba0f75
Loading
Loading
Loading
Loading
+16 −7
Original line number Diff line number Diff line
@@ -18,6 +18,7 @@ package com.android.systemui.keyguard.domain.interactor

import android.animation.ValueAnimator
import com.android.app.animation.Interpolators
import com.android.systemui.communal.domain.interactor.CommunalInteractor
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Background
import com.android.systemui.dagger.qualifiers.Main
@@ -25,7 +26,7 @@ import com.android.systemui.keyguard.data.repository.KeyguardTransitionRepositor
import com.android.systemui.keyguard.shared.model.BiometricUnlockModel.Companion.isWakeAndUnlock
import com.android.systemui.keyguard.shared.model.KeyguardState
import com.android.systemui.power.domain.interactor.PowerInteractor
import com.android.systemui.util.kotlin.Utils.Companion.toTriple
import com.android.systemui.util.kotlin.Utils.Companion.toQuad
import com.android.systemui.util.kotlin.sample
import javax.inject.Inject
import kotlin.time.Duration.Companion.milliseconds
@@ -45,6 +46,7 @@ constructor(
    @Main mainDispatcher: CoroutineDispatcher,
    private val keyguardInteractor: KeyguardInteractor,
    private val powerInteractor: PowerInteractor,
    private val communalInteractor: CommunalInteractor,
) :
    TransitionInteractor(
        fromState = KeyguardState.DOZING,
@@ -54,26 +56,33 @@ constructor(
    ) {

    override fun start() {
        listenForDozingToLockscreenOrOccluded()
        listenForDozingToLockscreenHubOrOccluded()
        listenForDozingToGone()
        listenForTransitionToCamera(scope, keyguardInteractor)
    }

    private fun listenForDozingToLockscreenOrOccluded() {
    private fun listenForDozingToLockscreenHubOrOccluded() {
        scope.launch {
            powerInteractor.isAwake
                .sample(
                    combine(
                        startedKeyguardTransitionStep,
                        keyguardInteractor.isKeyguardOccluded,
                        ::Pair
                        communalInteractor.isIdleOnCommunal,
                        ::Triple
                    ),
                    ::toTriple
                    ::toQuad
                )
                .collect { (isAwake, lastStartedTransition, occluded) ->
                .collect { (isAwake, lastStartedTransition, occluded, isIdleOnCommunal) ->
                    if (isAwake && lastStartedTransition.to == KeyguardState.DOZING) {
                        startTransitionTo(
                            if (occluded) KeyguardState.OCCLUDED else KeyguardState.LOCKSCREEN
                            if (occluded) {
                                KeyguardState.OCCLUDED
                            } else if (isIdleOnCommunal) {
                                KeyguardState.GLANCEABLE_HUB
                            } else {
                                KeyguardState.LOCKSCREEN
                            }
                        )
                    }
                }
+22 −0
Original line number Diff line number Diff line
@@ -25,17 +25,24 @@ import com.android.systemui.dagger.qualifiers.Background
import com.android.systemui.dagger.qualifiers.Main
import com.android.systemui.keyguard.data.repository.KeyguardTransitionRepository
import com.android.systemui.keyguard.shared.model.KeyguardState
import com.android.systemui.keyguard.shared.model.TransitionModeOnCanceled
import com.android.systemui.power.domain.interactor.PowerInteractor
import com.android.systemui.util.kotlin.sample
import javax.inject.Inject
import kotlin.time.Duration.Companion.milliseconds
import kotlinx.coroutines.CoroutineDispatcher
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.launch

@SysUISingleton
class FromGlanceableHubTransitionInteractor
@Inject
constructor(
    @Background private val scope: CoroutineScope,
    private val glanceableHubTransitions: GlanceableHubTransitions,
    override val transitionRepository: KeyguardTransitionRepository,
    transitionInteractor: KeyguardTransitionInteractor,
    private val powerInteractor: PowerInteractor,
    @Main mainDispatcher: CoroutineDispatcher,
    @Background bgDispatcher: CoroutineDispatcher,
) :
@@ -50,6 +57,7 @@ constructor(
            return
        }
        listenForHubToLockscreen()
        listenForHubToDozing()
    }

    override fun getDefaultAnimatorForTransitionsToState(toState: KeyguardState): ValueAnimator {
@@ -71,6 +79,20 @@ constructor(
        )
    }

    private fun listenForHubToDozing() {
        scope.launch {
            powerInteractor.isAsleep.sample(startedKeyguardTransitionStep, ::Pair).collect {
                (isAsleep, lastStartedStep) ->
                if (lastStartedStep.to == fromState && isAsleep) {
                    startTransitionTo(
                        toState = KeyguardState.DOZING,
                        modeOnCanceled = TransitionModeOnCanceled.LAST_VALUE,
                    )
                }
            }
        }
    }

    companion object {
        const val TAG = "FromGlanceableHubTransitionInteractor"
        val DEFAULT_DURATION = 500.milliseconds
+59 −0
Original line number Diff line number Diff line
@@ -250,6 +250,7 @@ class KeyguardTransitionScenariosTest : SysuiTestCase() {
                    transitionRepository = transitionRepository,
                    transitionInteractor = transitionInteractor,
                    powerInteractor = powerInteractor,
                    communalInteractor = communalInteractor,
                )
                .apply { start() }

@@ -279,11 +280,13 @@ class KeyguardTransitionScenariosTest : SysuiTestCase() {

        fromGlanceableHubTransitionInteractor =
            FromGlanceableHubTransitionInteractor(
                    scope = testScope,
                    bgDispatcher = testDispatcher,
                    mainDispatcher = testDispatcher,
                    glanceableHubTransitions = glanceableHubTransitions,
                    transitionRepository = transitionRepository,
                    transitionInteractor = transitionInteractor,
                    powerInteractor = powerInteractor,
                )
                .apply { start() }
    }
@@ -724,6 +727,38 @@ class KeyguardTransitionScenariosTest : SysuiTestCase() {
            coroutineContext.cancelChildren()
        }

    @Test
    fun dozingToGlanceableHub() =
        testScope.runTest {
            // GIVEN a prior transition has run to DOZING
            runTransitionAndSetWakefulness(KeyguardState.GLANCEABLE_HUB, KeyguardState.DOZING)
            runCurrent()

            // GIVEN the device is idle on the glanceable hub
            val idleTransitionState =
                MutableStateFlow<ObservableCommunalTransitionState>(
                    ObservableCommunalTransitionState.Idle(CommunalSceneKey.Communal)
                )
            communalInteractor.setTransitionState(idleTransitionState)
            runCurrent()

            // WHEN the device begins to wake
            powerInteractor.setAwakeForTest()
            runCurrent()

            val info =
                withArgCaptor<TransitionInfo> {
                    verify(transitionRepository).startTransition(capture())
                }
            // THEN a transition to DOZING should occur
            assertThat(info.ownerName).isEqualTo(FromDozingTransitionInteractor::class.simpleName)
            assertThat(info.from).isEqualTo(KeyguardState.DOZING)
            assertThat(info.to).isEqualTo(KeyguardState.GLANCEABLE_HUB)
            assertThat(info.animator).isNotNull()

            coroutineContext.cancelChildren()
        }

    @Test
    fun goneToDozing() =
        testScope.runTest {
@@ -1577,6 +1612,30 @@ class KeyguardTransitionScenariosTest : SysuiTestCase() {
            coroutineContext.cancelChildren()
        }

    @Test
    fun glanceableHubToDozing() =
        testScope.runTest {
            // GIVEN a prior transition has run to GLANCEABLE_HUB
            runTransitionAndSetWakefulness(KeyguardState.LOCKSCREEN, KeyguardState.GLANCEABLE_HUB)

            // WHEN the device begins to sleep
            powerInteractor.setAsleepForTest()
            runCurrent()

            val info =
                withArgCaptor<TransitionInfo> {
                    verify(transitionRepository).startTransition(capture())
                }
            // THEN a transition to DOZING should occur
            assertThat(info.ownerName)
                .isEqualTo(FromGlanceableHubTransitionInteractor::class.simpleName)
            assertThat(info.from).isEqualTo(KeyguardState.GLANCEABLE_HUB)
            assertThat(info.to).isEqualTo(KeyguardState.DOZING)
            assertThat(info.animator).isNotNull()

            coroutineContext.cancelChildren()
        }

    private fun createKeyguardInteractor(): KeyguardInteractor {
        return KeyguardInteractorFactory.create(
                featureFlags = featureFlags,