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

Commit 27cb2531 authored by Chandru S's avatar Chandru S
Browse files

Move device unlock initiation to DeviceEntryInteractor

Scene transitions from bouncer are managed by DeviceEntryInteractor instead of the BouncerInteractor

Bug: 310005730
Test: all affected unit tests
Flag: ACONFIG com.android.systemui.scene_container DEVELOPMENT

Change-Id: Ia3beab0f183eec06289f15f75c91a67a51087b7e
parent a4ee0ad0
Loading
Loading
Loading
Loading
+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);
        }
+10 −0
Original line number Diff line number Diff line
@@ -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)
        }
    }

+8 −2
Original line number Diff line number Diff line
@@ -16,7 +16,6 @@

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
@@ -40,6 +39,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 +47,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.
@@ -143,6 +142,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 {
+5 −39
Original line number Diff line number Diff line
@@ -26,7 +26,6 @@ import com.android.systemui.classifier.FalsingClassifier
import com.android.systemui.classifier.domain.interactor.FalsingInteractor
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Application
import com.android.systemui.deviceentry.domain.interactor.DeviceEntryInteractor
import com.android.systemui.res.R
import com.android.systemui.scene.domain.interactor.SceneInteractor
import com.android.systemui.scene.shared.flag.SceneContainerFlags
@@ -51,7 +50,6 @@ constructor(
    @Application private val applicationScope: CoroutineScope,
    @Application private val applicationContext: Context,
    private val repository: BouncerRepository,
    private val deviceEntryInteractor: DeviceEntryInteractor,
    private val authenticationInteractor: AuthenticationInteractor,
    private val sceneInteractor: SceneInteractor,
    flags: SceneContainerFlags,
@@ -141,32 +139,6 @@ constructor(
        )
    }

    /**
     * Either shows the bouncer or unlocks the device, if the bouncer doesn't need to be shown.
     *
     * @param message An optional message to show to the user in the bouncer.
     */
    fun showOrUnlockDevice(
        message: String? = null,
    ) {
        applicationScope.launch {
            if (deviceEntryInteractor.isAuthenticationRequired()) {
                repository.setMessage(
                    message ?: promptMessage(authenticationInteractor.getAuthenticationMethod())
                )
                sceneInteractor.changeScene(
                    scene = SceneModel(SceneKey.Bouncer),
                    loggingReason = "request to unlock device while authentication required",
                )
            } else {
                sceneInteractor.changeScene(
                    scene = SceneModel(SceneKey.Gone),
                    loggingReason = "request to unlock device while authentication isn't required",
                )
            }
        }
    }

    /**
     * Resets the user-facing message back to the default according to the current authentication
     * method.
@@ -212,17 +184,11 @@ constructor(
        return applicationScope
            .async {
                val authResult = authenticationInteractor.authenticate(input, tryAutoConfirm)
                when (authResult) {
                    // Authentication succeeded.
                    AuthenticationResult.SUCCEEDED ->
                        sceneInteractor.changeScene(
                            scene = SceneModel(SceneKey.Gone),
                            loggingReason = "successful authentication",
                        )
                    // Authentication failed.
                    AuthenticationResult.FAILED -> showErrorMessage()
                    // Authentication skipped.
                    AuthenticationResult.SKIPPED -> if (!tryAutoConfirm) showErrorMessage()
                if (
                    authResult == AuthenticationResult.FAILED ||
                        (authResult == AuthenticationResult.SKIPPED && !tryAutoConfirm)
                ) {
                    showErrorMessage()
                }
                authResult
            }
+18 −1
Original line number Diff line number Diff line
package com.android.systemui.deviceentry.data.repository

import android.util.Log
import com.android.internal.widget.LockPatternUtils
import com.android.systemui.common.coroutine.ChannelExt.trySendWithFailureLogging
import com.android.systemui.common.coroutine.ConflatedCallbackFlow.conflatedCallbackFlow
@@ -15,9 +16,12 @@ import javax.inject.Inject
import kotlinx.coroutines.CoroutineDispatcher
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.channels.awaitClose
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.SharingStarted
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.asStateFlow
import kotlinx.coroutines.flow.distinctUntilChanged
import kotlinx.coroutines.flow.onEach
import kotlinx.coroutines.flow.stateIn
import kotlinx.coroutines.withContext

@@ -40,6 +44,9 @@ interface DeviceEntryRepository {
     */
    suspend fun isInsecureLockscreenEnabled(): Boolean

    /** Report successful authentication for device entry. */
    fun reportSuccessfulAuthentication()

    /**
     * Whether lockscreen bypass is enabled. When enabled, the lockscreen will be automatically
     * dismissed once the authentication challenge is completed.
@@ -67,7 +74,9 @@ constructor(
    keyguardStateController: KeyguardStateController,
) : DeviceEntryRepository {

    override val isUnlocked =
    private val _isUnlocked = MutableStateFlow(false)

    private val isUnlockedReportedByLegacyKeyguard =
        conflatedCallbackFlow {
                val callback =
                    object : KeyguardStateController.Callback {
@@ -99,12 +108,15 @@ constructor(
                awaitClose { keyguardStateController.removeCallback(callback) }
            }
            .distinctUntilChanged()
            .onEach { _isUnlocked.value = it }
            .stateIn(
                applicationScope,
                SharingStarted.Eagerly,
                initialValue = false,
            )

    override val isUnlocked: StateFlow<Boolean> = _isUnlocked.asStateFlow()

    override suspend fun isInsecureLockscreenEnabled(): Boolean {
        return withContext(backgroundDispatcher) {
            val selectedUserId = userRepository.getSelectedUserInfo().id
@@ -112,6 +124,11 @@ constructor(
        }
    }

    override fun reportSuccessfulAuthentication() {
        Log.d(TAG, "Successful authentication reported.")
        _isUnlocked.value = true
    }

    override val isBypassEnabled: StateFlow<Boolean> =
        conflatedCallbackFlow {
                val listener =
Loading