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

Commit 8e4c4ae0 authored by Ale Nijamkin's avatar Ale Nijamkin Committed by Automerger Merge Worker
Browse files

Merge "[flexiglass] Hooks up real app state and logic in keyguard (3)" into...

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

Original change: https://googleplex-android-review.googlesource.com/c/platform/frameworks/base/+/23884810



Change-Id: Idabaaacc664b8e40e406426ad23d05a3640efcb4
Signed-off-by: default avatarAutomerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
parents 3554b85a 05971537
Loading
Loading
Loading
Loading
+42 −1
Original line number Original line Diff line number Diff line
@@ -79,17 +79,25 @@ import com.android.systemui.keyguard.domain.interactor.KeyguardFaceAuthInteracto
import com.android.systemui.log.SessionTracker;
import com.android.systemui.log.SessionTracker;
import com.android.systemui.plugins.ActivityStarter;
import com.android.systemui.plugins.ActivityStarter;
import com.android.systemui.plugins.FalsingManager;
import com.android.systemui.plugins.FalsingManager;
import com.android.systemui.scene.domain.interactor.SceneInteractor;
import com.android.systemui.scene.shared.model.SceneContainerNames;
import com.android.systemui.scene.shared.model.SceneKey;
import com.android.systemui.shared.system.SysUiStatsLog;
import com.android.systemui.shared.system.SysUiStatsLog;
import com.android.systemui.statusbar.policy.ConfigurationController;
import com.android.systemui.statusbar.policy.ConfigurationController;
import com.android.systemui.statusbar.policy.KeyguardStateController;
import com.android.systemui.statusbar.policy.KeyguardStateController;
import com.android.systemui.statusbar.policy.UserSwitcherController;
import com.android.systemui.statusbar.policy.UserSwitcherController;
import com.android.systemui.user.domain.interactor.UserInteractor;
import com.android.systemui.util.ViewController;
import com.android.systemui.util.ViewController;
import com.android.systemui.util.kotlin.JavaAdapter;
import com.android.systemui.util.settings.GlobalSettings;
import com.android.systemui.util.settings.GlobalSettings;


import java.io.File;
import java.io.File;
import java.util.Optional;
import java.util.Optional;


import javax.inject.Inject;
import javax.inject.Inject;
import javax.inject.Provider;

import kotlinx.coroutines.Job;


/** Controller for {@link KeyguardSecurityContainer} */
/** Controller for {@link KeyguardSecurityContainer} */
@KeyguardBouncerScope
@KeyguardBouncerScope
@@ -378,6 +386,10 @@ public class KeyguardSecurityContainerController extends ViewController<Keyguard
                    showPrimarySecurityScreen(false);
                    showPrimarySecurityScreen(false);
                }
                }
            };
            };
    private final UserInteractor mUserInteractor;
    private final Provider<SceneInteractor> mSceneInteractor;
    private final Provider<JavaAdapter> mJavaAdapter;
    @Nullable private Job mSceneTransitionCollectionJob;


    @Inject
    @Inject
    public KeyguardSecurityContainerController(KeyguardSecurityContainer view,
    public KeyguardSecurityContainerController(KeyguardSecurityContainer view,
@@ -402,7 +414,10 @@ public class KeyguardSecurityContainerController extends ViewController<Keyguard
            ViewMediatorCallback viewMediatorCallback,
            ViewMediatorCallback viewMediatorCallback,
            AudioManager audioManager,
            AudioManager audioManager,
            KeyguardFaceAuthInteractor keyguardFaceAuthInteractor,
            KeyguardFaceAuthInteractor keyguardFaceAuthInteractor,
            BouncerMessageInteractor bouncerMessageInteractor
            BouncerMessageInteractor bouncerMessageInteractor,
            Provider<JavaAdapter> javaAdapter,
            UserInteractor userInteractor,
            Provider<SceneInteractor> sceneInteractor
    ) {
    ) {
        super(view);
        super(view);
        mLockPatternUtils = lockPatternUtils;
        mLockPatternUtils = lockPatternUtils;
@@ -429,6 +444,9 @@ public class KeyguardSecurityContainerController extends ViewController<Keyguard
        mAudioManager = audioManager;
        mAudioManager = audioManager;
        mKeyguardFaceAuthInteractor = keyguardFaceAuthInteractor;
        mKeyguardFaceAuthInteractor = keyguardFaceAuthInteractor;
        mBouncerMessageInteractor = bouncerMessageInteractor;
        mBouncerMessageInteractor = bouncerMessageInteractor;
        mUserInteractor = userInteractor;
        mSceneInteractor = sceneInteractor;
        mJavaAdapter = javaAdapter;
    }
    }


    @Override
    @Override
@@ -451,6 +469,24 @@ public class KeyguardSecurityContainerController extends ViewController<Keyguard
        mView.setOnKeyListener(mOnKeyListener);
        mView.setOnKeyListener(mOnKeyListener);


        showPrimarySecurityScreen(false);
        showPrimarySecurityScreen(false);

        if (mFeatureFlags.isEnabled(Flags.SCENE_CONTAINER)) {
            // When the scene framework transitions from bouncer to gone, we dismiss the keyguard.
            mSceneTransitionCollectionJob = mJavaAdapter.get().alwaysCollectFlow(
                mSceneInteractor.get().sceneTransitions(SceneContainerNames.SYSTEM_UI_DEFAULT),
                sceneTransitionModel -> {
                    if (sceneTransitionModel != null
                            && sceneTransitionModel.getFrom() == SceneKey.Bouncer.INSTANCE
                            && sceneTransitionModel.getTo() == SceneKey.Gone.INSTANCE) {
                        final int selectedUserId = mUserInteractor.getSelectedUserId();
                        showNextSecurityScreenOrFinish(
                                /* authenticated= */ true,
                                selectedUserId,
                                /* bypassSecondaryLockScreen= */ true,
                                mSecurityModel.getSecurityMode(selectedUserId));
                    }
                });
        }
    }
    }


    @Override
    @Override
@@ -459,6 +495,11 @@ public class KeyguardSecurityContainerController extends ViewController<Keyguard
        mConfigurationController.removeCallback(mConfigurationListener);
        mConfigurationController.removeCallback(mConfigurationListener);
        mView.removeMotionEventListener(mGlobalTouchListener);
        mView.removeMotionEventListener(mGlobalTouchListener);
        mUserSwitcherController.removeUserSwitchCallback(mUserSwitchCallback);
        mUserSwitcherController.removeUserSwitchCallback(mUserSwitchCallback);

        if (mSceneTransitionCollectionJob != null) {
            mSceneTransitionCollectionJob.cancel(null);
            mSceneTransitionCollectionJob = null;
        }
    }
    }


    /** */
    /** */
+181 −38
Original line number Original line Diff line number Diff line
@@ -14,25 +14,39 @@
 * limitations under the License.
 * limitations under the License.
 */
 */


@file:OptIn(ExperimentalCoroutinesApi::class)

package com.android.systemui.authentication.data.repository
package com.android.systemui.authentication.data.repository


import com.android.internal.widget.LockPatternChecker
import com.android.internal.widget.LockPatternUtils
import com.android.internal.widget.LockPatternUtils
import com.android.internal.widget.LockscreenCredential
import com.android.keyguard.KeyguardSecurityModel
import com.android.keyguard.KeyguardSecurityModel
import com.android.systemui.authentication.shared.model.AuthenticationMethodModel
import com.android.systemui.authentication.shared.model.AuthenticationMethodModel
import com.android.systemui.authentication.shared.model.AuthenticationResultModel
import com.android.systemui.authentication.shared.model.AuthenticationThrottlingModel
import com.android.systemui.dagger.qualifiers.Application
import com.android.systemui.dagger.qualifiers.Application
import com.android.systemui.dagger.qualifiers.Background
import com.android.systemui.dagger.qualifiers.Background
import com.android.systemui.keyguard.data.repository.KeyguardRepository
import com.android.systemui.keyguard.data.repository.KeyguardRepository
import com.android.systemui.user.data.repository.UserRepository
import com.android.systemui.user.data.repository.UserRepository
import com.android.systemui.util.time.SystemClock
import dagger.Binds
import dagger.Binds
import dagger.Module
import dagger.Module
import java.util.function.Function
import java.util.function.Function
import javax.inject.Inject
import javax.inject.Inject
import kotlin.coroutines.resume
import kotlin.coroutines.suspendCoroutine
import kotlinx.coroutines.CoroutineDispatcher
import kotlinx.coroutines.CoroutineDispatcher
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.SharingStarted
import kotlinx.coroutines.flow.SharingStarted
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.asStateFlow
import kotlinx.coroutines.flow.asStateFlow
import kotlinx.coroutines.flow.flatMapLatest
import kotlinx.coroutines.flow.flow
import kotlinx.coroutines.flow.flowOn
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.stateIn
import kotlinx.coroutines.flow.stateIn
import kotlinx.coroutines.withContext
import kotlinx.coroutines.withContext


@@ -57,11 +71,17 @@ interface AuthenticationRepository {
     */
     */
    val isBypassEnabled: StateFlow<Boolean>
    val isBypassEnabled: StateFlow<Boolean>


    /**
    /** Whether the auto confirm feature is enabled for the currently-selected user. */
     * Number of consecutively failed authentication attempts. This resets to `0` when
    val isAutoConfirmEnabled: StateFlow<Boolean>
     * authentication succeeds.

     */
    /** The length of the PIN for which we should show a hint. */
    val failedAuthenticationAttempts: StateFlow<Int>
    val hintedPinLength: Int

    /** Whether the pattern should be visible for the currently-selected user. */
    val isPatternVisible: StateFlow<Boolean>

    /** The current throttling state, as cached via [setThrottling]. */
    val throttling: StateFlow<AuthenticationThrottlingModel>


    /**
    /**
     * Returns the currently-configured authentication method. This determines how the
     * Returns the currently-configured authentication method. This determines how the
@@ -69,11 +89,48 @@ interface AuthenticationRepository {
     */
     */
    suspend fun getAuthenticationMethod(): AuthenticationMethodModel
    suspend fun getAuthenticationMethod(): AuthenticationMethodModel


    /** Returns the length of the PIN or `0` if the current auth method is not PIN. */
    suspend fun getPinLength(): Int

    /**
     * Returns whether the lockscreen is enabled.
     *
     * When the lockscreen is not enabled, it shouldn't show in cases when the authentication method
     * is considered not secure (for example, "swipe" is considered to be "none").
     */
    suspend fun isLockscreenEnabled(): Boolean

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


    /** See [failedAuthenticationAttempts]. */
    /** Reports an authentication attempt. */
    fun setFailedAuthenticationAttempts(failedAuthenticationAttempts: Int)
    suspend fun reportAuthenticationAttempt(isSuccessful: Boolean)

    /** Returns the current number of failed authentication attempts. */
    suspend fun getFailedAuthenticationAttemptCount(): Int

    /**
     * Returns the timestamp for when the current throttling will end, allowing the user to attempt
     * authentication again.
     *
     * Note that this is in milliseconds and it matches [SystemClock.elapsedRealtime].
     */
    suspend fun getThrottlingEndTimestamp(): Long

    /** Sets the cached throttling state, updating the [throttling] flow. */
    fun setThrottling(throttlingModel: AuthenticationThrottlingModel)

    /**
     * Sets the throttling timeout duration (time during which the user should not be allowed to
     * attempt authentication).
     */
    suspend fun setThrottleDuration(durationMs: Int)

    /**
     * Checks the given [LockscreenCredential] to see if it's correct, returning an
     * [AuthenticationResultModel] representing what happened.
     */
    suspend fun checkCredential(credential: LockscreenCredential): AuthenticationResultModel
}
}


class AuthenticationRepositoryImpl
class AuthenticationRepositoryImpl
@@ -83,8 +140,8 @@ constructor(
    private val getSecurityMode: Function<Int, KeyguardSecurityModel.SecurityMode>,
    private val getSecurityMode: Function<Int, KeyguardSecurityModel.SecurityMode>,
    @Background private val backgroundDispatcher: CoroutineDispatcher,
    @Background private val backgroundDispatcher: CoroutineDispatcher,
    private val userRepository: UserRepository,
    private val userRepository: UserRepository,
    private val lockPatternUtils: LockPatternUtils,
    keyguardRepository: KeyguardRepository,
    keyguardRepository: KeyguardRepository,
    private val lockPatternUtils: LockPatternUtils,
) : AuthenticationRepository {
) : AuthenticationRepository {


    override val isUnlocked: StateFlow<Boolean> =
    override val isUnlocked: StateFlow<Boolean> =
@@ -94,54 +151,140 @@ constructor(
            initialValue = false,
            initialValue = false,
        )
        )


    override suspend fun isLockscreenEnabled(): Boolean {
        return withContext(backgroundDispatcher) {
            val selectedUserId = userRepository.selectedUserId
            !lockPatternUtils.isLockPatternEnabled(selectedUserId)
        }
    }

    private val _isBypassEnabled = MutableStateFlow(false)
    private val _isBypassEnabled = MutableStateFlow(false)
    override val isBypassEnabled: StateFlow<Boolean> = _isBypassEnabled.asStateFlow()
    override val isBypassEnabled: StateFlow<Boolean> = _isBypassEnabled.asStateFlow()


    private val _failedAuthenticationAttempts = MutableStateFlow(0)
    override val isAutoConfirmEnabled: StateFlow<Boolean> =
    override val failedAuthenticationAttempts: StateFlow<Int> =
        userRepository.selectedUserInfo
        _failedAuthenticationAttempts.asStateFlow()
            .map { it.id }
            .flatMapLatest { userId ->
                flow { emit(lockPatternUtils.isAutoPinConfirmEnabled(userId)) }
                    .flowOn(backgroundDispatcher)
            }
            .stateIn(
                scope = applicationScope,
                started = SharingStarted.WhileSubscribed(),
                initialValue = true,
            )

    override val hintedPinLength: Int = LockPatternUtils.MIN_AUTO_PIN_REQUIREMENT_LENGTH

    override val isPatternVisible: StateFlow<Boolean> =
        userRepository.selectedUserInfo
            .map { it.id }
            .flatMapLatest { userId ->
                flow { emit(lockPatternUtils.isVisiblePatternEnabled(userId)) }
                    .flowOn(backgroundDispatcher)
            }
            .stateIn(
                scope = applicationScope,
                started = SharingStarted.WhileSubscribed(),
                initialValue = true,
            )

    private val _throttling = MutableStateFlow(AuthenticationThrottlingModel())
    override val throttling: StateFlow<AuthenticationThrottlingModel> = _throttling.asStateFlow()

    private val UserRepository.selectedUserId: Int
        get() = getSelectedUserInfo().id


    override suspend fun getAuthenticationMethod(): AuthenticationMethodModel {
    override suspend fun getAuthenticationMethod(): AuthenticationMethodModel {
        return withContext(backgroundDispatcher) {
        return withContext(backgroundDispatcher) {
            val selectedUserId = userRepository.getSelectedUserInfo().id
            val selectedUserId = userRepository.selectedUserId
            when (getSecurityMode.apply(selectedUserId)) {
            when (getSecurityMode.apply(selectedUserId)) {
                KeyguardSecurityModel.SecurityMode.PIN,
                KeyguardSecurityModel.SecurityMode.PIN,
                KeyguardSecurityModel.SecurityMode.SimPin ->
                KeyguardSecurityModel.SecurityMode.SimPin,
                    AuthenticationMethodModel.Pin(
                KeyguardSecurityModel.SecurityMode.SimPuk -> AuthenticationMethodModel.Pin
                        code = listOf(1, 2, 3, 4), // TODO(b/280883900): remove this
                KeyguardSecurityModel.SecurityMode.Password -> AuthenticationMethodModel.Password
                        autoConfirm = lockPatternUtils.isAutoPinConfirmEnabled(selectedUserId),
                KeyguardSecurityModel.SecurityMode.Pattern -> AuthenticationMethodModel.Pattern
                    )
                KeyguardSecurityModel.SecurityMode.Password,
                KeyguardSecurityModel.SecurityMode.SimPuk ->
                    AuthenticationMethodModel.Password(
                        password = "password", // TODO(b/280883900): remove this
                    )
                KeyguardSecurityModel.SecurityMode.Pattern ->
                    AuthenticationMethodModel.Pattern(
                        coordinates =
                            listOf(
                                AuthenticationMethodModel.Pattern.PatternCoordinate(2, 0),
                                AuthenticationMethodModel.Pattern.PatternCoordinate(2, 1),
                                AuthenticationMethodModel.Pattern.PatternCoordinate(2, 2),
                                AuthenticationMethodModel.Pattern.PatternCoordinate(1, 1),
                                AuthenticationMethodModel.Pattern.PatternCoordinate(0, 0),
                                AuthenticationMethodModel.Pattern.PatternCoordinate(0, 1),
                                AuthenticationMethodModel.Pattern.PatternCoordinate(0, 2),
                            ), // TODO(b/280883900): remove this
                    )
                KeyguardSecurityModel.SecurityMode.None -> AuthenticationMethodModel.None
                KeyguardSecurityModel.SecurityMode.None -> AuthenticationMethodModel.None
                KeyguardSecurityModel.SecurityMode.Invalid -> error("Invalid security mode!")
                KeyguardSecurityModel.SecurityMode.Invalid -> error("Invalid security mode!")
                null -> error("Invalid security is null!")
            }
            }
        }
        }
    }
    }


    override suspend fun getPinLength(): Int {
        return withContext(backgroundDispatcher) {
            val selectedUserId = userRepository.selectedUserId
            lockPatternUtils.getPinLength(selectedUserId)
        }
    }

    override fun setBypassEnabled(isBypassEnabled: Boolean) {
    override fun setBypassEnabled(isBypassEnabled: Boolean) {
        _isBypassEnabled.value = isBypassEnabled
        _isBypassEnabled.value = isBypassEnabled
    }
    }


    override fun setFailedAuthenticationAttempts(failedAuthenticationAttempts: Int) {
    override suspend fun reportAuthenticationAttempt(isSuccessful: Boolean) {
        _failedAuthenticationAttempts.value = failedAuthenticationAttempts
        val selectedUserId = userRepository.selectedUserId
        withContext(backgroundDispatcher) {
            if (isSuccessful) {
                lockPatternUtils.reportSuccessfulPasswordAttempt(selectedUserId)
            } else {
                lockPatternUtils.reportFailedPasswordAttempt(selectedUserId)
            }
        }
    }

    override suspend fun getFailedAuthenticationAttemptCount(): Int {
        return withContext(backgroundDispatcher) {
            val selectedUserId = userRepository.selectedUserId
            lockPatternUtils.getCurrentFailedPasswordAttempts(selectedUserId)
        }
    }

    override suspend fun getThrottlingEndTimestamp(): Long {
        return withContext(backgroundDispatcher) {
            val selectedUserId = userRepository.selectedUserId
            lockPatternUtils.getLockoutAttemptDeadline(selectedUserId)
        }
    }

    override fun setThrottling(throttlingModel: AuthenticationThrottlingModel) {
        _throttling.value = throttlingModel
    }

    override suspend fun setThrottleDuration(durationMs: Int) {
        withContext(backgroundDispatcher) {
            lockPatternUtils.setLockoutAttemptDeadline(
                userRepository.selectedUserId,
                durationMs,
            )
        }
    }

    override suspend fun checkCredential(
        credential: LockscreenCredential
    ): AuthenticationResultModel {
        return suspendCoroutine { continuation ->
            LockPatternChecker.checkCredential(
                lockPatternUtils,
                credential,
                userRepository.selectedUserId,
                object : LockPatternChecker.OnCheckCallback {
                    override fun onChecked(matched: Boolean, throttleTimeoutMs: Int) {
                        continuation.resume(
                            AuthenticationResultModel(
                                isSuccessful = matched,
                                throttleDurationMs = throttleTimeoutMs,
                            )
                        )
                    }

                    override fun onCancelled() {
                        continuation.resume(AuthenticationResultModel(isSuccessful = false))
                    }

                    override fun onEarlyMatched() = Unit
                }
            )
        }
    }
    }
}
}


+165 −63

File changed.

Preview size limit exceeded, changes collapsed.

+3 −24
Original line number Original line Diff line number Diff line
@@ -16,8 +16,6 @@


package com.android.systemui.authentication.shared.model
package com.android.systemui.authentication.shared.model


import androidx.annotation.VisibleForTesting

/** Enumerates all known authentication methods. */
/** Enumerates all known authentication methods. */
sealed class AuthenticationMethodModel(
sealed class AuthenticationMethodModel(
    /**
    /**
@@ -34,30 +32,11 @@ sealed class AuthenticationMethodModel(
    /** The most basic authentication method. The lock screen can be swiped away when displayed. */
    /** The most basic authentication method. The lock screen can be swiped away when displayed. */
    object Swipe : AuthenticationMethodModel(isSecure = false)
    object Swipe : AuthenticationMethodModel(isSecure = false)


    /**
    object Pin : AuthenticationMethodModel(isSecure = true)
     * Authentication method using a PIN.
     *
     * In practice, a pin is restricted to 16 decimal digits , see
     * [android.app.admin.DevicePolicyManager.MAX_PASSWORD_LENGTH]
     */
    data class Pin(val code: List<Int>, val autoConfirm: Boolean) :
        AuthenticationMethodModel(isSecure = true) {

        /** Convenience constructor for tests only. */
        @VisibleForTesting
        constructor(
            code: Long,
            autoConfirm: Boolean = false
        ) : this(code.toString(10).map { it - '0' }, autoConfirm) {}
    }

    data class Password(val password: String) : AuthenticationMethodModel(isSecure = true)


    data class Pattern(
    object Password : AuthenticationMethodModel(isSecure = true)
        val coordinates: List<PatternCoordinate>,
        val isPatternVisible: Boolean = true,
    ) : AuthenticationMethodModel(isSecure = true) {


    object Pattern : AuthenticationMethodModel(isSecure = true) {
        data class PatternCoordinate(
        data class PatternCoordinate(
            val x: Int,
            val x: Int,
            val y: Int,
            val y: Int,
+25 −0
Original line number Original line Diff line number Diff line
/*
/*
 * Copyright (C) 2023 The Android Open Source Project
 * Copyright 2023 The Android Open Source Project
 *
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * you may not use this file except in compliance with the License.
@@ -14,17 +14,12 @@
 * limitations under the License.
 * limitations under the License.
 */
 */


package com.android.systemui.bouncer.shared.model
package com.android.systemui.authentication.shared.model


/**
/** Models the result of an authentication attempt. */
 * Models application state for when further authentication attempts are being throttled due to too
data class AuthenticationResultModel(
 * many consecutive failed authentication attempts.
    /** Whether authentication was successful. */
 */
    val isSuccessful: Boolean = false,
data class AuthenticationThrottledModel(
    /** If [isSuccessful] is `false`, how long the user must wait before trying again. */
    /** Total number of failed attempts so far. */
    val throttleDurationMs: Int = 0,
    val failedAttemptCount: Int,
    /** Total amount of time the user has to wait before attempting again. */
    val totalDurationSec: Int,
    /** Remaining amount of time the user has to wait before attempting again. */
    val remainingDurationSec: Int,
)
)
Loading