diff --git a/core/java/android/hardware/biometrics/SensorLocationInternal.java b/core/java/android/hardware/biometrics/SensorLocationInternal.java index fb25a2fcd8237..25c0f7c022539 100644 --- a/core/java/android/hardware/biometrics/SensorLocationInternal.java +++ b/core/java/android/hardware/biometrics/SensorLocationInternal.java @@ -18,6 +18,7 @@ package android.hardware.biometrics; import android.annotation.NonNull; import android.annotation.Nullable; +import android.graphics.Rect; import android.os.Parcel; import android.os.Parcelable; @@ -109,4 +110,12 @@ public class SensorLocationInternal implements Parcelable { + ", y: " + sensorLocationY + ", r: " + sensorRadius + "]"; } + + /** Returns coordinates of a bounding box around the sensor. */ + public Rect getRect() { + return new Rect(sensorLocationX - sensorRadius, + sensorLocationY - sensorRadius, + sensorLocationX + sensorRadius, + sensorLocationY + sensorRadius); + } } diff --git a/core/java/android/util/RotationUtils.java b/core/java/android/util/RotationUtils.java index cebdbf669f3ac..c54d9b604ba2b 100644 --- a/core/java/android/util/RotationUtils.java +++ b/core/java/android/util/RotationUtils.java @@ -87,6 +87,40 @@ public class RotationUtils { rotateBounds(inOutBounds, parentBounds, deltaRotation(oldRotation, newRotation)); } + /** + * Rotates inOutBounds together with the parent for a given rotation delta. This assumes that + * the parent starts at 0,0 and remains at 0,0 after the rotation. The inOutBounds will remain + * at the same physical position within the parent. + * + * Only 'inOutBounds' is mutated. + */ + public static void rotateBounds(Rect inOutBounds, int parentWidth, int parentHeight, + @Rotation int rotation) { + final int origLeft = inOutBounds.left; + final int origTop = inOutBounds.top; + switch (rotation) { + case ROTATION_0: + return; + case ROTATION_90: + inOutBounds.left = inOutBounds.top; + inOutBounds.top = parentWidth - inOutBounds.right; + inOutBounds.right = inOutBounds.bottom; + inOutBounds.bottom = parentWidth - origLeft; + return; + case ROTATION_180: + inOutBounds.left = parentWidth - inOutBounds.right; + inOutBounds.right = parentWidth - origLeft; + inOutBounds.top = parentHeight - inOutBounds.bottom; + inOutBounds.bottom = parentHeight - origTop; + return; + case ROTATION_270: + inOutBounds.left = parentHeight - inOutBounds.bottom; + inOutBounds.bottom = inOutBounds.right; + inOutBounds.right = parentHeight - inOutBounds.top; + inOutBounds.top = origLeft; + } + } + /** * Rotates bounds as if parentBounds and bounds are a group. The group is rotated by `delta` * 90-degree counter-clockwise increments. This assumes that parentBounds is at 0,0 and @@ -96,29 +130,7 @@ public class RotationUtils { * Only 'inOutBounds' is mutated. */ public static void rotateBounds(Rect inOutBounds, Rect parentBounds, @Rotation int rotation) { - final int origLeft = inOutBounds.left; - final int origTop = inOutBounds.top; - switch (rotation) { - case ROTATION_0: - return; - case ROTATION_90: - inOutBounds.left = inOutBounds.top; - inOutBounds.top = parentBounds.right - inOutBounds.right; - inOutBounds.right = inOutBounds.bottom; - inOutBounds.bottom = parentBounds.right - origLeft; - return; - case ROTATION_180: - inOutBounds.left = parentBounds.right - inOutBounds.right; - inOutBounds.right = parentBounds.right - origLeft; - inOutBounds.top = parentBounds.bottom - inOutBounds.bottom; - inOutBounds.bottom = parentBounds.bottom - origTop; - return; - case ROTATION_270: - inOutBounds.left = parentBounds.bottom - inOutBounds.bottom; - inOutBounds.bottom = inOutBounds.right; - inOutBounds.right = parentBounds.bottom - inOutBounds.top; - inOutBounds.top = origLeft; - } + rotateBounds(inOutBounds, parentBounds.right, parentBounds.bottom, rotation); } /** @return the rotation needed to rotate from oldRotation to newRotation. */ diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/AuthController.java b/packages/SystemUI/src/com/android/systemui/biometrics/AuthController.java index 15d0648ae163b..8e1132600a64a 100644 --- a/packages/SystemUI/src/com/android/systemui/biometrics/AuthController.java +++ b/packages/SystemUI/src/com/android/systemui/biometrics/AuthController.java @@ -30,7 +30,9 @@ import android.content.Intent; import android.content.IntentFilter; import android.content.res.Configuration; import android.content.res.Resources; +import android.graphics.Point; import android.graphics.PointF; +import android.graphics.Rect; import android.hardware.SensorPrivacyManager; import android.hardware.biometrics.BiometricAuthenticator.Modality; import android.hardware.biometrics.BiometricConstants; @@ -54,6 +56,7 @@ import android.os.RemoteException; import android.os.UserManager; import android.util.Log; import android.util.SparseBooleanArray; +import android.view.DisplayInfo; import android.view.MotionEvent; import android.view.WindowManager; @@ -104,16 +107,16 @@ public class AuthController extends CoreStartable implements CommandQueue.Callba private final CommandQueue mCommandQueue; private final StatusBarStateController mStatusBarStateController; private final ActivityTaskManager mActivityTaskManager; - @Nullable - private final FingerprintManager mFingerprintManager; - @Nullable - private final FaceManager mFaceManager; + @Nullable private final FingerprintManager mFingerprintManager; + @Nullable private final FaceManager mFaceManager; private final Provider mUdfpsControllerFactory; private final Provider mSidefpsControllerFactory; - @Nullable - private final PointF mFaceAuthSensorLocation; - @Nullable - private PointF mFingerprintLocation; + + @NonNull private Point mStableDisplaySize = new Point(); + + @Nullable private final PointF mFaceAuthSensorLocation; + @Nullable private PointF mFingerprintLocation; + @Nullable private Rect mUdfpsBounds; private final Set mCallbacks = new HashSet<>(); // TODO: These should just be saved from onSaveState @@ -122,14 +125,13 @@ public class AuthController extends CoreStartable implements CommandQueue.Callba AuthDialog mCurrentDialog; @NonNull private final WindowManager mWindowManager; + @NonNull private final DisplayManager mDisplayManager; @Nullable private UdfpsController mUdfpsController; @Nullable private IUdfpsHbmListener mUdfpsHbmListener; @Nullable private SidefpsController mSidefpsController; @Nullable private IBiometricContextListener mBiometricContextListener; - @VisibleForTesting - IBiometricSysuiReceiver mReceiver; - @VisibleForTesting - @NonNull final BiometricDisplayListener mOrientationListener; + @VisibleForTesting IBiometricSysuiReceiver mReceiver; + @VisibleForTesting @NonNull final BiometricDisplayListener mOrientationListener; @Nullable private final List mFaceProps; @Nullable private List mFpProps; @Nullable private List mUdfpsProps; @@ -249,6 +251,7 @@ public class AuthController extends CoreStartable implements CommandQueue.Callba } mAllFingerprintAuthenticatorsRegistered = true; mFpProps = sensors; + List udfpsProps = new ArrayList<>(); List sidefpsProps = new ArrayList<>(); for (FingerprintSensorPropertiesInternal props : mFpProps) { @@ -259,12 +262,14 @@ public class AuthController extends CoreStartable implements CommandQueue.Callba sidefpsProps.add(props); } } + mUdfpsProps = !udfpsProps.isEmpty() ? udfpsProps : null; if (mUdfpsProps != null) { mUdfpsController = mUdfpsControllerFactory.get(); mUdfpsController.addCallback(new UdfpsController.Callback() { @Override - public void onFingerUp() {} + public void onFingerUp() { + } @Override public void onFingerDown() { @@ -273,15 +278,22 @@ public class AuthController extends CoreStartable implements CommandQueue.Callba } } }); + mUdfpsController.setAuthControllerUpdateUdfpsLocation(this::updateUdfpsLocation); + mUdfpsBounds = mUdfpsProps.get(0).getLocation().getRect(); + updateUdfpsLocation(); } + mSidefpsProps = !sidefpsProps.isEmpty() ? sidefpsProps : null; if (mSidefpsProps != null) { mSidefpsController = mSidefpsControllerFactory.get(); } + + mFingerprintManager.registerBiometricStateListener(mBiometricStateListener); + updateFingerprintLocation(); + for (Callback cb : mCallbacks) { cb.onAllAuthenticatorsRegistered(); } - mFingerprintManager.registerBiometricStateListener(mBiometricStateListener); } private void handleEnrollmentsChanged(int userId, int sensorId, boolean hasEnrollments) { @@ -424,12 +436,11 @@ public class AuthController extends CoreStartable implements CommandQueue.Callba /** * @return where the UDFPS exists on the screen in pixels in portrait mode. */ - @Nullable public PointF getUdfpsSensorLocation() { - if (mUdfpsController == null) { + @Nullable public PointF getUdfpsLocation() { + if (mUdfpsController == null || mUdfpsBounds == null) { return null; } - return new PointF(mUdfpsController.getSensorLocation().centerX(), - mUdfpsController.getSensorLocation().centerY()); + return new PointF(mUdfpsBounds.centerX(), mUdfpsBounds.centerY()); } /** @@ -437,8 +448,8 @@ public class AuthController extends CoreStartable implements CommandQueue.Callba * overridden value will use the default value even if they don't have a fingerprint sensor */ @Nullable public PointF getFingerprintSensorLocation() { - if (getUdfpsSensorLocation() != null) { - return getUdfpsSensorLocation(); + if (getUdfpsLocation() != null) { + return getUdfpsLocation(); } return mFingerprintLocation; } @@ -525,12 +536,13 @@ public class AuthController extends CoreStartable implements CommandQueue.Callba mFaceManager = faceManager; mUdfpsControllerFactory = udfpsControllerFactory; mSidefpsControllerFactory = sidefpsControllerFactory; + mDisplayManager = displayManager; mWindowManager = windowManager; mUdfpsEnrolledForUser = new SparseBooleanArray(); mOrientationListener = new BiometricDisplayListener( context, - displayManager, + mDisplayManager, mHandler, BiometricDisplayListener.SensorType.Generic.INSTANCE, () -> { @@ -582,6 +594,27 @@ public class AuthController extends CoreStartable implements CommandQueue.Callba yLocation); } + // TODO(b/229290039): UDFPS controller should manage its dimensions on its own. Remove this. + // This is not combined with updateFingerprintLocation because this is invoked directly from + // UdfpsController, only when it cares about a rotation change. The implications of calling + // updateFingerprintLocation in such a case are unclear. + private void updateUdfpsLocation() { + if (mUdfpsController != null) { + final DisplayInfo displayInfo = new DisplayInfo(); + mContext.getDisplay().getDisplayInfo(displayInfo); + final float scaleFactor = android.util.DisplayUtils.getPhysicalPixelDisplaySizeRatio( + mStableDisplaySize.x, mStableDisplaySize.y, displayInfo.getNaturalWidth(), + displayInfo.getNaturalHeight()); + + final FingerprintSensorPropertiesInternal udfpsProp = mUdfpsProps.get(0); + mUdfpsBounds = udfpsProp.getLocation().getRect(); + mUdfpsBounds.scale(scaleFactor); + mUdfpsController.updateOverlayParams(udfpsProp.sensorId, + new UdfpsOverlayParams(mUdfpsBounds, displayInfo.getNaturalWidth(), + displayInfo.getNaturalHeight(), scaleFactor, displayInfo.rotation)); + } + } + @SuppressWarnings("deprecation") @Override public void start() { @@ -592,6 +625,7 @@ public class AuthController extends CoreStartable implements CommandQueue.Callba mFingerprintAuthenticatorsRegisteredCallback); } + mStableDisplaySize = mDisplayManager.getStableDisplaySize(); mActivityTaskManager.registerTaskStackListener(mTaskStackListener); } @@ -906,6 +940,7 @@ public class AuthController extends CoreStartable implements CommandQueue.Callba protected void onConfigurationChanged(Configuration newConfig) { super.onConfigurationChanged(newConfig); updateFingerprintLocation(); + updateUdfpsLocation(); // Save the state of the current dialog (buttons showing, etc) if (mCurrentDialog != null) { @@ -935,6 +970,7 @@ public class AuthController extends CoreStartable implements CommandQueue.Callba private void onOrientationChanged() { updateFingerprintLocation(); + updateUdfpsLocation(); if (mCurrentDialog != null) { mCurrentDialog.onOrientationChanged(); } diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/BiometricDisplayListener.kt b/packages/SystemUI/src/com/android/systemui/biometrics/BiometricDisplayListener.kt index dfbe348c6ede2..38a7c5d7a8af1 100644 --- a/packages/SystemUI/src/com/android/systemui/biometrics/BiometricDisplayListener.kt +++ b/packages/SystemUI/src/com/android/systemui/biometrics/BiometricDisplayListener.kt @@ -64,7 +64,11 @@ class BiometricDisplayListener( /** Listen for changes. */ fun enable() { lastRotation = context.display?.rotation ?: Surface.ROTATION_0 - displayManager.registerDisplayListener(this, handler) + displayManager.registerDisplayListener( + this, + handler, + DisplayManager.EVENT_FLAG_DISPLAY_CHANGED + ) } /** Stop listening for changes. */ @@ -80,9 +84,7 @@ class BiometricDisplayListener( */ sealed class SensorType { object Generic : SensorType() - data class UnderDisplayFingerprint( - val properties: FingerprintSensorPropertiesInternal - ) : SensorType() + object UnderDisplayFingerprint : SensorType() data class SideFingerprint( val properties: FingerprintSensorPropertiesInternal ) : SensorType() diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java index 284724687abcc..0096032a6e680 100644 --- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java +++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java @@ -19,7 +19,6 @@ package com.android.systemui.biometrics; import static android.hardware.biometrics.BiometricFingerprintConstants.FINGERPRINT_ACQUIRED_GOOD; import static android.hardware.biometrics.BiometricOverlayConstants.REASON_AUTH_KEYGUARD; -import static com.android.internal.util.Preconditions.checkArgument; import static com.android.internal.util.Preconditions.checkNotNull; import static com.android.systemui.classifier.Classifier.UDFPS_AUTHENTICATION; @@ -30,12 +29,9 @@ import android.content.Context; import android.content.Intent; import android.content.IntentFilter; import android.graphics.Point; -import android.graphics.RectF; import android.hardware.biometrics.BiometricFingerprintConstants; -import android.hardware.biometrics.SensorLocationInternal; import android.hardware.display.DisplayManager; import android.hardware.fingerprint.FingerprintManager; -import android.hardware.fingerprint.FingerprintSensorPropertiesInternal; import android.hardware.fingerprint.IUdfpsOverlayController; import android.hardware.fingerprint.IUdfpsOverlayControllerCallback; import android.os.Handler; @@ -45,6 +41,7 @@ import android.os.Trace; import android.os.VibrationAttributes; import android.os.VibrationEffect; import android.util.Log; +import android.util.RotationUtils; import android.view.LayoutInflater; import android.view.MotionEvent; import android.view.Surface; @@ -99,7 +96,6 @@ import kotlin.Unit; public class UdfpsController implements DozeReceiver { private static final String TAG = "UdfpsController"; private static final long AOD_INTERRUPT_TIMEOUT_MILLIS = 1000; - private static final long DEFAULT_VIBRATION_DURATION = 1000; // milliseconds // Minimum required delay between consecutive touch logs in milliseconds. private static final long MIN_TOUCH_LOG_INTERVAL = 50; @@ -129,10 +125,14 @@ public class UdfpsController implements DozeReceiver { mUnlockedScreenOffAnimationController; @NonNull private final LatencyTracker mLatencyTracker; @VisibleForTesting @NonNull final BiometricDisplayListener mOrientationListener; + @NonNull private final ActivityLaunchAnimator mActivityLaunchAnimator; + // 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; - @NonNull private final ActivityLaunchAnimator mActivityLaunchAnimator; + @VisibleForTesting int mSensorId; + @VisibleForTesting @NonNull UdfpsOverlayParams mOverlayParams = new UdfpsOverlayParams(); + // TODO(b/229290039): UDFPS controller should manage its dimensions on its own. Remove this. + @Nullable private Runnable mAuthControllerUpdateUdfpsLocation; @Nullable private final AlternateUdfpsTouchProvider mAlternateTouchProvider; // Tracks the velocity of a touch to help filter out the touches that move too fast. @@ -193,19 +193,16 @@ public class UdfpsController implements DozeReceiver { @Override public void showUdfpsOverlay(long requestId, int sensorId, int reason, @NonNull IUdfpsOverlayControllerCallback callback) { - mFgExecutor.execute( - () -> UdfpsController.this.showUdfpsOverlay(new UdfpsControllerOverlay( - mContext, mFingerprintManager, mInflater, mWindowManager, - mAccessibilityManager, mStatusBarStateController, + mFgExecutor.execute(() -> UdfpsController.this.showUdfpsOverlay( + new UdfpsControllerOverlay(mContext, mFingerprintManager, mInflater, + mWindowManager, mAccessibilityManager, mStatusBarStateController, mPanelExpansionStateManager, mKeyguardViewManager, mKeyguardUpdateMonitor, mDialogManager, mDumpManager, mLockscreenShadeTransitionController, mConfigurationController, mSystemClock, mKeyguardStateController, - mUnlockedScreenOffAnimationController, mSensorProps, - mHbmProvider, requestId, reason, callback, - (view, event, fromUdfpsView) -> - onTouch(requestId, event, fromUdfpsView), - mActivityLaunchAnimator))); + mUnlockedScreenOffAnimationController, mHbmProvider, requestId, reason, + callback, (view, event, fromUdfpsView) -> onTouch(requestId, event, + fromUdfpsView), mActivityLaunchAnimator))); } @Override @@ -280,6 +277,38 @@ public class UdfpsController implements DozeReceiver { } } + /** + * Updates the overlay parameters and reconstructs or redraws the overlay, if necessary. + * + * @param sensorId sensor for which the overlay is getting updated. + * @param overlayParams See {@link UdfpsOverlayParams}. + */ + public void updateOverlayParams(int sensorId, @NonNull UdfpsOverlayParams overlayParams) { + if (sensorId != mSensorId) { + mSensorId = sensorId; + Log.w(TAG, "updateUdfpsParams | sensorId has changed"); + } + + if (!mOverlayParams.equals(overlayParams)) { + mOverlayParams = overlayParams; + + final boolean wasShowingAltAuth = mKeyguardViewManager.isShowingAlternateAuth(); + + // When the bounds change it's always necessary to re-create the overlay's window with + // new LayoutParams. If the overlay needs to be shown, this will re-create and show the + // overlay with the updated LayoutParams. Otherwise, the overlay will remain hidden. + redrawOverlay(); + if (wasShowingAltAuth) { + mKeyguardViewManager.showGenericBouncer(true); + } + } + } + + // TODO(b/229290039): UDFPS controller should manage its dimensions on its own. Remove this. + public void setAuthControllerUpdateUdfpsLocation(@Nullable Runnable r) { + mAuthControllerUpdateUdfpsLocation = r; + } + /** * Calculate the pointer speed given a velocity tracker and the pointer id. * This assumes that the velocity tracker has already been passed all relevant motion events. @@ -340,10 +369,11 @@ public class UdfpsController implements DozeReceiver { } return !mOverlay.getAnimationViewController().shouldPauseAuth() - && getSensorLocation().contains(x, y); + && mOverlayParams.getSensorBounds().contains((int) x, (int) y); } - private boolean onTouch(long requestId, @NonNull MotionEvent event, boolean fromUdfpsView) { + @VisibleForTesting + boolean onTouch(long requestId, @NonNull MotionEvent event, boolean fromUdfpsView) { if (mOverlay == null) { Log.w(TAG, "ignoring onTouch with null overlay"); return false; @@ -438,33 +468,28 @@ public class UdfpsController implements DozeReceiver { final long sinceLastLog = mSystemClock.elapsedRealtime() - mTouchLogTime; if (!isIlluminationRequested && !mAcquiredReceived && !exceedsVelocityThreshold) { - final int rawX = (int) event.getRawX(); - final int rawY = (int) event.getRawY(); - // Default coordinates assume portrait mode. - int x = rawX; - int y = rawY; - - // Gets the size based on the current rotation of the display. - Point p = new Point(); - mContext.getDisplay().getRealSize(p); - - // Transform x, y to portrait mode if the device is in landscape mode. - switch (mContext.getDisplay().getRotation()) { - case Surface.ROTATION_90: - x = p.y - rawY; - y = rawX; - break; - - case Surface.ROTATION_270: - x = rawY; - y = p.x - rawX; - break; - - default: - // Do nothing to stay in portrait mode. + // Map the touch to portrait mode if the device is in landscape mode. + Point portraitTouch = new Point( + (int) event.getRawX(idx), + (int) event.getRawY(idx) + ); + final int rot = mOverlayParams.getRotation(); + if (rot == Surface.ROTATION_90 || rot == Surface.ROTATION_270) { + RotationUtils.rotatePoint(portraitTouch, + RotationUtils.deltaRotation(rot, Surface.ROTATION_0), + mOverlayParams.getLogicalDisplayWidth(), + mOverlayParams.getLogicalDisplayHeight() + ); } - onFingerDown(requestId, x, y, minor, major); + // Scale the coordinates to native resolution. + final float scale = mOverlayParams.getScaleFactor(); + int scaledX = (int) (portraitTouch.x / scale); + int scaledY = (int) (portraitTouch.y / scale); + float scaledMinor = minor / scale; + float scaledMajor = major / scale; + + onFingerDown(requestId, scaledX, scaledY, scaledMinor, scaledMajor); Log.v(TAG, "onTouch | finger down: " + touchInfo); mTouchLogTime = mSystemClock.elapsedRealtime(); mPowerManager.userActivity(mSystemClock.uptimeMillis(), @@ -571,16 +596,15 @@ public class UdfpsController implements DozeReceiver { mActivityLaunchAnimator = activityLaunchAnimator; mAlternateTouchProvider = aternateTouchProvider.orElse(null); - mSensorProps = findFirstUdfps(); - // At least one UDFPS sensor exists - checkArgument(mSensorProps != null); mOrientationListener = new BiometricDisplayListener( context, displayManager, mainHandler, - new BiometricDisplayListener.SensorType.UnderDisplayFingerprint(mSensorProps), + BiometricDisplayListener.SensorType.UnderDisplayFingerprint.INSTANCE, () -> { - onOrientationChanged(); + if (mAuthControllerUpdateUdfpsLocation != null) { + mAuthControllerUpdateUdfpsLocation.run(); + } return Unit.INSTANCE; }); @@ -609,17 +633,6 @@ public class UdfpsController implements DozeReceiver { } } - @Nullable - private FingerprintSensorPropertiesInternal findFirstUdfps() { - for (FingerprintSensorPropertiesInternal props : - mFingerprintManager.getSensorPropertiesInternal()) { - if (props.isAnyUdfpsType()) { - return props; - } - } - return null; - } - @Override public void dozeTimeTick() { if (mOverlay != null) { @@ -630,21 +643,6 @@ public class UdfpsController implements DozeReceiver { } } - /** - * @return where the UDFPS exists on the screen in pixels. - */ - public RectF getSensorLocation() { - // This is currently used to calculate the amount of space available for notifications - // on lockscreen and for the udfps light reveal animation on keyguard. - // Keyguard is only shown in portrait mode for now, so this will need to - // be updated if that ever changes. - final SensorLocationInternal location = mSensorProps.getLocation(); - return new RectF(location.sensorLocationX - location.sensorRadius, - location.sensorLocationY - location.sensorRadius, - location.sensorLocationX + location.sensorRadius, - location.sensorLocationY + location.sensorRadius); - } - private void redrawOverlay() { UdfpsControllerOverlay overlay = mOverlay; if (overlay != null) { @@ -653,26 +651,11 @@ public class UdfpsController implements DozeReceiver { } } - private void onOrientationChanged() { - // When the configuration changes it's almost always necessary to destroy and re-create - // the overlay's window to pass it the new LayoutParams. - // Hiding the overlay will destroy its window. It's safe to hide the overlay regardless - // of whether it is already hidden. - final boolean wasShowingAltAuth = mKeyguardViewManager.isShowingAlternateAuth(); - - // If the overlay needs to be shown, this will re-create and show the overlay with the - // updated LayoutParams. Otherwise, the overlay will remain hidden. - redrawOverlay(); - if (wasShowingAltAuth) { - mKeyguardViewManager.showGenericBouncer(true); - } - } - private void showUdfpsOverlay(@NonNull UdfpsControllerOverlay overlay) { mExecution.assertIsMainThread(); mOverlay = overlay; - if (overlay.show(this)) { + if (overlay.show(this, mOverlayParams)) { Log.v(TAG, "showUdfpsOverlay | adding window reason=" + overlay.getRequestReason()); mOnFingerDown = false; @@ -814,14 +797,14 @@ public class UdfpsController implements DozeReceiver { if (mAlternateTouchProvider != null) { mAlternateTouchProvider.onPointerDown(requestId, x, y, minor, major); } else { - mFingerprintManager.onPointerDown(requestId, mSensorProps.sensorId, x, y, minor, major); + mFingerprintManager.onPointerDown(requestId, mSensorId, x, y, minor, major); } Trace.endAsyncSection("UdfpsController.e2e.onPointerDown", 0); final UdfpsView view = mOverlay.getOverlayView(); if (view != null) { view.startIllumination(() -> { - mFingerprintManager.onUiReady(requestId, mSensorProps.sensorId); + mFingerprintManager.onUiReady(requestId, mSensorId); mLatencyTracker.onActionEnd(LatencyTracker.ACTION_UDFPS_ILLUMINATE); }); } @@ -839,7 +822,7 @@ public class UdfpsController implements DozeReceiver { if (mAlternateTouchProvider != null) { mAlternateTouchProvider.onPointerUp(requestId); } else { - mFingerprintManager.onPointerUp(requestId, mSensorProps.sensorId); + mFingerprintManager.onPointerUp(requestId, mSensorId); } for (Callback cb : mCallbacks) { cb.onFingerUp(); diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsControllerOverlay.kt b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsControllerOverlay.kt index ee43e932b344b..9c8aee4e93a72 100644 --- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsControllerOverlay.kt +++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsControllerOverlay.kt @@ -20,17 +20,16 @@ import android.annotation.SuppressLint import android.annotation.UiThread import android.content.Context import android.graphics.PixelFormat -import android.graphics.Point +import android.graphics.Rect import android.hardware.biometrics.BiometricOverlayConstants import android.hardware.biometrics.BiometricOverlayConstants.REASON_ENROLL_ENROLLING import android.hardware.biometrics.BiometricOverlayConstants.REASON_ENROLL_FIND_SENSOR import android.hardware.biometrics.BiometricOverlayConstants.ShowReason -import android.hardware.biometrics.SensorLocationInternal import android.hardware.fingerprint.FingerprintManager -import android.hardware.fingerprint.FingerprintSensorPropertiesInternal import android.hardware.fingerprint.IUdfpsOverlayControllerCallback import android.os.RemoteException import android.util.Log +import android.util.RotationUtils import android.view.LayoutInflater import android.view.MotionEvent import android.view.Surface @@ -78,7 +77,6 @@ class UdfpsControllerOverlay( private val systemClock: SystemClock, private val keyguardStateController: KeyguardStateController, private val unlockedScreenOffAnimationController: UnlockedScreenOffAnimationController, - private val sensorProps: FingerprintSensorPropertiesInternal, private var hbmProvider: UdfpsHbmProvider, val requestId: Long, @ShowReason val requestReason: Int, @@ -90,6 +88,8 @@ class UdfpsControllerOverlay( var overlayView: UdfpsView? = null private set + private var overlayParams: UdfpsOverlayParams = UdfpsOverlayParams() + private var overlayTouchListener: TouchExplorationStateChangeListener? = null private val coreLayoutParams = WindowManager.LayoutParams( @@ -101,7 +101,11 @@ class UdfpsControllerOverlay( fitInsetsTypes = 0 gravity = android.view.Gravity.TOP or android.view.Gravity.LEFT layoutInDisplayCutoutMode = WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS + flags = + (Utils.FINGERPRINT_OVERLAY_LAYOUT_PARAM_FLAGS or WindowManager.LayoutParams.FLAG_SPLIT_TOUCH) privateFlags = WindowManager.LayoutParams.PRIVATE_FLAG_TRUSTED_OVERLAY + // Avoid announcing window title. + accessibilityTitle = " " } /** A helper if the [requestReason] was due to enrollment. */ @@ -125,13 +129,14 @@ class UdfpsControllerOverlay( /** Show the overlay or return false and do nothing if it is already showing. */ @SuppressLint("ClickableViewAccessibility") - fun show(controller: UdfpsController): Boolean { + fun show(controller: UdfpsController, params: UdfpsOverlayParams): Boolean { if (overlayView == null) { + overlayParams = params try { overlayView = (inflater.inflate( R.layout.udfps_view, null, false ) as UdfpsView).apply { - sensorProperties = sensorProps + overlayParams = params setHbmProvider(hbmProvider) val animation = inflateUdfpsAnimation(this, controller) if (animation != null) { @@ -144,8 +149,7 @@ class UdfpsControllerOverlay( importantForAccessibility = View.IMPORTANT_FOR_ACCESSIBILITY_NO } - windowManager.addView(this, - coreLayoutParams.updateForLocation(sensorProps.location, animation)) + windowManager.addView(this, coreLayoutParams.updateDimensions(animation)) overlayTouchListener = TouchExplorationStateChangeListener { if (accessibilityManager.isTouchExplorationEnabled) { @@ -180,13 +184,14 @@ class UdfpsControllerOverlay( REASON_ENROLL_ENROLLING -> { UdfpsEnrollViewController( view.addUdfpsView(R.layout.udfps_enroll_view) { - updateSensorLocation(sensorProps) + updateSensorLocation(overlayParams.sensorBounds) }, enrollHelper ?: throw IllegalStateException("no enrollment helper"), statusBarStateController, panelExpansionStateManager, dialogManager, - dumpManager + dumpManager, + overlayParams.scaleFactor ) } BiometricOverlayConstants.REASON_AUTH_KEYGUARD -> { @@ -280,57 +285,42 @@ class UdfpsControllerOverlay( /** Checks if the id is relevant for this overlay. */ fun matchesRequestId(id: Long): Boolean = requestId == -1L || requestId == id - private fun WindowManager.LayoutParams.updateForLocation( - location: SensorLocationInternal, + private fun WindowManager.LayoutParams.updateDimensions( animation: UdfpsAnimationViewController<*>? ): WindowManager.LayoutParams { val paddingX = animation?.paddingX ?: 0 val paddingY = animation?.paddingY ?: 0 - flags = (Utils.FINGERPRINT_OVERLAY_LAYOUT_PARAM_FLAGS - or WindowManager.LayoutParams.FLAG_SPLIT_TOUCH) if (animation != null && animation.listenForTouchesOutsideView()) { flags = flags or WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH } - // Default dimensions assume portrait mode. - x = location.sensorLocationX - location.sensorRadius - paddingX - y = location.sensorLocationY - location.sensorRadius - paddingY - height = 2 * location.sensorRadius + 2 * paddingX - width = 2 * location.sensorRadius + 2 * paddingY + // Original sensorBounds assume portrait mode. + val rotatedSensorBounds = Rect(overlayParams.sensorBounds) - // Gets the size based on the current rotation of the display. - val p = Point() - context.display!!.getRealSize(p) - when (context.display!!.rotation) { - Surface.ROTATION_90 -> { - if (!shouldRotate(animation)) { - Log.v(TAG, "skip rotating udfps location ROTATION_90" + + val rot = overlayParams.rotation + if (rot == Surface.ROTATION_90 || rot == Surface.ROTATION_270) { + if (!shouldRotate(animation)) { + Log.v( + TAG, "Skip rotating UDFPS bounds " + Surface.rotationToString(rot) + " animation=$animation" + " isGoingToSleep=${keyguardUpdateMonitor.isGoingToSleep}" + - " isOccluded=${keyguardStateController.isOccluded}") - } else { - Log.v(TAG, "rotate udfps location ROTATION_90") - x = (location.sensorLocationY - location.sensorRadius - paddingX) - y = (p.y - location.sensorLocationX - location.sensorRadius - paddingY) - } + " isOccluded=${keyguardStateController.isOccluded}" + ) + } else { + Log.v(TAG, "Rotate UDFPS bounds " + Surface.rotationToString(rot)) + RotationUtils.rotateBounds( + rotatedSensorBounds, + overlayParams.naturalDisplayWidth, + overlayParams.naturalDisplayHeight, + rot + ) } - Surface.ROTATION_270 -> { - if (!shouldRotate(animation)) { - Log.v(TAG, "skip rotating udfps location ROTATION_270" + - " animation=$animation" + - " isGoingToSleep=${keyguardUpdateMonitor.isGoingToSleep}" + - " isOccluded=${keyguardStateController.isOccluded}") - } else { - Log.v(TAG, "rotate udfps location ROTATION_270") - x = (p.x - location.sensorLocationY - location.sensorRadius - paddingX) - y = (location.sensorLocationX - location.sensorRadius - paddingY) - } - } - else -> {} } - // avoid announcing window title - accessibilityTitle = " " + x = rotatedSensorBounds.left - paddingX + y = rotatedSensorBounds.top - paddingY + height = rotatedSensorBounds.height() + 2 * paddingX + width = rotatedSensorBounds.width() + 2 * paddingY return this } @@ -363,5 +353,5 @@ private fun Int.isEnrollmentReason() = @ShowReason private fun Int.isImportantForAccessibility() = this == REASON_ENROLL_FIND_SENSOR || - this == REASON_ENROLL_ENROLLING || - this == BiometricOverlayConstants.REASON_AUTH_BP + this == REASON_ENROLL_ENROLLING || + this == BiometricOverlayConstants.REASON_AUTH_BP diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsEnrollView.java b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsEnrollView.java index 93df2cf0f8355..69c37b2b9a62b 100644 --- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsEnrollView.java +++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsEnrollView.java @@ -17,7 +17,7 @@ package com.android.systemui.biometrics; import android.content.Context; -import android.hardware.fingerprint.FingerprintSensorPropertiesInternal; +import android.graphics.Rect; import android.os.Handler; import android.os.Looper; import android.util.AttributeSet; @@ -61,13 +61,11 @@ public class UdfpsEnrollView extends UdfpsAnimationView { return mFingerprintDrawable; } - void updateSensorLocation(@NonNull FingerprintSensorPropertiesInternal sensorProps) { + void updateSensorLocation(@NonNull Rect sensorBounds) { View fingerprintAccessibilityView = findViewById(R.id.udfps_enroll_accessibility_view); - final int sensorHeight = sensorProps.getLocation().sensorRadius * 2; - final int sensorWidth = sensorHeight; ViewGroup.LayoutParams params = fingerprintAccessibilityView.getLayoutParams(); - params.width = sensorWidth; - params.height = sensorHeight; + params.width = sensorBounds.width(); + params.height = sensorBounds.height(); fingerprintAccessibilityView.setLayoutParams(params); fingerprintAccessibilityView.requestLayout(); } diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsEnrollViewController.java b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsEnrollViewController.java index 2ca103bf942f6..2ed60e555c584 100644 --- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsEnrollViewController.java +++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsEnrollViewController.java @@ -56,11 +56,12 @@ public class UdfpsEnrollViewController extends UdfpsAnimationViewController? = null - /** Properties used to obtain the sensor location. */ - var sensorProperties: FingerprintSensorPropertiesInternal? = null + /** Parameters that affect the position and size of the overlay. Visible for testing. */ + var overlayParams = UdfpsOverlayParams() /** Debug message. */ var debugMessage: String? = null @@ -94,13 +95,12 @@ class UdfpsView( val paddingX = animationViewController?.paddingX ?: 0 val paddingY = animationViewController?.paddingY ?: 0 - val sensorRadius = sensorProperties?.location?.sensorRadius ?: 0 sensorRect.set( paddingX.toFloat(), paddingY.toFloat(), - (2 * sensorRadius + paddingX).toFloat(), - (2 * sensorRadius + paddingY).toFloat() + (overlayParams.sensorBounds.width() + paddingX).toFloat(), + (overlayParams.sensorBounds.height() + paddingY).toFloat() ) animationViewController?.onSensorRectUpdated(RectF(sensorRect)) } 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 28da2f13eb69f..03b18ae66d4ea 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthControllerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthControllerTest.java @@ -27,6 +27,7 @@ import static junit.framework.Assert.assertNull; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyInt; +import static org.mockito.ArgumentMatchers.anyLong; import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.doAnswer; @@ -46,6 +47,7 @@ import android.content.Context; import android.content.Intent; import android.content.pm.PackageManager; import android.content.res.Configuration; +import android.graphics.Point; import android.hardware.biometrics.BiometricAuthenticator; import android.hardware.biometrics.BiometricConstants; import android.hardware.biometrics.BiometricManager; @@ -185,6 +187,8 @@ public class AuthControllerTest extends SysuiTestCase { when(mDialog1.getRequestId()).thenReturn(REQUEST_ID); when(mDialog2.getRequestId()).thenReturn(REQUEST_ID); + when(mDisplayManager.getStableDisplaySize()).thenReturn(new Point()); + when(mFingerprintManager.isHardwareDetected()).thenReturn(true); final List componentInfo = new ArrayList<>(); @@ -663,7 +667,7 @@ public class AuthControllerTest extends SysuiTestCase { public void testSubscribesToOrientationChangesWhenShowingDialog() { showDialog(new int[]{1} /* sensorIds */, false /* credentialAllowed */); - verify(mDisplayManager).registerDisplayListener(any(), eq(mHandler)); + verify(mDisplayManager).registerDisplayListener(any(), eq(mHandler), anyLong()); mAuthController.hideAuthenticationDialog(REQUEST_ID); verify(mDisplayManager).unregisterDisplayListener(any()); diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthRippleControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthRippleControllerTest.kt index 5440b45a778f0..7f8656c1ecbc7 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthRippleControllerTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthRippleControllerTest.kt @@ -163,7 +163,7 @@ class AuthRippleControllerTest : SysuiTestCase() { fun testFingerprintTrigger_KeyguardNotVisible_NotDreaming_NoRipple() { // GIVEN fp exists & user doesn't need strong auth val fpsLocation = PointF(5f, 5f) - `when`(authController.udfpsSensorLocation).thenReturn(fpsLocation) + `when`(authController.udfpsLocation).thenReturn(fpsLocation) controller.onViewAttached() `when`(keyguardUpdateMonitor.userNeedsStrongAuth()).thenReturn(false) @@ -185,7 +185,7 @@ class AuthRippleControllerTest : SysuiTestCase() { fun testFingerprintTrigger_StrongAuthRequired_NoRipple() { // GIVEN fp exists & keyguard is visible val fpsLocation = PointF(5f, 5f) - `when`(authController.udfpsSensorLocation).thenReturn(fpsLocation) + `when`(authController.udfpsLocation).thenReturn(fpsLocation) controller.onViewAttached() `when`(keyguardUpdateMonitor.isKeyguardVisible).thenReturn(true) diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/BiometricDisplayListenerTest.java b/packages/SystemUI/tests/src/com/android/systemui/biometrics/BiometricDisplayListenerTest.java index 40f335dfc20dc..69c7f364d235d 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/BiometricDisplayListenerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/BiometricDisplayListenerTest.java @@ -20,6 +20,7 @@ import static com.android.systemui.biometrics.BiometricDisplayListener.SensorTyp import static com.android.systemui.biometrics.BiometricDisplayListener.SensorType.UnderDisplayFingerprint; import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.eq; import static org.mockito.ArgumentMatchers.same; import static org.mockito.Mockito.never; import static org.mockito.Mockito.reset; @@ -89,7 +90,8 @@ public class BiometricDisplayListenerTest extends SysuiTestCase { mContextSpy, mDisplayManager, mHandler, mUdfpsType, mOnChangedCallback); listener.enable(); - verify(mDisplayManager).registerDisplayListener(any(), same(mHandler)); + verify(mDisplayManager).registerDisplayListener(any(), same(mHandler), + eq(DisplayManager.EVENT_FLAG_DISPLAY_CHANGED)); } @Test @@ -113,7 +115,7 @@ public class BiometricDisplayListenerTest extends SysuiTestCase { when(mDisplay.getRotation()).thenReturn(Surface.ROTATION_90); listener.enable(); verify(mDisplayManager).registerDisplayListener(mDisplayListenerCaptor.capture(), - same(mHandler)); + same(mHandler), eq(DisplayManager.EVENT_FLAG_DISPLAY_CHANGED)); // Rotate the device back to portrait and ensure the rotation is detected. when(mDisplay.getRotation()).thenReturn(Surface.ROTATION_0); @@ -150,8 +152,8 @@ public class BiometricDisplayListenerTest extends SysuiTestCase { // The listener should record the current rotation and register a display listener. verify(mDisplay).getRotation(); - verify(mDisplayManager) - .registerDisplayListener(mDisplayListenerCaptor.capture(), same(mHandler)); + verify(mDisplayManager).registerDisplayListener(mDisplayListenerCaptor.capture(), + same(mHandler), eq(DisplayManager.EVENT_FLAG_DISPLAY_CHANGED)); // Test the first rotation since the listener was enabled. mDisplayListenerCaptor.getValue().onDisplayChanged(123); @@ -182,8 +184,8 @@ public class BiometricDisplayListenerTest extends SysuiTestCase { listener.enable(); // The listener should register a display listener. - verify(mDisplayManager) - .registerDisplayListener(mDisplayListenerCaptor.capture(), same(mHandler)); + verify(mDisplayManager).registerDisplayListener(mDisplayListenerCaptor.capture(), + same(mHandler), eq(DisplayManager.EVENT_FLAG_DISPLAY_CHANGED)); // mOnChangedCallback should be invoked for all calls to onDisplayChanged. mDisplayListenerCaptor.getValue().onDisplayChanged(123); diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/SidefpsControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/biometrics/SidefpsControllerTest.kt index 839c0ab1318f0..e1a348ead9b77 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/SidefpsControllerTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/SidefpsControllerTest.kt @@ -188,7 +188,7 @@ class SidefpsControllerTest : SysuiTestCase() { overlayController.show(SENSOR_ID, REASON_UNKNOWN) executor.runAllReady() - verify(displayManager).registerDisplayListener(any(), eq(handler)) + verify(displayManager).registerDisplayListener(any(), eq(handler), anyLong()) overlayController.hide(SENSOR_ID) executor.runAllReady() diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsControllerOverlayTest.kt b/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsControllerOverlayTest.kt index fd49766dafef8..a57b011d7125e 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsControllerOverlayTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsControllerOverlayTest.kt @@ -16,6 +16,7 @@ package com.android.systemui.biometrics +import android.graphics.Rect import android.hardware.biometrics.BiometricOverlayConstants.REASON_AUTH_BP import android.hardware.biometrics.BiometricOverlayConstants.REASON_AUTH_KEYGUARD import android.hardware.biometrics.BiometricOverlayConstants.REASON_AUTH_OTHER @@ -23,7 +24,6 @@ import android.hardware.biometrics.BiometricOverlayConstants.REASON_AUTH_SETTING import android.hardware.biometrics.BiometricOverlayConstants.REASON_ENROLL_ENROLLING import android.hardware.biometrics.BiometricOverlayConstants.REASON_ENROLL_FIND_SENSOR import android.hardware.biometrics.BiometricOverlayConstants.ShowReason -import android.hardware.biometrics.SensorLocationInternal import android.hardware.fingerprint.FingerprintManager import android.hardware.fingerprint.IUdfpsOverlayControllerCallback import android.testing.AndroidTestingRunner @@ -31,6 +31,8 @@ import android.testing.TestableLooper.RunWithLooper import android.view.LayoutInflater import android.view.MotionEvent import android.view.View +import android.view.Surface +import android.view.Surface.Rotation import android.view.WindowManager import android.view.accessibility.AccessibilityManager import androidx.test.filters.SmallTest @@ -53,8 +55,10 @@ import org.junit.Before import org.junit.Rule import org.junit.Test import org.junit.runner.RunWith +import org.mockito.ArgumentCaptor import org.mockito.ArgumentMatchers.any import org.mockito.ArgumentMatchers.eq +import org.mockito.Captor import org.mockito.Mock import org.mockito.Mockito.mock import org.mockito.Mockito.verify @@ -63,13 +67,18 @@ import org.mockito.Mockito.`when` as whenever private const val REQUEST_ID = 2L +// Dimensions for the current display resolution. +private const val DISPLAY_WIDTH = 1080 +private const val DISPLAY_HEIGHT = 1920 +private const val SENSOR_WIDTH = 30 +private const val SENSOR_HEIGHT = 60 + @SmallTest @RunWith(AndroidTestingRunner::class) @RunWithLooper(setAsMainLooper = true) class UdfpsControllerOverlayTest : SysuiTestCase() { - @JvmField @Rule - var rule = MockitoJUnit.rule() + @JvmField @Rule var rule = MockitoJUnit.rule() @Mock private lateinit var fingerprintManager: FingerprintManager @Mock private lateinit var inflater: LayoutInflater @@ -85,18 +94,17 @@ class UdfpsControllerOverlayTest : SysuiTestCase() { @Mock private lateinit var configurationController: ConfigurationController @Mock private lateinit var systemClock: SystemClock @Mock private lateinit var keyguardStateController: KeyguardStateController - @Mock - private lateinit var unlockedScreenOffAnimationController: UnlockedScreenOffAnimationController + @Mock private lateinit var unlockedScreenOffAnimationController: UnlockedScreenOffAnimationController @Mock private lateinit var hbmProvider: UdfpsHbmProvider @Mock private lateinit var controllerCallback: IUdfpsOverlayControllerCallback @Mock private lateinit var udfpsController: UdfpsController @Mock private lateinit var udfpsView: UdfpsView @Mock private lateinit var udfpsEnrollView: UdfpsEnrollView @Mock private lateinit var activityLaunchAnimator: ActivityLaunchAnimator + @Captor private lateinit var layoutParamsCaptor: ArgumentCaptor - private val sensorProps = SensorLocationInternal("", 10, 100, 20) - .asFingerprintSensorProperties() private val onTouch = { _: View, _: MotionEvent, _: Boolean -> true } + private var overlayParams: UdfpsOverlayParams = UdfpsOverlayParams() private lateinit var controllerOverlay: UdfpsControllerOverlay @Before @@ -121,7 +129,7 @@ class UdfpsControllerOverlayTest : SysuiTestCase() { statusBarStateController, panelExpansionStateManager, statusBarKeyguardViewManager, keyguardUpdateMonitor, dialogManager, dumpManager, transitionController, configurationController, systemClock, keyguardStateController, - unlockedScreenOffAnimationController, sensorProps, hbmProvider, REQUEST_ID, reason, + unlockedScreenOffAnimationController, hbmProvider, REQUEST_ID, reason, controllerCallback, onTouch, activityLaunchAnimator) block() } @@ -148,12 +156,96 @@ class UdfpsControllerOverlayTest : SysuiTestCase() { @Test fun showUdfpsOverlay_other() = withReason(REASON_AUTH_OTHER) { showUdfpsOverlay() } + private fun withRotation(@Rotation rotation: Int, block: () -> Unit) { + // Sensor that's in the top left corner of the display in natural orientation. + val sensorBounds = Rect(0, 0, SENSOR_WIDTH, SENSOR_HEIGHT) + overlayParams = UdfpsOverlayParams( + sensorBounds, + DISPLAY_WIDTH, + DISPLAY_HEIGHT, + scaleFactor = 1f, + rotation + ) + block() + } + + @Test + fun showUdfpsOverlay_withRotation0() = withRotation(Surface.ROTATION_0) { + withReason(REASON_AUTH_BP) { + controllerOverlay.show(udfpsController, overlayParams) + verify(windowManager).addView( + eq(controllerOverlay.overlayView), + layoutParamsCaptor.capture() + ) + + // ROTATION_0 is the native orientation. Sensor should stay in the top left corner. + val lp = layoutParamsCaptor.value + assertThat(lp.x).isEqualTo(0) + assertThat(lp.y).isEqualTo(0) + assertThat(lp.width).isEqualTo(SENSOR_WIDTH) + assertThat(lp.height).isEqualTo(SENSOR_HEIGHT) + } + } + + @Test + fun showUdfpsOverlay_withRotation180() = withRotation(Surface.ROTATION_180) { + withReason(REASON_AUTH_BP) { + controllerOverlay.show(udfpsController, overlayParams) + verify(windowManager).addView( + eq(controllerOverlay.overlayView), + layoutParamsCaptor.capture() + ) + + // ROTATION_180 is not supported. Sensor should stay in the top left corner. + val lp = layoutParamsCaptor.value + assertThat(lp.x).isEqualTo(0) + assertThat(lp.y).isEqualTo(0) + assertThat(lp.width).isEqualTo(SENSOR_WIDTH) + assertThat(lp.height).isEqualTo(SENSOR_HEIGHT) + } + } + + @Test + fun showUdfpsOverlay_withRotation90() = withRotation(Surface.ROTATION_90) { + withReason(REASON_AUTH_BP) { + controllerOverlay.show(udfpsController, overlayParams) + verify(windowManager).addView( + eq(controllerOverlay.overlayView), + layoutParamsCaptor.capture() + ) + + // Sensor should be in the bottom left corner in ROTATION_90. + val lp = layoutParamsCaptor.value + assertThat(lp.x).isEqualTo(0) + assertThat(lp.y).isEqualTo(DISPLAY_WIDTH - SENSOR_WIDTH) + assertThat(lp.width).isEqualTo(SENSOR_HEIGHT) + assertThat(lp.height).isEqualTo(SENSOR_WIDTH) + } + } + + @Test + fun showUdfpsOverlay_withRotation270() = withRotation(Surface.ROTATION_270) { + withReason(REASON_AUTH_BP) { + controllerOverlay.show(udfpsController, overlayParams) + verify(windowManager).addView( + eq(controllerOverlay.overlayView), + layoutParamsCaptor.capture() + ) + + // Sensor should be in the top right corner in ROTATION_270. + val lp = layoutParamsCaptor.value + assertThat(lp.x).isEqualTo(DISPLAY_HEIGHT - SENSOR_HEIGHT) + assertThat(lp.y).isEqualTo(0) + assertThat(lp.width).isEqualTo(SENSOR_HEIGHT) + assertThat(lp.height).isEqualTo(SENSOR_WIDTH) + } + } + private fun showUdfpsOverlay(isEnrollUseCase: Boolean = false) { - val didShow = controllerOverlay.show(udfpsController) + val didShow = controllerOverlay.show(udfpsController, overlayParams) verify(windowManager).addView(eq(controllerOverlay.overlayView), any()) verify(udfpsView).setHbmProvider(eq(hbmProvider)) - verify(udfpsView).sensorProperties = eq(sensorProps) verify(udfpsView).animationViewController = any() verify(udfpsView).addView(any()) @@ -162,7 +254,7 @@ class UdfpsControllerOverlayTest : SysuiTestCase() { assertThat(controllerOverlay.isHiding).isFalse() assertThat(controllerOverlay.overlayView).isNotNull() if (isEnrollUseCase) { - verify(udfpsEnrollView).updateSensorLocation(eq(sensorProps)) + verify(udfpsEnrollView).updateSensorLocation(eq(overlayParams.sensorBounds)) assertThat(controllerOverlay.enrollHelper).isNotNull() } else { assertThat(controllerOverlay.enrollHelper).isNull() @@ -188,7 +280,7 @@ class UdfpsControllerOverlayTest : SysuiTestCase() { fun hideUdfpsOverlay_other() = withReason(REASON_AUTH_OTHER) { hideUdfpsOverlay() } private fun hideUdfpsOverlay() { - val didShow = controllerOverlay.show(udfpsController) + val didShow = controllerOverlay.show(udfpsController, overlayParams) val view = controllerOverlay.overlayView val didHide = controllerOverlay.hide() @@ -209,13 +301,13 @@ class UdfpsControllerOverlayTest : SysuiTestCase() { @Test fun canNotReshow() = withReason(REASON_AUTH_BP) { - assertThat(controllerOverlay.show(udfpsController)).isTrue() - assertThat(controllerOverlay.show(udfpsController)).isFalse() + assertThat(controllerOverlay.show(udfpsController, overlayParams)).isTrue() + assertThat(controllerOverlay.show(udfpsController, overlayParams)).isFalse() } @Test fun forwardEnrollProgressEvents() = withReason(REASON_ENROLL_ENROLLING) { - controllerOverlay.show(udfpsController) + controllerOverlay.show(udfpsController, overlayParams) with(EnrollListener(controllerOverlay)) { controllerOverlay.onEnrollmentProgress(/* remaining */20) @@ -228,7 +320,7 @@ class UdfpsControllerOverlayTest : SysuiTestCase() { @Test fun forwardEnrollHelpEvents() = withReason(REASON_ENROLL_ENROLLING) { - controllerOverlay.show(udfpsController) + controllerOverlay.show(udfpsController, overlayParams) with(EnrollListener(controllerOverlay)) { controllerOverlay.onEnrollmentHelp() @@ -240,7 +332,7 @@ class UdfpsControllerOverlayTest : SysuiTestCase() { @Test fun forwardEnrollAcquiredEvents() = withReason(REASON_ENROLL_ENROLLING) { - controllerOverlay.show(udfpsController) + controllerOverlay.show(udfpsController, overlayParams) with(EnrollListener(controllerOverlay)) { controllerOverlay.onEnrollmentProgress(/* remaining */ 1) @@ -261,7 +353,7 @@ class UdfpsControllerOverlayTest : SysuiTestCase() { fun stopIlluminatingOnHide() = withReason(REASON_AUTH_BP) { whenever(udfpsView.isIlluminationRequested).thenReturn(true) - controllerOverlay.show(udfpsController) + controllerOverlay.show(udfpsController, overlayParams) controllerOverlay.hide() verify(udfpsView).stopIllumination() } diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsControllerTest.java index 5d624cdc47a10..80df1e3a7e5c5 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsControllerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsControllerTest.java @@ -16,6 +16,9 @@ package com.android.systemui.biometrics; +import static android.view.MotionEvent.ACTION_DOWN; +import static android.view.MotionEvent.ACTION_MOVE; + import static junit.framework.Assert.assertEquals; import static org.mockito.ArgumentMatchers.any; @@ -28,11 +31,12 @@ import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.inOrder; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.never; +import static org.mockito.Mockito.reset; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; -import android.content.res.TypedArray; +import android.graphics.Rect; import android.hardware.biometrics.BiometricOverlayConstants; import android.hardware.biometrics.ComponentInfoInternal; import android.hardware.biometrics.SensorProperties; @@ -50,6 +54,7 @@ import android.testing.AndroidTestingRunner; import android.testing.TestableLooper.RunWithLooper; import android.view.LayoutInflater; import android.view.MotionEvent; +import android.view.Surface; import android.view.View; import android.view.WindowManager; import android.view.accessibility.AccessibilityManager; @@ -67,7 +72,6 @@ import com.android.systemui.plugins.FalsingManager; import com.android.systemui.plugins.statusbar.StatusBarStateController; import com.android.systemui.statusbar.LockscreenShadeTransitionController; import com.android.systemui.statusbar.VibratorHelper; -import com.android.systemui.statusbar.phone.CentralSurfaces; import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager; import com.android.systemui.statusbar.phone.SystemUIDialogManager; import com.android.systemui.statusbar.phone.UnlockedScreenOffAnimationController; @@ -124,8 +128,6 @@ public class UdfpsControllerTest extends SysuiTestCase { @Mock private StatusBarStateController mStatusBarStateController; @Mock - private CentralSurfaces mCentralSurfaces; - @Mock private StatusBarKeyguardViewManager mStatusBarKeyguardViewManager; @Mock private DumpManager mDumpManager; @@ -174,18 +176,14 @@ public class UdfpsControllerTest extends SysuiTestCase { private UdfpsFpmOtherView mFpmOtherView; @Mock private UdfpsKeyguardView mKeyguardView; - private UdfpsAnimationViewController mUdfpsKeyguardViewController = + private final UdfpsAnimationViewController mUdfpsKeyguardViewController = mock(UdfpsKeyguardViewController.class); @Mock - private TypedArray mBrightnessValues; - @Mock - private TypedArray mBrightnessBacklight; - @Mock private SystemUIDialogManager mSystemUIDialogManager; @Mock private ActivityLaunchAnimator mActivityLaunchAnimator; @Mock - private AlternateUdfpsTouchProvider mTouchProvider; + private AlternateUdfpsTouchProvider mAlternateTouchProvider; // Capture listeners so that they can be used to send events @Captor private ArgumentCaptor mOverlayCaptor; @@ -198,7 +196,6 @@ public class UdfpsControllerTest extends SysuiTestCase { @Before public void setUp() { - setUpResources(); mExecution = new FakeExecution(); when(mLayoutInflater.inflate(R.layout.udfps_view, null, false)) @@ -260,22 +257,12 @@ public class UdfpsControllerTest extends SysuiTestCase { mSystemUIDialogManager, mLatencyTracker, mActivityLaunchAnimator, - Optional.of(mTouchProvider)); + Optional.of(mAlternateTouchProvider)); verify(mFingerprintManager).setUdfpsOverlayController(mOverlayCaptor.capture()); mOverlayController = mOverlayCaptor.getValue(); verify(mScreenLifecycle).addObserver(mScreenObserverCaptor.capture()); mScreenObserver = mScreenObserverCaptor.getValue(); - - assertEquals(TEST_UDFPS_SENSOR_ID, mUdfpsController.mSensorProps.sensorId); - } - - private void setUpResources() { - when(mBrightnessValues.length()).thenReturn(2); - when(mBrightnessValues.getFloat(0, PowerManager.BRIGHTNESS_OFF_FLOAT)).thenReturn(1f); - when(mBrightnessValues.getFloat(1, PowerManager.BRIGHTNESS_OFF_FLOAT)).thenReturn(2f); - when(mBrightnessBacklight.length()).thenReturn(2); - when(mBrightnessBacklight.getFloat(0, PowerManager.BRIGHTNESS_OFF_FLOAT)).thenReturn(1f); - when(mBrightnessBacklight.getFloat(1, PowerManager.BRIGHTNESS_OFF_FLOAT)).thenReturn(2f); + mUdfpsController.updateOverlayParams(TEST_UDFPS_SENSOR_ID, new UdfpsOverlayParams()); } @Test @@ -301,7 +288,7 @@ public class UdfpsControllerTest extends SysuiTestCase { // WHEN ACTION_DOWN is received verify(mUdfpsView).setOnTouchListener(mTouchListenerCaptor.capture()); - MotionEvent downEvent = MotionEvent.obtain(0, 0, MotionEvent.ACTION_DOWN, 0, 0, 0); + MotionEvent downEvent = MotionEvent.obtain(0, 0, ACTION_DOWN, 0, 0, 0); mTouchListenerCaptor.getValue().onTouch(mUdfpsView, downEvent); downEvent.recycle(); @@ -362,7 +349,7 @@ public class UdfpsControllerTest extends SysuiTestCase { // WHEN multiple touches are received verify(mUdfpsView).setOnTouchListener(mTouchListenerCaptor.capture()); - MotionEvent downEvent = MotionEvent.obtain(0, 0, MotionEvent.ACTION_DOWN, 0, 0, 0); + MotionEvent downEvent = MotionEvent.obtain(0, 0, ACTION_DOWN, 0, 0, 0); mTouchListenerCaptor.getValue().onTouch(mUdfpsView, downEvent); downEvent.recycle(); MotionEvent moveEvent = MotionEvent.obtain(0, 0, MotionEvent.ACTION_MOVE, 0, 0, 0); @@ -395,7 +382,7 @@ public class UdfpsControllerTest extends SysuiTestCase { BiometricOverlayConstants.REASON_AUTH_KEYGUARD, mUdfpsOverlayControllerCallback); mFgExecutor.runAllReady(); - verify(mDisplayManager).registerDisplayListener(any(), eq(mHandler)); + verify(mDisplayManager).registerDisplayListener(any(), eq(mHandler), anyLong()); mOverlayController.hideUdfpsOverlay(TEST_UDFPS_SENSOR_ID); mFgExecutor.runAllReady(); @@ -403,6 +390,175 @@ public class UdfpsControllerTest extends SysuiTestCase { verify(mDisplayManager).unregisterDisplayListener(any()); } + @Test + public void updateOverlayParams_recreatesOverlay_ifParamsChanged() throws Exception { + final Rect[] sensorBounds = new Rect[]{new Rect(10, 10, 20, 20), new Rect(5, 5, 25, 25)}; + final int[] displayWidth = new int[]{1080, 1440}; + final int[] displayHeight = new int[]{1920, 2560}; + final float[] scaleFactor = new float[]{1f, displayHeight[1] / (float) displayHeight[0]}; + final int[] rotation = new int[]{Surface.ROTATION_0, Surface.ROTATION_90}; + final UdfpsOverlayParams oldParams = new UdfpsOverlayParams(sensorBounds[0], + displayWidth[0], displayHeight[0], scaleFactor[0], rotation[0]); + + for (int i1 = 0; i1 <= 1; ++i1) + for (int i2 = 0; i2 <= 1; ++i2) + for (int i3 = 0; i3 <= 1; ++i3) + for (int i4 = 0; i4 <= 1; ++i4) + for (int i5 = 0; i5 <= 1; ++i5) { + final UdfpsOverlayParams newParams = new UdfpsOverlayParams(sensorBounds[i1], + displayWidth[i2], displayHeight[i3], scaleFactor[i4], rotation[i5]); + + if (newParams.equals(oldParams)) { + continue; + } + + // Initialize the overlay with old parameters. + mUdfpsController.updateOverlayParams(TEST_UDFPS_SENSOR_ID, oldParams); + + // Show the overlay. + reset(mWindowManager); + mOverlayController.showUdfpsOverlay(TEST_REQUEST_ID, TEST_UDFPS_SENSOR_ID, + BiometricOverlayConstants.REASON_ENROLL_ENROLLING, + mUdfpsOverlayControllerCallback); + mFgExecutor.runAllReady(); + verify(mWindowManager).addView(any(), any()); + + // Update overlay parameters. + reset(mWindowManager); + mUdfpsController.updateOverlayParams(TEST_UDFPS_SENSOR_ID, newParams); + mFgExecutor.runAllReady(); + + // Ensure the overlay was recreated. + verify(mWindowManager).removeView(any()); + verify(mWindowManager).addView(any(), any()); + } + } + + @Test + public void updateOverlayParams_doesNothing_ifParamsDidntChange() throws Exception { + final Rect sensorBounds = new Rect(10, 10, 20, 20); + final int displayWidth = 1080; + final int displayHeight = 1920; + final float scaleFactor = 1f; + final int rotation = Surface.ROTATION_0; + + // Initialize the overlay. + mUdfpsController.updateOverlayParams(TEST_UDFPS_SENSOR_ID, + new UdfpsOverlayParams(sensorBounds, displayWidth, displayHeight, scaleFactor, + rotation)); + + // Show the overlay. + mOverlayController.showUdfpsOverlay(TEST_REQUEST_ID, TEST_UDFPS_SENSOR_ID, + BiometricOverlayConstants.REASON_ENROLL_ENROLLING, mUdfpsOverlayControllerCallback); + mFgExecutor.runAllReady(); + verify(mWindowManager).addView(any(), any()); + + // Update overlay with the same parameters. + mUdfpsController.updateOverlayParams(TEST_UDFPS_SENSOR_ID, + new UdfpsOverlayParams(sensorBounds, displayWidth, displayHeight, scaleFactor, + rotation)); + mFgExecutor.runAllReady(); + + // Ensure the overlay was not recreated. + verify(mWindowManager, never()).removeView(any()); + } + + private static MotionEvent obtainMotionEvent(int action, float x, float y, float minor, + float major) { + MotionEvent.PointerProperties pp = new MotionEvent.PointerProperties(); + pp.id = 1; + MotionEvent.PointerCoords pc = new MotionEvent.PointerCoords(); + pc.x = x; + pc.y = y; + pc.touchMinor = minor; + pc.touchMajor = major; + return MotionEvent.obtain(0, 0, action, 1, new MotionEvent.PointerProperties[]{pp}, + new MotionEvent.PointerCoords[]{pc}, 0, 0, 1f, 1f, 0, 0, 0, 0); + } + + @Test + public void onTouch_propagatesTouchInNativeOrientationAndResolution() throws RemoteException { + final Rect sensorBounds = new Rect(1000, 1900, 1080, 1920); // Bottom right corner. + final int displayWidth = 1080; + final int displayHeight = 1920; + final float scaleFactor = 0.75f; // This means the native resolution is 1440x2560. + final float touchMinor = 10f; + final float touchMajor = 20f; + + // Expecting a touch at the very bottom right corner in native orientation and resolution. + final int expectedX = (int) (displayWidth / scaleFactor); + final int expectedY = (int) (displayHeight / scaleFactor); + final float expectedMinor = touchMinor / scaleFactor; + final float expectedMajor = touchMajor / scaleFactor; + + // Configure UdfpsView to accept the ACTION_DOWN event + when(mUdfpsView.isIlluminationRequested()).thenReturn(false); + when(mUdfpsView.isWithinSensorArea(anyFloat(), anyFloat())).thenReturn(true); + + // Show the overlay. + mOverlayController.showUdfpsOverlay(TEST_REQUEST_ID, TEST_UDFPS_SENSOR_ID, + BiometricOverlayConstants.REASON_ENROLL_ENROLLING, mUdfpsOverlayControllerCallback); + mFgExecutor.runAllReady(); + verify(mUdfpsView).setOnTouchListener(mTouchListenerCaptor.capture()); + + // Test ROTATION_0 + mUdfpsController.updateOverlayParams(TEST_UDFPS_SENSOR_ID, + new UdfpsOverlayParams(sensorBounds, displayWidth, displayHeight, scaleFactor, + Surface.ROTATION_0)); + MotionEvent event = obtainMotionEvent(ACTION_DOWN, displayWidth, displayHeight, touchMinor, + touchMajor); + mTouchListenerCaptor.getValue().onTouch(mUdfpsView, event); + event.recycle(); + event = obtainMotionEvent(ACTION_MOVE, displayWidth, displayHeight, touchMinor, touchMajor); + mTouchListenerCaptor.getValue().onTouch(mUdfpsView, event); + event.recycle(); + verify(mAlternateTouchProvider).onPointerDown(eq(TEST_REQUEST_ID), eq(expectedX), + eq(expectedY), eq(expectedMinor), eq(expectedMajor)); + + // Test ROTATION_90 + reset(mAlternateTouchProvider); + mUdfpsController.updateOverlayParams(TEST_UDFPS_SENSOR_ID, + new UdfpsOverlayParams(sensorBounds, displayWidth, displayHeight, scaleFactor, + Surface.ROTATION_90)); + event = obtainMotionEvent(ACTION_DOWN, displayHeight, 0, touchMinor, touchMajor); + mTouchListenerCaptor.getValue().onTouch(mUdfpsView, event); + event.recycle(); + event = obtainMotionEvent(ACTION_MOVE, displayHeight, 0, touchMinor, touchMajor); + mTouchListenerCaptor.getValue().onTouch(mUdfpsView, event); + event.recycle(); + verify(mAlternateTouchProvider).onPointerDown(eq(TEST_REQUEST_ID), eq(expectedX), + eq(expectedY), eq(expectedMinor), eq(expectedMajor)); + + // Test ROTATION_270 + reset(mAlternateTouchProvider); + mUdfpsController.updateOverlayParams(TEST_UDFPS_SENSOR_ID, + new UdfpsOverlayParams(sensorBounds, displayWidth, displayHeight, scaleFactor, + Surface.ROTATION_270)); + event = obtainMotionEvent(ACTION_DOWN, 0, displayWidth, touchMinor, touchMajor); + mTouchListenerCaptor.getValue().onTouch(mUdfpsView, event); + event.recycle(); + event = obtainMotionEvent(ACTION_MOVE, 0, displayWidth, touchMinor, touchMajor); + mTouchListenerCaptor.getValue().onTouch(mUdfpsView, event); + event.recycle(); + verify(mAlternateTouchProvider).onPointerDown(eq(TEST_REQUEST_ID), eq(expectedX), + eq(expectedY), eq(expectedMinor), eq(expectedMajor)); + + // Test ROTATION_180 + reset(mAlternateTouchProvider); + mUdfpsController.updateOverlayParams(TEST_UDFPS_SENSOR_ID, + new UdfpsOverlayParams(sensorBounds, displayWidth, displayHeight, scaleFactor, + Surface.ROTATION_180)); + // ROTATION_180 is not supported. It should be treated like ROTATION_0. + event = obtainMotionEvent(ACTION_DOWN, displayWidth, displayHeight, touchMinor, touchMajor); + mTouchListenerCaptor.getValue().onTouch(mUdfpsView, event); + event.recycle(); + event = obtainMotionEvent(ACTION_MOVE, displayWidth, displayHeight, touchMinor, touchMajor); + mTouchListenerCaptor.getValue().onTouch(mUdfpsView, event); + event.recycle(); + verify(mAlternateTouchProvider).onPointerDown(eq(TEST_REQUEST_ID), eq(expectedX), + eq(expectedY), eq(expectedMinor), eq(expectedMajor)); + } + @Test public void fingerDown() throws RemoteException { // Configure UdfpsView to accept the ACTION_DOWN event @@ -415,15 +571,17 @@ public class UdfpsControllerTest extends SysuiTestCase { mFgExecutor.runAllReady(); // WHEN ACTION_DOWN is received verify(mUdfpsView).setOnTouchListener(mTouchListenerCaptor.capture()); - MotionEvent downEvent = MotionEvent.obtain(0, 0, MotionEvent.ACTION_DOWN, 0, 0, 0); + MotionEvent downEvent = MotionEvent.obtain(0, 0, ACTION_DOWN, 0, 0, 0); mTouchListenerCaptor.getValue().onTouch(mUdfpsView, downEvent); downEvent.recycle(); MotionEvent moveEvent = MotionEvent.obtain(0, 0, MotionEvent.ACTION_MOVE, 0, 0, 0); + + // FIX THIS TEST mTouchListenerCaptor.getValue().onTouch(mUdfpsView, moveEvent); moveEvent.recycle(); // THEN FingerprintManager is notified about onPointerDown - verify(mTouchProvider).onPointerDown(eq(TEST_REQUEST_ID), - eq(0), eq(0), eq(0f), eq(0f)); + verify(mAlternateTouchProvider).onPointerDown(eq(TEST_REQUEST_ID), eq(0), eq(0), eq(0f), + eq(0f)); verify(mFingerprintManager, never()).onPointerDown(anyLong(), anyInt(), anyInt(), anyInt(), anyFloat(), anyFloat()); verify(mLatencyTracker).onActionStart(eq(LatencyTracker.ACTION_UDFPS_ILLUMINATE)); @@ -434,7 +592,7 @@ public class UdfpsControllerTest extends SysuiTestCase { mOnIlluminatedRunnableCaptor.getValue().run(); InOrder inOrder = inOrder(mFingerprintManager, mLatencyTracker); inOrder.verify(mFingerprintManager).onUiReady( - eq(TEST_REQUEST_ID), eq(mUdfpsController.mSensorProps.sensorId)); + eq(TEST_REQUEST_ID), eq(mUdfpsController.mSensorId)); inOrder.verify(mLatencyTracker).onActionEnd(eq(LatencyTracker.ACTION_UDFPS_ILLUMINATE)); } @@ -452,7 +610,7 @@ public class UdfpsControllerTest extends SysuiTestCase { // AND onIlluminatedRunnable that notifies FingerprintManager is set verify(mUdfpsView).startIllumination(mOnIlluminatedRunnableCaptor.capture()); mOnIlluminatedRunnableCaptor.getValue().run(); - verify(mTouchProvider).onPointerDown(eq(TEST_REQUEST_ID), + verify(mAlternateTouchProvider).onPointerDown(eq(TEST_REQUEST_ID), eq(0), eq(0), eq(3f) /* minor */, eq(2f) /* major */); verify(mFingerprintManager, never()).onPointerDown(anyLong(), anyInt(), anyInt(), anyInt(), anyFloat(), anyFloat()); @@ -573,7 +731,7 @@ public class UdfpsControllerTest extends SysuiTestCase { // WHEN ACTION_DOWN is received verify(mUdfpsView).setOnTouchListener(mTouchListenerCaptor.capture()); - MotionEvent downEvent = MotionEvent.obtain(0, 0, MotionEvent.ACTION_DOWN, 0, 0, 0); + MotionEvent downEvent = MotionEvent.obtain(0, 0, ACTION_DOWN, 0, 0, 0); mTouchListenerCaptor.getValue().onTouch(mUdfpsView, downEvent); downEvent.recycle(); MotionEvent moveEvent = MotionEvent.obtain(0, 0, MotionEvent.ACTION_MOVE, 0, 0, 0); diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsViewTest.kt b/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsViewTest.kt index 6d4cc4c96e0b7..744af589dfacf 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsViewTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsViewTest.kt @@ -23,6 +23,7 @@ import android.testing.AndroidTestingRunner import android.testing.TestableLooper import android.testing.ViewUtils import android.view.LayoutInflater +import android.view.Surface import androidx.test.filters.SmallTest import com.android.systemui.R import com.android.systemui.SysuiTestCase @@ -69,9 +70,8 @@ class UdfpsViewTest : SysuiTestCase() { com.android.internal.R.integer.config_udfps_illumination_transition_ms, 0) view = LayoutInflater.from(context).inflate(R.layout.udfps_view, null) as UdfpsView view.animationViewController = animationViewController - view.sensorProperties = - SensorLocationInternal(DISPLAY_ID, SENSOR_X, SENSOR_Y, SENSOR_RADIUS) - .asFingerprintSensorProperties() + val sensorBounds = SensorLocationInternal("", SENSOR_X, SENSOR_Y, SENSOR_RADIUS).rect + view.overlayParams = UdfpsOverlayParams(sensorBounds, 1920, 1080, 1f, Surface.ROTATION_0) view.setHbmProvider(hbmProvider) ViewUtils.attachView(view) } diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/LockIconViewControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/keyguard/LockIconViewControllerTest.java index 5ed1d656a1f5e..4d0feffa1d243 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/LockIconViewControllerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/LockIconViewControllerTest.java @@ -399,7 +399,7 @@ public class LockIconViewControllerTest extends SysuiTestCase { /* resetLockoutRequiresHwToken */ false, List.of(new SensorLocationInternal("" /* displayId */, (int) udfpsLocation.x, (int) udfpsLocation.y, radius))); - when(mAuthController.getUdfpsSensorLocation()).thenReturn(udfpsLocation); + when(mAuthController.getUdfpsLocation()).thenReturn(udfpsLocation); when(mAuthController.getUdfpsProps()).thenReturn(List.of(fpProps)); return new Pair(radius, udfpsLocation);