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

Commit 707c90cc authored by Beverly's avatar Beverly
Browse files

Use recommended architecture for keyguard dismissal

KeyguardDismissAction Interactor and Binder
 - Handles action to run when the keyguard dismisses

KeyguardDismiss Interactor and Binder
 - Handles sending the keyguardDone[Pending] signal
 when there's a request to dismiss the keyguard

Only runs if refactor_keyguard_dismiss_intent flag is enabled.
Currently doesn't trigger dismiss action when triggered when
there's an occluding activity since the KeyguardTransition
doesn't transition to GONE (b/278086361).

Test: manually test with security SWIPE, Fingerprint, Face, co-ex
Test: atest KeyguardDismissInteractorTest KeyguardDismissActionInteractorTest
Bug: 268240415
Change-Id: I0c631ea4df2a3b6610e9e98b5b65d3345cb99c24
parent a76fc627
Loading
Loading
Loading
Loading
+39 −21
Original line number Diff line number Diff line
@@ -17,7 +17,6 @@
package com.android.keyguard;

import static android.app.StatusBarManager.SESSION_KEYGUARD;

import static com.android.keyguard.KeyguardSecurityContainer.BOUNCER_DISMISS_BIOMETRIC;
import static com.android.keyguard.KeyguardSecurityContainer.BOUNCER_DISMISS_EXTENDED_ACCESS;
import static com.android.keyguard.KeyguardSecurityContainer.BOUNCER_DISMISS_NONE_SECURITY;
@@ -74,6 +73,7 @@ import com.android.systemui.biometrics.FaceAuthAccessibilityDelegate;
import com.android.systemui.biometrics.SideFpsController;
import com.android.systemui.biometrics.SideFpsUiRequestSource;
import com.android.systemui.bouncer.domain.interactor.BouncerMessageInteractor;
import com.android.systemui.bouncer.domain.interactor.PrimaryBouncerInteractor;
import com.android.systemui.classifier.FalsingA11yDelegate;
import com.android.systemui.classifier.FalsingCollector;
import com.android.systemui.flags.FeatureFlags;
@@ -94,6 +94,8 @@ import com.android.systemui.util.ViewController;
import com.android.systemui.util.kotlin.JavaAdapter;
import com.android.systemui.util.settings.GlobalSettings;

import dagger.Lazy;

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

@@ -201,7 +203,6 @@ public class KeyguardSecurityContainerController extends ViewController<Keyguard
    };

    private KeyguardSecurityCallback mKeyguardSecurityCallback = new KeyguardSecurityCallback() {

        @Override
        public void onUserInput() {
            mBouncerMessageInteractor.onPrimaryBouncerUserInput();
@@ -297,6 +298,7 @@ public class KeyguardSecurityContainerController extends ViewController<Keyguard
         */
        @Override
        public void finish(int targetUserId) {
            if (!mFeatureFlags.isEnabled(Flags.REFACTOR_KEYGUARD_DISMISS_INTENT)) {
                // If there's a pending runnable because the user interacted with a widget
                // and we're leaving keyguard, then run it.
                boolean deferKeyguardDone = false;
@@ -314,6 +316,7 @@ public class KeyguardSecurityContainerController extends ViewController<Keyguard
                        mViewMediatorCallback.keyguardDone(targetUserId);
                    }
                }
            }

            if (mFeatureFlags.isEnabled(Flags.KEYGUARD_WM_STATE_REFACTOR)) {
                mKeyguardTransitionInteractor.startDismissKeyguardTransition();
@@ -326,7 +329,6 @@ public class KeyguardSecurityContainerController extends ViewController<Keyguard
        }
    };


    private final SwipeListener mSwipeListener = new SwipeListener() {
        @Override
        public void onSwipeUp() {
@@ -416,6 +418,7 @@ public class KeyguardSecurityContainerController extends ViewController<Keyguard
    private final Provider<AuthenticationInteractor> mAuthenticationInteractor;
    private final Provider<JavaAdapter> mJavaAdapter;
    private final DeviceProvisionedController mDeviceProvisionedController;
    private final Lazy<PrimaryBouncerInteractor> mPrimaryBouncerInteractor;
    @Nullable private Job mSceneTransitionCollectionJob;

    @Inject
@@ -448,6 +451,7 @@ public class KeyguardSecurityContainerController extends ViewController<Keyguard
            DeviceProvisionedController deviceProvisionedController,
            FaceAuthAccessibilityDelegate faceAuthAccessibilityDelegate,
            KeyguardTransitionInteractor keyguardTransitionInteractor,
            Lazy<PrimaryBouncerInteractor> primaryBouncerInteractor,
            Provider<AuthenticationInteractor> authenticationInteractor
    ) {
        super(view);
@@ -482,6 +486,7 @@ public class KeyguardSecurityContainerController extends ViewController<Keyguard
        mJavaAdapter = javaAdapter;
        mKeyguardTransitionInteractor = keyguardTransitionInteractor;
        mDeviceProvisionedController = deviceProvisionedController;
        mPrimaryBouncerInteractor = primaryBouncerInteractor;
    }

    @Override
@@ -618,6 +623,9 @@ public class KeyguardSecurityContainerController extends ViewController<Keyguard
     * @param action callback to be invoked when keyguard disappear animation completes.
     */
    public void setOnDismissAction(ActivityStarter.OnDismissAction action, Runnable cancelAction) {
        if (mFeatureFlags.isEnabled(Flags.REFACTOR_KEYGUARD_DISMISS_INTENT)) {
            return;
        }
        if (mCancelAction != null) {
            mCancelAction.run();
        }
@@ -820,7 +828,6 @@ public class KeyguardSecurityContainerController extends ViewController<Keyguard
     */
    public boolean showNextSecurityScreenOrFinish(boolean authenticated, int targetUserId,
            boolean bypassSecondaryLockScreen, SecurityMode expectedSecurityMode) {

        if (DEBUG) Log.d(TAG, "showNextSecurityScreenOrFinish(" + authenticated + ")");
        if (expectedSecurityMode != SecurityMode.Invalid
                && expectedSecurityMode != getCurrentSecurityMode()) {
@@ -829,8 +836,8 @@ public class KeyguardSecurityContainerController extends ViewController<Keyguard
            return false;
        }

        boolean authenticatedWithPrimaryAuth = false;
        boolean finish = false;
        boolean primaryAuth = false;
        int eventSubtype = -1;
        BouncerUiEvent uiEvent = BouncerUiEvent.UNKNOWN;
        if (mUpdateMonitor.getUserHasTrust(targetUserId)) {
@@ -855,7 +862,7 @@ public class KeyguardSecurityContainerController extends ViewController<Keyguard
                case Pattern:
                case Password:
                case PIN:
                    primaryAuth = true;
                    authenticatedWithPrimaryAuth = true;
                    finish = true;
                    eventSubtype = BOUNCER_DISMISS_PASSWORD;
                    uiEvent = BouncerUiEvent.BOUNCER_DISMISS_PASSWORD;
@@ -901,6 +908,17 @@ public class KeyguardSecurityContainerController extends ViewController<Keyguard
        if (uiEvent != BouncerUiEvent.UNKNOWN) {
            mUiEventLogger.log(uiEvent, getSessionId());
        }

        if (mFeatureFlags.isEnabled(Flags.REFACTOR_KEYGUARD_DISMISS_INTENT)) {
            if (authenticatedWithPrimaryAuth) {
                mPrimaryBouncerInteractor.get()
                        .notifyKeyguardAuthenticatedPrimaryAuth(targetUserId);
            } else if (finish) {
                mPrimaryBouncerInteractor.get().notifyUserRequestedBouncerWhenAlreadyAuthenticated(
                        targetUserId);
            }
        }

        if (finish) {
            mKeyguardSecurityCallback.finish(targetUserId);
        }
+55 −8
Original line number Diff line number Diff line
@@ -28,8 +28,11 @@ import com.android.systemui.log.table.logDiffsForTable
import com.android.systemui.util.time.SystemClock
import javax.inject.Inject
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.MutableSharedFlow
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.asSharedFlow
import kotlinx.coroutines.flow.asStateFlow
import kotlinx.coroutines.flow.filterNotNull
import kotlinx.coroutines.flow.launchIn
@@ -47,8 +50,10 @@ interface KeyguardBouncerRepository {
    val primaryBouncerShowingSoon: StateFlow<Boolean>
    val primaryBouncerStartingToHide: StateFlow<Boolean>
    val primaryBouncerStartingDisappearAnimation: StateFlow<Runnable?>

    /** Determines if we want to instantaneously show the primary bouncer instead of translating. */
    val primaryBouncerScrimmed: StateFlow<Boolean>

    /**
     * Set how much of the notification panel is showing on the screen.
     *
@@ -60,8 +65,23 @@ interface KeyguardBouncerRepository {
    val panelExpansionAmount: StateFlow<Float>
    val keyguardPosition: StateFlow<Float?>
    val isBackButtonEnabled: StateFlow<Boolean?>
    /** Determines if user is already unlocked */
    val keyguardAuthenticated: StateFlow<Boolean?>

    /**
     * Triggers when the user has successfully used biometrics to authenticate. True = biometrics
     * used to authenticate is Class 3, else false. When null, biometrics haven't authenticated the
     * device.
     */
    val keyguardAuthenticatedBiometrics: StateFlow<Boolean?>

    /**
     * Triggers when the given userId (Int) has successfully used primary authentication to
     * authenticate
     */
    val keyguardAuthenticatedPrimaryAuth: Flow<Int>

    /** Triggers when the given userId (Int) has requested the bouncer when already authenticated */
    val userRequestedBouncerWhenAlreadyAuthenticated: Flow<Int>

    val showMessage: StateFlow<BouncerShowMessageModel?>
    val resourceUpdateRequests: StateFlow<Boolean>
    val alternateBouncerVisible: StateFlow<Boolean>
@@ -88,7 +108,11 @@ interface KeyguardBouncerRepository {

    fun setShowMessage(bouncerShowMessageModel: BouncerShowMessageModel?)

    fun setKeyguardAuthenticated(keyguardAuthenticated: Boolean?)
    fun setKeyguardAuthenticatedBiometrics(keyguardAuthenticatedBiometrics: Boolean?)

    suspend fun setKeyguardAuthenticatedPrimaryAuth(userId: Int)

    suspend fun setUserRequestedBouncerWhenAlreadyAuthenticated(userId: Int)

    fun setIsBackButtonEnabled(isBackButtonEnabled: Boolean)

@@ -117,9 +141,11 @@ constructor(
    private val _primaryBouncerDisappearAnimation = MutableStateFlow<Runnable?>(null)
    override val primaryBouncerStartingDisappearAnimation =
        _primaryBouncerDisappearAnimation.asStateFlow()

    /** Determines if we want to instantaneously show the primary bouncer instead of translating. */
    private val _primaryBouncerScrimmed = MutableStateFlow(false)
    override val primaryBouncerScrimmed = _primaryBouncerScrimmed.asStateFlow()

    /**
     * Set how much of the notification panel is showing on the screen.
     *
@@ -134,13 +160,26 @@ constructor(
    override val keyguardPosition = _keyguardPosition.asStateFlow()
    private val _isBackButtonEnabled = MutableStateFlow<Boolean?>(null)
    override val isBackButtonEnabled = _isBackButtonEnabled.asStateFlow()
    private val _keyguardAuthenticated = MutableStateFlow<Boolean?>(null)
    /** Determines if user is already unlocked */
    override val keyguardAuthenticated = _keyguardAuthenticated.asStateFlow()

    /** Whether the user is already unlocked by biometrics */
    private val _keyguardAuthenticatedBiometrics = MutableStateFlow<Boolean?>(null)
    override val keyguardAuthenticatedBiometrics = _keyguardAuthenticatedBiometrics.asStateFlow()

    /** Whether the user is unlocked via a primary authentication method (pin/pattern/password). */
    private val _keyguardAuthenticatedPrimaryAuth = MutableSharedFlow<Int>()
    override val keyguardAuthenticatedPrimaryAuth: Flow<Int> =
        _keyguardAuthenticatedPrimaryAuth.asSharedFlow()

    /** Whether the user requested to show the bouncer when device is already authenticated */
    private val _userRequestedBouncerWhenAlreadyAuthenticated = MutableSharedFlow<Int>()
    override val userRequestedBouncerWhenAlreadyAuthenticated: Flow<Int> =
        _userRequestedBouncerWhenAlreadyAuthenticated.asSharedFlow()

    private val _showMessage = MutableStateFlow<BouncerShowMessageModel?>(null)
    override val showMessage = _showMessage.asStateFlow()
    private val _resourceUpdateRequests = MutableStateFlow(false)
    override val resourceUpdateRequests = _resourceUpdateRequests.asStateFlow()

    /** Values associated with the AlternateBouncer */
    private val _alternateBouncerVisible = MutableStateFlow(false)
    override val alternateBouncerVisible = _alternateBouncerVisible.asStateFlow()
@@ -204,8 +243,16 @@ constructor(
        _showMessage.value = bouncerShowMessageModel
    }

    override fun setKeyguardAuthenticated(keyguardAuthenticated: Boolean?) {
        _keyguardAuthenticated.value = keyguardAuthenticated
    override fun setKeyguardAuthenticatedBiometrics(keyguardAuthenticatedBiometrics: Boolean?) {
        _keyguardAuthenticatedBiometrics.value = keyguardAuthenticatedBiometrics
    }

    override suspend fun setKeyguardAuthenticatedPrimaryAuth(userId: Int) {
        _keyguardAuthenticatedPrimaryAuth.emit(userId)
    }

    override suspend fun setUserRequestedBouncerWhenAlreadyAuthenticated(userId: Int) {
        _userRequestedBouncerWhenAlreadyAuthenticated.emit(userId)
    }

    override fun setIsBackButtonEnabled(isBackButtonEnabled: Boolean) {
+23 −7
Original line number Diff line number Diff line
@@ -79,14 +79,18 @@ constructor(
) {
    private val passiveAuthBouncerDelay =
        context.resources.getInteger(R.integer.primary_bouncer_passive_auth_delay).toLong()

    /** Runnable to show the primary bouncer. */
    val showRunnable = Runnable {
        repository.setPrimaryShow(true)
        repository.setPrimaryShowingSoon(false)
        primaryBouncerCallbackInteractor.dispatchVisibilityChanged(View.VISIBLE)
    }

    val keyguardAuthenticated: Flow<Boolean> = repository.keyguardAuthenticated.filterNotNull()
    val keyguardAuthenticatedPrimaryAuth: Flow<Int> = repository.keyguardAuthenticatedPrimaryAuth
    val keyguardAuthenticatedBiometrics: Flow<Boolean> =
        repository.keyguardAuthenticatedBiometrics.filterNotNull()
    val userRequestedBouncerWhenAlreadyAuthenticated: Flow<Int> =
        repository.userRequestedBouncerWhenAlreadyAuthenticated.filterNotNull()
    val isShowing: StateFlow<Boolean> = repository.primaryBouncerShow
    val startingToHide: Flow<Unit> = repository.primaryBouncerStartingToHide.filter { it }.map {}
    val isBackButtonEnabled: Flow<Boolean> = repository.isBackButtonEnabled.filterNotNull()
@@ -96,6 +100,7 @@ constructor(
    val resourceUpdateRequests: Flow<Boolean> = repository.resourceUpdateRequests.filter { it }
    val keyguardPosition: Flow<Float> = repository.keyguardPosition.filterNotNull()
    val panelExpansionAmount: Flow<Float> = repository.panelExpansionAmount

    /** 0f = bouncer fully hidden. 1f = bouncer fully visible. */
    val bouncerExpansion: Flow<Float> =
        combine(repository.panelExpansionAmount, repository.primaryBouncerShow) {
@@ -107,6 +112,7 @@ constructor(
                0f
            }
        }

    /** Allow for interaction when just about fully visible */
    val isInteractable: Flow<Boolean> = bouncerExpansion.map { it > 0.9 }
    val sideFpsShowing: Flow<Boolean> = repository.sideFpsShowing
@@ -144,7 +150,7 @@ constructor(
    @JvmOverloads
    fun show(isScrimmed: Boolean) {
        // Reset some states as we show the bouncer.
        repository.setKeyguardAuthenticated(null)
        repository.setKeyguardAuthenticatedBiometrics(null)
        repository.setPrimaryStartingToHide(false)

        val resumeBouncer =
@@ -268,9 +274,19 @@ constructor(
        repository.setResourceUpdateRequests(true)
    }

    /** Tell the bouncer that keyguard is authenticated. */
    fun notifyKeyguardAuthenticated(strongAuth: Boolean) {
        repository.setKeyguardAuthenticated(strongAuth)
    /** Tell the bouncer that keyguard is authenticated with primary authentication. */
    fun notifyKeyguardAuthenticatedPrimaryAuth(userId: Int) {
        applicationScope.launch { repository.setKeyguardAuthenticatedPrimaryAuth(userId) }
    }

    /** Tell the bouncer that bouncer is requested when device is already authenticated */
    fun notifyUserRequestedBouncerWhenAlreadyAuthenticated(userId: Int) {
        applicationScope.launch { repository.setKeyguardAuthenticatedPrimaryAuth(userId) }
    }

    /** Tell the bouncer that keyguard is authenticated with biometrics. */
    fun notifyKeyguardAuthenticatedBiometrics(strongAuth: Boolean) {
        repository.setKeyguardAuthenticatedBiometrics(strongAuth)
    }

    /** Update the position of the bouncer when showing. */
@@ -280,7 +296,7 @@ constructor(

    /** Notifies that the state change was handled. */
    fun notifyKeyguardAuthenticatedHandled() {
        repository.setKeyguardAuthenticated(null)
        repository.setKeyguardAuthenticatedBiometrics(null)
    }

    /** Notifies that the message was shown. */
+1 −1
Original line number Diff line number Diff line
@@ -59,7 +59,7 @@ constructor(
    val bouncerShowMessage: Flow<BouncerShowMessageModel> = interactor.showMessage

    /** Observe whether keyguard is authenticated already. */
    val keyguardAuthenticated: Flow<Boolean> = interactor.keyguardAuthenticated
    val keyguardAuthenticated: Flow<Boolean> = interactor.keyguardAuthenticatedBiometrics

    /** Observe whether the side fps is showing. */
    val sideFpsShowing: Flow<Boolean> = interactor.sideFpsShowing
+21 −7
Original line number Diff line number Diff line
@@ -34,9 +34,11 @@ import com.android.systemui.dreams.DreamMonitor
import com.android.systemui.globalactions.GlobalActionsComponent
import com.android.systemui.keyboard.KeyboardUI
import com.android.systemui.keyboard.PhysicalKeyboardCoreStartable
import com.android.systemui.keyguard.KeyguardViewMediator
import com.android.systemui.keyguard.KeyguardViewConfigurator
import com.android.systemui.keyguard.KeyguardViewMediator
import com.android.systemui.keyguard.data.quickaffordance.MuteQuickAffordanceCoreStartable
import com.android.systemui.keyguard.ui.binder.KeyguardDismissActionBinder
import com.android.systemui.keyguard.ui.binder.KeyguardDismissBinder
import com.android.systemui.log.SessionTracker
import com.android.systemui.media.RingtonePlayer
import com.android.systemui.media.dialog.MediaOutputSwitcherDialogUI
@@ -74,12 +76,14 @@ import dagger.multibindings.IntoMap
/**
 * Collection of {@link CoreStartable}s that should be run on AOSP.
 */
@Module(includes = [
@Module(
    includes = [
        MultiUserUtilsModule::class,
        StartControlsStartableModule::class,
        StartBinderLoggerModule::class,
        WallpaperModule::class,
])
    ]
)
abstract class SystemUICoreStartableModule {
    /** Inject into AuthController.  */
    @Binds
@@ -352,4 +356,14 @@ abstract class SystemUICoreStartableModule {
    @IntoMap
    @ClassKey(BackActionInteractor::class)
    abstract fun bindBackActionInteractor(impl: BackActionInteractor): CoreStartable

    @Binds
    @IntoMap
    @ClassKey(KeyguardDismissActionBinder::class)
    abstract fun bindKeyguardDismissActionBinder(impl: KeyguardDismissActionBinder): CoreStartable

    @Binds
    @IntoMap
    @ClassKey(KeyguardDismissBinder::class)
    abstract fun bindKeyguardDismissBinder(impl: KeyguardDismissBinder): CoreStartable
}
Loading