From b7b70ace2eccc6ce40243825047e82db42251b3e Mon Sep 17 00:00:00 2001 From: Kevin Chyn Date: Thu, 21 Jan 2021 17:22:55 -0800 Subject: [PATCH] Hide Udfps icon when shade is expanded 1) Adds interface for ScrimController to notify listeners of new alpha 2) For SysUI modules such as UdfpsView that have views in layers ABOVE the notification shade (such as during lockscreen auth), yet need to pretend to be behind the shade (such as during enrollment), this allows UdfpsView to set its alpha and color to the right level Bug: 177931181 Test: atest com.android.systemui.biometrics Change-Id: I9b7bd5d72acee8ccbba9aef5b1c935bbf1da815f --- .../systemui/biometrics/UdfpsAnimation.java | 5 ++ .../biometrics/UdfpsAnimationEnroll.java | 17 ++++++- .../biometrics/UdfpsAnimationFpmOther.java | 5 -- .../biometrics/UdfpsAnimationKeyguard.java | 5 -- .../systemui/biometrics/UdfpsController.java | 6 ++- .../systemui/biometrics/UdfpsView.java | 49 +++++++++++++++++-- .../statusbar/phone/ScrimController.java | 22 +++++++++ .../biometrics/UdfpsControllerTest.java | 12 ++++- 8 files changed, 105 insertions(+), 16 deletions(-) diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsAnimation.java b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsAnimation.java index 5fc2e5361689d..40fe7b17f37d5 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 @@ public abstract class UdfpsAnimation extends Drawable { (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 1a2a4927c3fd8..8e6cd5d2b97fe 100644 --- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsAnimationEnroll.java +++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsAnimationEnroll.java @@ -27,6 +27,8 @@ import android.graphics.RectF; import androidx.annotation.NonNull; import androidx.annotation.Nullable; +import com.android.internal.graphics.ColorUtils; +import com.android.settingslib.Utils; import com.android.systemui.R; /** @@ -35,8 +37,11 @@ import com.android.systemui.R; 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); @@ -44,8 +49,11 @@ public class UdfpsAnimationEnroll extends UdfpsAnimation { 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 @@ -73,7 +81,14 @@ public class UdfpsAnimationEnroll extends UdfpsAnimation { @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 7563e739c93a8..efc864ade5ff5 100644 --- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsAnimationFpmOther.java +++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsAnimationFpmOther.java @@ -43,11 +43,6 @@ public class UdfpsAnimationFpmOther extends UdfpsAnimation { mFingerprintDrawable.draw(canvas); } - @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 3e46a656ecd5c..501de9df575bf 100644 --- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsAnimationKeyguard.java +++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsAnimationKeyguard.java @@ -98,11 +98,6 @@ public class UdfpsAnimationKeyguard extends UdfpsAnimation implements DozeReceiv canvas.restore(); } - @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 a2b2bea8a06f8..5d75133b6bb68 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.R; 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; @@ -174,7 +175,8 @@ class UdfpsController implements DozeReceiver { 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. @@ -210,6 +212,8 @@ class UdfpsController implements DozeReceiver { 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 4cb8101385eaf..686c2784c7825 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 android.view.ViewTreeObserver; 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; @@ -71,6 +79,9 @@ public class UdfpsView extends View implements DozeReceiver { 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. @@ -137,6 +148,22 @@ public class UdfpsView extends View implements DozeReceiver { } } + @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. @@ -148,10 +175,12 @@ public class UdfpsView extends View implements DozeReceiver { // 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; @@ -223,6 +252,8 @@ public class UdfpsView extends View implements DozeReceiver { canvas.drawOval(mSensorRect, mSensorPaint); } else { if (mUdfpsAnimation != null) { + final int alpha = shouldPauseAuth() ? 255 - mNotificationPanelAlpha : 255; + mUdfpsAnimation.setAlpha(alpha); mUdfpsAnimation.draw(canvas); } } @@ -261,7 +292,19 @@ public class UdfpsView extends View implements DozeReceiver { 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 03d17e5050da0..19c0b6dc193a4 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.ViewTreeObserver; 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.FileDescriptor; 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 @@ public class ScrimController implements ViewTreeObserver.OnPreDrawListener, Dump 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 mScrimChangedListeners; + @Inject public ScrimController(LightBarController lightBarController, DozeParameters dozeParameters, AlarmManager alarmManager, KeyguardStateController keyguardStateController, @@ -208,6 +221,7 @@ public class ScrimController implements ViewTreeObserver.OnPreDrawListener, Dump 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 @@ public class ScrimController implements ViewTreeObserver.OnPreDrawListener, Dump mScrimVisibleListener = listener; } + public void addScrimChangedListener(@NonNull ScrimChangedListener listener) { + mScrimChangedListeners.add(listener); + } + public void transitionTo(ScrimState state) { transitionTo(state, null); } @@ -559,6 +577,10 @@ public class ScrimController implements ViewTreeObserver.OnPreDrawListener, Dump 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 ed3cf9a49a340..dd145e4193215 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 androidx.test.filters.SmallTest; 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 @@ public class UdfpsControllerTest extends SysuiTestCase { private WindowManager mWindowManager; @Mock private StatusBarStateController mStatusBarStateController; + @Mock + private ScrimController mScrimController; private FakeSettings mSystemSettings; private FakeExecutor mFgExecutor; @@ -130,7 +133,8 @@ public class UdfpsControllerTest extends SysuiTestCase { mWindowManager, mSystemSettings, mStatusBarStateController, - mFgExecutor); + mFgExecutor, + mScrimController); verify(mFingerprintManager).setUdfpsOverlayController(mOverlayCaptor.capture()); mOverlayController = mOverlayCaptor.getValue(); @@ -245,4 +249,10 @@ public class UdfpsControllerTest extends SysuiTestCase { // THEN the scrim and dot is hidden verify(mUdfpsView).hideScrimAndDot(); } + + @Test + public void registersViewForCallbacks() throws RemoteException { + verify(mStatusBarStateController).addCallback(mUdfpsView); + verify(mScrimController).addScrimChangedListener(mUdfpsView); + } }