diff --git a/packages/SystemUI/res/drawable/fingerprint_bg.xml b/packages/SystemUI/res/drawable/fingerprint_bg.xml new file mode 100644 index 0000000000000..2b0ab6f9a8d24 --- /dev/null +++ b/packages/SystemUI/res/drawable/fingerprint_bg.xml @@ -0,0 +1,25 @@ + + + + + + + diff --git a/packages/SystemUI/res/layout/udfps_keyguard_view.xml b/packages/SystemUI/res/layout/udfps_keyguard_view.xml index 0199ccb04be6b..562040b0ad826 100644 --- a/packages/SystemUI/res/layout/udfps_keyguard_view.xml +++ b/packages/SystemUI/res/layout/udfps_keyguard_view.xml @@ -20,7 +20,13 @@ android:layout_width="match_parent" android:layout_height="match_parent"> - + + - extends ViewController { + extends ViewController implements Dumpable { @NonNull final StatusBarStateController mStatusBarStateController; @NonNull final StatusBar mStatusBar; + @NonNull final DumpManager mDumpManger; private boolean mNotificationShadeExpanded; private int mStatusBarState; protected UdfpsAnimationViewController( T view, - StatusBarStateController statusBarStateController, - StatusBar statusBar) { + @NonNull StatusBarStateController statusBarStateController, + @NonNull StatusBar statusBar, + @NonNull DumpManager dumpManager) { super(view); mStatusBarStateController = statusBarStateController; mStatusBar = statusBar; + mDumpManger = dumpManager; } + abstract @NonNull String getTag(); + @Override protected void onViewAttached() { mStatusBarStateController.addCallback(mStateListener); mStateListener.onStateChanged(mStatusBarStateController.getState()); mStatusBar.addExpansionChangedListener(mStatusBarExpansionChangedListener); + + mDumpManger.registerDumpable(getTag(), this); } @Override protected void onViewDetached() { mStatusBarStateController.removeCallback(mStateListener); mStatusBar.removeExpansionChangedListener(mStatusBarExpansionChangedListener); + + mDumpManger.unregisterDumpable(getTag()); + } + + @Override + public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { + pw.println("mStatusBarState=" + StatusBarState.toShortString(mStatusBarState)); + pw.println("mNotificationShadeExpanded=" + mNotificationShadeExpanded); + pw.println("shouldPauseAuth()=" + shouldPauseAuth()); + pw.println("isPauseAuth=" + mView.isPauseAuth()); } /** diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsBpViewController.java b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsBpViewController.java index b712c655a6e70..93d80e29aded8 100644 --- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsBpViewController.java +++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsBpViewController.java @@ -16,6 +16,9 @@ package com.android.systemui.biometrics; +import android.annotation.NonNull; + +import com.android.systemui.dump.DumpManager; import com.android.systemui.plugins.statusbar.StatusBarStateController; import com.android.systemui.statusbar.phone.StatusBar; @@ -24,9 +27,15 @@ import com.android.systemui.statusbar.phone.StatusBar; */ class UdfpsBpViewController extends UdfpsAnimationViewController { protected UdfpsBpViewController( - UdfpsBpView view, - StatusBarStateController statusBarStateController, - StatusBar statusBar) { - super(view, statusBarStateController, statusBar); + @NonNull UdfpsBpView view, + @NonNull StatusBarStateController statusBarStateController, + @NonNull StatusBar statusBar, + @NonNull DumpManager dumpManager) { + super(view, statusBarStateController, statusBar, dumpManager); + } + + @Override + @NonNull String getTag() { + return "UdfpsBpViewController"; } } diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java index 94aeb73c4b42c..797a4411b8c96 100644 --- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java +++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java @@ -50,8 +50,10 @@ import com.android.systemui.R; import com.android.systemui.dagger.SysUISingleton; import com.android.systemui.dagger.qualifiers.Main; import com.android.systemui.doze.DozeReceiver; +import com.android.systemui.dump.DumpManager; import com.android.systemui.plugins.statusbar.StatusBarStateController; import com.android.systemui.statusbar.phone.StatusBar; +import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager; import com.android.systemui.util.concurrency.DelayableExecutor; import javax.inject.Inject; @@ -83,6 +85,8 @@ public class UdfpsController implements DozeReceiver, HbmCallback { private final DelayableExecutor mFgExecutor; @NonNull private final StatusBar mStatusBar; @NonNull private final StatusBarStateController mStatusBarStateController; + @NonNull private final StatusBarKeyguardViewManager mKeyguardViewManager; + @NonNull private final DumpManager mDumpManager; // Currently the UdfpsController supports a single UDFPS sensor. If devices have multiple // sensors, this, in addition to a lot of the code here, will be updated. @VisibleForTesting final FingerprintSensorPropertiesInternal mSensorProps; @@ -299,7 +303,9 @@ public class UdfpsController implements DozeReceiver, HbmCallback { WindowManager windowManager, @NonNull StatusBarStateController statusBarStateController, @Main DelayableExecutor fgExecutor, - @NonNull StatusBar statusBar) { + @NonNull StatusBar statusBar, + @NonNull StatusBarKeyguardViewManager statusBarKeyguardViewManager, + @NonNull DumpManager dumpManager) { mContext = context; mInflater = inflater; // The fingerprint manager is queried for UDFPS before this class is constructed, so the @@ -309,6 +315,8 @@ public class UdfpsController implements DozeReceiver, HbmCallback { mFgExecutor = fgExecutor; mStatusBar = statusBar; mStatusBarStateController = statusBarStateController; + mKeyguardViewManager = statusBarKeyguardViewManager; + mDumpManager = dumpManager; mSensorProps = findFirstUdfps(); // At least one UDFPS sensor exists @@ -457,7 +465,8 @@ public class UdfpsController implements DozeReceiver, HbmCallback { enrollView, mServerRequest.mEnrollHelper, mStatusBarStateController, - mStatusBar + mStatusBar, + mDumpManager ); case IUdfpsOverlayController.REASON_AUTH_FPM_KEYGUARD: UdfpsKeyguardView keyguardView = (UdfpsKeyguardView) @@ -466,7 +475,9 @@ public class UdfpsController implements DozeReceiver, HbmCallback { return new UdfpsKeyguardViewController( keyguardView, mStatusBarStateController, - mStatusBar + mStatusBar, + mKeyguardViewManager, + mDumpManager ); case IUdfpsOverlayController.REASON_AUTH_BP: // note: empty controller, currently shows no visual affordance @@ -475,7 +486,8 @@ public class UdfpsController implements DozeReceiver, HbmCallback { return new UdfpsBpViewController( bpView, mStatusBarStateController, - mStatusBar + mStatusBar, + mDumpManager ); case IUdfpsOverlayController.REASON_AUTH_FPM_OTHER: UdfpsFpmOtherView authOtherView = (UdfpsFpmOtherView) @@ -484,7 +496,8 @@ public class UdfpsController implements DozeReceiver, HbmCallback { return new UdfpsFpmOtherViewController( authOtherView, mStatusBarStateController, - mStatusBar + mStatusBar, + mDumpManager ); default: Log.d(TAG, "Animation for reason " + reason + " not supported yet"); diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsDrawable.java b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsDrawable.java index 13d31cb87fdc5..18f54166ad28c 100644 --- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsDrawable.java +++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsDrawable.java @@ -61,12 +61,14 @@ public abstract class UdfpsDrawable extends Drawable { */ protected void updateFingerprintIconBounds(@NonNull Rect bounds) { mFingerprintDrawable.setBounds(bounds); + invalidateSelf(); } @Override public void setAlpha(int alpha) { mAlpha = alpha; mFingerprintDrawable.setAlpha(mAlpha); + invalidateSelf(); } boolean isIlluminationShowing() { @@ -74,7 +76,11 @@ public abstract class UdfpsDrawable extends Drawable { } void setIlluminationShowing(boolean showing) { + if (mIlluminationShowing == showing) { + return; + } mIlluminationShowing = showing; + invalidateSelf(); } @Override diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsEnrollViewController.java b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsEnrollViewController.java index da8d712ebbdc4..1ebbfbf848143 100644 --- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsEnrollViewController.java +++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsEnrollViewController.java @@ -21,6 +21,7 @@ import android.graphics.PointF; import android.view.View; import com.android.systemui.R; +import com.android.systemui.dump.DumpManager; import com.android.systemui.plugins.statusbar.StatusBarStateController; import com.android.systemui.statusbar.phone.StatusBar; @@ -32,16 +33,22 @@ public class UdfpsEnrollViewController extends UdfpsAnimationViewController { protected UdfpsFpmOtherViewController( - UdfpsFpmOtherView view, - StatusBarStateController statusBarStateController, - StatusBar statusBar) { - super(view, statusBarStateController, statusBar); + @NonNull UdfpsFpmOtherView view, + @NonNull StatusBarStateController statusBarStateController, + @NonNull StatusBar statusBar, + @NonNull DumpManager dumpManager) { + super(view, statusBarStateController, statusBar, dumpManager); + } + + @Override + @NonNull String getTag() { + return "UdfpsFpmOtherViewController"; } } diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsKeyguardDrawable.java b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsKeyguardDrawable.java index b0c5da09d9160..12c15a0882f94 100644 --- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsKeyguardDrawable.java +++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsKeyguardDrawable.java @@ -36,14 +36,14 @@ import com.android.systemui.doze.DozeReceiver; public class UdfpsKeyguardDrawable extends UdfpsDrawable implements DozeReceiver { private static final String TAG = "UdfpsAnimationKeyguard"; - private final int mLockScreenColor; private final int mAmbientDisplayColor; @NonNull private final Context mContext; - private final int mMaxBurnInOffsetX; - private final int mMaxBurnInOffsetY; + private int mLockScreenColor; // AOD anti-burn-in offsets + private final int mMaxBurnInOffsetX; + private final int mMaxBurnInOffsetY; private float mInterpolatedDarkAmount; private float mBurnInOffsetX; private float mBurnInOffsetY; @@ -95,4 +95,10 @@ public class UdfpsKeyguardDrawable extends UdfpsDrawable implements DozeReceiver mInterpolatedDarkAmount = eased; updateAodPositionAndColor(); } + + void setLockScreenColor(int color) { + if (mLockScreenColor == color) return; + mLockScreenColor = color; + updateAodPositionAndColor(); + } } diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsKeyguardView.java b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsKeyguardView.java index 6a9356034d224..a78c223bf8838 100644 --- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsKeyguardView.java +++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsKeyguardView.java @@ -16,13 +16,23 @@ package com.android.systemui.biometrics; +import android.animation.Animator; +import android.animation.AnimatorListenerAdapter; +import android.animation.AnimatorSet; +import android.animation.ArgbEvaluator; +import android.animation.ObjectAnimator; +import android.animation.ValueAnimator; import android.content.Context; import android.util.AttributeSet; +import android.view.View; import android.widget.ImageView; import androidx.annotation.Nullable; +import com.android.settingslib.Utils; +import com.android.systemui.Interpolators; import com.android.systemui.R; +import com.android.systemui.statusbar.StatusBarState; /** * View corresponding with udfps_keyguard_view.xml @@ -30,6 +40,14 @@ import com.android.systemui.R; public class UdfpsKeyguardView extends UdfpsAnimationView { private final UdfpsKeyguardDrawable mFingerprintDrawable; private ImageView mFingerprintView; + private int mWallpaperTexColor; + private int mStatusBarState; + + // used when highlighting fp icon: + private int mTextColorPrimary; + private ImageView mBgProtection; + + private AnimatorSet mAnimatorSet; public UdfpsKeyguardView(Context context, @Nullable AttributeSet attrs) { super(context, attrs); @@ -38,8 +56,15 @@ public class UdfpsKeyguardView extends UdfpsAnimationView { @Override protected void onFinishInflate() { + super.onFinishInflate(); mFingerprintView = findViewById(R.id.udfps_keyguard_animation_fp_view); - mFingerprintView.setImageDrawable(mFingerprintDrawable); + mFingerprintView.setForeground(mFingerprintDrawable); + + mBgProtection = findViewById(R.id.udfps_keyguard_fp_bg); + + mWallpaperTexColor = Utils.getColorAttrDefaultColor(mContext, R.attr.wallpaperTextColor); + mTextColorPrimary = Utils.getColorAttrDefaultColor(mContext, + android.R.attr.textColorPrimary); } @Override @@ -54,7 +79,114 @@ public class UdfpsKeyguardView extends UdfpsAnimationView { return true; } + void setStatusBarState(int statusBarState) { + mStatusBarState = statusBarState; + if (!isShadeLocked()) { + mFingerprintView.setAlpha(1f); + mFingerprintDrawable.setLockScreenColor(mWallpaperTexColor); + } + } + void onDozeAmountChanged(float linear, float eased) { mFingerprintDrawable.onDozeAmountChanged(linear, eased); + invalidate(); + } + + /** + * Animates in the bg protection circle behind the fp icon to highlight the icon. + */ + void animateHighlightFp() { + if (mBgProtection.getVisibility() == View.VISIBLE && mBgProtection.getAlpha() == 1f) { + // already fully highlighted, don't re-animate + return; + } + + if (mAnimatorSet != null) { + mAnimatorSet.cancel(); + } + ValueAnimator fpIconAnim; + if (isShadeLocked()) { + // set color and fade in since we weren't showing before + mFingerprintDrawable.setLockScreenColor(mTextColorPrimary); + fpIconAnim = ObjectAnimator.ofFloat(mFingerprintView, View.ALPHA, 0f, 1f); + } else { + // update icon color + fpIconAnim = new ValueAnimator(); + fpIconAnim.setIntValues(mWallpaperTexColor, mTextColorPrimary); + fpIconAnim.setEvaluator(new ArgbEvaluator()); + fpIconAnim.addUpdateListener(valueAnimator -> mFingerprintDrawable.setLockScreenColor( + (Integer) valueAnimator.getAnimatedValue())); + } + + mAnimatorSet = new AnimatorSet(); + mAnimatorSet.setInterpolator(Interpolators.FAST_OUT_SLOW_IN); + mAnimatorSet.setDuration(500); + mAnimatorSet.addListener(new AnimatorListenerAdapter() { + @Override + public void onAnimationStart(Animator animation) { + mBgProtection.setVisibility(View.VISIBLE); + } + }); + + mAnimatorSet.playTogether( + ObjectAnimator.ofFloat(mBgProtection, View.ALPHA, 0f, 1f), + ObjectAnimator.ofFloat(mBgProtection, View.SCALE_X, 0f, 1f), + ObjectAnimator.ofFloat(mBgProtection, View.SCALE_Y, 0f, 1f), + fpIconAnim); + mAnimatorSet.start(); + } + + private boolean isShadeLocked() { + return mStatusBarState == StatusBarState.SHADE_LOCKED; + } + + /** + * Animates out the bg protection circle behind the fp icon to unhighlight the icon. + */ + void animateUnhighlightFp(@Nullable Runnable onEndAnimation) { + if (mBgProtection.getVisibility() == View.GONE) { + // already hidden + return; + } + + if (mAnimatorSet != null) { + mAnimatorSet.cancel(); + } + ValueAnimator fpIconAnim; + if (isShadeLocked()) { + // fade out + fpIconAnim = ObjectAnimator.ofFloat(mFingerprintView, View.ALPHA, 1f, 0f); + } else { + // update icon color + fpIconAnim = new ValueAnimator(); + fpIconAnim.setIntValues(mTextColorPrimary, mWallpaperTexColor); + fpIconAnim.setEvaluator(new ArgbEvaluator()); + fpIconAnim.addUpdateListener(valueAnimator -> mFingerprintDrawable.setLockScreenColor( + (Integer) valueAnimator.getAnimatedValue())); + } + + mAnimatorSet = new AnimatorSet(); + mAnimatorSet.playTogether( + ObjectAnimator.ofFloat(mBgProtection, View.ALPHA, 1f, 0f), + ObjectAnimator.ofFloat(mBgProtection, View.SCALE_X, 1f, 0f), + ObjectAnimator.ofFloat(mBgProtection, View.SCALE_Y, 1f, 0f), + fpIconAnim); + mAnimatorSet.setInterpolator(Interpolators.FAST_OUT_SLOW_IN); + mAnimatorSet.setDuration(500); + + mAnimatorSet.addListener(new AnimatorListenerAdapter() { + @Override + public void onAnimationEnd(Animator animation) { + mBgProtection.setVisibility(View.GONE); + if (onEndAnimation != null) { + onEndAnimation.run(); + } + } + }); + mAnimatorSet.start(); + } + + boolean isAnimating() { + return mAnimatorSet != null && mAnimatorSet.isRunning(); } } diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsKeyguardViewController.java b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsKeyguardViewController.java index 14bb3fee11747..08e5d562113d6 100644 --- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsKeyguardViewController.java +++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsKeyguardViewController.java @@ -16,34 +16,62 @@ package com.android.systemui.biometrics; +import android.annotation.NonNull; + +import com.android.systemui.dump.DumpManager; import com.android.systemui.plugins.statusbar.StatusBarStateController; import com.android.systemui.statusbar.phone.StatusBar; +import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager; + +import java.io.FileDescriptor; +import java.io.PrintWriter; /** * Class that coordinates non-HBM animations during keyguard authentication. */ public class UdfpsKeyguardViewController extends UdfpsAnimationViewController { + @NonNull private final StatusBarKeyguardViewManager mKeyguardViewManager; + private boolean mForceShow; protected UdfpsKeyguardViewController( - UdfpsKeyguardView view, - StatusBarStateController statusBarStateController, - StatusBar statusBar) { - super(view, statusBarStateController, statusBar); + @NonNull UdfpsKeyguardView view, + @NonNull StatusBarStateController statusBarStateController, + @NonNull StatusBar statusBar, + @NonNull StatusBarKeyguardViewManager statusBarKeyguardViewManager, + @NonNull DumpManager dumpManager) { + super(view, statusBarStateController, statusBar, dumpManager); + mKeyguardViewManager = statusBarKeyguardViewManager; + } + + @Override + @NonNull String getTag() { + return "UdfpsKeyguardViewController"; } @Override protected void onViewAttached() { super.onViewAttached(); - mStatusBarStateController.addCallback(mStateListener); + final float dozeAmount = mStatusBarStateController.getDozeAmount(); + mStatusBarStateController.addCallback(mStateListener); mStateListener.onDozeAmountChanged(dozeAmount, dozeAmount); + mStateListener.onStateChanged(mStatusBarStateController.getState()); + mKeyguardViewManager.setAlternateAuthInterceptor(mAlternateAuthInterceptor); } @Override protected void onViewDetached() { super.onViewDetached(); mStatusBarStateController.removeCallback(mStateListener); + mAlternateAuthInterceptor.reset(); + mKeyguardViewManager.setAlternateAuthInterceptor(null); + } + + @Override + public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { + super.dump(fd, pw, args); + pw.println("mForceShow=" + mForceShow); } /** @@ -56,7 +84,11 @@ public class UdfpsKeyguardViewController extends UdfpsAnimationViewController mKeyguardViewManager.cancelPostAuthActions()); + } } /** @@ -76,6 +108,50 @@ public class UdfpsKeyguardViewController extends UdfpsAnimationViewController