From 2155889f5246f25b9904ecf17915d149b8ca4a1c Mon Sep 17 00:00:00 2001 From: Ming-Shin Lu Date: Tue, 6 Dec 2022 00:53:05 +0800 Subject: [PATCH] [Shell-trantition] Fix keyguard exit animation may no-op at first boot When NotificationPanelView starts fade-out by swiping up, will notify KeyguardUnlockAnimationController to call onKeyguardExitRemoteAnimationFinished for starting keyguard going away remote animation. Unlike legacy animation that will call KeyguardViewMediater#handleHide -> set KeyguardViewMediater#mHiding -> handleStartKeyguardExitAnimation, with shell-transition, SystemUI will call through KeyguardService#mExitAnimationRunner#onAnimationStart -> KeyguardviewMediater#startKeyguardExitAnimation without setting mHiding as true, that will unexpectedly cancel the animation sometimes. Fix this unexpected keyguard hiding state handling and also add a unit test for verifying this behavior. Fix: 260100540 Test: manual as steps with enabling shell-transition 1) Turn on device with power key to boot the device. 2) After booted, swiping the lockscreen to home 3) Verify if home surface was visible to user after unlocked Test: atest KeyguardViewMediatorTest#\ testStartKeyguardExitAnimation_expectSurfaceBehindRemoteAnimation Change-Id: Ib927daea954bf1e9e6f6202a2b778c743e8bcd59 --- .../keyguard/KeyguardViewMediator.java | 3 ++ .../keyguard/KeyguardViewMediatorTest.java | 51 +++++++++++++++++-- 2 files changed, 50 insertions(+), 4 deletions(-) diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java index 5ed3ba76cc224..188c88c7b276a 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java +++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java @@ -2209,6 +2209,9 @@ public class KeyguardViewMediator implements CoreStartable, Dumpable, case START_KEYGUARD_EXIT_ANIM: Trace.beginSection( "KeyguardViewMediator#handleMessage START_KEYGUARD_EXIT_ANIM"); + synchronized (KeyguardViewMediator.this) { + mHiding = true; + } StartKeyguardExitAnimParams params = (StartKeyguardExitAnimParams) msg.obj; mNotificationShadeWindowControllerLazy.get().batchApplyWindowLayoutParams( () -> { diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardViewMediatorTest.java b/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardViewMediatorTest.java index d17e3744edc68..798839dcc1f63 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardViewMediatorTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardViewMediatorTest.java @@ -16,6 +16,7 @@ package com.android.systemui.keyguard; +import static android.view.WindowManager.TRANSIT_OLD_KEYGUARD_GOING_AWAY; import static android.view.WindowManagerPolicyConstants.OFF_BECAUSE_OF_USER; import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_DPM_LOCK_NOW; @@ -34,6 +35,7 @@ import static org.mockito.Mockito.never; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; +import android.app.IActivityManager; import android.app.admin.DevicePolicyManager; import android.app.trust.TrustManager; import android.os.PowerManager; @@ -41,6 +43,11 @@ import android.os.PowerManager.WakeLock; import android.telephony.TelephonyManager; import android.testing.AndroidTestingRunner; import android.testing.TestableLooper; +import android.view.IRemoteAnimationFinishedCallback; +import android.view.RemoteAnimationTarget; +import android.view.View; +import android.view.ViewRootImpl; +import android.view.WindowManager; import androidx.test.filters.SmallTest; @@ -52,21 +59,27 @@ import com.android.keyguard.KeyguardUpdateMonitor; import com.android.keyguard.mediator.ScreenOnCoordinator; import com.android.systemui.SysuiTestCase; import com.android.systemui.animation.ActivityLaunchAnimator; +import com.android.systemui.biometrics.AuthController; import com.android.systemui.broadcast.BroadcastDispatcher; import com.android.systemui.classifier.FalsingCollectorFake; +import com.android.systemui.colorextraction.SysuiColorExtractor; import com.android.systemui.dreams.DreamOverlayStateController; import com.android.systemui.dump.DumpManager; import com.android.systemui.navigationbar.NavigationModeController; import com.android.systemui.settings.UserTracker; +import com.android.systemui.shade.NotificationShadeWindowControllerImpl; import com.android.systemui.shade.ShadeController; +import com.android.systemui.shade.ShadeExpansionStateManager; import com.android.systemui.statusbar.NotificationShadeDepthController; import com.android.systemui.statusbar.NotificationShadeWindowController; import com.android.systemui.statusbar.SysuiStatusBarStateController; import com.android.systemui.statusbar.phone.CentralSurfaces; import com.android.systemui.statusbar.phone.DozeParameters; +import com.android.systemui.statusbar.phone.KeyguardBypassController; import com.android.systemui.statusbar.phone.ScreenOffAnimationController; import com.android.systemui.statusbar.phone.ScrimController; import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager; +import com.android.systemui.statusbar.policy.ConfigurationController; import com.android.systemui.statusbar.policy.KeyguardStateController; import com.android.systemui.statusbar.policy.UserSwitcherController; import com.android.systemui.util.DeviceConfigProxy; @@ -80,8 +93,6 @@ import org.junit.runner.RunWith; import org.mockito.Mock; import org.mockito.MockitoAnnotations; -import dagger.Lazy; - @RunWith(AndroidTestingRunner.class) @TestableLooper.RunWithLooper @SmallTest @@ -96,11 +107,15 @@ public class KeyguardViewMediatorTest extends SysuiTestCase { private @Mock BroadcastDispatcher mBroadcastDispatcher; private @Mock DismissCallbackRegistry mDismissCallbackRegistry; private @Mock DumpManager mDumpManager; + private @Mock WindowManager mWindowManager; + private @Mock IActivityManager mActivityManager; + private @Mock ConfigurationController mConfigurationController; private @Mock PowerManager mPowerManager; private @Mock TrustManager mTrustManager; private @Mock UserSwitcherController mUserSwitcherController; private @Mock NavigationModeController mNavigationModeController; private @Mock KeyguardDisplayManager mKeyguardDisplayManager; + private @Mock KeyguardBypassController mKeyguardBypassController; private @Mock DozeParameters mDozeParameters; private @Mock SysuiStatusBarStateController mStatusBarStateController; private @Mock KeyguardStateController mKeyguardStateController; @@ -110,10 +125,13 @@ public class KeyguardViewMediatorTest extends SysuiTestCase { private @Mock InteractionJankMonitor mInteractionJankMonitor; private @Mock ScreenOnCoordinator mScreenOnCoordinator; private @Mock ShadeController mShadeController; - private @Mock Lazy mNotificationShadeWindowControllerLazy; + private NotificationShadeWindowController mNotificationShadeWindowController; private @Mock DreamOverlayStateController mDreamOverlayStateController; private @Mock ActivityLaunchAnimator mActivityLaunchAnimator; private @Mock ScrimController mScrimController; + private @Mock SysuiColorExtractor mColorExtractor; + private @Mock AuthController mAuthController; + private @Mock ShadeExpansionStateManager mShadeExpansionStateManager; private DeviceConfigProxy mDeviceConfig = new DeviceConfigProxyFake(); private FakeExecutor mUiBgExecutor = new FakeExecutor(new FakeSystemClock()); @@ -130,6 +148,14 @@ public class KeyguardViewMediatorTest extends SysuiTestCase { when(mPowerManager.newWakeLock(anyInt(), any())).thenReturn(mock(WakeLock.class)); when(mInteractionJankMonitor.begin(any(), anyInt())).thenReturn(true); when(mInteractionJankMonitor.end(anyInt())).thenReturn(true); + final ViewRootImpl testViewRoot = mock(ViewRootImpl.class); + when(testViewRoot.getView()).thenReturn(mock(View.class)); + when(mStatusBarKeyguardViewManager.getViewRootImpl()).thenReturn(testViewRoot); + mNotificationShadeWindowController = new NotificationShadeWindowControllerImpl(mContext, + mWindowManager, mActivityManager, mDozeParameters, mStatusBarStateController, + mConfigurationController, mViewMediator, mKeyguardBypassController, + mColorExtractor, mDumpManager, mKeyguardStateController, + mScreenOffAnimationController, mAuthController, mShadeExpansionStateManager); createAndStartViewMediator(); } @@ -287,6 +313,23 @@ public class KeyguardViewMediatorTest extends SysuiTestCase { verify(mCentralSurfaces).updateIsKeyguard(); } + @Test + @TestableLooper.RunWithLooper(setAsMainLooper = true) + public void testStartKeyguardExitAnimation_expectSurfaceBehindRemoteAnimation() { + 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); + TestableLooper.get(this).processAllMessages(); + assertTrue(mViewMediator.isAnimatingBetweenKeyguardAndSurfaceBehind()); + } + private void createAndStartViewMediator() { mViewMediator = new KeyguardViewMediator( mContext, @@ -315,7 +358,7 @@ public class KeyguardViewMediatorTest extends SysuiTestCase { mInteractionJankMonitor, mDreamOverlayStateController, () -> mShadeController, - mNotificationShadeWindowControllerLazy, + () -> mNotificationShadeWindowController, () -> mActivityLaunchAnimator, () -> mScrimController); mViewMediator.start();