Merge changes Ic62b7358,Ic3f7e62a into tm-qpr-dev am: 0c76ea59be am: 23c9b021be

Original change: https://googleplex-android-review.googlesource.com/c/platform/frameworks/base/+/20237808

Change-Id: I3a3ff337869ac8fb4251c31754a6cf1303f4b4b1
Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
index 0d74dc8..480fd93 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
@@ -91,6 +91,7 @@
 
 import androidx.annotation.NonNull;
 import androidx.annotation.Nullable;
+import androidx.annotation.VisibleForTesting;
 
 import com.android.internal.jank.InteractionJankMonitor;
 import com.android.internal.jank.InteractionJankMonitor.Configuration;
@@ -322,6 +323,12 @@
     // true if the keyguard is hidden by another window
     private boolean mOccluded = false;
 
+    /**
+     * Whether the {@link #mOccludeAnimationController} is currently playing the occlusion
+     * animation.
+     */
+    private boolean mOccludeAnimationPlaying = false;
+
     private boolean mWakeAndUnlocking = false;
 
     /**
@@ -837,15 +844,22 @@
     /**
      * Animation launch controller for activities that occlude the keyguard.
      */
-    private final ActivityLaunchAnimator.Controller mOccludeAnimationController =
+    @VisibleForTesting
+    final ActivityLaunchAnimator.Controller mOccludeAnimationController =
             new ActivityLaunchAnimator.Controller() {
                 @Override
-                public void onLaunchAnimationStart(boolean isExpandingFullyAbove) {}
+                public void onLaunchAnimationStart(boolean isExpandingFullyAbove) {
+                    mOccludeAnimationPlaying = true;
+                }
 
                 @Override
                 public void onLaunchAnimationCancelled(@Nullable Boolean newKeyguardOccludedState) {
                     Log.d(TAG, "Occlude launch animation cancelled. Occluded state is now: "
                             + mOccluded);
+                    mOccludeAnimationPlaying = false;
+
+                    // Ensure keyguard state is set correctly if we're cancelled.
+                    mCentralSurfaces.updateIsKeyguard();
                 }
 
                 @Override
@@ -854,6 +868,12 @@
                         mCentralSurfaces.instantCollapseNotificationPanel();
                     }
 
+                    mOccludeAnimationPlaying = false;
+
+                    // Hide the keyguard now that we're done launching the occluding activity over
+                    // it.
+                    mCentralSurfaces.updateIsKeyguard();
+
                     mInteractionJankMonitor.end(CUJ_LOCKSCREEN_OCCLUSION);
                 }
 
@@ -1768,6 +1788,10 @@
         return mShowing && !mOccluded;
     }
 
+    public boolean isOccludeAnimationPlaying() {
+        return mOccludeAnimationPlaying;
+    }
+
     /**
      * Notify us when the keyguard is occluded by another window
      */
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesImpl.java
index 29642be..43bc99f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesImpl.java
@@ -2960,7 +2960,10 @@
             //  * When phone is unlocked: we still don't want to execute hiding of the keyguard
             //    as the animation could prepare 'fake AOD' interface (without actually
             //    transitioning to keyguard state) and this might reset the view states
-            if (!mScreenOffAnimationController.isKeyguardHideDelayed()) {
+            if (!mScreenOffAnimationController.isKeyguardHideDelayed()
+                    // If we're animating occluded, there's an activity launching over the keyguard
+                    // UI. Wait to hide it until after the animation concludes.
+                    && !mKeyguardViewMediator.isOccludeAnimationPlaying()) {
                 return hideKeyguardImpl(forceStateChange);
             }
         }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
index 8490768..cf3a48c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
@@ -53,6 +53,7 @@
 import com.android.systemui.dagger.qualifiers.Main;
 import com.android.systemui.dock.DockManager;
 import com.android.systemui.keyguard.KeyguardUnlockAnimationController;
+import com.android.systemui.keyguard.KeyguardViewMediator;
 import com.android.systemui.scrim.ScrimView;
 import com.android.systemui.shade.NotificationPanelViewController;
 import com.android.systemui.statusbar.notification.stack.ViewState;
@@ -204,6 +205,7 @@
     private final ScreenOffAnimationController mScreenOffAnimationController;
     private final KeyguardUnlockAnimationController mKeyguardUnlockAnimationController;
     private final StatusBarKeyguardViewManager mStatusBarKeyguardViewManager;
+    private KeyguardViewMediator mKeyguardViewMediator;
 
     private GradientColors mColors;
     private boolean mNeedsDrawableColorUpdate;
@@ -273,7 +275,8 @@
             @Main Executor mainExecutor,
             ScreenOffAnimationController screenOffAnimationController,
             KeyguardUnlockAnimationController keyguardUnlockAnimationController,
-            StatusBarKeyguardViewManager statusBarKeyguardViewManager) {
+            StatusBarKeyguardViewManager statusBarKeyguardViewManager,
+            KeyguardViewMediator keyguardViewMediator) {
         mScrimStateListener = lightBarController::setScrimState;
         mDefaultScrimAlpha = BUSY_SCRIM_ALPHA;
 
@@ -312,6 +315,8 @@
             }
         });
         mColors = new GradientColors();
+
+        mKeyguardViewMediator = keyguardViewMediator;
     }
 
     /**
@@ -807,6 +812,13 @@
                         mBehindTint,
                         interpolatedFraction);
             }
+
+            // If we're unlocked but still playing the occlude animation, remain at the keyguard
+            // alpha temporarily.
+            if (mKeyguardViewMediator.isOccludeAnimationPlaying()
+                    || mState.mLaunchingAffordanceWithPreview) {
+                mNotificationsAlpha = KEYGUARD_SCRIM_ALPHA;
+            }
         } else if (mState == ScrimState.AUTH_SCRIMMED_SHADE) {
             float behindFraction = getInterpolatedFraction();
             behindFraction = (float) Math.pow(behindFraction, 0.8f);
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 4c986bf..2c3ddd5 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardViewMediatorTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardViewMediatorTest.java
@@ -60,6 +60,7 @@
 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.ScreenOffAnimationController;
 import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager;
@@ -112,6 +113,8 @@
 
     private FalsingCollectorFake mFalsingCollector;
 
+    private @Mock CentralSurfaces mCentralSurfaces;
+
     @Before
     public void setUp() throws Exception {
         MockitoAnnotations.initMocks(this);
@@ -258,6 +261,26 @@
         verify(mKeyguardStateController).notifyKeyguardGoingAway(false);
     }
 
+    @Test
+    public void testUpdateIsKeyguardAfterOccludeAnimationEnds() {
+        mViewMediator.mOccludeAnimationController.onLaunchAnimationEnd(
+                false /* isExpandingFullyAbove */);
+
+        // Since the updateIsKeyguard call is delayed during the animation, ensure it's called once
+        // it ends.
+        verify(mCentralSurfaces).updateIsKeyguard();
+    }
+
+    @Test
+    public void testUpdateIsKeyguardAfterOccludeAnimationIsCancelled() {
+        mViewMediator.mOccludeAnimationController.onLaunchAnimationCancelled(
+                null /* newKeyguardOccludedState */);
+
+        // Since the updateIsKeyguard call is delayed during the animation, ensure it's called if
+        // it's cancelled.
+        verify(mCentralSurfaces).updateIsKeyguard();
+    }
+
     private void createAndStartViewMediator() {
         mViewMediator = new KeyguardViewMediator(
                 mContext,
@@ -287,5 +310,7 @@
                 mNotificationShadeWindowControllerLazy,
                 () -> mActivityLaunchAnimator);
         mViewMediator.start();
+
+        mViewMediator.registerCentralSurfaces(mCentralSurfaces, null, null, null, null, null);
     }
 }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/CentralSurfacesImplTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/CentralSurfacesImplTest.java
index 6de8bd5..5755782 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/CentralSurfacesImplTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/CentralSurfacesImplTest.java
@@ -235,6 +235,7 @@
     @Mock private NavigationBarController mNavigationBarController;
     @Mock private AccessibilityFloatingMenuController mAccessibilityFloatingMenuController;
     @Mock private SysuiColorExtractor mColorExtractor;
+    private WakefulnessLifecycle mWakefulnessLifecycle;
     @Mock private ColorExtractor.GradientColors mGradientColors;
     @Mock private PulseExpansionHandler mPulseExpansionHandler;
     @Mock private NotificationWakeUpCoordinator mNotificationWakeUpCoordinator;
@@ -366,10 +367,10 @@
             return null;
         }).when(mStatusBarKeyguardViewManager).addAfterKeyguardGoneRunnable(any());
 
-        WakefulnessLifecycle wakefulnessLifecycle =
+        mWakefulnessLifecycle =
                 new WakefulnessLifecycle(mContext, mIWallpaperManager, mDumpManager);
-        wakefulnessLifecycle.dispatchStartedWakingUp(PowerManager.WAKE_REASON_UNKNOWN);
-        wakefulnessLifecycle.dispatchFinishedWakingUp();
+        mWakefulnessLifecycle.dispatchStartedWakingUp(PowerManager.WAKE_REASON_UNKNOWN);
+        mWakefulnessLifecycle.dispatchFinishedWakingUp();
 
         when(mGradientColors.supportsDarkText()).thenReturn(true);
         when(mColorExtractor.getNeutralColors()).thenReturn(mGradientColors);
@@ -428,7 +429,7 @@
                 mBatteryController,
                 mColorExtractor,
                 new ScreenLifecycle(mDumpManager),
-                wakefulnessLifecycle,
+                mWakefulnessLifecycle,
                 mStatusBarStateController,
                 Optional.of(mBubbles),
                 mDeviceProvisionedController,
@@ -507,6 +508,8 @@
         mCentralSurfaces.mKeyguardIndicationController = mKeyguardIndicationController;
         mCentralSurfaces.mBarService = mBarService;
         mCentralSurfaces.mStackScroller = mStackScroller;
+        mCentralSurfaces.mGestureWakeLock = mPowerManager.newWakeLock(
+                PowerManager.SCREEN_BRIGHT_WAKE_LOCK, "sysui:GestureWakeLock");
         mCentralSurfaces.startKeyguard();
         mInitController.executePostInitTasks();
         notificationLogger.setUpWithContainer(mNotificationListContainer);
@@ -1125,6 +1128,55 @@
         assertThat(onDismissActionCaptor.getValue().onDismiss()).isFalse();
     }
 
+    @Test
+    public void testKeyguardHideDelayedIfOcclusionAnimationRunning() {
+        // Show the keyguard and verify we've done so.
+        setKeyguardShowingAndOccluded(true /* showing */, false /* occluded */);
+        verify(mStatusBarStateController).setState(StatusBarState.KEYGUARD);
+
+        // Request to hide the keyguard, but while the occlude animation is playing. We should delay
+        // this hide call, since we're playing the occlude animation over the keyguard and thus want
+        // it to remain visible.
+        when(mKeyguardViewMediator.isOccludeAnimationPlaying()).thenReturn(true);
+        setKeyguardShowingAndOccluded(false /* showing */, true /* occluded */);
+        verify(mStatusBarStateController, never()).setState(StatusBarState.SHADE);
+
+        // Once the animation ends, verify that the keyguard is actually hidden.
+        when(mKeyguardViewMediator.isOccludeAnimationPlaying()).thenReturn(false);
+        setKeyguardShowingAndOccluded(false /* showing */, true /* occluded */);
+        verify(mStatusBarStateController).setState(StatusBarState.SHADE);
+    }
+
+    @Test
+    public void testKeyguardHideNotDelayedIfOcclusionAnimationNotRunning() {
+        // Show the keyguard and verify we've done so.
+        setKeyguardShowingAndOccluded(true /* showing */, false /* occluded */);
+        verify(mStatusBarStateController).setState(StatusBarState.KEYGUARD);
+
+        // Hide the keyguard while the occlusion animation is not running. Verify that we
+        // immediately hide the keyguard.
+        when(mKeyguardViewMediator.isOccludeAnimationPlaying()).thenReturn(false);
+        setKeyguardShowingAndOccluded(false /* showing */, true /* occluded */);
+        verify(mStatusBarStateController).setState(StatusBarState.SHADE);
+    }
+
+    /**
+     * Configures the appropriate mocks and then calls {@link CentralSurfacesImpl#updateIsKeyguard}
+     * to reconfigure the keyguard to reflect the requested showing/occluded states.
+     */
+    private void setKeyguardShowingAndOccluded(boolean showing, boolean occluded) {
+        when(mStatusBarStateController.isKeyguardRequested()).thenReturn(showing);
+        when(mKeyguardStateController.isOccluded()).thenReturn(occluded);
+
+        // If we want to show the keyguard, make sure that we think we're awake and not unlocking.
+        if (showing) {
+            when(mBiometricUnlockController.isWakeAndUnlock()).thenReturn(false);
+            mWakefulnessLifecycle.dispatchStartedWakingUp(PowerManager.WAKE_REASON_UNKNOWN);
+        }
+
+        mCentralSurfaces.updateIsKeyguard(false /* forceStateChange */);
+    }
+
     private void setDeviceState(int state) {
         ArgumentCaptor<DeviceStateManager.DeviceStateCallback> callbackCaptor =
                 ArgumentCaptor.forClass(DeviceStateManager.DeviceStateCallback.class);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ScrimControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ScrimControllerTest.java
index 4d1a52c..a5deaa4 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ScrimControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ScrimControllerTest.java
@@ -16,6 +16,7 @@
 
 package com.android.systemui.statusbar.phone;
 
+import static com.android.systemui.statusbar.phone.ScrimController.KEYGUARD_SCRIM_ALPHA;
 import static com.android.systemui.statusbar.phone.ScrimController.OPAQUE;
 import static com.android.systemui.statusbar.phone.ScrimController.SEMI_TRANSPARENT;
 import static com.android.systemui.statusbar.phone.ScrimController.TRANSPARENT;
@@ -58,6 +59,7 @@
 import com.android.systemui.animation.ShadeInterpolation;
 import com.android.systemui.dock.DockManager;
 import com.android.systemui.keyguard.KeyguardUnlockAnimationController;
+import com.android.systemui.keyguard.KeyguardViewMediator;
 import com.android.systemui.scrim.ScrimView;
 import com.android.systemui.statusbar.policy.FakeConfigurationController;
 import com.android.systemui.statusbar.policy.KeyguardStateController;
@@ -117,6 +119,7 @@
     // TODO(b/204991468): Use a real PanelExpansionStateManager object once this bug is fixed. (The
     //   event-dispatch-on-registration pattern caused some of these unit tests to fail.)
     @Mock private StatusBarKeyguardViewManager mStatusBarKeyguardViewManager;
+    @Mock private KeyguardViewMediator mKeyguardViewMediator;
 
     private static class AnimatorListener implements Animator.AnimatorListener {
         private int mNumStarts;
@@ -230,7 +233,8 @@
                 mDockManager, mConfigurationController, new FakeExecutor(new FakeSystemClock()),
                 mScreenOffAnimationController,
                 mKeyguardUnlockAnimationController,
-                mStatusBarKeyguardViewManager);
+                mStatusBarKeyguardViewManager,
+                mKeyguardViewMediator);
         mScrimController.setScrimVisibleListener(visible -> mScrimVisibility = visible);
         mScrimController.attachViews(mScrimBehind, mNotificationsScrim, mScrimInFront);
         mScrimController.setAnimatorListener(mAnimatorListener);
@@ -239,6 +243,8 @@
         mScrimController.setWallpaperSupportsAmbientMode(false);
         mScrimController.transitionTo(ScrimState.KEYGUARD);
         finishAnimationsImmediately();
+
+        mScrimController.setLaunchingAffordanceWithPreview(false);
     }
 
     @After
@@ -852,7 +858,8 @@
                 mDockManager, mConfigurationController, new FakeExecutor(new FakeSystemClock()),
                 mScreenOffAnimationController,
                 mKeyguardUnlockAnimationController,
-                mStatusBarKeyguardViewManager);
+                mStatusBarKeyguardViewManager,
+                mKeyguardViewMediator);
         mScrimController.setScrimVisibleListener(visible -> mScrimVisibility = visible);
         mScrimController.attachViews(mScrimBehind, mNotificationsScrim, mScrimInFront);
         mScrimController.setAnimatorListener(mAnimatorListener);
@@ -1592,6 +1599,30 @@
         assertScrimAlpha(mScrimBehind, 0);
     }
 
+    @Test
+    public void keyguardAlpha_whenUnlockedForOcclusion_ifPlayingOcclusionAnimation() {
+        mScrimController.transitionTo(ScrimState.KEYGUARD);
+
+        when(mKeyguardViewMediator.isOccludeAnimationPlaying()).thenReturn(true);
+
+        mScrimController.transitionTo(ScrimState.UNLOCKED);
+        finishAnimationsImmediately();
+
+        assertScrimAlpha(mNotificationsScrim, (int) (KEYGUARD_SCRIM_ALPHA * 255f));
+    }
+
+    @Test
+    public void keyguardAlpha_whenUnlockedForLaunch_ifLaunchingAffordance() {
+        mScrimController.transitionTo(ScrimState.KEYGUARD);
+        when(mKeyguardViewMediator.isOccludeAnimationPlaying()).thenReturn(true);
+        mScrimController.setLaunchingAffordanceWithPreview(true);
+
+        mScrimController.transitionTo(ScrimState.UNLOCKED);
+        finishAnimationsImmediately();
+
+        assertScrimAlpha(mNotificationsScrim, (int) (KEYGUARD_SCRIM_ALPHA * 255f));
+    }
+
     private void assertAlphaAfterExpansion(ScrimView scrim, float expectedAlpha, float expansion) {
         mScrimController.setRawPanelExpansionFraction(expansion);
         finishAnimationsImmediately();