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

Commit 65b6112f authored by Matt Pietal's avatar Matt Pietal
Browse files

Fix race condition with SIM bouncer on start

The user could end up with a blank screen or a strange
looking lockscreeen.

The SIM bouncer may decide to show in two bad conditions:
1. The bouncer hasn't been bound yet - So return false
2. The device is entering doze but hasn't quite made it -
   so don't show it.

Test: atest StatusBarKeyguardViewManagerTest
Fixes: 351426938
Flag: com.android.systemui.sim_pin_race_condition_on_restart
Change-Id: I5f69563ee94aea092c2f179e66a5c51c67886fda
parent 4ce9afb4
Loading
Loading
Loading
Loading
+10 −0
Original line number Diff line number Diff line
@@ -1187,3 +1187,13 @@ flag {
  description: "Enables MSDL feedback in SysUI surfaces."
  bug: "352600066"
}

flag {
   name: "sim_pin_race_condition_on_restart"
   namespace: "systemui"
   description: "The SIM PIN screen may be shown incorrectly on reboot"
   bug: "351426938"
   metadata {
        purpose: PURPOSE_BUGFIX
   }
}
 No newline at end of file
+6 −0
Original line number Diff line number Diff line
@@ -159,6 +159,12 @@ class PrimaryBouncerInteractorTest : SysuiTestCase() {
        verify(mPrimaryBouncerCallbackInteractor, never()).dispatchStartingToShow()
    }

    @Test
    fun testShowReturnsFalseWhenDelegateIsNotSet() {
        whenever(bouncerView.delegate).thenReturn(null)
        assertThat(underTest.show(true)).isEqualTo(false)
    }

    @Test
    fun testShow_isResumed() {
        whenever(repository.primaryBouncerShow.value).thenReturn(true)
+35 −31
Original line number Diff line number Diff line
@@ -134,7 +134,7 @@ constructor(
    // TODO(b/243695312): Encapsulate all of the show logic for the bouncer.
    /** Show the bouncer if necessary and set the relevant states. */
    @JvmOverloads
    fun show(isScrimmed: Boolean) {
    fun show(isScrimmed: Boolean): Boolean {
        // When the scene container framework is enabled, instead of calling this, call
        // SceneInteractor#changeScene(Scenes.Bouncer, ...).
        SceneContainerFlag.assertInLegacyMode()
@@ -146,9 +146,11 @@ constructor(
                    "primaryBouncerDelegate is set. Let's exit early so we don't " +
                    "set the wrong primaryBouncer state."
            )
            return
            return false
        }

        try {
            Trace.beginSection("KeyguardBouncer#show")
            // Reset some states as we show the bouncer.
            repository.setKeyguardAuthenticatedBiometrics(null)
            repository.setPrimaryStartingToHide(false)
@@ -157,7 +159,6 @@ constructor(
                (isBouncerShowing() || repository.primaryBouncerShowingSoon.value) &&
                    needsFullscreenBouncer()

        Trace.beginSection("KeyguardBouncer#show")
            repository.setPrimaryScrimmed(isScrimmed)
            if (isScrimmed) {
                setPanelExpansion(KeyguardBouncerConstants.EXPANSION_VISIBLE)
@@ -171,7 +172,7 @@ constructor(

            if (primaryBouncerView.delegate?.showNextSecurityScreenOrFinish() == true) {
                // Keyguard is done.
            return
                return false
            }

            repository.setPrimaryShowingSoon(true)
@@ -183,8 +184,11 @@ constructor(
            }
            keyguardStateController.notifyPrimaryBouncerShowing(true)
            primaryBouncerCallbackInteractor.dispatchStartingToShow()
            return true
        } finally {
            Trace.endSection()
        }
    }

    /** Sets the correct bouncer states to hide the bouncer. */
    fun hide() {
+19 −3
Original line number Diff line number Diff line
@@ -55,6 +55,7 @@ import com.android.keyguard.KeyguardUpdateMonitorCallback;
import com.android.keyguard.KeyguardViewController;
import com.android.keyguard.TrustGrantFlags;
import com.android.keyguard.ViewMediatorCallback;
import com.android.systemui.Flags;
import com.android.systemui.biometrics.domain.interactor.UdfpsOverlayInteractor;
import com.android.systemui.bouncer.domain.interactor.AlternateBouncerInteractor;
import com.android.systemui.bouncer.domain.interactor.PrimaryBouncerCallbackInteractor;
@@ -708,16 +709,31 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb
     * {@link #needsFullscreenBouncer()}.
     */
    protected void showBouncerOrKeyguard(boolean hideBouncerWhenShowing) {
        if (needsFullscreenBouncer() && !mDozing) {
        boolean isDozing = mDozing;
        if (Flags.simPinRaceConditionOnRestart()) {
            KeyguardState toState = mKeyguardTransitionInteractor.getTransitionState().getValue()
                    .getTo();
            isDozing = mDozing || toState == KeyguardState.DOZING || toState == KeyguardState.AOD;
        }
        if (needsFullscreenBouncer() && !isDozing) {
            // The keyguard might be showing (already). So we need to hide it.
            if (!primaryBouncerIsShowing()) {
                mCentralSurfaces.hideKeyguard();
                if (SceneContainerFlag.isEnabled()) {
                    mCentralSurfaces.hideKeyguard();
                    mSceneInteractorLazy.get().changeScene(
                            Scenes.Bouncer, "StatusBarKeyguardViewManager.showBouncerOrKeyguard");
                } else {
                    if (Flags.simPinRaceConditionOnRestart()) {
                        if (mPrimaryBouncerInteractor.show(/* isScrimmed= */ true)) {
                            mCentralSurfaces.hideKeyguard();
                        } else {
                            mCentralSurfaces.showKeyguard();
                        }
                    } else {
                        mCentralSurfaces.hideKeyguard();
                        mPrimaryBouncerInteractor.show(/* isScrimmed= */ true);
                    }
                }
            } else {
                Log.e(TAG, "Attempted to show the sim bouncer when it is already showing.");
            }
+20 −1
Original line number Diff line number Diff line
@@ -116,6 +116,7 @@ import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Answers;
import org.mockito.ArgumentCaptor;
import org.mockito.Captor;
import org.mockito.Mock;
@@ -176,6 +177,8 @@ public class StatusBarKeyguardViewManagerTest extends SysuiTestCase {
    private ViewRootImpl mViewRootImpl;
    @Mock
    private WindowOnBackInvokedDispatcher mOnBackInvokedDispatcher;
    @Mock(answer = Answers.RETURNS_DEEP_STUBS)
    private KeyguardTransitionInteractor mKeyguardTransitionInteractor;
    @Captor
    private ArgumentCaptor<OnBackInvokedCallback> mBackCallbackCaptor;
    @Captor
@@ -223,7 +226,7 @@ public class StatusBarKeyguardViewManagerTest extends SysuiTestCase {
                        mAlternateBouncerInteractor,
                        mUdfpsOverlayInteractor,
                        mActivityStarter,
                        mock(KeyguardTransitionInteractor.class),
                        mKeyguardTransitionInteractor,
                        StandardTestDispatcher(null, null),
                        () -> mock(WindowManagerLockscreenVisibilityInteractor.class),
                        () -> mock(KeyguardDismissActionInteractor.class),
@@ -1064,6 +1067,22 @@ public class StatusBarKeyguardViewManagerTest extends SysuiTestCase {
        verify(mPrimaryBouncerInteractor).show(true);
    }

    @Test
    @DisableSceneContainer
    @EnableFlags(Flags.FLAG_SIM_PIN_RACE_CONDITION_ON_RESTART)
    public void testShowBouncerOrKeyguard_showsKeyguardIfShowBouncerReturnsFalse() {
        when(mKeyguardSecurityModel.getSecurityMode(anyInt())).thenReturn(
                KeyguardSecurityModel.SecurityMode.SimPin);
        when(mPrimaryBouncerInteractor.show(true)).thenReturn(false);
        when(mKeyguardTransitionInteractor.getTransitionState().getValue().getTo())
                .thenReturn(KeyguardState.LOCKSCREEN);

        reset(mCentralSurfaces);
        mStatusBarKeyguardViewManager.showBouncerOrKeyguard(false);
        verify(mPrimaryBouncerInteractor).show(true);
        verify(mCentralSurfaces).showKeyguard();
    }

    @Test
    @DisableSceneContainer
    public void testShowBouncerOrKeyguard_needsFullScreen_bouncerAlreadyShowing() {