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

Commit 28ee2589 authored by Matt Pietal's avatar Matt Pietal Committed by Android (Google) Code Review
Browse files

Merge "Ensure exit animations are canceled prior to user switch" into udc-dev

parents 134ba6b4 5adb3167
Loading
Loading
Loading
Loading
+15 −7
Original line number Diff line number Diff line
@@ -2444,6 +2444,7 @@ public class KeyguardViewMediator implements CoreStartable, Dumpable,
                mHandler.removeCallbacksAndMessages(mDismissToken);
                mHandler.removeMessages(DISMISS);
                mHandler.removeMessages(HIDE);
                mHandler.removeMessages(START_KEYGUARD_EXIT_ANIM);
                notifyTrustedChangedLocked(mUpdateMonitor.getUserHasTrust(newUserId));
                resetKeyguardDonePendingLocked();
                adjustStatusBarLocked();
@@ -3275,6 +3276,12 @@ public class KeyguardViewMediator implements CoreStartable, Dumpable,
        }
    }

    // Allows the runnable to be controlled for tests by overriding this method
    @VisibleForTesting
    void postAfterTraversal(Runnable runnable) {
        DejankUtils.postAfterTraversal(runnable);
    }

    /**
     * Called when we're done running the keyguard exit animation, we should now end up unlocked.
     *
@@ -3306,13 +3313,7 @@ public class KeyguardViewMediator implements CoreStartable, Dumpable,
        InteractionJankMonitor.getInstance().end(CUJ_LOCKSCREEN_UNLOCK_ANIMATION);

        // Post layout changes to the next frame, so we don't hang at the end of the animation.
        DejankUtils.postAfterTraversal(() -> {
            if (mIsKeyguardExitAnimationCanceled) {
                Log.d(TAG, "Ignoring dejank exitKeyguardAndFinishSurfaceBehindRemoteAnimation. "
                        + "mIsKeyguardExitAnimationCanceled==true");
                return;
            }

        postAfterTraversal(() -> {
            if (!mPM.isInteractive() && !mPendingLock) {
                Log.e(TAG, "exitKeyguardAndFinishSurfaceBehindRemoteAnimation#postAfterTraversal:"
                        + " mPM.isInteractive()=" + mPM.isInteractive()
@@ -3326,6 +3327,13 @@ public class KeyguardViewMediator implements CoreStartable, Dumpable,

                return;
            }
            if (mIsKeyguardExitAnimationCanceled) {
                Log.d(TAG, "Ignoring exitKeyguardAndFinishSurfaceBehindRemoteAnimation. "
                        + "mIsKeyguardExitAnimationCanceled==true");
                finishSurfaceBehindRemoteAnimation(true /* showKeyguard */);
                setShowingLocked(true /* showing */, true /* force */);
                return;
            }

            onKeyguardExitFinished();

+70 −3
Original line number Diff line number Diff line
@@ -38,6 +38,7 @@ import static org.mockito.Mockito.clearInvocations;
import static org.mockito.Mockito.eq;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.startsWith;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;

@@ -176,12 +177,16 @@ public class KeyguardViewMediatorTest extends SysuiTestCase {

    private FakeFeatureFlags mFeatureFlags;
    private int mInitialUserId;
    private final int mDefaultUserId = 100;
    private boolean mUsePostAfterTraversalRunnable;
    private Runnable mPostAfterTraversalRunnable;

    @Before
    public void setUp() throws Exception {
        MockitoAnnotations.initMocks(this);
        mFalsingCollector = new FalsingCollectorFake();

        mUsePostAfterTraversalRunnable = false;
        mPostAfterTraversalRunnable = null;
        when(mLockPatternUtils.getDevicePolicyManager()).thenReturn(mDevicePolicyManager);
        when(mPowerManager.newWakeLock(anyInt(), any())).thenReturn(mock(WakeLock.class));
        when(mInteractionJankMonitor.begin(any(), anyInt())).thenReturn(true);
@@ -243,12 +248,64 @@ public class KeyguardViewMediatorTest extends SysuiTestCase {
                null, callback);
        processAllMessagesAndBgExecutorMessages();

        // Followed by a request to dismiss the keyguard completely, which needs to be rejected
        mViewMediator.mViewMediatorCallback.keyguardDonePending(true, mDefaultUserId);
        mViewMediator.mViewMediatorCallback.readyForKeyguardDone();

        // The call to exit should be rejected, and keyguard should still be visible
        verify(mKeyguardUnlockAnimationController, never()).notifyStartSurfaceBehindRemoteAnimation(
                any(), any(), anyLong(), anyBoolean());
        assertTrue(mViewMediator.isShowingAndNotOccluded());
    }

    @Test
    @TestableLooper.RunWithLooper(setAsMainLooper = true)
    public void testGoingAwayFollowedByBeforeUserSwitchWithDelayedExitAnimationDoesNotHideKeyguard() {
        mUsePostAfterTraversalRunnable = true;

        int insecureUserId = 1099;
        setCurrentUser(/* userId= */insecureUserId, /* isSecure= */false);

        // Setup keyguard
        mViewMediator.onSystemReady();
        processAllMessagesAndBgExecutorMessages();
        mViewMediator.setShowingLocked(true);

        // Request keyguard going away
        when(mKeyguardStateController.isKeyguardGoingAway()).thenReturn(true);
        mViewMediator.showSurfaceBehindKeyguard();

        // WM will have started the exit animation...
        RemoteAnimationTarget[] apps = new RemoteAnimationTarget[]{
                mock(RemoteAnimationTarget.class)
        };
        RemoteAnimationTarget[] wallpapers = new RemoteAnimationTarget[]{
                mock(RemoteAnimationTarget.class)
        };
        IRemoteAnimationFinishedCallback callback = mock(IRemoteAnimationFinishedCallback.class);
        mViewMediator.startKeyguardExitAnimation(TRANSIT_OLD_KEYGUARD_GOING_AWAY, apps, wallpapers,
                null, callback);
        processAllMessagesAndBgExecutorMessages();

        // Followed by a request to dismiss the keyguard completely
        mViewMediator.mViewMediatorCallback.keyguardDonePending(true, insecureUserId);
        mViewMediator.mViewMediatorCallback.readyForKeyguardDone();

        // ...but while the exit animation is running, a user switch comes in
        int nextUserId = 500;
        setCurrentUser(nextUserId, /* isSecure= */true);

        processAllMessagesAndBgExecutorMessages();

        // This simulates the race condition in DejankUtils.postAfterTraversal()
        mPostAfterTraversalRunnable.run();

        // At this point, the exit animation should have been canceled, with a true value
        // indicating that keyguard will be showing
        verify(mKeyguardUnlockAnimationController).notifyFinishedKeyguardExitAnimation(eq(true));
        assertTrue(mViewMediator.isShowingAndNotOccluded());
    }

    @Test
    @TestableLooper.RunWithLooper(setAsMainLooper = true)
    public void testUserSwitchToSecureUserWhileKeyguardNotVisibleShowsKeyguard() {
@@ -354,7 +411,8 @@ public class KeyguardViewMediatorTest extends SysuiTestCase {

    @Test
    public void testRegisterDumpable() {
        verify(mDumpManager).registerDumpable(KeyguardViewMediator.class.getName(), mViewMediator);
        verify(mDumpManager).registerDumpable(startsWith(KeyguardViewMediator.class.getName()),
                eq(mViewMediator));
        verify(mStatusBarKeyguardViewManager, never()).setKeyguardGoingAwayState(anyBoolean());
    }

@@ -999,7 +1057,16 @@ public class KeyguardViewMediatorTest extends SysuiTestCase {
                mFeatureFlags,
                mDispatcher,
                () -> mDreamingToLockscreenTransitionViewModel,
                mSystemPropertiesHelper);
                mSystemPropertiesHelper) {
                    @Override
                    void postAfterTraversal(Runnable runnable) {
                        if (mUsePostAfterTraversalRunnable) {
                            mPostAfterTraversalRunnable = runnable;
                        } else {
                            super.postAfterTraversal(runnable);
                        }
                    }
            };
        mViewMediator.start();

        mViewMediator.registerCentralSurfaces(mCentralSurfaces, null, null, null, null, null);