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

Commit 9a5b360c authored by burakov's avatar burakov Committed by Danny Burakov
Browse files

[flexiglass] Resets the scene when the device goes to sleep.

When the device goes to sleep (usually following a power button click or
screen timeout), we will switch to either Gone or Lockscreen as the
current scene, depending on whether the device was unlocked or not,
respectively.

We use the ASLEEP wakefulness state as our signal instead of listening
to screen off events because the latter does not necessarily need to
trigger a scene reset, e.g. in the case of a screen turning off when
unfolding a foldable device.

Fix: 290403062
Test: new unit tests added
Test: manually verified in system UI that screen timeout moves back to
the Lockscreen scene when the device is locked, and to the Gone scene
when the device is unlocked.

Change-Id: Iee5474d45c281bbd5a76c06ba9c64de31a1d8255
parent 929cb5c3
Loading
Loading
Loading
Loading
+1 −6
Original line number Diff line number Diff line
@@ -144,12 +144,7 @@ constructor(
    private val lockPatternUtils: LockPatternUtils,
) : AuthenticationRepository {

    override val isUnlocked: StateFlow<Boolean> =
        keyguardRepository.isKeyguardUnlocked.stateIn(
            scope = applicationScope,
            started = SharingStarted.WhileSubscribed(),
            initialValue = false,
        )
    override val isUnlocked: StateFlow<Boolean> = keyguardRepository.isKeyguardUnlocked

    override suspend fun isLockscreenEnabled(): Boolean {
        return withContext(backgroundDispatcher) {
+7 −3
Original line number Diff line number Diff line
@@ -87,7 +87,7 @@ interface KeyguardRepository {
    val isKeyguardShowing: Flow<Boolean>

    /** Is the keyguard in a unlocked state? */
    val isKeyguardUnlocked: Flow<Boolean>
    val isKeyguardUnlocked: StateFlow<Boolean>

    /** Is an activity showing over the keyguard? */
    val isKeyguardOccluded: Flow<Boolean>
@@ -299,7 +299,7 @@ constructor(
            }
            .distinctUntilChanged()

    override val isKeyguardUnlocked: Flow<Boolean> =
    override val isKeyguardUnlocked: StateFlow<Boolean> =
        conflatedCallbackFlow {
                val callback =
                    object : KeyguardStateController.Callback {
@@ -330,7 +330,11 @@ constructor(

                awaitClose { keyguardStateController.removeCallback(callback) }
            }
            .distinctUntilChanged()
            .stateIn(
                scope = scope,
                started = SharingStarted.WhileSubscribed(),
                initialValue = keyguardStateController.isUnlocked,
            )

    override val isKeyguardGoingAway: Flow<Boolean> = conflatedCallbackFlow {
        val callback =
+24 −6
Original line number Diff line number Diff line
@@ -22,6 +22,8 @@ import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Application
import com.android.systemui.flags.FeatureFlags
import com.android.systemui.flags.Flags
import com.android.systemui.keyguard.domain.interactor.KeyguardInteractor
import com.android.systemui.keyguard.shared.model.WakefulnessState
import com.android.systemui.scene.domain.interactor.SceneInteractor
import com.android.systemui.scene.shared.model.SceneContainerNames
import com.android.systemui.scene.shared.model.SceneKey
@@ -45,6 +47,7 @@ constructor(
    @Application private val applicationScope: CoroutineScope,
    private val sceneInteractor: SceneInteractor,
    private val authenticationInteractor: AuthenticationInteractor,
    private val keyguardInteractor: KeyguardInteractor,
    private val featureFlags: FeatureFlags,
) : CoreStartable {

@@ -78,7 +81,7 @@ constructor(
                    when {
                        isUnlocked ->
                            when (currentSceneKey) {
                                // When the device becomes unlocked in Bouncer, go to the Gone.
                                // When the device becomes unlocked in Bouncer, go to Gone.
                                is SceneKey.Bouncer -> SceneKey.Gone
                                // When the device becomes unlocked in Lockscreen, go to Gone if
                                // bypass is enabled.
@@ -101,14 +104,29 @@ constructor(
                    }
                }
                .filterNotNull()
                .collect { targetSceneKey ->
                .collect { targetSceneKey -> switchToScene(targetSceneKey) }
        }

        applicationScope.launch {
            keyguardInteractor.wakefulnessModel
                .map { it.state == WakefulnessState.ASLEEP }
                .distinctUntilChanged()
                .collect { isAsleep ->
                    if (isAsleep) {
                        // When the device goes to sleep, reset the current scene.
                        val isUnlocked = authenticationInteractor.isUnlocked.value
                        switchToScene(if (isUnlocked) SceneKey.Gone else SceneKey.Lockscreen)
                    }
                }
        }
    }

    private fun switchToScene(targetSceneKey: SceneKey) {
        sceneInteractor.setCurrentScene(
            containerName = CONTAINER_NAME,
            scene = SceneModel(targetSceneKey),
        )
    }
        }
    }

    companion object {
        private const val CONTAINER_NAME = SceneContainerNames.SYSTEM_UI_DEFAULT
+106 −0
Original line number Diff line number Diff line
@@ -20,6 +20,9 @@ import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.coroutines.collectLastValue
import com.android.systemui.flags.Flags
import com.android.systemui.keyguard.shared.model.WakeSleepReason
import com.android.systemui.keyguard.shared.model.WakefulnessModel
import com.android.systemui.keyguard.shared.model.WakefulnessState
import com.android.systemui.scene.SceneTestUtils
import com.android.systemui.scene.shared.model.SceneContainerNames
import com.android.systemui.scene.shared.model.SceneKey
@@ -47,12 +50,18 @@ class SystemUiDefaultSceneContainerStartableTest : SysuiTestCase() {
        utils.authenticationInteractor(
            repository = authenticationRepository,
        )
    private val keyguardRepository = utils.keyguardRepository()
    private val keyguardInteractor =
        utils.keyguardInteractor(
            repository = keyguardRepository,
        )

    private val underTest =
        SystemUiDefaultSceneContainerStartable(
            applicationScope = testScope.backgroundScope,
            sceneInteractor = sceneInteractor,
            authenticationInteractor = authenticationInteractor,
            keyguardInteractor = keyguardInteractor,
            featureFlags = featureFlags,
        )

@@ -280,6 +289,94 @@ class SystemUiDefaultSceneContainerStartableTest : SysuiTestCase() {
            assertThat(currentSceneKey).isEqualTo(SceneKey.Lockscreen)
        }

    @Test
    fun switchToGoneWhenDeviceSleepsUnlocked_featureEnabled() =
        testScope.runTest {
            val currentSceneKey by
                collectLastValue(
                    sceneInteractor.currentScene(SceneContainerNames.SYSTEM_UI_DEFAULT).map {
                        it.key
                    }
                )
            prepareState(
                isFeatureEnabled = true,
                isDeviceUnlocked = true,
                initialSceneKey = SceneKey.Shade,
            )
            assertThat(currentSceneKey).isEqualTo(SceneKey.Shade)
            underTest.start()

            keyguardRepository.setWakefulnessModel(ASLEEP)

            assertThat(currentSceneKey).isEqualTo(SceneKey.Gone)
        }

    @Test
    fun switchToGoneWhenDeviceSleepsUnlocked_featureDisabled() =
        testScope.runTest {
            val currentSceneKey by
                collectLastValue(
                    sceneInteractor.currentScene(SceneContainerNames.SYSTEM_UI_DEFAULT).map {
                        it.key
                    }
                )
            prepareState(
                isFeatureEnabled = false,
                isDeviceUnlocked = true,
                initialSceneKey = SceneKey.Shade,
            )
            assertThat(currentSceneKey).isEqualTo(SceneKey.Shade)
            underTest.start()

            keyguardRepository.setWakefulnessModel(ASLEEP)

            assertThat(currentSceneKey).isEqualTo(SceneKey.Shade)
        }

    @Test
    fun switchToLockscreenWhenDeviceSleepsLocked_featureEnabled() =
        testScope.runTest {
            val currentSceneKey by
                collectLastValue(
                    sceneInteractor.currentScene(SceneContainerNames.SYSTEM_UI_DEFAULT).map {
                        it.key
                    }
                )
            prepareState(
                isFeatureEnabled = true,
                isDeviceUnlocked = false,
                initialSceneKey = SceneKey.Shade,
            )
            assertThat(currentSceneKey).isEqualTo(SceneKey.Shade)
            underTest.start()

            keyguardRepository.setWakefulnessModel(ASLEEP)

            assertThat(currentSceneKey).isEqualTo(SceneKey.Lockscreen)
        }

    @Test
    fun switchToLockscreenWhenDeviceSleepsLocked_featureDisabled() =
        testScope.runTest {
            val currentSceneKey by
                collectLastValue(
                    sceneInteractor.currentScene(SceneContainerNames.SYSTEM_UI_DEFAULT).map {
                        it.key
                    }
                )
            prepareState(
                isFeatureEnabled = false,
                isDeviceUnlocked = false,
                initialSceneKey = SceneKey.Shade,
            )
            assertThat(currentSceneKey).isEqualTo(SceneKey.Shade)
            underTest.start()

            keyguardRepository.setWakefulnessModel(ASLEEP)

            assertThat(currentSceneKey).isEqualTo(SceneKey.Shade)
        }

    private fun prepareState(
        isFeatureEnabled: Boolean = true,
        isDeviceUnlocked: Boolean = false,
@@ -293,4 +390,13 @@ class SystemUiDefaultSceneContainerStartableTest : SysuiTestCase() {
            sceneInteractor.setCurrentScene(SceneContainerNames.SYSTEM_UI_DEFAULT, SceneModel(it))
        }
    }

    companion object {
        private val ASLEEP =
            WakefulnessModel(
                state = WakefulnessState.ASLEEP,
                lastWakeReason = WakeSleepReason.POWER_BUTTON,
                lastSleepReason = WakeSleepReason.POWER_BUTTON
            )
    }
}
+1 −1
Original line number Diff line number Diff line
@@ -48,7 +48,7 @@ class FakeKeyguardRepository : KeyguardRepository {
    override val isKeyguardShowing: Flow<Boolean> = _isKeyguardShowing

    private val _isKeyguardUnlocked = MutableStateFlow(false)
    override val isKeyguardUnlocked: Flow<Boolean> = _isKeyguardUnlocked
    override val isKeyguardUnlocked: StateFlow<Boolean> = _isKeyguardUnlocked.asStateFlow()

    private val _isKeyguardOccluded = MutableStateFlow(false)
    override val isKeyguardOccluded: Flow<Boolean> = _isKeyguardOccluded
Loading