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

Commit e40f3736 authored by Beverly's avatar Beverly
Browse files

Resolve race condition when requesting bouncer from AOD/dozing

Don't allow showing the alterate bouncer if transitioning to
or from aod/dozing.

Flag: ACONFIG com.android.systemui.device_entry_udfps_refactor TEAMFOOD
Test: atest AlternateBouncerInteractorTest
Bug: 329642162
Change-Id: I3e8611cac529cffce3a52fa3cac7c87f1bc09f92
parent 7d796f4f
Loading
Loading
Loading
Loading
+6 −0
Original line number Diff line number Diff line
@@ -60,9 +60,12 @@ import com.android.systemui.biometrics.domain.interactor.DisplayStateInteractor
import com.android.systemui.biometrics.domain.interactor.DisplayStateInteractorImpl
import com.android.systemui.bouncer.data.repository.FakeKeyguardBouncerRepository
import com.android.systemui.bouncer.domain.interactor.AlternateBouncerInteractor
import com.android.systemui.deviceentry.domain.interactor.DeviceEntryFingerprintAuthInteractor
import com.android.systemui.display.data.repository.FakeDisplayRepository
import com.android.systemui.dump.DumpManager
import com.android.systemui.keyguard.data.repository.FakeBiometricSettingsRepository
import com.android.systemui.keyguard.domain.interactor.KeyguardInteractor
import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor
import com.android.systemui.plugins.statusbar.StatusBarStateController
import com.android.systemui.res.R
import com.android.systemui.shared.Flags.FLAG_SIDEFPS_CONTROLLER_REFACTOR
@@ -158,6 +161,9 @@ class SideFpsControllerTest : SysuiTestCase() {
                FakeBiometricSettingsRepository(),
                FakeSystemClock(),
                mock(KeyguardUpdateMonitor::class.java),
                { mock(DeviceEntryFingerprintAuthInteractor::class.java) },
                { mock(KeyguardInteractor::class.java) },
                { mock(KeyguardTransitionInteractor::class.java) },
                testScope.backgroundScope,
            )
        displayStateInteractor =
+14 −0
Original line number Diff line number Diff line
@@ -24,14 +24,18 @@ import com.android.systemui.SysuiTestCase
import com.android.systemui.biometrics.data.repository.FakeFingerprintPropertyRepository
import com.android.systemui.bouncer.data.repository.KeyguardBouncerRepository
import com.android.systemui.bouncer.data.repository.KeyguardBouncerRepositoryImpl
import com.android.systemui.deviceentry.domain.interactor.DeviceEntryFingerprintAuthInteractor
import com.android.systemui.deviceentry.shared.DeviceEntryUdfpsRefactor
import com.android.systemui.keyguard.data.repository.FakeBiometricSettingsRepository
import com.android.systemui.keyguard.domain.interactor.KeyguardInteractor
import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor
import com.android.systemui.log.table.TableLogBuffer
import com.android.systemui.plugins.statusbar.StatusBarStateController
import com.android.systemui.statusbar.policy.KeyguardStateController
import com.android.systemui.util.mockito.whenever
import com.android.systemui.util.time.FakeSystemClock
import com.android.systemui.util.time.SystemClock
import dagger.Lazy
import kotlinx.coroutines.test.TestScope
import org.junit.Assert.assertFalse
import org.junit.Assert.assertTrue
@@ -39,6 +43,7 @@ import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
import org.mockito.Mock
import org.mockito.Mockito.mock
import org.mockito.MockitoAnnotations

@SmallTest
@@ -81,10 +86,19 @@ class AlternateBouncerInteractorTest : SysuiTestCase() {
                biometricSettingsRepository,
                systemClock,
                keyguardUpdateMonitor,
                Lazy { mock(DeviceEntryFingerprintAuthInteractor::class.java) },
                Lazy { mock(KeyguardInteractor::class.java) },
                Lazy { mock(KeyguardTransitionInteractor::class.java) },
                TestScope().backgroundScope,
            )
    }

    @Test(expected = IllegalStateException::class)
    fun enableUdfpsRefactor_deprecatedShowMethod_throwsIllegalStateException() {
        mSetFlagsRule.enableFlags(Flags.FLAG_DEVICE_ENTRY_UDFPS_REFACTOR)
        underTest.show()
    }

    @Test
    fun canShowAlternateBouncerForFingerprint_givenCanShow() {
        givenCanShowAlternateBouncer()
+84 −0
Original line number Diff line number Diff line
@@ -21,16 +21,27 @@ import com.android.systemui.biometrics.data.repository.FingerprintPropertyReposi
import com.android.systemui.bouncer.data.repository.KeyguardBouncerRepository
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Application
import com.android.systemui.deviceentry.domain.interactor.DeviceEntryFingerprintAuthInteractor
import com.android.systemui.deviceentry.shared.DeviceEntryUdfpsRefactor
import com.android.systemui.keyguard.data.repository.BiometricSettingsRepository
import com.android.systemui.keyguard.domain.interactor.KeyguardInteractor
import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor
import com.android.systemui.keyguard.shared.model.KeyguardState
import com.android.systemui.keyguard.shared.model.TransitionState
import com.android.systemui.plugins.statusbar.StatusBarStateController
import com.android.systemui.statusbar.policy.KeyguardStateController
import com.android.systemui.util.time.SystemClock
import dagger.Lazy
import javax.inject.Inject
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.SharingStarted
import kotlinx.coroutines.flow.SharingStarted.Companion.WhileSubscribed
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.map
import kotlinx.coroutines.flow.stateIn

@@ -46,6 +57,9 @@ constructor(
    private val biometricSettingsRepository: BiometricSettingsRepository,
    private val systemClock: SystemClock,
    private val keyguardUpdateMonitor: KeyguardUpdateMonitor,
    private val deviceEntryFingerprintAuthInteractor: Lazy<DeviceEntryFingerprintAuthInteractor>,
    private val keyguardInteractor: Lazy<KeyguardInteractor>,
    keyguardTransitionInteractor: Lazy<KeyguardTransitionInteractor>,
    @Application scope: CoroutineScope,
) {
    var receivedDownTouch = false
@@ -63,13 +77,80 @@ constructor(
        } else {
            bouncerRepository.alternateBouncerUIAvailable
        }
    private val isDozingOrAod: Flow<Boolean> =
        keyguardTransitionInteractor
            .get()
            .transitions
            .map {
                it.to == KeyguardState.DOZING ||
                    it.to == KeyguardState.AOD ||
                    ((it.from == KeyguardState.DOZING || it.from == KeyguardState.AOD) &&
                        it.transitionState != TransitionState.FINISHED)
            }
            .distinctUntilChanged()

    /**
     * Whether the current biometric, bouncer, and keyguard states allow the alternate bouncer to
     * show.
     */
    val canShowAlternateBouncer: StateFlow<Boolean> =
        alternateBouncerSupported
            .flatMapLatest { alternateBouncerSupported ->
                if (alternateBouncerSupported) {
                    keyguardTransitionInteractor.get().currentKeyguardState.flatMapLatest {
                        currentKeyguardState ->
                        if (currentKeyguardState == KeyguardState.GONE) {
                            flowOf(false)
                        } else {
                            combine(
                                deviceEntryFingerprintAuthInteractor
                                    .get()
                                    .isFingerprintAuthCurrentlyAllowed,
                                keyguardInteractor.get().isKeyguardDismissible,
                                bouncerRepository.primaryBouncerShow,
                                isDozingOrAod
                            ) {
                                fingerprintAllowed,
                                keyguardDismissible,
                                primaryBouncerShowing,
                                dozing ->
                                fingerprintAllowed &&
                                    !keyguardDismissible &&
                                    !primaryBouncerShowing &&
                                    !dozing
                            }
                        }
                    }
                } else {
                    flowOf(false)
                }
            }
            .stateIn(
                scope = scope,
                started = WhileSubscribed(),
                initialValue = false,
            )

    /**
     * Always shows the alternate bouncer. Requesters must check [canShowAlternateBouncer]` before
     * calling this.
     */
    fun forceShow() {
        if (DeviceEntryUdfpsRefactor.isUnexpectedlyInLegacyMode()) {
            show()
            return
        }
        bouncerRepository.setAlternateVisible(true)
    }

    /**
     * Sets the correct bouncer states to show the alternate bouncer if it can show.
     *
     * @return whether alternateBouncer is visible
     * @deprecated use [forceShow] and manually check [canShowAlternateBouncer] beforehand
     */
    fun show(): Boolean {
        DeviceEntryUdfpsRefactor.assertInLegacyMode()
        bouncerRepository.setAlternateVisible(canShowAlternateBouncerForFingerprint())
        return isVisibleState()
    }
@@ -105,6 +186,9 @@ constructor(
    }

    fun canShowAlternateBouncerForFingerprint(): Boolean {
        if (DeviceEntryUdfpsRefactor.isEnabled) {
            return canShowAlternateBouncer.value
        }
        return alternateBouncerSupported.value &&
            biometricSettingsRepository.isFingerprintAuthCurrentlyAllowed.value &&
            !keyguardUpdateMonitor.isFingerprintLockedOut &&
+33 −2
Original line number Diff line number Diff line
@@ -106,6 +106,8 @@ import com.android.systemui.util.kotlin.JavaAdapter;

import dagger.Lazy;

import kotlin.Unit;

import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.HashSet;
@@ -115,7 +117,6 @@ import java.util.Set;

import javax.inject.Inject;

import kotlin.Unit;
import kotlinx.coroutines.CoroutineDispatcher;
import kotlinx.coroutines.ExperimentalCoroutinesApi;
import kotlinx.coroutines.Job;
@@ -168,6 +169,7 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb

    private Job mListenForAlternateBouncerTransitionSteps = null;
    private Job mListenForKeyguardAuthenticatedBiometricsHandled = null;
    private Job mListenForCanShowAlternateBouncer = null;

    // Local cache of expansion events, to avoid duplicates
    private float mFraction = -1f;
@@ -505,6 +507,10 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb
            mListenForKeyguardAuthenticatedBiometricsHandled.cancel(null);
        }
        mListenForKeyguardAuthenticatedBiometricsHandled = null;
        if (mListenForCanShowAlternateBouncer != null) {
            mListenForCanShowAlternateBouncer.cancel(null);
        }
        mListenForCanShowAlternateBouncer = null;
        if (!DeviceEntryUdfpsRefactor.isEnabled()) {
            mListenForAlternateBouncerTransitionSteps = mJavaAdapter.alwaysCollectFlow(
                    mKeyguardTransitionInteractor.transitionStepsFromState(
@@ -516,6 +522,11 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb
                    mPrimaryBouncerInteractor.getKeyguardAuthenticatedBiometricsHandled(),
                    this::consumeKeyguardAuthenticatedBiometricsHandled
            );
        } else {
            mListenForCanShowAlternateBouncer = mJavaAdapter.alwaysCollectFlow(
                    mAlternateBouncerInteractor.getCanShowAlternateBouncer(),
                    this::consumeCanShowAlternateBouncer
            );
        }

        if (KeyguardWmStateRefactor.isEnabled()) {
@@ -557,6 +568,11 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb
        }
    }

    private void consumeCanShowAlternateBouncer(boolean canShow) {
        // do nothing, we only are registering for the flow to ensure that there's at least
        // one subscriber that will update AlternateBouncerInteractor.canShowAlternateBouncer.value
    }

    /** Register a callback, to be invoked by the Predictive Back system. */
    private void registerBackCallback() {
        if (!mIsBackCallbackRegistered) {
@@ -722,6 +738,16 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb
     *                 {@see KeyguardBouncer#show(boolean, boolean)}
     */
    public void showBouncer(boolean scrimmed) {
        if (DeviceEntryUdfpsRefactor.isEnabled()) {
            if (mAlternateBouncerInteractor.canShowAlternateBouncerForFingerprint()) {
                mAlternateBouncerInteractor.forceShow();
                updateAlternateBouncerShowing(mAlternateBouncerInteractor.isVisibleState());
            } else {
                showPrimaryBouncer(scrimmed);
            }
            return;
        }

        if (!mAlternateBouncerInteractor.show()) {
            showPrimaryBouncer(scrimmed);
        } else {
@@ -833,7 +859,12 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb
                        mKeyguardGoneCancelAction = null;
                    }

                    if (DeviceEntryUdfpsRefactor.isEnabled()) {
                        mAlternateBouncerInteractor.forceShow();
                        updateAlternateBouncerShowing(mAlternateBouncerInteractor.isVisibleState());
                    } else {
                        updateAlternateBouncerShowing(mAlternateBouncerInteractor.show());
                    }
                    setKeyguardMessage(message, null, null);
                    return;
                }
+6 −0
Original line number Diff line number Diff line
@@ -58,6 +58,7 @@ import com.android.systemui.bouncer.domain.interactor.PrimaryBouncerInteractor
import com.android.systemui.bouncer.ui.BouncerView
import com.android.systemui.classifier.FalsingCollector
import com.android.systemui.deviceentry.domain.interactor.DeviceEntryFaceAuthInteractor
import com.android.systemui.deviceentry.domain.interactor.DeviceEntryFingerprintAuthInteractor
import com.android.systemui.deviceentry.domain.interactor.deviceEntryFingerprintAuthInteractor
import com.android.systemui.display.data.repository.FakeDisplayRepository
import com.android.systemui.keyguard.DismissCallbackRegistry
@@ -66,6 +67,8 @@ import com.android.systemui.keyguard.data.repository.FakeDeviceEntryFingerprintA
import com.android.systemui.keyguard.data.repository.FakeTrustRepository
import com.android.systemui.keyguard.data.repository.biometricSettingsRepository
import com.android.systemui.keyguard.domain.interactor.DeviceEntrySideFpsOverlayInteractor
import com.android.systemui.keyguard.domain.interactor.KeyguardInteractor
import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor
import com.android.systemui.keyguard.domain.interactor.keyguardInteractor
import com.android.systemui.keyguard.domain.interactor.keyguardTransitionInteractor
import com.android.systemui.keyguard.ui.viewmodel.SideFpsProgressBarViewModel
@@ -193,6 +196,9 @@ class SideFpsOverlayViewBinderTest : SysuiTestCase() {
                biometricSettingsRepository,
                FakeSystemClock(),
                keyguardUpdateMonitor,
                { mock(DeviceEntryFingerprintAuthInteractor::class.java) },
                { mock(KeyguardInteractor::class.java) },
                { mock(KeyguardTransitionInteractor::class.java) },
                testScope.backgroundScope,
            )

Loading