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

Commit 94d43c05 authored by Will Leshner's avatar Will Leshner
Browse files

Transition to hub from screen off when applicable.

This change fixes the dream->off->hub transition so that hub appears
instead of lockscreen on power on.

Bug: 339315487
Flag: com.android.systemui.communal_hub
Test: atest CommunalSceneStartableTest
Test: atest FromDozingTransitionInteractorTest

Change-Id: Ie3c41f68dcdfa9d40552cbc830ad25fc6332b52c
parent 43ef074d
Loading
Loading
Loading
Loading
+18 −0
Original line number Diff line number Diff line
@@ -451,6 +451,24 @@ class CommunalSceneStartableTest : SysuiTestCase() {
            }
        }

    @Test
    fun transitionFromDozingToGlanceableHub_forcesCommunal() =
        with(kosmos) {
            testScope.runTest {
                val scene by collectLastValue(communalSceneInteractor.currentScene)
                communalSceneInteractor.changeScene(CommunalScenes.Blank)
                assertThat(scene).isEqualTo(CommunalScenes.Blank)

                fakeKeyguardTransitionRepository.sendTransitionSteps(
                    from = KeyguardState.DOZING,
                    to = KeyguardState.GLANCEABLE_HUB,
                    testScope = this
                )

                assertThat(scene).isEqualTo(CommunalScenes.Communal)
            }
        }

    private fun TestScope.updateDocked(docked: Boolean) =
        with(kosmos) {
            runCurrent()
+64 −0
Original line number Diff line number Diff line
@@ -34,12 +34,14 @@ package com.android.systemui.keyguard.domain.interactor

import android.os.PowerManager
import android.platform.test.annotations.EnableFlags
import android.service.dream.dreamManager
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.compose.animation.scene.ObservableTransitionState
import com.android.systemui.Flags
import com.android.systemui.SysuiTestCase
import com.android.systemui.communal.data.repository.fakeCommunalSceneRepository
import com.android.systemui.communal.domain.interactor.setCommunalAvailable
import com.android.systemui.communal.shared.model.CommunalScenes
import com.android.systemui.keyguard.data.repository.FakeKeyguardTransitionRepository
import com.android.systemui.keyguard.data.repository.fakeKeyguardRepository
@@ -64,8 +66,10 @@ import kotlinx.coroutines.test.runTest
import org.junit.Before
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

@OptIn(ExperimentalCoroutinesApi::class)
@SmallTest
@@ -118,6 +122,66 @@ class FromDozingTransitionInteractorTest : SysuiTestCase() {
                )
        }

    @Test
    @EnableFlags(Flags.FLAG_KEYGUARD_WM_STATE_REFACTOR)
    fun testTransitionToLockscreen_onWakeup_canDream_glanceableHubAvailable() =
        testScope.runTest {
            whenever(kosmos.dreamManager.canStartDreaming(anyBoolean())).thenReturn(true)
            kosmos.setCommunalAvailable(true)
            runCurrent()

            powerInteractor.setAwakeForTest()
            runCurrent()

            // If dreaming is possible and communal is available, then we should transition to
            // GLANCEABLE_HUB when waking up.
            assertThat(transitionRepository)
                .startedTransition(
                    from = KeyguardState.DOZING,
                    to = KeyguardState.GLANCEABLE_HUB,
                )
        }

    @Test
    @EnableFlags(Flags.FLAG_KEYGUARD_WM_STATE_REFACTOR)
    fun testTransitionToLockscreen_onWakeup_canNotDream_glanceableHubAvailable() =
        testScope.runTest {
            whenever(kosmos.dreamManager.canStartDreaming(anyBoolean())).thenReturn(false)
            kosmos.setCommunalAvailable(true)
            runCurrent()

            powerInteractor.setAwakeForTest()
            runCurrent()

            // If dreaming is NOT possible but communal is available, then we should transition to
            // LOCKSCREEN when waking up.
            assertThat(transitionRepository)
                .startedTransition(
                    from = KeyguardState.DOZING,
                    to = KeyguardState.LOCKSCREEN,
                )
        }

    @Test
    @EnableFlags(Flags.FLAG_KEYGUARD_WM_STATE_REFACTOR)
    fun testTransitionToLockscreen_onWakeup_canNDream_glanceableHubNotAvailable() =
        testScope.runTest {
            whenever(kosmos.dreamManager.canStartDreaming(anyBoolean())).thenReturn(true)
            kosmos.setCommunalAvailable(false)
            runCurrent()

            powerInteractor.setAwakeForTest()
            runCurrent()

            // If dreaming is possible but communal is NOT available, then we should transition to
            // LOCKSCREEN when waking up.
            assertThat(transitionRepository)
                .startedTransition(
                    from = KeyguardState.DOZING,
                    to = KeyguardState.LOCKSCREEN,
                )
        }

    @Test
    @EnableFlags(Flags.FLAG_KEYGUARD_WM_STATE_REFACTOR)
    fun testTransitionToGlanceableHub_onWakeup_ifIdleOnCommunal_noOccludingActivity() =
+13 −7
Original line number Diff line number Diff line
@@ -18,6 +18,7 @@ package com.android.systemui.communal

import android.provider.Settings
import com.android.compose.animation.scene.SceneKey
import com.android.compose.animation.scene.TransitionKey
import com.android.systemui.CoreStartable
import com.android.systemui.communal.domain.interactor.CommunalInteractor
import com.android.systemui.communal.domain.interactor.CommunalSceneInteractor
@@ -91,8 +92,8 @@ constructor(
        keyguardTransitionInteractor.startedKeyguardTransitionStep
            .mapLatest(::determineSceneAfterTransition)
            .filterNotNull()
            .onEach { nextScene ->
                communalSceneInteractor.changeScene(nextScene, CommunalTransitionKeys.SimpleFade)
            .onEach { (nextScene, nextTransition) ->
                communalSceneInteractor.changeScene(nextScene, nextTransition)
            }
            .launchIn(applicationScope)

@@ -188,7 +189,7 @@ constructor(

    private suspend fun determineSceneAfterTransition(
        lastStartedTransition: TransitionStep,
    ): SceneKey? {
    ): Pair<SceneKey, TransitionKey>? {
        val to = lastStartedTransition.to
        val from = lastStartedTransition.from
        val docked = dockManager.isDocked
@@ -201,22 +202,27 @@ constructor(
                // underneath the hub is shown. When launching activities over lockscreen, we only
                // change scenes once the activity launch animation is finished, so avoid
                // changing the scene here.
                CommunalScenes.Blank
                Pair(CommunalScenes.Blank, CommunalTransitionKeys.SimpleFade)
            }
            to == KeyguardState.GLANCEABLE_HUB && from == KeyguardState.OCCLUDED -> {
                // When transitioning to the hub from an occluded state, fade out the hub without
                // doing any translation.
                CommunalScenes.Communal
                Pair(CommunalScenes.Communal, CommunalTransitionKeys.SimpleFade)
            }
            // Transitioning to Blank scene when entering the edit mode will be handled separately
            // with custom animations.
            to == KeyguardState.GONE && !communalInteractor.editModeOpen.value ->
                CommunalScenes.Blank
                Pair(CommunalScenes.Blank, CommunalTransitionKeys.SimpleFade)
            !docked && !KeyguardState.deviceIsAwakeInState(to) -> {
                // If the user taps the screen and wakes the device within this timeout, we don't
                // want to dismiss the hub
                delay(AWAKE_DEBOUNCE_DELAY)
                CommunalScenes.Blank
                Pair(CommunalScenes.Blank, CommunalTransitionKeys.SimpleFade)
            }
            from == KeyguardState.DOZING && to == KeyguardState.GLANCEABLE_HUB -> {
                // Make sure the communal hub is showing (immediately, not fading in) when
                // transitioning from dozing to hub.
                Pair(CommunalScenes.Communal, CommunalTransitionKeys.Immediately)
            }
            else -> null
        }
+18 −2
Original line number Diff line number Diff line
@@ -17,8 +17,10 @@
package com.android.systemui.keyguard.domain.interactor

import android.animation.ValueAnimator
import android.app.DreamManager
import com.android.app.animation.Interpolators
import com.android.systemui.communal.domain.interactor.CommunalInteractor
import com.android.systemui.communal.domain.interactor.CommunalSceneInteractor
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Background
import com.android.systemui.dagger.qualifiers.Main
@@ -51,8 +53,10 @@ constructor(
    keyguardInteractor: KeyguardInteractor,
    powerInteractor: PowerInteractor,
    private val communalInteractor: CommunalInteractor,
    private val communalSceneInteractor: CommunalSceneInteractor,
    keyguardOcclusionInteractor: KeyguardOcclusionInteractor,
    val deviceEntryRepository: DeviceEntryRepository,
    private val dreamManager: DreamManager,
) :
    TransitionInteractor(
        fromState = KeyguardState.DOZING,
@@ -119,7 +123,8 @@ constructor(
                .filterRelevantKeyguardStateAnd { isAwake -> isAwake }
                .sample(
                    keyguardInteractor.isKeyguardOccluded,
                    communalInteractor.isIdleOnCommunal,
                    communalInteractor.isCommunalAvailable,
                    communalSceneInteractor.isIdleOnCommunal,
                    canTransitionToGoneOnWake,
                    keyguardInteractor.primaryBouncerShowing,
                )
@@ -127,6 +132,7 @@ constructor(
                    (
                        _,
                        occluded,
                        isCommunalAvailable,
                        isIdleOnCommunal,
                        canTransitionToGoneOnWake,
                        primaryBouncerShowing) ->
@@ -141,6 +147,10 @@ constructor(
                            KeyguardState.OCCLUDED
                        } else if (isIdleOnCommunal) {
                            KeyguardState.GLANCEABLE_HUB
                        } else if (isCommunalAvailable && dreamManager.canStartDreaming(true)) {
                            // This case handles tapping the power button to transition through
                            // dream -> off -> hub.
                            KeyguardState.GLANCEABLE_HUB
                        } else {
                            KeyguardState.LOCKSCREEN
                        }
@@ -159,7 +169,8 @@ constructor(
            powerInteractor.detailedWakefulness
                .filterRelevantKeyguardStateAnd { it.isAwake() }
                .sample(
                    communalInteractor.isIdleOnCommunal,
                    communalInteractor.isCommunalAvailable,
                    communalSceneInteractor.isIdleOnCommunal,
                    keyguardInteractor.biometricUnlockState,
                    canTransitionToGoneOnWake,
                    keyguardInteractor.primaryBouncerShowing,
@@ -167,6 +178,7 @@ constructor(
                .collect {
                    (
                        _,
                        isCommunalAvailable,
                        isIdleOnCommunal,
                        biometricUnlockState,
                        canDismissLockscreen,
@@ -188,6 +200,10 @@ constructor(
                                KeyguardState.PRIMARY_BOUNCER
                            } else if (isIdleOnCommunal) {
                                KeyguardState.GLANCEABLE_HUB
                            } else if (isCommunalAvailable && dreamManager.canStartDreaming(true)) {
                                // This case handles tapping the power button to transition through
                                // dream -> off -> hub.
                                KeyguardState.GLANCEABLE_HUB
                            } else {
                                KeyguardState.LOCKSCREEN
                            },
+4 −0
Original line number Diff line number Diff line
@@ -16,6 +16,7 @@
package com.android.systemui

import android.app.ActivityManager
import android.app.DreamManager
import android.app.admin.DevicePolicyManager
import android.app.trust.TrustManager
import android.os.UserManager
@@ -32,6 +33,7 @@ import com.android.systemui.animation.DialogTransitionAnimator
import com.android.systemui.biometrics.AuthController
import com.android.systemui.bouncer.domain.interactor.PrimaryBouncerInteractor
import com.android.systemui.communal.domain.interactor.CommunalInteractor
import com.android.systemui.communal.domain.interactor.CommunalSceneInteractor
import com.android.systemui.demomode.DemoModeController
import com.android.systemui.dump.DumpManager
import com.android.systemui.keyguard.ScreenLifecycle
@@ -93,6 +95,7 @@ data class TestMocksModule(
    @get:Provides val demoModeController: DemoModeController = mock(),
    @get:Provides val deviceProvisionedController: DeviceProvisionedController = mock(),
    @get:Provides val dozeParameters: DozeParameters = mock(),
    @get:Provides val dreamManager: DreamManager = mock(),
    @get:Provides val dumpManager: DumpManager = mock(),
    @get:Provides val headsUpManager: HeadsUpManager = mock(),
    @get:Provides val guestResumeSessionReceiver: GuestResumeSessionReceiver = mock(),
@@ -130,6 +133,7 @@ data class TestMocksModule(
    @get:Provides val systemUIDialogManager: SystemUIDialogManager = mock(),
    @get:Provides val deviceEntryIconTransitions: Set<DeviceEntryIconTransition> = emptySet(),
    @get:Provides val communalInteractor: CommunalInteractor = mock(),
    @get:Provides val communalSceneInteractor: CommunalSceneInteractor = mock(),
    @get:Provides val sceneLogger: SceneLogger = mock(),
    @get:Provides val trustManager: TrustManager = mock(),
    @get:Provides val primaryBouncerInteractor: PrimaryBouncerInteractor = mock(),
Loading