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
This commit is contained in:
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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) {
|
||||
|
||||
|
||||
@@ -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) {
|
||||
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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<ScrimChangedListener> 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() {
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user