From cfd0176fdc50ba248663ff883796dc8c44d4d844 Mon Sep 17 00:00:00 2001 From: Beverly Date: Wed, 19 May 2021 10:36:18 -0400 Subject: Udfps icon, udfps bouncer, and lockicon/button bug fixes - Delay updating visibility of the LockIcon/Button when the FPS running state changes to false. The fingeprint listening state may be cancelled on screen off and immediately restarted on entering AOD. During this brief moment, we don't want to flash the grey button (affordance for bouncer when fps isn't running). - Remove keyguard visibility check from UdfpsKeyguardViewController - this was delaying showing the udfps icon on AOD since the visibilty changes too late. - Update udfps bouncer logic - only show the generic bouncer from showBouncerIfKeyguard if we're on the keyguard and bouncer isn't about to show (from swiping up from the bottom). - Reset leaveOpenOnKeyguardHide when a user exits the bouncer from a backpress. We don't want this state to linger into the next auth attempt. Test: manual Fixes: 188605736 Fixes: 187131910 Fixes: 185951882 Change-Id: Ibcddccdde0173b312404ea33741adc6a15efab6b (cherry picked from commit bc67508d6d04c54d08d513f8ed303e3055835e31) --- .../android/keyguard/LockIconViewController.java | 58 ++++++++++++++++++---- 1 file changed, 47 insertions(+), 11 deletions(-) (limited to 'packages/SystemUI/src/com/android/keyguard/LockIconViewController.java') diff --git a/packages/SystemUI/src/com/android/keyguard/LockIconViewController.java b/packages/SystemUI/src/com/android/keyguard/LockIconViewController.java index 0ea01fdb0bf6..6b85ba8420fc 100644 --- a/packages/SystemUI/src/com/android/keyguard/LockIconViewController.java +++ b/packages/SystemUI/src/com/android/keyguard/LockIconViewController.java @@ -40,6 +40,7 @@ import com.android.settingslib.Utils; import com.android.systemui.Dumpable; import com.android.systemui.R; import com.android.systemui.biometrics.AuthController; +import com.android.systemui.dagger.qualifiers.Main; import com.android.systemui.dump.DumpManager; import com.android.systemui.plugins.FalsingManager; import com.android.systemui.plugins.statusbar.StatusBarStateController; @@ -48,6 +49,7 @@ import com.android.systemui.statusbar.phone.dagger.StatusBarComponent; import com.android.systemui.statusbar.policy.ConfigurationController; import com.android.systemui.statusbar.policy.KeyguardStateController; import com.android.systemui.util.ViewController; +import com.android.systemui.util.concurrency.DelayableExecutor; import java.io.FileDescriptor; import java.io.PrintWriter; @@ -70,6 +72,7 @@ public class LockIconViewController extends ViewController impleme @NonNull private final AuthController mAuthController; @NonNull private final AccessibilityManager mAccessibilityManager; @NonNull private final ConfigurationController mConfigurationController; + @NonNull private final DelayableExecutor mExecutor; private boolean mHasUdfpsOrFaceAuthFeatures; private boolean mUdfpsEnrolled; @@ -90,6 +93,7 @@ public class LockIconViewController extends ViewController impleme private int mStatusBarState; private boolean mIsKeyguardShowing; private boolean mUserUnlockedWithBiometric; + private Runnable mCancelDelayedUpdateVisibilityRunnable; private boolean mShowButton; private boolean mShowUnlockIcon; @@ -106,7 +110,8 @@ public class LockIconViewController extends ViewController impleme @NonNull AuthController authController, @NonNull DumpManager dumpManager, @NonNull AccessibilityManager accessibilityManager, - @NonNull ConfigurationController configurationController + @NonNull ConfigurationController configurationController, + @NonNull @Main DelayableExecutor executor ) { super(view); mStatusBarStateController = statusBarStateController; @@ -117,6 +122,7 @@ public class LockIconViewController extends ViewController impleme mFalsingManager = falsingManager; mAccessibilityManager = accessibilityManager; mConfigurationController = configurationController; + mExecutor = executor; final Context context = view.getContext(); mButton = context.getResources().getDrawable( @@ -202,6 +208,11 @@ public class LockIconViewController extends ViewController impleme mKeyguardStateController.removeCallback(mKeyguardStateCallback); mAccessibilityManager.removeTouchExplorationStateChangeListener( mTouchExplorationStateChangeListener); + + if (mCancelDelayedUpdateVisibilityRunnable != null) { + mCancelDelayedUpdateVisibilityRunnable.run(); + mCancelDelayedUpdateVisibilityRunnable = null; + } } public float getTop() { @@ -213,8 +224,8 @@ public class LockIconViewController extends ViewController impleme return false; } - // pre-emptively set to false to hide view - mIsKeyguardShowing = false; + // pre-emptively set to true to hide view + mIsBouncerShowing = true; updateVisibility(); mKeyguardViewController.showBouncer(/* scrim */ true); return true; @@ -229,6 +240,11 @@ public class LockIconViewController extends ViewController impleme } private void updateVisibility() { + if (mCancelDelayedUpdateVisibilityRunnable != null) { + mCancelDelayedUpdateVisibilityRunnable.run(); + mCancelDelayedUpdateVisibilityRunnable = null; + } + if (!mIsKeyguardShowing || (!mUdfpsEnrolled && !mFaceAuthEnrolled)) { mView.setVisibility(View.INVISIBLE); return; @@ -318,13 +334,13 @@ public class LockIconViewController extends ViewController impleme @Override public void dump(@NonNull FileDescriptor fd, @NonNull PrintWriter pw, @NonNull String[] args) { - pw.println(" mShowBouncerButton: " + mShowButton); - pw.println(" mShowUnlockIcon: " + mShowUnlockIcon); - pw.println(" mShowLockIcon: " + mShowLockIcon); - pw.println(" mHasUdfpsOrFaceAuthFeatures: " + mHasUdfpsOrFaceAuthFeatures); - pw.println(" mUdfpsEnrolled: " + mUdfpsEnrolled); - pw.println(" mFaceAuthEnrolled: " + mFaceAuthEnrolled); - pw.println(" mIsKeyguardShowing: " + mIsKeyguardShowing); + pw.println("mHasUdfpsOrFaceAuthFeatures: " + mHasUdfpsOrFaceAuthFeatures); + pw.println("mUdfpsEnrolled: " + mUdfpsEnrolled); + pw.println("mFaceAuthEnrolled: " + mFaceAuthEnrolled); + pw.println("mIsKeyguardShowing: " + mIsKeyguardShowing); + pw.println(" mShowBouncerButton: " + mShowButton); + pw.println(" mShowUnlockIcon: " + mShowUnlockIcon); + pw.println(" mShowLockIcon: " + mShowLockIcon); pw.println(" mIsDozing: " + mIsDozing); pw.println(" mIsBouncerShowing: " + mIsBouncerShowing); pw.println(" mUserUnlockedWithBiometric: " + mUserUnlockedWithBiometric); @@ -351,6 +367,14 @@ public class LockIconViewController extends ViewController impleme private final KeyguardUpdateMonitorCallback mKeyguardUpdateMonitorCallback = new KeyguardUpdateMonitorCallback() { + @Override + public void onKeyguardVisibilityChanged(boolean showing) { + // reset mIsBouncerShowing state in case it was preemptively set + // onAffordanceClick + mIsBouncerShowing = mKeyguardViewController.isBouncerShowing(); + updateVisibility(); + } + @Override public void onKeyguardBouncerChanged(boolean bouncer) { mIsBouncerShowing = bouncer; @@ -366,7 +390,19 @@ public class LockIconViewController extends ViewController impleme if (biometricSourceType == FINGERPRINT) { mRunningFPS = running; - updateVisibility(); + if (!mRunningFPS) { + if (mCancelDelayedUpdateVisibilityRunnable != null) { + mCancelDelayedUpdateVisibilityRunnable.run(); + } + + // For some devices, auth is cancelled immediately on screen off but + // before dozing state is set. We want to avoid briefly showing the + // button in this case, so we delay updating the visibility by 50ms. + mCancelDelayedUpdateVisibilityRunnable = + mExecutor.executeDelayed(() -> updateVisibility(), 50); + } else { + updateVisibility(); + } } } }; -- cgit v1.2.3 From 1d12061ff58b998d3ac8f901dbf5c03c541486d3 Mon Sep 17 00:00:00 2001 From: Beverly Date: Thu, 26 Aug 2021 12:19:57 -0400 Subject: Remove ZigZagClassifer from lock-icon longpress falsing algo If the touch leaves the lock icon area, we already drop the touch. Therefore, we don't also need to also take into consideration the ZigZagClassifier for the lock icon. Also, only play the longpress vibration if we will be bringing up the bouncer. If the FalsingManager think we're falsing, there's no reason to play the longpress vibration. Test: manually longpress lock icon on device with udfps capability (after lockdown or reboot) and observe longpress consistently brings up the bouncer Fixes: 197271526 Change-Id: Ic9fa82a549599e48d281b4db69c04627803c6c5a Merged-In: Ic9fa82a549599e48d281b4db69c04627803c6c5a (cherry picked from commit 374f321fca4572401911f1493122600140e918eb) (cherry picked from commit e77ab2c10955bf553673cf4c471f0336d96790d5) --- .../src/com/android/keyguard/LockIconViewController.java | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) (limited to 'packages/SystemUI/src/com/android/keyguard/LockIconViewController.java') diff --git a/packages/SystemUI/src/com/android/keyguard/LockIconViewController.java b/packages/SystemUI/src/com/android/keyguard/LockIconViewController.java index 509ac8a6d9fe..8f34e5d0c764 100644 --- a/packages/SystemUI/src/com/android/keyguard/LockIconViewController.java +++ b/packages/SystemUI/src/com/android/keyguard/LockIconViewController.java @@ -497,8 +497,10 @@ public class LockIconViewController extends ViewController impleme if (!wasClickableOnDownEvent()) { return; } + mDetectedLongPress = true; - if (mVibrator != null) { + if (onAffordanceClick() && mVibrator != null) { + // only vibrate if the click went through and wasn't intercepted by falsing mVibrator.vibrate( Process.myUid(), getContext().getOpPackageName(), @@ -506,8 +508,6 @@ public class LockIconViewController extends ViewController impleme "lockIcon-onLongPress", VIBRATION_SONIFICATION_ATTRIBUTES); } - mDetectedLongPress = true; - onAffordanceClick(); } public boolean onSingleTapUp(MotionEvent e) { @@ -531,15 +531,21 @@ public class LockIconViewController extends ViewController impleme return mDownDetected; } - private void onAffordanceClick() { + /** + * Whether we tried to launch the affordance. + * + * If falsing intercepts the click, returns false. + */ + private boolean onAffordanceClick() { if (mFalsingManager.isFalseTouch(LOCK_ICON)) { - return; + return false; } // pre-emptively set to true to hide view mIsBouncerShowing = true; updateVisibility(); mKeyguardViewController.showBouncer(/* scrim */ true); + return true; } }); -- cgit v1.2.3 From 4ca180d63469e1168325af91b729ed917930f027 Mon Sep 17 00:00:00 2001 From: Beverly Date: Mon, 13 Sep 2021 17:25:00 -0400 Subject: Show UDFPS icon on AOD even if fp auth isn't running * shows udfps if it's enrolled on AOD even if: * device requires strong auth (ie: after reboot, lockdown) * device is unlocked via smart lock On click of the udfps icon in the above cases: * If the device is locked, the bouncer will show. * If the device is unlocked, the user will enter the device. Fixes: 198315404 Test: manual Change-Id: Id766df8f77427ae1db672507716bd38dc3462452 Merged-In: Id766df8f77427ae1db672507716bd38dc3462452 (cherry picked from commit c06bb2d2a65aeb15ca194c9cb47702a94079dfec) --- .../android/keyguard/LockIconViewController.java | 113 +++++++++++++++++++-- 1 file changed, 102 insertions(+), 11 deletions(-) (limited to 'packages/SystemUI/src/com/android/keyguard/LockIconViewController.java') diff --git a/packages/SystemUI/src/com/android/keyguard/LockIconViewController.java b/packages/SystemUI/src/com/android/keyguard/LockIconViewController.java index 8f34e5d0c764..a41997ce3107 100644 --- a/packages/SystemUI/src/com/android/keyguard/LockIconViewController.java +++ b/packages/SystemUI/src/com/android/keyguard/LockIconViewController.java @@ -19,6 +19,8 @@ package com.android.keyguard; import static android.hardware.biometrics.BiometricSourceType.FINGERPRINT; import static com.android.systemui.classifier.Classifier.LOCK_ICON; +import static com.android.systemui.doze.util.BurnInHelperKt.getBurnInOffset; +import static com.android.systemui.doze.util.BurnInHelperKt.getBurnInProgressOffset; import android.content.Context; import android.content.res.Configuration; @@ -32,6 +34,7 @@ import android.media.AudioAttributes; import android.os.Process; import android.os.Vibrator; import android.util.DisplayMetrics; +import android.util.MathUtils; import android.view.GestureDetector; import android.view.GestureDetector.SimpleOnGestureListener; import android.view.MotionEvent; @@ -58,6 +61,8 @@ import com.android.systemui.statusbar.policy.KeyguardStateController; import com.android.systemui.util.ViewController; import com.android.systemui.util.concurrency.DelayableExecutor; +import com.airbnb.lottie.LottieAnimationView; + import java.io.FileDescriptor; import java.io.PrintWriter; import java.util.Objects; @@ -92,6 +97,8 @@ public class LockIconViewController extends ViewController impleme @NonNull private final DelayableExecutor mExecutor; private boolean mUdfpsEnrolled; + @NonNull private LottieAnimationView mAodFp; + @NonNull private final AnimatedVectorDrawable mFpToUnlockIcon; @NonNull private final AnimatedVectorDrawable mLockToUnlockIcon; @NonNull private final Drawable mLockIcon; @@ -109,6 +116,7 @@ public class LockIconViewController extends ViewController impleme private boolean mIsKeyguardShowing; private boolean mUserUnlockedWithBiometric; private Runnable mCancelDelayedUpdateVisibilityRunnable; + private Runnable mOnGestureDetectedRunnable; private boolean mUdfpsSupported; private float mHeightPixels; @@ -118,6 +126,12 @@ public class LockIconViewController extends ViewController impleme private boolean mShowUnlockIcon; private boolean mShowLockIcon; + // for udfps when strong auth is required or unlocked on AOD + private boolean mShowAODFpIcon; + private final int mMaxBurnInOffsetX; + private final int mMaxBurnInOffsetY; + private float mInterpolatedDarkAmount; + private boolean mDownDetected; private boolean mDetectedLongPress; private final Rect mSensorTouchLocation = new Rect(); @@ -150,6 +164,12 @@ public class LockIconViewController extends ViewController impleme mVibrator = vibrator; final Context context = view.getContext(); + mAodFp = mView.findViewById(R.id.lock_udfps_aod_fp); + mMaxBurnInOffsetX = context.getResources() + .getDimensionPixelSize(R.dimen.udfps_burn_in_offset_x); + mMaxBurnInOffsetY = context.getResources() + .getDimensionPixelSize(R.dimen.udfps_burn_in_offset_y); + mUnlockIcon = mView.getContext().getResources().getDrawable( R.drawable.ic_unlock, mView.getContext().getTheme()); @@ -173,15 +193,14 @@ public class LockIconViewController extends ViewController impleme @Override protected void onViewAttached() { - // we check this here instead of onInit since the FingerprintManager + FaceManager may not - // have started up yet onInit - mUdfpsSupported = mAuthController.getUdfpsSensorLocation() != null; - + updateIsUdfpsEnrolled(); updateConfiguration(); updateKeyguardShowing(); mUserUnlockedWithBiometric = false; + mIsBouncerShowing = mKeyguardViewController.isBouncerShowing(); mIsDozing = mStatusBarStateController.isDozing(); + mInterpolatedDarkAmount = mStatusBarStateController.getDozeAmount(); mRunningFPS = mKeyguardUpdateMonitor.isFingerprintDetectionRunning(); mCanDismissLockScreen = mKeyguardStateController.canDismissLockScreen(); mStatusBarState = mStatusBarStateController.getState(); @@ -189,15 +208,18 @@ public class LockIconViewController extends ViewController impleme updateColors(); mConfigurationController.addCallback(mConfigurationListener); + mAuthController.addCallback(mAuthControllerCallback); mKeyguardUpdateMonitor.registerCallback(mKeyguardUpdateMonitorCallback); mStatusBarStateController.addCallback(mStatusBarStateListener); mKeyguardStateController.addCallback(mKeyguardStateCallback); mDownDetected = false; + updateBurnInOffsets(); updateVisibility(); } @Override protected void onViewDetached() { + mAuthController.removeCallback(mAuthControllerCallback); mConfigurationController.removeCallback(mConfigurationListener); mKeyguardUpdateMonitor.removeCallback(mKeyguardUpdateMonitorCallback); mStatusBarStateController.removeCallback(mStatusBarStateListener); @@ -227,7 +249,7 @@ public class LockIconViewController extends ViewController impleme mCancelDelayedUpdateVisibilityRunnable = null; } - if (!mIsKeyguardShowing) { + if (!mIsKeyguardShowing && !mIsDozing) { mView.setVisibility(View.INVISIBLE); return; } @@ -238,6 +260,7 @@ public class LockIconViewController extends ViewController impleme mShowLockIcon = !mCanDismissLockScreen && !mUserUnlockedWithBiometric && isLockScreen() && (!mUdfpsEnrolled || !mRunningFPS); mShowUnlockIcon = mCanDismissLockScreen && isLockScreen(); + mShowAODFpIcon = mIsDozing && mUdfpsEnrolled && !mRunningFPS; final CharSequence prevContentDescription = mView.getContentDescription(); if (mShowLockIcon) { @@ -260,10 +283,22 @@ public class LockIconViewController extends ViewController impleme } mView.setVisibility(View.VISIBLE); mView.setContentDescription(mUnlockedLabel); + } else if (mShowAODFpIcon) { + mView.setImageDrawable(null); + mView.setContentDescription(null); + mAodFp.setVisibility(View.VISIBLE); + mAodFp.setContentDescription(mCanDismissLockScreen ? mUnlockedLabel : mLockedLabel); + mView.setVisibility(View.VISIBLE); } else { mView.setVisibility(View.INVISIBLE); mView.setContentDescription(null); } + + if (!mShowAODFpIcon) { + mAodFp.setVisibility(View.INVISIBLE); + mAodFp.setContentDescription(null); + } + if (!Objects.equals(prevContentDescription, mView.getContentDescription()) && mView.getContentDescription() != null) { mView.announceForAccessibility(mView.getContentDescription()); @@ -340,10 +375,12 @@ public class LockIconViewController extends ViewController impleme @Override public void dump(@NonNull FileDescriptor fd, @NonNull PrintWriter pw, @NonNull String[] args) { + pw.println("mUdfpsSupported: " + mUdfpsSupported); pw.println("mUdfpsEnrolled: " + mUdfpsEnrolled); pw.println("mIsKeyguardShowing: " + mIsKeyguardShowing); pw.println(" mShowUnlockIcon: " + mShowUnlockIcon); pw.println(" mShowLockIcon: " + mShowLockIcon); + pw.println(" mShowAODFpIcon: " + mShowAODFpIcon); pw.println(" mIsDozing: " + mIsDozing); pw.println(" mIsBouncerShowing: " + mIsBouncerShowing); pw.println(" mUserUnlockedWithBiometric: " + mUserUnlockedWithBiometric); @@ -351,17 +388,57 @@ public class LockIconViewController extends ViewController impleme pw.println(" mCanDismissLockScreen: " + mCanDismissLockScreen); pw.println(" mStatusBarState: " + StatusBarState.toShortString(mStatusBarState)); pw.println(" mQsExpanded: " + mQsExpanded); + pw.println(" mInterpolatedDarkAmount: " + mInterpolatedDarkAmount); if (mView != null) { mView.dump(fd, pw, args); } } + /** Every minute, update the aod icon's burn in offset */ + public void dozeTimeTick() { + updateBurnInOffsets(); + } + + private void updateBurnInOffsets() { + float offsetX = MathUtils.lerp(0f, + getBurnInOffset(mMaxBurnInOffsetX * 2, true /* xAxis */) + - mMaxBurnInOffsetX, mInterpolatedDarkAmount); + float offsetY = MathUtils.lerp(0f, + getBurnInOffset(mMaxBurnInOffsetY * 2, false /* xAxis */) + - mMaxBurnInOffsetY, mInterpolatedDarkAmount); + float progress = MathUtils.lerp(0f, getBurnInProgressOffset(), mInterpolatedDarkAmount); + + mAodFp.setTranslationX(offsetX); + mAodFp.setTranslationY(offsetY); + mAodFp.setProgress(progress); + mAodFp.setAlpha(255 * mInterpolatedDarkAmount); + } + + private void updateIsUdfpsEnrolled() { + boolean wasUdfpsSupported = mUdfpsSupported; + boolean wasUdfpsEnrolled = mUdfpsEnrolled; + + mUdfpsSupported = mAuthController.getUdfpsSensorLocation() != null; + mUdfpsEnrolled = mKeyguardUpdateMonitor.isUdfpsEnrolled(); + if (wasUdfpsSupported != mUdfpsSupported || wasUdfpsEnrolled != mUdfpsEnrolled) { + updateVisibility(); + } + } + private StatusBarStateController.StateListener mStatusBarStateListener = new StatusBarStateController.StateListener() { + @Override + public void onDozeAmountChanged(float linear, float eased) { + mInterpolatedDarkAmount = eased; + updateBurnInOffsets(); + } + @Override public void onDozingChanged(boolean isDozing) { mIsDozing = isDozing; + updateBurnInOffsets(); + updateIsUdfpsEnrolled(); updateVisibility(); } @@ -435,7 +512,7 @@ public class LockIconViewController extends ViewController impleme mKeyguardUpdateMonitor.getUserUnlockedWithBiometric( KeyguardUpdateMonitor.getCurrentUser()); } - mUdfpsEnrolled = mKeyguardUpdateMonitor.isUdfpsEnrolled(); + updateIsUdfpsEnrolled(); updateVisibility(); } @@ -481,8 +558,7 @@ public class LockIconViewController extends ViewController impleme // intercept all following touches until we see MotionEvent.ACTION_CANCEL UP or // MotionEvent.ACTION_UP (see #onTouchEvent) - mDownDetected = true; - if (mVibrator != null) { + if (mVibrator != null && !mDownDetected) { mVibrator.vibrate( Process.myUid(), getContext().getOpPackageName(), @@ -490,6 +566,8 @@ public class LockIconViewController extends ViewController impleme "lockIcon-onDown", VIBRATION_SONIFICATION_ATTRIBUTES); } + + mDownDetected = true; return true; } @@ -544,6 +622,9 @@ public class LockIconViewController extends ViewController impleme // pre-emptively set to true to hide view mIsBouncerShowing = true; updateVisibility(); + if (mOnGestureDetectedRunnable != null) { + mOnGestureDetectedRunnable.run(); + } mKeyguardViewController.showBouncer(/* scrim */ true); return true; } @@ -554,16 +635,18 @@ public class LockIconViewController extends ViewController impleme * in a 'clickable' state * @return whether to intercept the touch event */ - public boolean onTouchEvent(MotionEvent event) { + public boolean onTouchEvent(MotionEvent event, Runnable onGestureDetectedRunnable) { if (mSensorTouchLocation.contains((int) event.getX(), (int) event.getY()) - && mView.getVisibility() == View.VISIBLE) { + && (mView.getVisibility() == View.VISIBLE + || mAodFp.getVisibility() == View.VISIBLE)) { + mOnGestureDetectedRunnable = onGestureDetectedRunnable; mGestureDetector.onTouchEvent(event); } // we continue to intercept all following touches until we see MotionEvent.ACTION_CANCEL UP // or MotionEvent.ACTION_UP. this is to avoid passing the touch to NPV // after the lock icon disappears on device entry - if (mDownDetected && mDetectedLongPress) { + if (mDownDetected) { if (event.getAction() == MotionEvent.ACTION_CANCEL || event.getAction() == MotionEvent.ACTION_UP) { mDownDetected = false; @@ -583,4 +666,12 @@ public class LockIconViewController extends ViewController impleme public void setAlpha(float alpha) { mView.setAlpha(alpha); } + + private final AuthController.Callback mAuthControllerCallback = new AuthController.Callback() { + @Override + public void onAllAuthenticatorsRegistered() { + updateIsUdfpsEnrolled(); + updateConfiguration(); + } + }; } -- cgit v1.2.3