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

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

Merge "[flexiglass] Hooks up real app state and logic in keyguard (2)" into udc-qpr-dev

parents e3f273f5 48b75025
Loading
Loading
Loading
Loading
+15 −11
Original line number Diff line number Diff line
@@ -19,17 +19,22 @@ package com.android.systemui.authentication.data.repository
import com.android.internal.widget.LockPatternUtils
import com.android.keyguard.KeyguardSecurityModel
import com.android.systemui.authentication.shared.model.AuthenticationMethodModel
import com.android.systemui.dagger.qualifiers.Application
import com.android.systemui.dagger.qualifiers.Background
import com.android.systemui.keyguard.data.repository.KeyguardRepository
import com.android.systemui.user.data.repository.UserRepository
import dagger.Binds
import dagger.Module
import java.util.function.Function
import javax.inject.Inject
import kotlinx.coroutines.CoroutineDispatcher
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.SharingStarted
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.asStateFlow
import kotlinx.coroutines.flow.stateIn
import kotlinx.coroutines.withContext
import java.util.function.Function
import javax.inject.Inject

/** Defines interface for classes that can access authentication-related application state. */
interface AuthenticationRepository {
@@ -64,9 +69,6 @@ interface AuthenticationRepository {
     */
    suspend fun getAuthenticationMethod(): AuthenticationMethodModel

    /** See [isUnlocked]. */
    fun setUnlocked(isUnlocked: Boolean)

    /** See [isBypassEnabled]. */
    fun setBypassEnabled(isBypassEnabled: Boolean)

@@ -77,14 +79,20 @@ interface AuthenticationRepository {
class AuthenticationRepositoryImpl
@Inject
constructor(
    @Application private val applicationScope: CoroutineScope,
    private val getSecurityMode: Function<Int, KeyguardSecurityModel.SecurityMode>,
    @Background private val backgroundDispatcher: CoroutineDispatcher,
    private val userRepository: UserRepository,
    private val lockPatternUtils: LockPatternUtils,
    keyguardRepository: KeyguardRepository,
) : AuthenticationRepository {

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

    private val _isBypassEnabled = MutableStateFlow(false)
    override val isBypassEnabled: StateFlow<Boolean> = _isBypassEnabled.asStateFlow()
@@ -128,10 +136,6 @@ constructor(
        }
    }

    override fun setUnlocked(isUnlocked: Boolean) {
        _isUnlocked.value = isUnlocked
    }

    override fun setBypassEnabled(isBypassEnabled: Boolean) {
        _isBypassEnabled.value = isBypassEnabled
    }
+0 −23
Original line number Diff line number Diff line
@@ -89,22 +89,6 @@ constructor(
        return !isUnlocked.value && getAuthenticationMethod().isSecure
    }

    /**
     * Unlocks the device, assuming that the authentication challenge has been completed
     * successfully.
     */
    fun unlockDevice() {
        repository.setUnlocked(true)
    }

    /**
     * Locks the device. From now on, the device will remain locked until [authenticate] is called
     * with the correct input.
     */
    fun lockDevice() {
        repository.setUnlocked(false)
    }

    /**
     * Attempts to authenticate the user and unlock the device.
     *
@@ -146,7 +130,6 @@ constructor(

        if (isSuccessful) {
            repository.setFailedAuthenticationAttempts(0)
            repository.setUnlocked(true)
        } else {
            repository.setFailedAuthenticationAttempts(
                repository.failedAuthenticationAttempts.value + 1
@@ -156,12 +139,6 @@ constructor(
        return isSuccessful
    }

    /** Triggers a biometric-powered unlock of the device. */
    fun biometricUnlock() {
        // TODO(b/280883900): only allow this if the biometric is enabled and there's a match.
        repository.setUnlocked(true)
    }

    /** See [isBypassEnabled]. */
    fun toggleBypassEnabled() {
        repository.setBypassEnabled(!repository.isBypassEnabled.value)
+22 −16
Original line number Diff line number Diff line
@@ -35,6 +35,9 @@ import kotlinx.coroutines.delay
import kotlinx.coroutines.flow.SharingStarted
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.flow.distinctUntilChanged
import kotlinx.coroutines.flow.flatMapLatest
import kotlinx.coroutines.flow.flowOf
import kotlinx.coroutines.flow.stateIn
import kotlinx.coroutines.launch

@@ -72,22 +75,26 @@ constructor(
    val throttling: StateFlow<AuthenticationThrottledModel?> = repository.throttling

    init {
        // UNLOCKING SHOWS Gone.
        //
        // Move to the gone scene if the device becomes unlocked while on the bouncer scene.
        applicationScope.launch {
            sceneInteractor.currentScene(containerName).collect { currentScene ->
            sceneInteractor
                .currentScene(containerName)
                .flatMapLatest { currentScene ->
                    if (currentScene.key == SceneKey.Bouncer) {
                    when (getAuthenticationMethod()) {
                        is AuthenticationMethodModel.None ->
                            sceneInteractor.setCurrentScene(
                                containerName,
                                SceneModel(SceneKey.Gone),
                            )
                        is AuthenticationMethodModel.Swipe ->
                        authenticationInteractor.isUnlocked
                    } else {
                        flowOf(false)
                    }
                }
                .distinctUntilChanged()
                .collect { isUnlocked ->
                    if (isUnlocked) {
                        sceneInteractor.setCurrentScene(
                                containerName,
                                SceneModel(SceneKey.Lockscreen),
                            containerName = containerName,
                            scene = SceneModel(SceneKey.Gone),
                        )
                        else -> Unit
                    }
                    }
                }
        }
@@ -119,7 +126,6 @@ constructor(
                    scene = SceneModel(SceneKey.Bouncer),
                )
            } else {
                authenticationInteractor.unlockDevice()
                sceneInteractor.setCurrentScene(
                    containerName = containerName,
                    scene = SceneModel(SceneKey.Gone),
+36 −18
Original line number Diff line number Diff line
@@ -22,17 +22,19 @@ import com.android.systemui.authentication.shared.model.AuthenticationMethodMode
import com.android.systemui.bouncer.domain.interactor.BouncerInteractor
import com.android.systemui.bouncer.shared.model.AuthenticationThrottledModel
import com.android.systemui.dagger.qualifiers.Application
import com.android.systemui.util.kotlin.pairwise
import dagger.assisted.Assisted
import dagger.assisted.AssistedFactory
import dagger.assisted.AssistedInject
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.channels.BufferOverflow
import kotlinx.coroutines.flow.MutableSharedFlow
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.SharingStarted
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.asStateFlow
import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.flow.distinctUntilChanged
import kotlinx.coroutines.flow.flow
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.stateIn
import kotlinx.coroutines.launch
@@ -83,26 +85,31 @@ constructor(
    }

    /** View-model for the current UI, based on the current authentication method. */
    val authMethod: StateFlow<AuthMethodBouncerViewModel?>
        get() =
            flow {
                    emit(null)
                    emit(interactor.getAuthenticationMethod())
                }
                .map { authMethod ->
                    when (authMethod) {
                        is AuthenticationMethodModel.Pin -> pin
                        is AuthenticationMethodModel.Password -> password
                        is AuthenticationMethodModel.Pattern -> pattern
                        else -> null
                    }
                }
                .stateIn(
    private val _authMethod =
        MutableSharedFlow<AuthMethodBouncerViewModel?>(
            replay = 1,
            onBufferOverflow = BufferOverflow.DROP_OLDEST,
        )
    val authMethod: StateFlow<AuthMethodBouncerViewModel?> =
        _authMethod.stateIn(
            scope = applicationScope,
            started = SharingStarted.WhileSubscribed(),
            initialValue = null,
        )

    init {
        applicationScope.launch {
            _authMethod.subscriptionCount
                .pairwise()
                .map { (previousCount, currentCount) -> currentCount > previousCount }
                .collect { subscriberAdded ->
                    if (subscriberAdded) {
                        reloadAuthMethod()
                    }
                }
        }
    }

    /** The user-facing message to show in the bouncer. */
    val message: StateFlow<MessageViewModel> =
        combine(
@@ -184,6 +191,17 @@ constructor(
        )
    }

    private suspend fun reloadAuthMethod() {
        _authMethod.tryEmit(
            when (interactor.getAuthenticationMethod()) {
                is AuthenticationMethodModel.Pin -> pin
                is AuthenticationMethodModel.Password -> password
                is AuthenticationMethodModel.Pattern -> pattern
                else -> null
            }
        )
    }

    data class MessageViewModel(
        val text: String,

+1 −4
Original line number Diff line number Diff line
@@ -42,10 +42,7 @@ class PinBouncerViewModel(

    /** The length of the hinted PIN, or `null` if pin length hint should not be shown. */
    val hintedPinLength: StateFlow<Int?> =
        flow {
                emit(null)
                emit(interactor.getAuthenticationMethod())
            }
        flow { emit(interactor.getAuthenticationMethod()) }
            .map { authMethod ->
                // Hinting is enabled for 6-digit codes only
                autoConfirmPinLength(authMethod).takeIf { it == HINTING_PASSCODE_LENGTH }
Loading