From 5082eadba8ebc77142d281cffdf499ee081b0b13 Mon Sep 17 00:00:00 2001 From: Beverly Date: Wed, 21 Apr 2021 08:36:47 -0400 Subject: [PATCH] Support slide to udfps auth on keyguard - Allow udfps fingerprint to run when the bouncer is about to show; instead, we'll manually pause auth in UdfpsKeyguardViewController when we don't want to allow the user to authenticate - On Keyguard, when bringing up the bouncer (swipe up on LS), continue to show the udfps target until it hits a threshold - then we fade out the icon Test: manual Bug: 178509275 Change-Id: I6e883a619b38a1a136f9d6e39b755a75c5028553 --- .../keyguard/KeyguardUpdateMonitor.java | 4 +- .../systemui/biometrics/AuthController.java | 6 +- .../systemui/biometrics/UdfpsController.java | 100 ++++++++++++------ .../biometrics/UdfpsKeyguardView.java | 14 ++- .../UdfpsKeyguardViewController.java | 47 +++++++- .../statusbar/phone/KeyguardBouncer.java | 4 +- .../NotificationPanelViewController.java | 3 - ...NotificationShadeWindowViewController.java | 6 +- .../phone/StatusBarKeyguardViewManager.java | 34 +++++- .../keyguard/KeyguardUpdateMonitorTest.java | 15 --- .../UdfpsKeyguardViewControllerTest.java | 16 ++- .../NotificationShadeWindowViewTest.java | 4 +- 12 files changed, 188 insertions(+), 65 deletions(-) diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java index 68a4194e113db..321c6b75d6713 100644 --- a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java @@ -2112,13 +2112,13 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab && mBiometricEnabledForUser.get(getCurrentUser()); final boolean shouldListenBouncerState = - isUdfps ? !mBouncer - : !(mFingerprintLockedOut && mBouncer && mCredentialAttempted); + !(mFingerprintLockedOut && mBouncer && mCredentialAttempted); final boolean shouldListenUdfpsState = !isUdfps || (!getUserCanSkipBouncer(getCurrentUser()) && !isEncryptedOrLockdown(getCurrentUser()) && mStrongAuthTracker.hasUserAuthenticatedSinceBoot()); + return shouldListenKeyguardState && shouldListenUserState && shouldListenBouncerState && shouldListenUdfpsState; } diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/AuthController.java b/packages/SystemUI/src/com/android/systemui/biometrics/AuthController.java index 0c7b55d6ecbbb..3d86034093423 100644 --- a/packages/SystemUI/src/com/android/systemui/biometrics/AuthController.java +++ b/packages/SystemUI/src/com/android/systemui/biometrics/AuthController.java @@ -265,7 +265,7 @@ public class AuthController extends SystemUI implements CommandQueue.Callbacks, /** * @return where the UDFPS exists on the screen in pixels in portrait mode. */ - public RectF getUdfpsRegion() { + @Nullable public RectF getUdfpsRegion() { return mUdfpsController == null ? null : mUdfpsController.getSensorLocation(); @@ -274,7 +274,7 @@ public class AuthController extends SystemUI implements CommandQueue.Callbacks, /** * @return where the UDFPS exists on the screen in pixels in portrait mode. */ - public PointF getUdfpsSensorLocation() { + @Nullable public PointF getUdfpsSensorLocation() { if (mUdfpsController == null) { return null; } @@ -286,7 +286,7 @@ public class AuthController extends SystemUI implements CommandQueue.Callbacks, * @return where the face authentication sensor exists relative to the screen in pixels in * portrait mode. */ - public PointF getFaceAuthSensorLocation() { + @Nullable public PointF getFaceAuthSensorLocation() { if (mFaceProps == null || mFaceAuthSensorLocation == null) { return null; } diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java index 47c4a63b4a8c1..edb90c21361d6 100644 --- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java +++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java @@ -260,10 +260,36 @@ public class UdfpsController implements DozeReceiver, HbmCallback { } }; - @SuppressLint("ClickableViewAccessibility") - private final UdfpsView.OnTouchListener mOnTouchListener = this::onTouch; + /** + * Forwards touches to the udfps controller / view + */ + public boolean onTouch(MotionEvent event) { + if (mView == null) { + return false; + } + return onTouch(mView, event, false); + } - private boolean onTouch(View view, MotionEvent event) { + @SuppressLint("ClickableViewAccessibility") + private final UdfpsView.OnTouchListener mOnTouchListener = (view, event) -> + onTouch(view, event, true); + + /** + * @param x coordinate + * @param y coordinate + * @param relativeToUdfpsView true if the coordinates are relative to the udfps view; else, + * calculate from the display dimensions in portrait orientation + */ + private boolean isWithinSensorArea(UdfpsView udfpsView, float x, float y, + boolean relativeToUdfpsView) { + if (relativeToUdfpsView) { + // TODO: move isWithinSensorArea to UdfpsController. + return udfpsView.isWithinSensorArea(x, y); + } + return getSensorLocation().contains(x, y); + } + + private boolean onTouch(View view, MotionEvent event, boolean fromUdfpsView) { UdfpsView udfpsView = (UdfpsView) view; final boolean isFingerDown = udfpsView.isIlluminationRequested(); boolean handled = false; @@ -281,8 +307,7 @@ public class UdfpsController implements DozeReceiver, HbmCallback { // ACTION_DOWN, in that case we should just reuse the old instance. mVelocityTracker.clear(); } - // TODO: move isWithinSensorArea to UdfpsController. - if (udfpsView.isWithinSensorArea(event.getX(), event.getY())) { + if (isWithinSensorArea(udfpsView, event.getX(), event.getY(), fromUdfpsView)) { Trace.beginAsyncSection( "UdfpsController.mOnTouchListener#isWithinSensorArea", 1); // The pointer that causes ACTION_DOWN is always at index 0. @@ -290,37 +315,23 @@ public class UdfpsController implements DozeReceiver, HbmCallback { // data for many other pointers because of multi-touch support. mActivePointerId = event.getPointerId(0); mVelocityTracker.addMovement(event); - - // TODO: (b/185124905) these settings are for ux testing purposes and should - // be removed (or cached) before going into production - final ContentResolver contentResolver = mContext.getContentResolver(); - int startEnabled = Settings.Global.getInt(contentResolver, - "udfps_start", 0); - if (startEnabled > 0) { - String startEffectSetting = Settings.Global.getString(contentResolver, - "udfps_start_type"); - mVibrator.vibrate(getVibration(startEffectSetting, mEffectClick), - VIBRATION_SONIFICATION_ATTRIBUTES); - } - - int acquiredEnabled = Settings.Global.getInt(contentResolver, - "udfps_acquired", 0); - if (acquiredEnabled > 0) { - int delay = Settings.Global.getInt(contentResolver, - "udfps_acquired_delay", 500); - mMainHandler.removeCallbacks(mAcquiredVibration); - mMainHandler.postDelayed(mAcquiredVibration, delay); - } handled = true; } break; case MotionEvent.ACTION_MOVE: - final int idx = event.findPointerIndex(mActivePointerId); + final int idx = mActivePointerId == -1 + ? event.getPointerId(0) + : event.findPointerIndex(mActivePointerId); if (idx == event.getActionIndex()) { final float x = event.getX(idx); final float y = event.getY(idx); - if (udfpsView.isWithinSensorArea(x, y)) { + if (isWithinSensorArea(udfpsView, x, y, fromUdfpsView)) { + if (mVelocityTracker == null) { + // touches could be injected, so the velocity tracker may not have + // been initialized (via ACTION_DOWN). + mVelocityTracker = VelocityTracker.obtain(); + } mVelocityTracker.addMovement(event); // Compute pointer velocity in pixels per second. mVelocityTracker.computeCurrentVelocity(1000); @@ -328,10 +339,12 @@ public class UdfpsController implements DozeReceiver, HbmCallback { final float v = computePointerSpeed(mVelocityTracker, mActivePointerId); final float minor = event.getTouchMinor(idx); final float major = event.getTouchMajor(idx); - final String touchInfo = String.format("minor: %.1f, major: %.1f, v: %.1f", - minor, major, v); + final boolean exceedsVelocityThreshold = v > 750f; + final String touchInfo = String.format( + "minor: %.1f, major: %.1f, v: %.1f, exceedsVelocityThreshold: %b", + minor, major, v, exceedsVelocityThreshold); final long sinceLastLog = SystemClock.elapsedRealtime() - mTouchLogTime; - if (!isFingerDown) { + if (!isFingerDown && !exceedsVelocityThreshold) { Trace.endAsyncSection( "UdfpsController.mOnTouchListener#isWithinSensorArea", 1); onFingerDown((int) x, (int) y, minor, major); @@ -339,6 +352,26 @@ public class UdfpsController implements DozeReceiver, HbmCallback { mTouchLogTime = SystemClock.elapsedRealtime(); mPowerManager.userActivity(SystemClock.uptimeMillis(), PowerManager.USER_ACTIVITY_EVENT_TOUCH, 0); + + // TODO: this should eventually be removed after ux testing + final ContentResolver contentResolver = mContext.getContentResolver(); + int startEnabled = Settings.Global.getInt(contentResolver, + "udfps_start", 0); + if (startEnabled > 0) { + String startEffectSetting = Settings.Global.getString( + contentResolver, "udfps_start_type"); + mVibrator.vibrate(getVibration(startEffectSetting, mEffectClick), + VIBRATION_SONIFICATION_ATTRIBUTES); + } + + int acquiredEnabled = Settings.Global.getInt(contentResolver, + "udfps_acquired", 0); + if (acquiredEnabled > 0) { + int delay = Settings.Global.getInt(contentResolver, + "udfps_acquired_delay", 500); + mMainHandler.removeCallbacks(mAcquiredVibration); + mMainHandler.postDelayed(mAcquiredVibration, delay); + } handled = true; } else if (sinceLastLog >= MIN_TOUCH_LOG_INTERVAL) { Log.v(TAG, "onTouch | finger move: " + touchInfo); @@ -353,6 +386,7 @@ public class UdfpsController implements DozeReceiver, HbmCallback { case MotionEvent.ACTION_UP: case MotionEvent.ACTION_CANCEL: + mActivePointerId = -1; if (mVelocityTracker != null) { mVelocityTracker.recycle(); mVelocityTracker = null; @@ -577,7 +611,8 @@ public class UdfpsController implements DozeReceiver, HbmCallback { mKeyguardUpdateMonitor, mFgExecutor, mDumpManager, - mKeyguardViewMediator + mKeyguardViewMediator, + this ); case IUdfpsOverlayController.REASON_AUTH_BP: // note: empty controller, currently shows no visual affordance @@ -679,6 +714,7 @@ public class UdfpsController implements DozeReceiver, HbmCallback { // This method can be called from the UI thread. private void onFingerUp() { + mActivePointerId = -1; mMainHandler.removeCallbacks(mAcquiredVibration); if (mView == null) { Log.w(TAG, "Null view in onFingerUp"); diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsKeyguardView.java b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsKeyguardView.java index 565e65fbbc92c..37ea251c08b8f 100644 --- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsKeyguardView.java +++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsKeyguardView.java @@ -48,6 +48,7 @@ public class UdfpsKeyguardView extends UdfpsAnimationView { private ImageView mBgProtection; private AnimatorSet mAnimatorSet; + private int mAlpha; // 0-255 public UdfpsKeyguardView(Context context, @Nullable AttributeSet attrs) { super(context, attrs); @@ -97,9 +98,20 @@ public class UdfpsKeyguardView extends UdfpsAnimationView { } } + /** + * @param alpha between 0 and 255 + */ + void setUnpausedAlpha(int alpha) { + mAlpha = alpha; + updateAlpha(); + } + @Override int calculateAlpha() { - return mPauseAuth ? 0 : 255; + if (mPauseAuth) { + return 0; + } + return mAlpha; } void onDozeAmountChanged(float linear, float eased) { diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsKeyguardViewController.java b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsKeyguardViewController.java index 63af6aac30b3e..4d2f809531fdd 100644 --- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsKeyguardViewController.java +++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsKeyguardViewController.java @@ -20,6 +20,8 @@ import static com.android.systemui.statusbar.StatusBarState.KEYGUARD; import android.annotation.NonNull; import android.hardware.biometrics.BiometricSourceType; +import android.util.MathUtils; +import android.view.MotionEvent; import androidx.annotation.Nullable; @@ -29,6 +31,7 @@ import com.android.systemui.dump.DumpManager; import com.android.systemui.keyguard.KeyguardViewMediator; import com.android.systemui.plugins.statusbar.StatusBarStateController; import com.android.systemui.statusbar.StatusBarState; +import com.android.systemui.statusbar.phone.KeyguardBouncer; import com.android.systemui.statusbar.phone.StatusBar; import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager; import com.android.systemui.util.concurrency.DelayableExecutor; @@ -50,6 +53,7 @@ public class UdfpsKeyguardViewController extends UdfpsAnimationViewController