Merge "Hide Udfps icon when shade is expanded" into sc-dev
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsAnimation.java b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsAnimation.java
index 5fc2e53..40fe7b1 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsAnimation.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsAnimation.java
@@ -47,4 +47,9 @@
                 (int) sensorRect.right - margin,
                 (int) sensorRect.bottom - margin);
     }
+
+    @Override
+    public void setAlpha(int alpha) {
+        mFingerprintDrawable.setAlpha(alpha);
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsAnimationEnroll.java b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsAnimationEnroll.java
index 58ebadeb..52662ae 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsAnimationEnroll.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsAnimationEnroll.java
@@ -28,6 +28,8 @@
 import androidx.annotation.NonNull;
 import androidx.annotation.Nullable;
 
+import com.android.internal.graphics.ColorUtils;
+import com.android.settingslib.Utils;
 import com.android.systemui.R;
 
 /**
@@ -36,8 +38,11 @@
 public class UdfpsAnimationEnroll extends UdfpsAnimation {
     private static final String TAG = "UdfpsAnimationEnroll";
 
+    private static final float SHADOW_RADIUS = 5.f;
+
     @Nullable private RectF mSensorRect;
     @NonNull private final Paint mSensorPaint;
+    private final int mNotificationShadeColor;
 
     UdfpsAnimationEnroll(@NonNull Context context) {
         super(context);
@@ -45,8 +50,11 @@
         mSensorPaint = new Paint(0 /* flags */);
         mSensorPaint.setAntiAlias(true);
         mSensorPaint.setColor(Color.WHITE);
-        mSensorPaint.setShadowLayer(UdfpsView.SENSOR_SHADOW_RADIUS, 0, 0, Color.BLACK);
+        mSensorPaint.setShadowLayer(SHADOW_RADIUS, 0, 0, Color.BLACK);
         mSensorPaint.setStyle(Paint.Style.FILL);
+
+        mNotificationShadeColor = Utils.getColorAttr(context,
+                android.R.attr.colorBackgroundFloating).getDefaultColor();
     }
 
     @Override
@@ -74,7 +82,14 @@
 
     @Override
     public void setAlpha(int alpha) {
+        super.setAlpha(alpha);
 
+        // Gradually fade into the notification shade color. This needs to be done because the
+        // UDFPS view is drawn on a layer on top of the notification shade
+        final float percent = alpha / 255.f;
+        mSensorPaint.setColor(ColorUtils.blendARGB(mNotificationShadeColor, Color.WHITE, percent));
+        mSensorPaint.setShadowLayer(SHADOW_RADIUS, 0, 0,
+                ColorUtils.blendARGB(mNotificationShadeColor, Color.BLACK, percent));
     }
 
     @Override
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsAnimationFpmOther.java b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsAnimationFpmOther.java
index 7563e73..efc864a 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsAnimationFpmOther.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsAnimationFpmOther.java
@@ -44,11 +44,6 @@
     }
 
     @Override
-    public void setAlpha(int alpha) {
-
-    }
-
-    @Override
     public void setColorFilter(@Nullable ColorFilter colorFilter) {
 
     }
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsAnimationKeyguard.java b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsAnimationKeyguard.java
index 3e46a65..501de9d 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsAnimationKeyguard.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsAnimationKeyguard.java
@@ -99,11 +99,6 @@
     }
 
     @Override
-    public void setAlpha(int alpha) {
-
-    }
-
-    @Override
     public void setColorFilter(@Nullable ColorFilter colorFilter) {
 
     }
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java
index 001730a..dc09fa7 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java
@@ -50,6 +50,7 @@
 import com.android.systemui.dagger.qualifiers.Main;
 import com.android.systemui.doze.DozeReceiver;
 import com.android.systemui.plugins.statusbar.StatusBarStateController;
+import com.android.systemui.statusbar.phone.ScrimController;
 import com.android.systemui.util.concurrency.DelayableExecutor;
 import com.android.systemui.util.settings.SystemSettings;
 
@@ -184,7 +185,8 @@
             WindowManager windowManager,
             SystemSettings systemSettings,
             @NonNull StatusBarStateController statusBarStateController,
-            @Main DelayableExecutor fgExecutor) {
+            @Main DelayableExecutor fgExecutor,
+            @NonNull ScrimController scrimController) {
         mContext = context;
         // The fingerprint manager is queried for UDFPS before this class is constructed, so the
         // fingerprint manager should never be null.
@@ -220,6 +222,8 @@
 
         mHbmSupported = !TextUtils.isEmpty(mHbmPath);
         mView.setHbmSupported(mHbmSupported);
+        scrimController.addScrimChangedListener(mView);
+        statusBarStateController.addCallback(mView);
 
         // This range only consists of the minimum and maximum values, which only cover
         // non-high-brightness mode.
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsView.java b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsView.java
index 983206e..265703e 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsView.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsView.java
@@ -16,6 +16,10 @@
 
 package com.android.systemui.biometrics;
 
+import static com.android.systemui.statusbar.StatusBarState.FULLSCREEN_USER_SWITCHER;
+import static com.android.systemui.statusbar.StatusBarState.KEYGUARD;
+import static com.android.systemui.statusbar.StatusBarState.SHADE_LOCKED;
+
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.content.Context;
@@ -35,15 +39,19 @@
 
 import com.android.systemui.R;
 import com.android.systemui.doze.DozeReceiver;
+import com.android.systemui.plugins.statusbar.StatusBarStateController;
+import com.android.systemui.statusbar.StatusBarState;
+import com.android.systemui.statusbar.phone.ScrimController;
 
 /**
  * A full screen view with a configurable illumination dot and scrim.
  */
-public class UdfpsView extends View implements DozeReceiver {
+public class UdfpsView extends View implements DozeReceiver,
+        StatusBarStateController.StateListener,  ScrimController.ScrimChangedListener{
     private static final String TAG = "UdfpsView";
 
     // Values in pixels.
-    public static final float SENSOR_SHADOW_RADIUS = 2.0f;
+    private static final float SENSOR_SHADOW_RADIUS = 2.0f;
 
     private static final int DEBUG_TEXT_SIZE_PX = 32;
 
@@ -70,6 +78,9 @@
     private boolean mShowScrimAndDot;
     private boolean mIsHbmSupported;
     @Nullable private String mDebugMessage;
+    private int mStatusBarState;
+    private boolean mNotificationShadeExpanded;
+    private int mNotificationPanelAlpha;
 
     // Runnable that will be run after the illumination dot and scrim are shown.
     // The runnable is reset to null after it's executed once.
@@ -136,6 +147,22 @@
         }
     }
 
+    @Override
+    public void onExpandedChanged(boolean isExpanded) {
+        mNotificationShadeExpanded = isExpanded;
+    }
+
+    @Override
+    public void onStateChanged(int newState) {
+        mStatusBarState = newState;
+    }
+
+    @Override
+    public void onAlphaChanged(float alpha) {
+        mNotificationPanelAlpha = (int) (alpha * 255);
+        postInvalidate();
+    }
+
     // The "h" and "w" are the display's height and width relative to its current rotation.
     protected void updateSensorRect(int h, int w) {
         // mSensorProps coordinates assume portrait mode.
@@ -147,10 +174,12 @@
         // Transform mSensorRect if the device is in landscape mode.
         switch (mContext.getDisplay().getRotation()) {
             case Surface.ROTATION_90:
+                //noinspection SuspiciousNameCombination
                 mSensorRect.set(mSensorRect.top, h - mSensorRect.right, mSensorRect.bottom,
                         h - mSensorRect.left);
                 break;
             case Surface.ROTATION_270:
+                //noinspection SuspiciousNameCombination
                 mSensorRect.set(w - mSensorRect.bottom, mSensorRect.left, w - mSensorRect.top,
                         mSensorRect.right);
                 break;
@@ -222,6 +251,8 @@
             canvas.drawOval(mSensorRect, mSensorPaint);
         } else {
             if (mUdfpsAnimation != null) {
+                final int alpha = shouldPauseAuth() ? 255 - mNotificationPanelAlpha : 255;
+                mUdfpsAnimation.setAlpha(alpha);
                 mUdfpsAnimation.draw(canvas);
             }
         }
@@ -260,7 +291,19 @@
         return x > (cx - rx * mSensorTouchAreaCoefficient)
                 && x < (cx + rx * mSensorTouchAreaCoefficient)
                 && y > (cy - ry * mSensorTouchAreaCoefficient)
-                && y < (cy + ry * mSensorTouchAreaCoefficient);
+                && y < (cy + ry * mSensorTouchAreaCoefficient)
+                && !shouldPauseAuth();
+    }
+
+    /**
+     * States where UDFPS should temporarily not be authenticating. Instead of completely stopping
+     * authentication which would cause the UDFPS icons to abruptly disappear, do it here by not
+     * sending onFingerDown and smoothly animating away.
+     */
+    private boolean shouldPauseAuth() {
+        return (mNotificationShadeExpanded && mStatusBarState != KEYGUARD)
+                || mStatusBarState == SHADE_LOCKED
+                || mStatusBarState == FULLSCREEN_USER_SWITCHER;
     }
 
     void setScrimAlpha(int alpha) {
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 03d17e5..19c0b6d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
@@ -34,6 +34,7 @@
 import android.view.animation.DecelerateInterpolator;
 import android.view.animation.Interpolator;
 
+import androidx.annotation.NonNull;
 import androidx.annotation.Nullable;
 
 import com.android.internal.annotations.VisibleForTesting;
@@ -62,6 +63,8 @@
 import java.io.PrintWriter;
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
+import java.util.ArrayList;
+import java.util.List;
 import java.util.function.Consumer;
 
 import javax.inject.Inject;
@@ -195,6 +198,16 @@
     private boolean mWakeLockHeld;
     private boolean mKeyguardOccluded;
 
+    /**
+     * Notifies listeners of animation-related changes (currently just opacity changes).
+     */
+    public interface ScrimChangedListener {
+        void onAlphaChanged(float alpha);
+    }
+
+    @NonNull
+    private final List<ScrimChangedListener> mScrimChangedListeners;
+
     @Inject
     public ScrimController(LightBarController lightBarController, DozeParameters dozeParameters,
             AlarmManager alarmManager, KeyguardStateController keyguardStateController,
@@ -208,6 +221,7 @@
         ScrimState.BUBBLE_EXPANDED.setBubbleAlpha(featureFlags.isShadeOpaque()
                 ? BUSY_SCRIM_ALPHA : GAR_SCRIM_ALPHA);
         mBlurUtils = blurUtils;
+        mScrimChangedListeners = new ArrayList<>();
 
         mKeyguardStateController = keyguardStateController;
         mDarkenWhileDragging = !mKeyguardStateController.canDismissLockScreen();
@@ -284,6 +298,10 @@
         mScrimVisibleListener = listener;
     }
 
+    public void addScrimChangedListener(@NonNull ScrimChangedListener listener) {
+        mScrimChangedListeners.add(listener);
+    }
+
     public void transitionTo(ScrimState state) {
         transitionTo(state, null);
     }
@@ -559,6 +577,10 @@
             throw new IllegalStateException("Scrim opacity is NaN for state: " + mState
                     + ", front: " + mInFrontAlpha + ", back: " + mBehindAlpha);
         }
+
+        for (ScrimChangedListener listener : mScrimChangedListeners) {
+            listener.onAlphaChanged(mBehindAlpha);
+        }
     }
 
     private void applyAndDispatchExpansion() {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsControllerTest.java
index ed3cf9a..dd145e4 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsControllerTest.java
@@ -45,6 +45,7 @@
 import com.android.systemui.R;
 import com.android.systemui.SysuiTestCase;
 import com.android.systemui.plugins.statusbar.StatusBarStateController;
+import com.android.systemui.statusbar.phone.ScrimController;
 import com.android.systemui.util.concurrency.FakeExecutor;
 import com.android.systemui.util.settings.FakeSettings;
 import com.android.systemui.util.time.FakeSystemClock;
@@ -90,6 +91,8 @@
     private WindowManager mWindowManager;
     @Mock
     private StatusBarStateController mStatusBarStateController;
+    @Mock
+    private ScrimController mScrimController;
 
     private FakeSettings mSystemSettings;
     private FakeExecutor mFgExecutor;
@@ -130,7 +133,8 @@
                 mWindowManager,
                 mSystemSettings,
                 mStatusBarStateController,
-                mFgExecutor);
+                mFgExecutor,
+                mScrimController);
         verify(mFingerprintManager).setUdfpsOverlayController(mOverlayCaptor.capture());
         mOverlayController = mOverlayCaptor.getValue();
 
@@ -245,4 +249,10 @@
         // THEN the scrim and dot is hidden
         verify(mUdfpsView).hideScrimAndDot();
     }
+
+    @Test
+    public void registersViewForCallbacks() throws RemoteException {
+        verify(mStatusBarStateController).addCallback(mUdfpsView);
+        verify(mScrimController).addScrimChangedListener(mUdfpsView);
+    }
 }