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

Commit 748126c8 authored by Ale Nijamkin's avatar Ale Nijamkin Committed by Android (Google) Code Review
Browse files

Merge "[flexiglass] Fixes crashloop on Wear" into main

parents fab8de21 1a576fe3
Loading
Loading
Loading
Loading
+7 −0
Original line number Diff line number Diff line
@@ -24,6 +24,7 @@ import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.coroutines.collectLastValue
import com.android.systemui.deviceentry.domain.interactor.deviceEntryInteractor
import com.android.systemui.deviceentry.domain.interactor.deviceUnlockedInteractor
import com.android.systemui.display.data.repository.DeviceStateRepository
import com.android.systemui.display.data.repository.fakeDeviceStateRepository
import com.android.systemui.flags.DisableSceneContainer
@@ -41,6 +42,7 @@ import com.android.systemui.scene.domain.interactor.sceneInteractor
import com.android.systemui.scene.shared.model.Scenes
import com.android.systemui.testKosmos
import com.google.common.truth.Truth.assertThat
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.test.runCurrent
import kotlinx.coroutines.test.runTest
import org.junit.Before
@@ -174,10 +176,15 @@ class LogContextInteractorImplTest : SysuiTestCase() {
            assertThat(displayState()).isEqualTo(AuthenticateOptions.DISPLAY_STATE_LOCKSCREEN)

            // Unlock the device.
            val isDeviceUnlocked by
                collectLastValue(
                    kosmos.deviceUnlockedInteractor.deviceUnlockStatus.map { it.isUnlocked }
                )
            kosmos.fakeDeviceEntryFingerprintAuthRepository.setAuthenticationStatus(
                SuccessFingerprintAuthenticationStatus(0, true)
            )
            runCurrent()
            assertThat(isDeviceUnlocked).isTrue()
            kosmos.sceneInteractor.snapToScene(Scenes.Gone, "")

            keyguardTransitionRepository.startTransitionTo(KeyguardState.GONE)
+7 −0
Original line number Diff line number Diff line
@@ -28,6 +28,7 @@ import com.android.systemui.authentication.shared.model.AuthenticationMethodMode
import com.android.systemui.common.ui.data.repository.fakeConfigurationRepository
import com.android.systemui.coroutines.collectLastValue
import com.android.systemui.deviceentry.domain.interactor.deviceEntryInteractor
import com.android.systemui.deviceentry.domain.interactor.deviceUnlockedInteractor
import com.android.systemui.flags.EnableSceneContainer
import com.android.systemui.keyguard.data.repository.fakeDeviceEntryFingerprintAuthRepository
import com.android.systemui.keyguard.shared.model.SuccessFingerprintAuthenticationStatus
@@ -48,6 +49,7 @@ import com.google.common.truth.Truth.assertThat
import java.util.Locale
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.update
import kotlinx.coroutines.test.TestScope
import kotlinx.coroutines.test.runCurrent
@@ -210,10 +212,15 @@ class ShadeSceneContentViewModelTest : SysuiTestCase() {
    private fun TestScope.setDeviceEntered(isEntered: Boolean) {
        if (isEntered) {
            // Unlock the device marking the device has entered.
            val isDeviceUnlocked by
                collectLastValue(
                    kosmos.deviceUnlockedInteractor.deviceUnlockStatus.map { it.isUnlocked }
                )
            kosmos.fakeDeviceEntryFingerprintAuthRepository.setAuthenticationStatus(
                SuccessFingerprintAuthenticationStatus(0, true)
            )
            runCurrent()
            assertThat(isDeviceUnlocked).isTrue()
        }
        setScene(
            if (isEntered) {
+51 −36
Original line number Diff line number Diff line
@@ -34,6 +34,7 @@ import com.android.systemui.scene.shared.model.Overlays
import com.android.systemui.scene.shared.model.Scenes
import com.android.systemui.util.kotlin.pairwise
import com.android.systemui.utils.coroutines.flow.mapLatestConflated
import dagger.Lazy
import javax.inject.Inject
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.flow.Flow
@@ -59,14 +60,14 @@ class DeviceEntryInteractor
@Inject
constructor(
    @Application private val applicationScope: CoroutineScope,
    private val repository: DeviceEntryRepository,
    private val authenticationInteractor: AuthenticationInteractor,
    private val sceneInteractor: SceneInteractor,
    private val deviceUnlockedInteractor: DeviceUnlockedInteractor,
    private val alternateBouncerInteractor: AlternateBouncerInteractor,
    private val dismissCallbackRegistry: DismissCallbackRegistry,
    sceneBackInteractor: SceneBackInteractor,
    @SceneFrameworkTableLog private val tableLogBuffer: TableLogBuffer,
    private val repository: Lazy<DeviceEntryRepository>,
    private val authenticationInteractor: Lazy<AuthenticationInteractor>,
    private val sceneInteractor: Lazy<SceneInteractor>,
    private val deviceUnlockedInteractor: Lazy<DeviceUnlockedInteractor>,
    private val alternateBouncerInteractor: Lazy<AlternateBouncerInteractor>,
    private val dismissCallbackRegistry: Lazy<DismissCallbackRegistry>,
    sceneBackInteractor: Lazy<SceneBackInteractor>,
    @SceneFrameworkTableLog private val tableLogBuffer: Lazy<TableLogBuffer>,
) {
    /**
     * Whether the device is unlocked.
@@ -77,14 +78,17 @@ constructor(
     * of this flow will always be `true`, even if the lockscreen is showing and still needs to be
     * dismissed by the user to proceed.
     */
    val isUnlocked: StateFlow<Boolean> =
        deviceUnlockedInteractor.deviceUnlockStatus
    val isUnlocked: StateFlow<Boolean> by lazy {
        deviceUnlockedInteractor
            .get()
            .deviceUnlockStatus
            .map { it.isUnlocked }
            .stateIn(
                scope = applicationScope,
                started = SharingStarted.WhileSubscribed(),
                initialValue = deviceUnlockedInteractor.deviceUnlockStatus.value.isUnlocked,
                initialValue = deviceUnlockedInteractor.get().deviceUnlockStatus.value.isUnlocked,
            )
    }

    /**
     * Emits `true` when the current scene switches to [Scenes.Gone] for the first time after having
@@ -96,8 +100,10 @@ constructor(
     * [Scenes.Gone] but the bottommost entry of the navigation back stack switched from
     * [Scenes.Lockscreen] to [Scenes.Gone] while the user is staring at another scene.
     */
    val isDeviceEnteredDirectly: StateFlow<Boolean> =
        sceneInteractor.currentScene
    val isDeviceEnteredDirectly: StateFlow<Boolean> by lazy {
        sceneInteractor
            .get()
            .currentScene
            .filter { currentScene ->
                currentScene == Scenes.Gone || currentScene == Scenes.Lockscreen
            }
@@ -105,7 +111,7 @@ constructor(
                if (scene == Scenes.Gone) {
                    // Make sure device unlock status is definitely unlocked before we
                    // consider the device "entered".
                    deviceUnlockedInteractor.deviceUnlockStatus.first { it.isUnlocked }
                    deviceUnlockedInteractor.get().deviceUnlockStatus.first { it.isUnlocked }
                    true
                } else {
                    false
@@ -116,6 +122,7 @@ constructor(
                started = SharingStarted.Eagerly,
                initialValue = false,
            )
    }

    /**
     * Whether the device has been entered (i.e. the lockscreen has been dismissed, by any method).
@@ -129,7 +136,7 @@ constructor(
     * navigation back stack into account and will only produce a `true` value even when the current
     * scene is actually [Scenes.Gone].
     */
    val isDeviceEntered: StateFlow<Boolean> =
    val isDeviceEntered: StateFlow<Boolean> by lazy {
        combine(
                // This flow emits true when the currentScene switches to Gone for the first time
                // after having been on Lockscreen.
@@ -137,7 +144,9 @@ constructor(
                // This flow emits true only if the bottom of the navigation back stack has been
                // switched from Lockscreen to Gone. In other words, only if the device was unlocked
                // while visiting at least one scene "above" the Lockscreen scene.
                sceneBackInteractor.backStack
                sceneBackInteractor
                    .get()
                    .backStack
                    // The bottom of the back stack, which is Lockscreen, Gone, or null if empty.
                    .map { it.asIterable().lastOrNull() }
                    // Filter out cases where the stack changes but the bottom remains unchanged.
@@ -153,7 +162,7 @@ constructor(
                enteredOnBackStack || enteredDirectly
            }
            .logDiffsForTable(
                tableLogBuffer = tableLogBuffer,
                tableLogBuffer = tableLogBuffer.get(),
                columnName = "isDeviceEntered",
                initialValue = false,
            )
@@ -162,9 +171,10 @@ constructor(
                started = SharingStarted.Eagerly,
                initialValue = false,
            )
    }

    val isLockscreenEnabled: Flow<Boolean> by lazy {
        repository.isLockscreenEnabled.onStart { refreshLockscreenEnabled() }
        repository.get().isLockscreenEnabled.onStart { refreshLockscreenEnabled() }
    }

    /**
@@ -181,11 +191,11 @@ constructor(
     */
    val canSwipeToEnter: StateFlow<Boolean?> by lazy {
        combine(
                authenticationInteractor.authenticationMethod.map {
                authenticationInteractor.get().authenticationMethod.map {
                    it == AuthenticationMethodModel.None
                },
                isLockscreenEnabled,
                deviceUnlockedInteractor.deviceUnlockStatus,
                deviceUnlockedInteractor.get().deviceUnlockStatus,
                isDeviceEntered,
            ) { isNoneAuthMethod, isLockscreenEnabled, deviceUnlockStatus, isDeviceEntered ->
                val isSwipeAuthMethod = isNoneAuthMethod && isLockscreenEnabled
@@ -195,7 +205,7 @@ constructor(
                    !isDeviceEntered
            }
            .logDiffsForTable(
                tableLogBuffer = tableLogBuffer,
                tableLogBuffer = tableLogBuffer.get(),
                columnName = "canSwipeToEnter",
                initialValue = false,
            )
@@ -218,7 +228,7 @@ constructor(
     */
    @JvmOverloads
    fun attemptDeviceEntry(callback: IKeyguardDismissCallback? = null) {
        callback?.let { dismissCallbackRegistry.addCallback(it) }
        callback?.let { dismissCallbackRegistry.get().addCallback(it) }

        // TODO (b/307768356),
        //       1. Check if the device is already authenticated by trust agent/passive biometrics
@@ -228,18 +238,23 @@ constructor(
        //       4. Transition to bouncer scene
        applicationScope.launch {
            if (isAuthenticationRequired()) {
                if (alternateBouncerInteractor.canShowAlternateBouncer.value) {
                    alternateBouncerInteractor.forceShow()
                if (alternateBouncerInteractor.get().canShowAlternateBouncer.value) {
                    alternateBouncerInteractor.get().forceShow()
                } else {
                    sceneInteractor.showOverlay(
                    sceneInteractor
                        .get()
                        .showOverlay(
                            overlay = Overlays.Bouncer,
                            loggingReason = "request to unlock device while authentication required",
                        )
                }
            } else {
                sceneInteractor.changeScene(
                sceneInteractor
                    .get()
                    .changeScene(
                        toScene = Scenes.Gone,
                    loggingReason = "request to unlock device while authentication isn't required",
                        loggingReason =
                            "request to unlock device while authentication isn't required",
                    )
            }
        }
@@ -250,8 +265,8 @@ constructor(
     * `false` if the device can be entered without authenticating first.
     */
    suspend fun isAuthenticationRequired(): Boolean {
        return !deviceUnlockedInteractor.deviceUnlockStatus.value.isUnlocked &&
            authenticationInteractor.getAuthenticationMethod().isSecure
        return !deviceUnlockedInteractor.get().deviceUnlockStatus.value.isUnlocked &&
            authenticationInteractor.get().getAuthenticationMethod().isSecure
    }

    /**
@@ -260,7 +275,7 @@ constructor(
     * when the user swipes on it.
     */
    suspend fun isLockscreenEnabled(): Boolean {
        return repository.isLockscreenEnabled()
        return repository.get().isLockscreenEnabled()
    }

    /**
@@ -276,6 +291,6 @@ constructor(

    /** Locks the device instantly. */
    fun lockNow(debuggingReason: String) {
        deviceUnlockedInteractor.lockNow(debuggingReason)
        deviceUnlockedInteractor.get().lockNow(debuggingReason)
    }
}
+8 −8
Original line number Diff line number Diff line
@@ -30,13 +30,13 @@ val Kosmos.deviceEntryInteractor by
    Kosmos.Fixture {
        DeviceEntryInteractor(
            applicationScope = applicationCoroutineScope,
            repository = deviceEntryRepository,
            authenticationInteractor = authenticationInteractor,
            sceneInteractor = sceneInteractor,
            deviceUnlockedInteractor = deviceUnlockedInteractor,
            alternateBouncerInteractor = alternateBouncerInteractor,
            dismissCallbackRegistry = dismissCallbackRegistry,
            sceneBackInteractor = sceneBackInteractor,
            tableLogBuffer = logcatTableLogBuffer(this, "sceneFrameworkTableLogBuffer"),
            repository = { deviceEntryRepository },
            authenticationInteractor = { authenticationInteractor },
            sceneInteractor = { sceneInteractor },
            deviceUnlockedInteractor = { deviceUnlockedInteractor },
            alternateBouncerInteractor = { alternateBouncerInteractor },
            dismissCallbackRegistry = { dismissCallbackRegistry },
            sceneBackInteractor = { sceneBackInteractor },
            tableLogBuffer = { logcatTableLogBuffer(this, "sceneFrameworkTableLogBuffer") },
        )
    }