Fix race condition for doze mode and wake-and-unlocking

When pulse was about to turn on and at the same time we were starting
a wake-and-unlock sequence, there was jank because the scrim handling
was not correct anymore. Now, abort the pulse when we are wake-and-
unlocking so we don't see flickering with the scrims anymore.

Bug: 23217476
Change-Id: I331f513b68fb1832b4372d3e2e518b31b556a43c
diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitor.java b/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitor.java
index 3232f65..80b6f28 100644
--- a/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitor.java
+++ b/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitor.java
@@ -409,6 +409,10 @@
     }
 
     private void handleFingerprintAuthFailed() {
+        if (mFpWakeMode == FP_WAKE_DIRECT_UNLOCK) {
+            notifyOnFingerprintWakeAndUnlockingFinished();
+        }
+        mFpWakeMode = FP_WAKE_NONE;
         releaseFingerprintWakeLock();
         handleFingerprintHelp(-1, mContext.getString(R.string.fingerprint_not_recognized));
     }
@@ -428,6 +432,9 @@
             }
             mHandler.postDelayed(mReleaseFingerprintWakeLockRunnable,
                     FINGERPRINT_WAKELOCK_TIMEOUT_MS);
+            if (mFpWakeMode == FP_WAKE_DIRECT_UNLOCK) {
+                notifyOnFingerprintWakeAndUnlockingStarted();
+            }
         } else if (!mDeviceInteractive) {
             mFpWakeMode = FP_WAKE_TO_BOUNCER;
         } else {
@@ -435,6 +442,24 @@
         }
     }
 
+    private void notifyOnFingerprintWakeAndUnlockingStarted() {
+        for (int i = 0; i < mCallbacks.size(); i++) {
+            KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get();
+            if (cb != null) {
+                cb.onFingerprintWakeAndUnlockingStarted();
+            }
+        }
+    }
+
+    private void notifyOnFingerprintWakeAndUnlockingFinished() {
+        for (int i = 0; i < mCallbacks.size(); i++) {
+            KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get();
+            if (cb != null) {
+                cb.onFingerprintWakeAndUnlockingFinished();
+            }
+        }
+    }
+
     private final Runnable mReleaseFingerprintWakeLockRunnable = new Runnable() {
         @Override
         public void run() {
@@ -890,6 +915,10 @@
                 cb.onScreenTurnedOn();
             }
         }
+        if (mFpWakeMode == FP_WAKE_DIRECT_UNLOCK) {
+            notifyOnFingerprintWakeAndUnlockingFinished();
+        }
+        mFpWakeMode = FP_WAKE_NONE;
     }
 
     private void handleScreenTurnedOff() {
diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitorCallback.java b/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitorCallback.java
index 52412f7..bf9435e 100644
--- a/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitorCallback.java
+++ b/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitorCallback.java
@@ -194,6 +194,17 @@
     public void onFingerprintAuthenticated(int userId, boolean wakeAndUnlocking) { }
 
     /**
+     * Called when we might be starting a wake-and-unlock sequence.
+     */
+    public void onFingerprintWakeAndUnlockingStarted() { }
+
+    /**
+     * Called when we're done with the wake-and-unlock sequence. This can either happen when we
+     * figure out that the fingerprint didn't match, or when the phone is fully unlocked.
+     */
+    public void onFingerprintWakeAndUnlockingFinished() { }
+
+    /**
      * Called when fingerprint provides help string (e.g. "Try again")
      * @param msgId
      * @param helpString
diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeHost.java b/packages/SystemUI/src/com/android/systemui/doze/DozeHost.java
index 89a2c74..82a1bfe 100644
--- a/packages/SystemUI/src/com/android/systemui/doze/DozeHost.java
+++ b/packages/SystemUI/src/com/android/systemui/doze/DozeHost.java
@@ -29,6 +29,7 @@
     void stopDozing();
     boolean isPowerSaveActive();
     boolean isNotificationLightOn();
+    boolean isPulsingBlocked();
 
     public interface Callback {
         void onNewNotifications();
diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeService.java b/packages/SystemUI/src/com/android/systemui/doze/DozeService.java
index 887391c..a60b4e7 100644
--- a/packages/SystemUI/src/com/android/systemui/doze/DozeService.java
+++ b/packages/SystemUI/src/com/android/systemui/doze/DozeService.java
@@ -255,6 +255,9 @@
     }
 
     private void continuePulsing(int reason) {
+        if (mHost.isPulsingBlocked()) {
+            return;
+        }
         mHost.pulseWhileDozing(new DozeHost.PulseCallback() {
             @Override
             public void onPulseStarted() {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeScrimController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeScrimController.java
index 86b8972..c0077b8 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeScrimController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeScrimController.java
@@ -100,6 +100,17 @@
         mHandler.post(mPulseIn);
     }
 
+    /**
+     * Aborts pulsing immediately.
+     */
+    public void abortPulsing() {
+        mHandler.removeCallbacks(mPulseIn);
+        abortAnimations();
+        mScrimController.setDozeBehindAlpha(1f);
+        mScrimController.setDozeInFrontAlpha(1f);
+        mPulseCallback = null;
+    }
+
     public void onScreenTurnedOn() {
         if (isPulsing()) {
             final boolean pickup = mPulseReason == DozeLog.PULSE_REASON_SENSOR_PICKUP;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
index 1b9faa3..1062db9 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
@@ -99,6 +99,7 @@
 import com.android.internal.statusbar.StatusBarIcon;
 import com.android.keyguard.KeyguardHostView.OnDismissAction;
 import com.android.keyguard.KeyguardUpdateMonitor;
+import com.android.keyguard.KeyguardUpdateMonitorCallback;
 import com.android.keyguard.ViewMediatorCallback;
 import com.android.systemui.BatteryMeterView;
 import com.android.systemui.DemoMode;
@@ -621,6 +622,7 @@
         startKeyguard();
 
         mDozeServiceHost = new DozeServiceHost();
+        KeyguardUpdateMonitor.getInstance(mContext).registerCallback(mDozeServiceHost);
         putComponent(DozeHost.class, mDozeServiceHost);
         putComponent(PhoneStatusBar.class, this);
 
@@ -4027,7 +4029,7 @@
         }
     }
 
-    private final class DozeServiceHost implements DozeHost {
+    private final class DozeServiceHost extends KeyguardUpdateMonitorCallback implements DozeHost  {
         // Amount of time to allow to update the time shown on the screen before releasing
         // the wakelock.  This timeout is design to compensate for the fact that we don't
         // currently have a way to know when time display contents have actually been
@@ -4039,6 +4041,7 @@
 
         // Keeps the last reported state by fireNotificationLight.
         private boolean mNotificationLightOn;
+        private boolean mWakeAndUnlocking;
 
         @Override
         public String toString() {
@@ -4101,6 +4104,22 @@
         }
 
         @Override
+        public boolean isPulsingBlocked() {
+            return mWakeAndUnlocking;
+        }
+
+        @Override
+        public void onFingerprintWakeAndUnlockingStarted() {
+            mWakeAndUnlocking = true;
+            mDozeScrimController.abortPulsing();
+        }
+
+        @Override
+        public void onFingerprintWakeAndUnlockingFinished() {
+            mWakeAndUnlocking = false;
+        }
+
+        @Override
         public boolean isNotificationLightOn() {
             return mNotificationLightOn;
         }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
index 9d47713..2070c96 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
@@ -48,6 +48,8 @@
     // with the appear animations of the PIN/pattern/password views.
     private static final long NAV_BAR_SHOW_DELAY_BOUNCER = 320;
 
+    private static final long WAKE_AND_UNLOCK_SCRIM_FADEOUT_DURATION_MS = 200;
+
     private static String TAG = "StatusBarKeyguardViewManager";
 
     private final Context mContext;
@@ -178,16 +180,16 @@
 
     public void onScreenTurnedOn() {
         mScreenTurnedOn = true;
-        mWakeAndUnlocking = false;
         if (mDeferScrimFadeOut) {
             mDeferScrimFadeOut = false;
-            animateScrimControllerKeyguardFadingOut(0, 200);
+            animateScrimControllerKeyguardFadingOut(0, WAKE_AND_UNLOCK_SCRIM_FADEOUT_DURATION_MS);
             updateStates();
         }
         mPhoneStatusBar.onScreenTurnedOn();
     }
 
     public void onScreenTurnedOff() {
+        mWakeAndUnlocking = false;
         mScreenTurnedOn = false;
     }
 
@@ -279,7 +281,12 @@
                 mStatusBarWindowManager.setKeyguardFadingAway(true);
                 if (mWakeAndUnlocking && !mScreenTurnedOn) {
                     mDeferScrimFadeOut = true;
-                } else {
+                } else if (mWakeAndUnlocking){
+
+                    // Screen is already on, don't defer with fading out.
+                    animateScrimControllerKeyguardFadingOut(0,
+                            WAKE_AND_UNLOCK_SCRIM_FADEOUT_DURATION_MS);
+                } else  {
                     animateScrimControllerKeyguardFadingOut(delay, fadeoutDuration);
                 }
             } else {
@@ -292,7 +299,7 @@
             executeAfterKeyguardGoneAction();
             updateStates();
         }
-
+        mWakeAndUnlocking = false;
     }
 
     private void animateScrimControllerKeyguardFadingOut(long delay, long duration) {