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

Commit fd49807d authored by Chandru S's avatar Chandru S Committed by Android (Google) Code Review
Browse files

Merge changes from topics "device-entry-interactor", "make-bouncer-reusable" into main

* changes:
  Remove sceneInteractor and deviceEntry dependencies from BouncerInteractor and AuthenticationInteractor
  Move device unlock initiation to DeviceEntryInteractor
parents d0842b2e 6235bfc6
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -25,7 +25,7 @@ import com.android.internal.logging.nano.MetricsProto
import com.android.internal.logging.testing.FakeMetricsLogger
import com.android.internal.util.EmergencyAffordanceManager
import com.android.systemui.SysuiTestCase
import com.android.systemui.authentication.data.model.AuthenticationMethodModel
import com.android.systemui.authentication.shared.model.AuthenticationMethodModel
import com.android.systemui.coroutines.collectLastValue
import com.android.systemui.flags.Flags.REFACTOR_GETCURRENTUSER
import com.android.systemui.log.table.TableLogBuffer
+5 −5
Original line number Diff line number Diff line
@@ -60,10 +60,10 @@ import com.android.systemui.biometrics.AuthController;
import com.android.systemui.biometrics.AuthRippleController;
import com.android.systemui.biometrics.UdfpsController;
import com.android.systemui.biometrics.shared.model.UdfpsOverlayParams;
import com.android.systemui.bouncer.domain.interactor.BouncerInteractor;
import com.android.systemui.bouncer.domain.interactor.PrimaryBouncerInteractor;
import com.android.systemui.dagger.SysUISingleton;
import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.deviceentry.domain.interactor.DeviceEntryInteractor;
import com.android.systemui.dump.DumpManager;
import com.android.systemui.flags.FeatureFlags;
import com.android.systemui.flags.Flags;
@@ -127,7 +127,7 @@ public class LockIconViewController implements Dumpable {
    @NonNull private final KeyguardTransitionInteractor mTransitionInteractor;
    @NonNull private final KeyguardInteractor mKeyguardInteractor;
    @NonNull private final View.AccessibilityDelegate mAccessibilityDelegate;
    @NonNull private final Lazy<BouncerInteractor> mBouncerInteractor;
    @NonNull private final Lazy<DeviceEntryInteractor> mDeviceEntryInteractor;
    @NonNull private final SceneContainerFlags mSceneContainerFlags;

    // Tracks the velocity of a touch to help filter out the touches that move too fast.
@@ -205,7 +205,7 @@ public class LockIconViewController implements Dumpable {
            @NonNull FeatureFlags featureFlags,
            PrimaryBouncerInteractor primaryBouncerInteractor,
            Context context,
            Lazy<BouncerInteractor> bouncerInteractor,
            Lazy<DeviceEntryInteractor> deviceEntryInteractor,
            SceneContainerFlags sceneContainerFlags
    ) {
        mStatusBarStateController = statusBarStateController;
@@ -232,7 +232,7 @@ public class LockIconViewController implements Dumpable {
        dumpManager.registerDumpable(TAG, this);
        mResources = resources;
        mContext = context;
        mBouncerInteractor = bouncerInteractor;
        mDeviceEntryInteractor = deviceEntryInteractor;
        mSceneContainerFlags = sceneContainerFlags;

        mAccessibilityDelegate = new View.AccessibilityDelegate() {
@@ -747,7 +747,7 @@ public class LockIconViewController implements Dumpable {
        vibrateOnLongPress();

        if (mSceneContainerFlags.isEnabled()) {
            mBouncerInteractor.get().showOrUnlockDevice(null);
            mDeviceEntryInteractor.get().attemptDeviceEntry();
        } else {
            mKeyguardViewController.showPrimaryBouncer(/* scrim */ true);
        }
+11 −1
Original line number Diff line number Diff line
@@ -25,7 +25,7 @@ import com.android.internal.widget.LockPatternChecker
import com.android.internal.widget.LockPatternUtils
import com.android.internal.widget.LockscreenCredential
import com.android.keyguard.KeyguardSecurityModel
import com.android.systemui.authentication.data.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.broadcast.BroadcastDispatcher
@@ -45,7 +45,9 @@ import kotlinx.coroutines.CoroutineDispatcher
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.MutableSharedFlow
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.SharedFlow
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.asStateFlow
import kotlinx.coroutines.flow.combine
@@ -67,6 +69,12 @@ interface AuthenticationRepository {
     */
    val isAutoConfirmFeatureEnabled: StateFlow<Boolean>

    /**
     * Emits the result whenever a PIN/Pattern/Password security challenge is attempted by the user
     * in order to unlock the device.
     */
    val authenticationChallengeResult: SharedFlow<Boolean>

    /**
     * The exact length a PIN should be for us to enable PIN length hinting.
     *
@@ -164,6 +172,7 @@ constructor(
            initialValue = false,
            getFreshValue = lockPatternUtils::isAutoPinConfirmEnabled,
        )
    override val authenticationChallengeResult = MutableSharedFlow<Boolean>()

    override val hintedPinLength: Int = 6

@@ -224,6 +233,7 @@ constructor(
            } else {
                lockPatternUtils.reportFailedPasswordAttempt(selectedUserId)
            }
            authenticationChallengeResult.emit(isSuccessful)
        }
    }

+17 −41
Original line number Diff line number Diff line
@@ -16,19 +16,16 @@

package com.android.systemui.authentication.domain.interactor

import com.android.app.tracing.TraceUtils.Companion.async
import com.android.app.tracing.TraceUtils.Companion.withContext
import com.android.internal.widget.LockPatternView
import com.android.internal.widget.LockscreenCredential
import com.android.systemui.authentication.data.model.AuthenticationMethodModel as DataLayerAuthenticationMethodModel
import com.android.systemui.authentication.data.repository.AuthenticationRepository
import com.android.systemui.authentication.domain.model.AuthenticationMethodModel as DomainLayerAuthenticationMethodModel
import com.android.systemui.authentication.shared.model.AuthenticationMethodModel
import com.android.systemui.authentication.shared.model.AuthenticationPatternCoordinate
import com.android.systemui.authentication.shared.model.AuthenticationThrottlingModel
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Application
import com.android.systemui.dagger.qualifiers.Background
import com.android.systemui.deviceentry.data.repository.DeviceEntryRepository
import com.android.systemui.user.data.repository.UserRepository
import com.android.systemui.util.time.SystemClock
import javax.inject.Inject
@@ -40,6 +37,7 @@ import kotlinx.coroutines.Job
import kotlinx.coroutines.async
import kotlinx.coroutines.delay
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.SharedFlow
import kotlinx.coroutines.flow.SharingStarted
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.combine
@@ -47,7 +45,6 @@ import kotlinx.coroutines.flow.distinctUntilChanged
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.stateIn
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext

/**
 * Hosts application business logic related to user authentication.
@@ -64,7 +61,6 @@ constructor(
    private val repository: AuthenticationRepository,
    @Background private val backgroundDispatcher: CoroutineDispatcher,
    private val userRepository: UserRepository,
    private val deviceEntryRepository: DeviceEntryRepository,
    private val clock: SystemClock,
) {
    /**
@@ -85,8 +81,7 @@ constructor(
     * `true` even when the lockscreen is showing and still needs to be dismissed by the user to
     * proceed.
     */
    val authenticationMethod: Flow<DomainLayerAuthenticationMethodModel> =
        repository.authenticationMethod.map { rawModel -> rawModel.toDomainLayer() }
    val authenticationMethod: Flow<AuthenticationMethodModel> = repository.authenticationMethod

    /** The current authentication throttling state, only meaningful if [isThrottled] is `true`. */
    val throttling: StateFlow<AuthenticationThrottlingModel> = repository.throttling
@@ -143,6 +138,13 @@ constructor(
    /** Whether the pattern should be visible for the currently-selected user. */
    val isPatternVisible: StateFlow<Boolean> = repository.isPatternVisible

    /**
     * Emits the outcome (successful or unsuccessful) whenever a PIN/Pattern/Password security
     * challenge is attempted by the user in order to unlock the device.
     */
    val authenticationChallengeResult: SharedFlow<Boolean> =
        repository.authenticationChallengeResult

    private var throttlingCountdownJob: Job? = null

    init {
@@ -165,17 +167,8 @@ constructor(
     * The flow should be used for code that wishes to stay up-to-date its logic as the
     * authentication changes over time and this method should be used for simple code that only
     * needs to check the current value.
     *
     * Note: this layer adds the synthetic authentication method of "swipe" which is special. When
     * the current authentication method is "swipe", the user does not need to complete any
     * authentication challenge to unlock the device; they just need to dismiss the lockscreen to
     * get past it. This also means that the value of `DeviceEntryInteractor#isUnlocked` remains
     * `true` even when the lockscreen is showing and still needs to be dismissed by the user to
     * proceed.
     */
    suspend fun getAuthenticationMethod(): DomainLayerAuthenticationMethodModel {
        return repository.getAuthenticationMethod().toDomainLayer()
    }
    suspend fun getAuthenticationMethod() = repository.getAuthenticationMethod()

    /**
     * Attempts to authenticate the user and unlock the device.
@@ -205,13 +198,13 @@ constructor(
                // attempt.
                isThrottled.value -> true
                // The pattern is too short; skip the attempt.
                authMethod == DomainLayerAuthenticationMethodModel.Pattern &&
                authMethod == AuthenticationMethodModel.Pattern &&
                    input.size < repository.minPatternLength -> true
                // Auto-confirm attempt when the feature is not enabled; skip the attempt.
                tryAutoConfirm && !isAutoConfirmEnabled.value -> true
                // Auto-confirm should skip the attempt if the pin entered is too short.
                tryAutoConfirm &&
                    authMethod == DomainLayerAuthenticationMethodModel.Pin &&
                    authMethod == AuthenticationMethodModel.Pin &&
                    input.size < repository.getPinLength() -> true
                else -> false
            }
@@ -297,15 +290,15 @@ constructor(
        }
    }

    private fun DomainLayerAuthenticationMethodModel.createCredential(
    private fun AuthenticationMethodModel.createCredential(
        input: List<Any>
    ): LockscreenCredential? {
        return when (this) {
            is DomainLayerAuthenticationMethodModel.Pin ->
            is AuthenticationMethodModel.Pin ->
                LockscreenCredential.createPin(input.joinToString(""))
            is DomainLayerAuthenticationMethodModel.Password ->
            is AuthenticationMethodModel.Password ->
                LockscreenCredential.createPassword(input.joinToString(""))
            is DomainLayerAuthenticationMethodModel.Pattern ->
            is AuthenticationMethodModel.Pattern ->
                LockscreenCredential.createPattern(
                    input
                        .map { it as AuthenticationPatternCoordinate }
@@ -315,23 +308,6 @@ constructor(
        }
    }

    private suspend fun DataLayerAuthenticationMethodModel.toDomainLayer():
        DomainLayerAuthenticationMethodModel {
        return when (this) {
            is DataLayerAuthenticationMethodModel.None ->
                if (deviceEntryRepository.isInsecureLockscreenEnabled()) {
                    DomainLayerAuthenticationMethodModel.Swipe
                } else {
                    DomainLayerAuthenticationMethodModel.None
                }
            is DataLayerAuthenticationMethodModel.Pin -> DomainLayerAuthenticationMethodModel.Pin
            is DataLayerAuthenticationMethodModel.Password ->
                DomainLayerAuthenticationMethodModel.Password
            is DataLayerAuthenticationMethodModel.Pattern ->
                DomainLayerAuthenticationMethodModel.Pattern
        }
    }

    companion object {
        const val TAG = "AuthenticationInteractor"
    }
+0 −40
Original line number Diff line number Diff line
/*
 * Copyright (C) 2023 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.android.systemui.authentication.domain.model

/** Enumerates all known authentication methods. */
sealed class AuthenticationMethodModel(
    /**
     * Whether the authentication method is considered to be "secure".
     *
     * "Secure" authentication methods require authentication to unlock the device. Non-secure auth
     * methods simply require user dismissal.
     */
    open val isSecure: Boolean,
) {
    /** There is no authentication method on the device. We shouldn't even show the lock screen. */
    object None : AuthenticationMethodModel(isSecure = false)

    /** The most basic authentication method. The lock screen can be swiped away when displayed. */
    object Swipe : AuthenticationMethodModel(isSecure = false)

    object Pin : AuthenticationMethodModel(isSecure = true)

    object Password : AuthenticationMethodModel(isSecure = true)

    object Pattern : AuthenticationMethodModel(isSecure = true)
}
Loading