Loading packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java +15 −7 Original line number Diff line number Diff line Loading @@ -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(); Loading Loading @@ -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. * Loading Loading @@ -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() Loading @@ -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(); Loading packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardViewMediatorTest.java +70 −3 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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); Loading Loading @@ -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() { Loading Loading @@ -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()); } Loading Loading @@ -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); Loading Loading
packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java +15 −7 Original line number Diff line number Diff line Loading @@ -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(); Loading Loading @@ -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. * Loading Loading @@ -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() Loading @@ -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(); Loading
packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardViewMediatorTest.java +70 −3 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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); Loading Loading @@ -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() { Loading Loading @@ -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()); } Loading Loading @@ -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); Loading