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

Commit 2bcc948c authored by Ale Nijamkin's avatar Ale Nijamkin
Browse files

[flexiglass] Sleep, unlock state, and auth method logic changes

1. No longer change scenes if the device becomes unlocked while
   asleep; stay on the lockscreen; we especially don't want to go from
   bouncer to gone while asleep

2. If the auth method changes to a non-secure one, hide the bouncer overlay

Bug: 404470548
Test: unit tests added
Test: manually verified that unlocking the device while its asleep
doesn't move to the gone scene (used adb to change the auth method to a
non-secure one while the device was asleep and observed the
SceneFramework logcat tag to see what scene changes are started in
response)
Test: manually verified that changing the auth method to a non-secure
one while the device is awake and on the bouncer scene correctly hides
the bouncer and returns to the lockscreen scene (using the same method
as above)
Flag: com.android.systemui.scene_container

Change-Id: I7ecc74824adf25b5c05116de783417eb3fa7c85f
parent 502a5b56
Loading
Loading
Loading
Loading
+76 −1
Original line number Diff line number Diff line
@@ -14,6 +14,8 @@
 * limitations under the License.
 */

@file:OptIn(ExperimentalCoroutinesApi::class)

package com.android.systemui.scene.domain.startable

import android.app.StatusBarManager
@@ -121,6 +123,7 @@ import com.android.systemui.util.mockito.mock
import com.android.systemui.util.settings.data.repository.userAwareSecureSettingsRepository
import com.google.android.msdl.data.model.MSDLToken
import com.google.common.truth.Truth.assertThat
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.flowOf
import kotlinx.coroutines.flow.map
@@ -2607,6 +2610,75 @@ class SceneContainerStartableTest : SysuiTestCase() {
            assertThat(currentScene).isEqualTo(Scenes.Communal)
        }

    @Test
    fun handleDeviceUnlockStatus_returnsToLsFromBouncer_whenGoesToSleep() =
        testScope.runTest {
            val authMethod by collectLastValue(kosmos.authenticationInteractor.authenticationMethod)
            val isUnlocked by
                collectLastValue(
                    kosmos.deviceUnlockedInteractor.deviceUnlockStatus.map { it.isUnlocked }
                )
            val currentScene by collectLastValue(sceneInteractor.currentScene)
            val currentOverlays by collectLastValue(sceneInteractor.currentOverlays)
            val isAwake by collectLastValue(powerInteractor.isAwake)
            prepareState(
                isDeviceUnlocked = false,
                initialSceneKey = Scenes.Lockscreen,
                authenticationMethod = AuthenticationMethodModel.Pin,
                startsAwake = true,
            )
            underTest.start()
            assertThat(authMethod).isEqualTo(AuthenticationMethodModel.Pin)
            assertThat(isUnlocked).isFalse()
            assertThat(currentScene).isEqualTo(Scenes.Lockscreen)
            assertThat(currentOverlays).doesNotContain(Overlays.Bouncer)
            assertThat(isAwake).isTrue()

            sceneInteractor.showOverlay(Overlays.Bouncer, "")
            assertThat(authMethod).isEqualTo(AuthenticationMethodModel.Pin)
            assertThat(isUnlocked).isFalse()
            assertThat(currentScene).isEqualTo(Scenes.Lockscreen)
            assertThat(currentOverlays).contains(Overlays.Bouncer)
            assertThat(isAwake).isTrue()

            powerInteractor.setAsleepForTest()
            assertThat(authMethod).isEqualTo(AuthenticationMethodModel.Pin)
            assertThat(isUnlocked).isFalse()
            assertThat(currentScene).isEqualTo(Scenes.Lockscreen)
            assertThat(currentOverlays).doesNotContain(Overlays.Bouncer)
            assertThat(isAwake).isFalse()
        }

    @Test
    fun hidesBouncer_whenAuthMethodChangesToNonSecure() =
        testScope.runTest {
            val authMethod by collectLastValue(kosmos.authenticationInteractor.authenticationMethod)
            val currentScene by collectLastValue(kosmos.sceneInteractor.currentScene)
            val currentOverlays by collectLastValue(kosmos.sceneInteractor.currentOverlays)
            prepareState(
                authenticationMethod = AuthenticationMethodModel.Password,
                initialSceneKey = Scenes.Lockscreen,
            )
            underTest.start()
            assertThat(authMethod).isEqualTo(AuthenticationMethodModel.Password)
            assertThat(currentScene).isEqualTo(Scenes.Lockscreen)
            assertThat(currentOverlays).doesNotContain(Overlays.Bouncer)

            sceneInteractor.showOverlay(Overlays.Bouncer, "")
            assertThat(authMethod).isEqualTo(AuthenticationMethodModel.Password)
            assertThat(currentScene).isEqualTo(Scenes.Lockscreen)
            assertThat(currentOverlays).contains(Overlays.Bouncer)

            kosmos.fakeAuthenticationRepository.setAuthenticationMethod(
                AuthenticationMethodModel.None
            )
            runCurrent()

            assertThat(authMethod).isEqualTo(AuthenticationMethodModel.None)
            assertThat(currentScene).isEqualTo(Scenes.Lockscreen)
            assertThat(currentOverlays).doesNotContain(Overlays.Bouncer)
        }

    @Test
    fun replacesLockscreenSceneOnBackStack_whenFaceUnlocked_fromShade_noAlternateBouncer() =
        testScope.runTest {
@@ -2898,7 +2970,10 @@ class SceneContainerStartableTest : SysuiTestCase() {
            sceneInteractor.changeScene(it, "prepareState, initialSceneKey isn't null")
        }
        for (overlay in initialOverlays) {
            sceneInteractor.showOverlay(overlay, "prepareState, initialOverlays isn't empty")
            sceneInteractor.instantlyShowOverlay(
                overlay,
                "prepareState, initialOverlays isn't empty",
            )
        }
        if (startsAwake) {
            powerInteractor.setAwakeForTest()
+26 −1
Original line number Diff line number Diff line
@@ -332,6 +332,7 @@ constructor(
    /** Switches between scenes based on ever-changing application state. */
    private fun automaticallySwitchScenes() {
        handleBouncerImeVisibility()
        handleBouncerHiding()
        handleSimUnlock()
        handleDeviceUnlockStatus()
        handlePowerState()
@@ -352,6 +353,24 @@ constructor(
        }
    }

    private fun handleBouncerHiding() {
        applicationScope.launch {
            repeatWhen(
                condition =
                    authenticationInteractor
                        .get()
                        .authenticationMethod
                        .map { !it.isSecure }
                        .distinctUntilChanged()
            ) {
                sceneInteractor.hideOverlay(
                    overlay = Overlays.Bouncer,
                    loggingReason = "Authentication method changed to a non-secure one.",
                )
            }
        }
    }

    private fun handleSimUnlock() {
        applicationScope.launch {
            simBouncerInteractor
@@ -434,6 +453,12 @@ constructor(
                        }
                    }

                    if (powerInteractor.detailedWakefulness.value.isAsleep()) {
                        // The logic below is for when the device becomes unlocked. That must be a
                        // no-op if the device is not awake.
                        return@mapNotNull null
                    }

                    if (
                        isOnPrimaryBouncer &&
                            deviceUnlockStatus.deviceUnlockSource == DeviceUnlockSource.TrustAgent
@@ -833,7 +858,7 @@ constructor(
                }
                .collect {
                    val loggingReason = "Falsing detected."
                    switchToScene(Scenes.Lockscreen, loggingReason)
                    switchToScene(targetSceneKey = Scenes.Lockscreen, loggingReason = loggingReason)
                }
        }
    }