Merge "Order awakening from dream after unlocking." into udc-dev
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/BiometricUnlockController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/BiometricUnlockController.java
index 2d8f371..1f9c9f2 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/BiometricUnlockController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/BiometricUnlockController.java
@@ -160,6 +160,7 @@
     private KeyguardViewController mKeyguardViewController;
     private DozeScrimController mDozeScrimController;
     private KeyguardViewMediator mKeyguardViewMediator;
+    private StatusBarKeyguardViewManager mStatusBarKeyguardViewManager;
     private PendingAuthenticated mPendingAuthenticated = null;
     private boolean mHasScreenTurnedOnSinceAuthenticating;
     private boolean mFadedAwayAfterWakeAndUnlock;
@@ -280,7 +281,8 @@
             LatencyTracker latencyTracker,
             ScreenOffAnimationController screenOffAnimationController,
             VibratorHelper vibrator,
-            SystemClock systemClock
+            SystemClock systemClock,
+            StatusBarKeyguardViewManager statusBarKeyguardViewManager
     ) {
         mPowerManager = powerManager;
         mUpdateMonitor = keyguardUpdateMonitor;
@@ -308,6 +310,7 @@
         mVibratorHelper = vibrator;
         mLogger = biometricUnlockLogger;
         mSystemClock = systemClock;
+        mStatusBarKeyguardViewManager = statusBarKeyguardViewManager;
 
         dumpManager.registerDumpable(getClass().getName(), this);
     }
@@ -449,8 +452,19 @@
         // During wake and unlock, we need to draw black before waking up to avoid abrupt
         // brightness changes due to display state transitions.
         Runnable wakeUp = ()-> {
-            if (!wasDeviceInteractive || mUpdateMonitor.isDreaming()) {
+            // Check to see if we are still locked when we are waking and unlocking from dream.
+            // This runnable should be executed after unlock. If that's true, we could be not
+            // dreaming, but still locked. In this case, we should attempt to authenticate instead
+            // of waking up.
+            if (mode == MODE_WAKE_AND_UNLOCK_FROM_DREAM
+                    && !mKeyguardStateController.isUnlocked()
+                    && !mUpdateMonitor.isDreaming()) {
+                // Post wakeUp runnable is called from a callback in keyguard.
+                mHandler.post(() -> mKeyguardViewController.notifyKeyguardAuthenticated(
+                        false /* primaryAuth */));
+            } else if (!wasDeviceInteractive || mUpdateMonitor.isDreaming()) {
                 mLogger.i("bio wakelock: Authenticated, waking up...");
+
                 mPowerManager.wakeUp(
                         mSystemClock.uptimeMillis(),
                         PowerManager.WAKE_REASON_BIOMETRIC,
@@ -462,7 +476,7 @@
             Trace.endSection();
         };
 
-        if (mMode != MODE_NONE) {
+        if (mMode != MODE_NONE && mMode != MODE_WAKE_AND_UNLOCK_FROM_DREAM) {
             wakeUp.run();
         }
         switch (mMode) {
@@ -484,6 +498,10 @@
                 Trace.endSection();
                 break;
             case MODE_WAKE_AND_UNLOCK_FROM_DREAM:
+                // In the case of waking and unlocking from dream, waking up is delayed until after
+                // unlock is complete to avoid conflicts during each sequence's transitions.
+                mStatusBarKeyguardViewManager.addAfterKeyguardGoneRunnable(wakeUp);
+                // Execution falls through here to proceed unlocking.
             case MODE_WAKE_AND_UNLOCK_PULSING:
             case MODE_WAKE_AND_UNLOCK:
                 if (mMode == MODE_WAKE_AND_UNLOCK_PULSING) {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/BiometricsUnlockControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/BiometricsUnlockControllerTest.java
index 89f8bdb..479803e 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/BiometricsUnlockControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/BiometricsUnlockControllerTest.java
@@ -142,7 +142,8 @@
                 mNotificationMediaManager, mWakefulnessLifecycle, mScreenLifecycle,
                 mAuthController, mStatusBarStateController,
                 mSessionTracker, mLatencyTracker, mScreenOffAnimationController, mVibratorHelper,
-                mSystemClock
+                mSystemClock,
+                mStatusBarKeyguardViewManager
         );
         mBiometricUnlockController.setKeyguardViewController(mStatusBarKeyguardViewManager);
         mBiometricUnlockController.addListener(mBiometricUnlockEventsListener);
@@ -464,6 +465,69 @@
     }
 
     @Test
+    public void onSideFingerprintSuccess_dreaming_unlockThenWake() {
+        when(mAuthController.isSfpsEnrolled(anyInt())).thenReturn(true);
+        when(mWakefulnessLifecycle.getLastWakeReason())
+                .thenReturn(PowerManager.WAKE_REASON_POWER_BUTTON);
+        final ArgumentCaptor<Runnable> afterKeyguardGoneRunnableCaptor =
+                ArgumentCaptor.forClass(Runnable.class);
+        givenDreamingLocked();
+        mBiometricUnlockController.startWakeAndUnlock(BiometricSourceType.FINGERPRINT, true);
+
+        // Make sure the BiometricUnlockController has registered a callback for when the keyguard
+        // is gone
+        verify(mStatusBarKeyguardViewManager).addAfterKeyguardGoneRunnable(
+                afterKeyguardGoneRunnableCaptor.capture());
+        // Ensure that the power hasn't been told to wake up yet.
+        verify(mPowerManager, never()).wakeUp(anyLong(), anyInt(), anyString());
+        // Check that the keyguard has been told to unlock.
+        verify(mKeyguardViewMediator).onWakeAndUnlocking();
+
+        // Simulate the keyguard disappearing.
+        afterKeyguardGoneRunnableCaptor.getValue().run();
+        // Verify that the power manager has been told to wake up now.
+        verify(mPowerManager).wakeUp(anyLong(), anyInt(), anyString());
+    }
+
+    @Test
+    public void onSideFingerprintSuccess_dreaming_unlockIfStillLockedNotDreaming() {
+        when(mAuthController.isSfpsEnrolled(anyInt())).thenReturn(true);
+        when(mWakefulnessLifecycle.getLastWakeReason())
+                .thenReturn(PowerManager.WAKE_REASON_POWER_BUTTON);
+        final ArgumentCaptor<Runnable> afterKeyguardGoneRunnableCaptor =
+                ArgumentCaptor.forClass(Runnable.class);
+        givenDreamingLocked();
+        mBiometricUnlockController.startWakeAndUnlock(BiometricSourceType.FINGERPRINT, true);
+
+        // Make sure the BiometricUnlockController has registered a callback for when the keyguard
+        // is gone
+        verify(mStatusBarKeyguardViewManager).addAfterKeyguardGoneRunnable(
+                afterKeyguardGoneRunnableCaptor.capture());
+        // Ensure that the power hasn't been told to wake up yet.
+        verify(mPowerManager, never()).wakeUp(anyLong(), anyInt(), anyString());
+        // Check that the keyguard has been told to unlock.
+        verify(mKeyguardViewMediator).onWakeAndUnlocking();
+
+        when(mUpdateMonitor.isDreaming()).thenReturn(false);
+        when(mKeyguardStateController.isUnlocked()).thenReturn(false);
+
+        // Simulate the keyguard disappearing.
+        afterKeyguardGoneRunnableCaptor.getValue().run();
+
+        final ArgumentCaptor<Runnable> dismissKeyguardRunnableCaptor =
+                ArgumentCaptor.forClass(Runnable.class);
+        verify(mHandler).post(dismissKeyguardRunnableCaptor.capture());
+
+        // Verify that the power manager was not told to wake up.
+        verify(mPowerManager, never()).wakeUp(anyLong(), anyInt(), anyString());
+
+        dismissKeyguardRunnableCaptor.getValue().run();
+        // Verify that the keyguard controller is told to unlock.
+        verify(mStatusBarKeyguardViewManager).notifyKeyguardAuthenticated(eq(false));
+    }
+
+
+    @Test
     public void onSideFingerprintSuccess_oldPowerButtonPress_playHaptic() {
         // GIVEN side fingerprint enrolled, last wake reason was power button
         when(mAuthController.isSfpsEnrolled(anyInt())).thenReturn(true);
@@ -537,6 +601,11 @@
         verify(mStatusBarKeyguardViewManager).showPrimaryBouncer(anyBoolean());
     }
 
+    private void givenDreamingLocked() {
+        when(mUpdateMonitor.isDreaming()).thenReturn(true);
+        when(mUpdateMonitor.isUnlockingWithBiometricAllowed(anyBoolean())).thenReturn(true);
+    }
+
     private void givenFingerprintModeUnlockCollapsing() {
         when(mUpdateMonitor.isUnlockingWithBiometricAllowed(anyBoolean())).thenReturn(true);
         when(mUpdateMonitor.isDeviceInteractive()).thenReturn(true);