Merge "Enable RRS (FHD<->QHD) support for UDFPS" into tm-dev

This commit is contained in:
Ilya Matyukhin
2022-04-21 05:55:03 +00:00
committed by Android (Google) Code Review
18 changed files with 599 additions and 269 deletions

View File

@@ -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);
}
}

View File

@@ -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. */

View File

@@ -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<UdfpsController> mUdfpsControllerFactory;
private final Provider<SidefpsController> 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<Callback> 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<FaceSensorPropertiesInternal> mFaceProps;
@Nullable private List<FingerprintSensorPropertiesInternal> mFpProps;
@Nullable private List<FingerprintSensorPropertiesInternal> mUdfpsProps;
@@ -249,6 +251,7 @@ public class AuthController extends CoreStartable implements CommandQueue.Callba
}
mAllFingerprintAuthenticatorsRegistered = true;
mFpProps = sensors;
List<FingerprintSensorPropertiesInternal> udfpsProps = new ArrayList<>();
List<FingerprintSensorPropertiesInternal> 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();
}

View File

@@ -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()

View File

@@ -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();

View File

@@ -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

View File

@@ -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();
}

View File

@@ -56,11 +56,12 @@ public class UdfpsEnrollViewController extends UdfpsAnimationViewController<Udfp
@NonNull StatusBarStateController statusBarStateController,
@NonNull PanelExpansionStateManager panelExpansionStateManager,
@NonNull SystemUIDialogManager systemUIDialogManager,
@NonNull DumpManager dumpManager) {
@NonNull DumpManager dumpManager,
float scaleFactor) {
super(view, statusBarStateController, panelExpansionStateManager, systemUIDialogManager,
dumpManager);
mEnrollProgressBarRadius = getContext().getResources()
.getInteger(R.integer.config_udfpsEnrollProgressBar);
mEnrollProgressBarRadius = (int) (scaleFactor * getContext().getResources().getInteger(
R.integer.config_udfpsEnrollProgressBar));
mEnrollHelper = enrollHelper;
mView.setEnrollHelper(mEnrollHelper);
}

View File

@@ -0,0 +1,43 @@
package com.android.systemui.biometrics
import android.graphics.Rect
import android.view.Surface
import android.view.Surface.Rotation
/**
* Collection of parameters that define an under-display fingerprint sensor (UDFPS) overlay.
*
* @property sensorBounds coordinates of the bounding box around the sensor, in natural orientation,
* in pixels, for the current resolution.
* @property naturalDisplayWidth width of the physical display, in natural orientation, in pixels,
* for the current resolution.
* @property naturalDisplayHeight height of the physical display, in natural orientation, in pixels,
* for the current resolution.
* @property scaleFactor ratio of a dimension in the current resolution to the corresponding
* dimension in the native resolution.
* @property rotation current rotation of the display.
*/
data class UdfpsOverlayParams(
val sensorBounds: Rect = Rect(),
val naturalDisplayWidth: Int = 0,
val naturalDisplayHeight: Int = 0,
val scaleFactor: Float = 1f,
@Rotation val rotation: Int = Surface.ROTATION_0
) {
/** See [android.view.DisplayInfo.logicalWidth] */
val logicalDisplayWidth
get() = if (rotation == Surface.ROTATION_90 || rotation == Surface.ROTATION_270) {
naturalDisplayHeight
} else {
naturalDisplayWidth
}
/** See [android.view.DisplayInfo.logicalHeight] */
val logicalDisplayHeight
get() = if (rotation == Surface.ROTATION_90 || rotation == Surface.ROTATION_270) {
naturalDisplayWidth
} else {
naturalDisplayHeight
}
}

View File

@@ -21,7 +21,6 @@ import android.graphics.Color
import android.graphics.Paint
import android.graphics.PointF
import android.graphics.RectF
import android.hardware.fingerprint.FingerprintSensorPropertiesInternal
import android.util.AttributeSet
import android.util.Log
import android.view.MotionEvent
@@ -39,6 +38,8 @@ class UdfpsView(
attrs: AttributeSet?
) : FrameLayout(context, attrs), DozeReceiver, UdfpsIlluminator {
// sensorRect may be bigger than the sensor. True sensor dimensions are defined in
// overlayParams.sensorBounds
private val sensorRect = RectF()
private var hbmProvider: UdfpsHbmProvider? = null
private val debugTextPaint = Paint().apply {
@@ -62,8 +63,8 @@ class UdfpsView(
/** View controller (can be different for enrollment, BiometricPrompt, Keyguard, etc.). */
var animationViewController: 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))
}

View File

@@ -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<ComponentInfoInternal> 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());

View File

@@ -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)

View File

@@ -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);

View File

@@ -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()

View File

@@ -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<WindowManager.LayoutParams>
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()
}

View File

@@ -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<IUdfpsOverlayController> 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);

View File

@@ -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)
}

View File

@@ -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);