From dc1e4a97a60d9cc0d12c0c251ac4849dc5391412 Mon Sep 17 00:00:00 2001 From: Kevin Chyn Date: Wed, 12 Aug 2020 14:54:08 -0700 Subject: [PATCH 1/2] Update Fingerprint21, add Fingerprint21UdfpsMock 1) It may not be practical in all cases to bump the HIDL to fingerprint2.3. So, give the framework a way to override this parameter. 2) Updates Fingerprint21 so the HAL callback is a static inner class. This A) allows subclasses to extend/override its functionality, and B) is necessary now because the callback needs to be created prior to Fingerprint21 construction (see 3 below) 3) Changes Fingerprint21 so that several objects are created before its constructor. This is necessary because Fingerprint21's constructor requires usage of the HAL, which implies the callback must be ready, since using the HAL requires a valid callback. In other words, the callback must be created before Fingerprint21UdfpsMock invokes Fingerprint21's constructor. 4) UDFPS accept must be touched within 10s of sensor auth succeeding 5) Shows debug messages on UdfpsOverlay since fingerprint sensor no longer gives feedback, etc Bug: 163864182 Test: adb shell settings put secure ... (see defs in Fingerprint21UdfpsMock) adb shell stop && adb shell start Change-Id: I07c3801024087f2e8ef10f125d20cb536aefbd91 --- .../fingerprint/IUdfpsOverlayController.aidl | 3 + core/res/res/values/config.xml | 2 + core/res/res/values/symbols.xml | 1 + .../systemui/biometrics/UdfpsController.java | 8 + .../systemui/biometrics/UdfpsView.java | 30 +- .../biometrics/sensors/AcquisitionClient.java | 6 +- .../sensors/AuthenticationClient.java | 8 + .../sensors/BiometricScheduler.java | 32 +- .../biometrics/sensors/ClientMonitor.java | 1 + .../biometrics/sensors/LoggableMonitor.java | 4 + .../sensors/fingerprint/Fingerprint21.java | 86 ++- .../fingerprint/Fingerprint21UdfpsMock.java | 555 ++++++++++++++++++ .../FingerprintAuthenticationClient.java | 11 +- .../fingerprint/FingerprintService.java | 25 +- .../server/trust/TrustManagerService.java | 2 +- 15 files changed, 729 insertions(+), 45 deletions(-) create mode 100644 services/core/java/com/android/server/biometrics/sensors/fingerprint/Fingerprint21UdfpsMock.java diff --git a/core/java/android/hardware/fingerprint/IUdfpsOverlayController.aidl b/core/java/android/hardware/fingerprint/IUdfpsOverlayController.aidl index 32530da74e897..a57726c4afe4b 100644 --- a/core/java/android/hardware/fingerprint/IUdfpsOverlayController.aidl +++ b/core/java/android/hardware/fingerprint/IUdfpsOverlayController.aidl @@ -25,4 +25,7 @@ oneway interface IUdfpsOverlayController { // Hides the overlay. void hideUdfpsOverlay(); + + // Shows debug messages on the UDFPS overlay. + void setDebugMessage(String message); } diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml index f99be880cbe33..613111d512be4 100644 --- a/core/res/res/values/config.xml +++ b/core/res/res/values/config.xml @@ -4189,6 +4189,8 @@ + + false 15dp + + 8dp + 8dp + 8dp 0dp 48dp diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/AuthController.java b/packages/SystemUI/src/com/android/systemui/biometrics/AuthController.java index ade106fb2223b..3cd4fca0e8771 100644 --- a/packages/SystemUI/src/com/android/systemui/biometrics/AuthController.java +++ b/packages/SystemUI/src/com/android/systemui/biometrics/AuthController.java @@ -49,6 +49,8 @@ import com.android.internal.R; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.os.SomeArgs; import com.android.systemui.SystemUI; +import com.android.systemui.doze.DozeReceiver; +import com.android.systemui.plugins.statusbar.StatusBarStateController; import com.android.systemui.statusbar.CommandQueue; import java.util.List; @@ -62,12 +64,13 @@ import javax.inject.Singleton; */ @Singleton public class AuthController extends SystemUI implements CommandQueue.Callbacks, - AuthDialogCallback { + AuthDialogCallback, DozeReceiver { - private static final String TAG = "BiometricPrompt/AuthController"; + private static final String TAG = "AuthController"; private static final boolean DEBUG = true; private final CommandQueue mCommandQueue; + private final StatusBarStateController mStatusBarStateController; private final Injector mInjector; // TODO: These should just be saved from onSaveState @@ -77,6 +80,7 @@ public class AuthController extends SystemUI implements CommandQueue.Callbacks, private Handler mHandler = new Handler(Looper.getMainLooper()); private WindowManager mWindowManager; + @Nullable private UdfpsController mUdfpsController; @VisibleForTesting IActivityTaskManager mActivityTaskManager; @@ -142,6 +146,13 @@ public class AuthController extends SystemUI implements CommandQueue.Callbacks, } }; + @Override + public void dozeTimeTick() { + if (mUdfpsController != null) { + mUdfpsController.dozeTimeTick(); + } + } + @Override public void onTryAgainPressed() { if (mReceiver == null) { @@ -251,14 +262,17 @@ public class AuthController extends SystemUI implements CommandQueue.Callbacks, } @Inject - public AuthController(Context context, CommandQueue commandQueue) { - this(context, commandQueue, new Injector()); + public AuthController(Context context, CommandQueue commandQueue, + StatusBarStateController statusBarStateController) { + this(context, commandQueue, statusBarStateController, new Injector()); } @VisibleForTesting - AuthController(Context context, CommandQueue commandQueue, Injector injector) { + AuthController(Context context, CommandQueue commandQueue, + StatusBarStateController statusBarStateController, Injector injector) { super(context); mCommandQueue = commandQueue; + mStatusBarStateController = statusBarStateController; mInjector = injector; IntentFilter filter = new IntentFilter(); @@ -280,7 +294,7 @@ public class AuthController extends SystemUI implements CommandQueue.Callbacks, fpm.getSensorProperties(); for (FingerprintSensorProperties props : fingerprintSensorProperties) { if (props.sensorType == FingerprintSensorProperties.TYPE_UDFPS) { - mUdfpsController = new UdfpsController(mContext); + mUdfpsController = new UdfpsController(mContext, mStatusBarStateController); break; } } diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java index fdd3b2603a893..82fb80892ab16 100644 --- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java +++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java @@ -16,6 +16,7 @@ package com.android.systemui.biometrics; +import android.annotation.NonNull; import android.annotation.SuppressLint; import android.content.ContentResolver; import android.content.Context; @@ -39,6 +40,8 @@ import android.view.WindowManager; import com.android.internal.BrightnessSynchronizer; import com.android.systemui.R; +import com.android.systemui.doze.DozeReceiver; +import com.android.systemui.plugins.statusbar.StatusBarStateController; import java.io.FileWriter; import java.io.IOException; @@ -47,7 +50,7 @@ import java.io.IOException; * Shows and hides the under-display fingerprint sensor (UDFPS) overlay, handles UDFPS touch events, * and coordinates triggering of the high-brightness mode (HBM). */ -class UdfpsController { +class UdfpsController implements DozeReceiver { private static final String TAG = "UdfpsController"; // Gamma approximation for the sRGB color space. private static final float DISPLAY_GAMMA = 2.2f; @@ -62,6 +65,7 @@ class UdfpsController { private final String mHbmPath; private final String mHbmEnableCommand; private final String mHbmDisableCommand; + private final boolean mHbmSupported; // Brightness in nits in the high-brightness mode. private final float mHbmNits; // A spline mapping from the device's backlight value, normalized to the range [0, 1.0], to a @@ -122,7 +126,8 @@ class UdfpsController { } }; - UdfpsController(Context context) { + UdfpsController(@NonNull Context context, + @NonNull StatusBarStateController statusBarStateController) { mFingerprintManager = context.getSystemService(FingerprintManager.class); mWindowManager = context.getSystemService(WindowManager.class); mContentResolver = context.getContentResolver(); @@ -135,7 +140,9 @@ class UdfpsController { mHbmEnableCommand = context.getResources().getString(R.string.udfps_hbm_enable_command); mHbmDisableCommand = context.getResources().getString(R.string.udfps_hbm_disable_command); - mView.setHbmSupported(!TextUtils.isEmpty(mHbmPath)); + mHbmSupported = !TextUtils.isEmpty(mHbmPath); + mView.setHbmSupported(mHbmSupported); + statusBarStateController.addCallback(mView); // This range only consists of the minimum and maximum values, which only cover // non-high-brightness mode. @@ -170,6 +177,11 @@ class UdfpsController { mIsOverlayShowing = false; } + @Override + public void dozeTimeTick() { + mView.dozeTimeTick(); + } + private void showUdfpsOverlay() { mHandler.post(() -> { if (!mIsOverlayShowing) { @@ -232,9 +244,11 @@ class UdfpsController { mView.setScrimAlpha(computeScrimOpacity()); mView.showScrimAndDot(); try { - FileWriter fw = new FileWriter(mHbmPath); - fw.write(mHbmEnableCommand); - fw.close(); + if (mHbmSupported) { + FileWriter fw = new FileWriter(mHbmPath); + fw.write(mHbmEnableCommand); + fw.close(); + } mFingerprintManager.onFingerDown(x, y, minor, major); } catch (IOException e) { mView.hideScrimAndDot(); @@ -246,13 +260,15 @@ class UdfpsController { mFingerprintManager.onFingerUp(); // Hiding the scrim before disabling HBM results in less noticeable flicker. mView.hideScrimAndDot(); - try { - FileWriter fw = new FileWriter(mHbmPath); - fw.write(mHbmDisableCommand); - fw.close(); - } catch (IOException e) { - mView.showScrimAndDot(); - Log.e(TAG, "onFingerUp | failed to disable HBM: " + e.getMessage()); + if (mHbmSupported) { + try { + FileWriter fw = new FileWriter(mHbmPath); + fw.write(mHbmDisableCommand); + fw.close(); + } catch (IOException e) { + mView.showScrimAndDot(); + Log.e(TAG, "onFingerUp | failed to disable HBM: " + e.getMessage()); + } } } diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsView.java b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsView.java index 69883eaa76a7c..36353fa969560 100644 --- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsView.java +++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsView.java @@ -16,6 +16,8 @@ package com.android.systemui.biometrics; +import static com.android.systemui.doze.util.BurnInHelperKt.getBurnInOffset; + import android.content.Context; import android.content.res.TypedArray; import android.graphics.Canvas; @@ -23,17 +25,22 @@ import android.graphics.Color; import android.graphics.Paint; import android.graphics.Rect; import android.graphics.RectF; +import android.text.TextUtils; import android.util.AttributeSet; import android.util.Log; +import android.util.MathUtils; import android.view.View; import android.view.ViewTreeObserver; import com.android.systemui.R; +import com.android.systemui.doze.DozeReceiver; +import com.android.systemui.plugins.statusbar.StatusBarStateController; /** * A full screen view with a configurable illumination dot and scrim. */ -public class UdfpsView extends View { +public class UdfpsView extends View implements DozeReceiver, + StatusBarStateController.StateListener { private static final String TAG = "UdfpsView"; // Values in pixels. @@ -53,10 +60,17 @@ public class UdfpsView extends View { private final float mSensorRadius; private final float mSensorMarginBottom; private final float mSensorTouchAreaCoefficient; + private final int mMaxBurnInOffsetX; + private final int mMaxBurnInOffsetY; private final Rect mTouchableRegion; private final ViewTreeObserver.OnComputeInternalInsetsListener mInsetsListener; + // AOD anti-burn-in offsets + private float mInterpolatedDarkAmount; + private float mBurnInOffsetX; + private float mBurnInOffsetY; + private boolean mIsScrimShowing; private boolean mHbmSupported; private String mDebugMessage; @@ -85,6 +99,11 @@ public class UdfpsView extends View { a.recycle(); } + mMaxBurnInOffsetX = getResources() + .getDimensionPixelSize(R.dimen.udfps_burn_in_offset_x); + mMaxBurnInOffsetY = getResources() + .getDimensionPixelSize(R.dimen.udfps_burn_in_offset_y); + mScrimRect = new Rect(); mScrimPaint = new Paint(0 /* flags */); mScrimPaint.setColor(Color.BLACK); @@ -113,6 +132,29 @@ public class UdfpsView extends View { mIsScrimShowing = false; } + @Override + public void dozeTimeTick() { + updateAodPosition(); + } + + @Override + public void onDozeAmountChanged(float linear, float eased) { + mInterpolatedDarkAmount = eased; + updateAodPosition(); + } + + private void updateAodPosition() { + mBurnInOffsetX = MathUtils.lerp(0f, + getBurnInOffset(mMaxBurnInOffsetX * 2, true /* xAxis */) + - mMaxBurnInOffsetX, + mInterpolatedDarkAmount); + mBurnInOffsetY = MathUtils.lerp(0f, + getBurnInOffset(mMaxBurnInOffsetY * 2, false /* xAxis */) + - 0.5f * mMaxBurnInOffsetY, + mInterpolatedDarkAmount); + postInvalidate(); + } + @Override protected void onAttachedToWindow() { super.onAttachedToWindow(); @@ -142,14 +184,20 @@ public class UdfpsView extends View { @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); + if (mIsScrimShowing && mHbmSupported) { // Only draw the scrim if HBM is supported. canvas.drawRect(mScrimRect, mScrimPaint); } - canvas.drawText(mDebugMessage, 0, 60, mDebugTextPaint); - + // Translation should affect everything but the scrim. + canvas.save(); + canvas.translate(mBurnInOffsetX, mBurnInOffsetY); + if (!TextUtils.isEmpty(mDebugMessage)) { + canvas.drawText(mDebugMessage, 0, 160, mDebugTextPaint); + } canvas.drawOval(mSensorRect, mSensorPaint); + canvas.restore(); } void setHbmSupported(boolean hbmSupported) { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeServiceHost.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeServiceHost.java index de74d4e04921a..5aca0dfd677ab 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeServiceHost.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeServiceHost.java @@ -31,6 +31,7 @@ import android.view.View; import com.android.internal.annotations.VisibleForTesting; import com.android.keyguard.KeyguardUpdateMonitor; import com.android.systemui.assist.AssistManager; +import com.android.systemui.biometrics.AuthController; import com.android.systemui.doze.DozeHost; import com.android.systemui.doze.DozeLog; import com.android.systemui.doze.DozeReceiver; @@ -88,6 +89,7 @@ public final class DozeServiceHost implements DozeHost { private final NotificationWakeUpCoordinator mNotificationWakeUpCoordinator; private NotificationShadeWindowViewController mNotificationShadeWindowViewController; private final LockscreenLockIconController mLockscreenLockIconController; + private final AuthController mAuthController; private NotificationIconAreaController mNotificationIconAreaController; private StatusBarKeyguardViewManager mStatusBarKeyguardViewManager; private NotificationPanelViewController mNotificationPanel; @@ -110,7 +112,8 @@ public final class DozeServiceHost implements DozeHost { PulseExpansionHandler pulseExpansionHandler, NotificationShadeWindowController notificationShadeWindowController, NotificationWakeUpCoordinator notificationWakeUpCoordinator, - LockscreenLockIconController lockscreenLockIconController) { + LockscreenLockIconController lockscreenLockIconController, + AuthController authController) { super(); mDozeLog = dozeLog; mPowerManager = powerManager; @@ -130,6 +133,7 @@ public final class DozeServiceHost implements DozeHost { mNotificationShadeWindowController = notificationShadeWindowController; mNotificationWakeUpCoordinator = notificationWakeUpCoordinator; mLockscreenLockIconController = lockscreenLockIconController; + mAuthController = authController; } // TODO: we should try to not pass status bar in here if we can avoid it. @@ -297,6 +301,7 @@ public final class DozeServiceHost implements DozeHost { @Override public void dozeTimeTick() { mNotificationPanel.dozeTimeTick(); + mAuthController.dozeTimeTick(); if (mAmbientIndicationContainer instanceof DozeReceiver) { ((DozeReceiver) mAmbientIndicationContainer).dozeTimeTick(); } diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthControllerTest.java index d4a94c5b9e66c..c8566c599108e 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthControllerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthControllerTest.java @@ -54,6 +54,7 @@ import android.testing.TestableLooper.RunWithLooper; import com.android.internal.R; import com.android.systemui.SysuiTestCase; +import com.android.systemui.plugins.statusbar.StatusBarStateController; import com.android.systemui.statusbar.CommandQueue; import org.junit.Before; @@ -103,8 +104,8 @@ public class AuthControllerTest extends SysuiTestCase { when(mDialog1.isAllowDeviceCredentials()).thenReturn(false); when(mDialog2.isAllowDeviceCredentials()).thenReturn(false); - mAuthController = new TestableAuthController( - context, mock(CommandQueue.class), new MockInjector()); + mAuthController = new TestableAuthController(context, mock(CommandQueue.class), + mock(StatusBarStateController.class), new MockInjector()); mAuthController.start(); } @@ -502,8 +503,9 @@ public class AuthControllerTest extends SysuiTestCase { private int mBuildCount = 0; private PromptInfo mLastBiometricPromptInfo; - TestableAuthController(Context context, CommandQueue commandQueue, Injector injector) { - super(context, commandQueue, injector); + TestableAuthController(Context context, CommandQueue commandQueue, + StatusBarStateController statusBarStateController, Injector injector) { + super(context, commandQueue, statusBarStateController, injector); } @Override diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/DozeServiceHostTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/DozeServiceHostTest.java index a5f4e51ea13c7..713a7c92e1cfc 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/DozeServiceHostTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/DozeServiceHostTest.java @@ -36,6 +36,7 @@ import androidx.test.filters.SmallTest; import com.android.keyguard.KeyguardUpdateMonitor; import com.android.systemui.SysuiTestCase; import com.android.systemui.assist.AssistManager; +import com.android.systemui.biometrics.AuthController; import com.android.systemui.doze.DozeHost; import com.android.systemui.doze.DozeLog; import com.android.systemui.keyguard.KeyguardViewMediator; @@ -90,6 +91,7 @@ public class DozeServiceHostTest extends SysuiTestCase { @Mock private View mAmbientIndicationContainer; @Mock private BiometricUnlockController mBiometricUnlockController; @Mock private LockscreenLockIconController mLockscreenLockIconController; + @Mock private AuthController mAuthController; @Before public void setup() { @@ -100,7 +102,7 @@ public class DozeServiceHostTest extends SysuiTestCase { mKeyguardViewMediator, () -> mAssistManager, mDozeScrimController, mKeyguardUpdateMonitor, mVisualStabilityManager, mPulseExpansionHandler, mNotificationShadeWindowController, mNotificationWakeUpCoordinator, - mLockscreenLockIconController); + mLockscreenLockIconController, mAuthController); mDozeServiceHost.initialize(mStatusBar, mNotificationIconAreaController, mStatusBarKeyguardViewManager, mNotificationShadeWindowViewController,