diff options
11 files changed, 313 insertions, 154 deletions
diff --git a/packages/SystemUI/src/com/android/keyguard/LockIconView.java b/packages/SystemUI/src/com/android/keyguard/LockIconView.java index fdde40296511..0a82968ae4cb 100644 --- a/packages/SystemUI/src/com/android/keyguard/LockIconView.java +++ b/packages/SystemUI/src/com/android/keyguard/LockIconView.java @@ -19,7 +19,7 @@ package com.android.keyguard; import android.content.Context; import android.content.res.ColorStateList; import android.graphics.Color; -import android.graphics.PointF; +import android.graphics.Point; import android.graphics.RectF; import android.graphics.drawable.Drawable; import android.util.AttributeSet; @@ -54,7 +54,7 @@ public class LockIconView extends FrameLayout implements Dumpable { private boolean mAod; @NonNull private final RectF mSensorRect; - @NonNull private PointF mLockIconCenter = new PointF(0f, 0f); + @NonNull private Point mLockIconCenter = new Point(0, 0); private float mRadius; private int mLockIconPadding; @@ -126,7 +126,7 @@ public class LockIconView extends FrameLayout implements Dumpable { * Set the location of the lock icon. */ @VisibleForTesting - public void setCenterLocation(@NonNull PointF center, float radius, int drawablePadding) { + public void setCenterLocation(@NonNull Point center, float radius, int drawablePadding) { mLockIconCenter = center; mRadius = radius; mLockIconPadding = drawablePadding; diff --git a/packages/SystemUI/src/com/android/keyguard/LockIconViewController.java b/packages/SystemUI/src/com/android/keyguard/LockIconViewController.java index 06e1828ef9f4..2a3667610f9c 100644 --- a/packages/SystemUI/src/com/android/keyguard/LockIconViewController.java +++ b/packages/SystemUI/src/com/android/keyguard/LockIconViewController.java @@ -26,7 +26,7 @@ import static com.android.systemui.doze.util.BurnInHelperKt.getBurnInOffset; import android.content.res.Configuration; import android.content.res.Resources; -import android.graphics.PointF; +import android.graphics.Point; import android.graphics.Rect; import android.graphics.drawable.AnimatedStateListDrawable; import android.hardware.biometrics.BiometricSourceType; @@ -357,8 +357,9 @@ public class LockIconViewController extends ViewController<LockIconView> impleme mAuthController.getUdfpsRadius(), scaledPadding); } else { mView.setCenterLocation( - new PointF(mWidthPixels / 2, - mHeightPixels - ((mBottomPaddingPx + sLockIconRadiusPx) * scaleFactor)), + new Point((int) mWidthPixels / 2, + (int) (mHeightPixels + - ((mBottomPaddingPx + sLockIconRadiusPx) * scaleFactor))), sLockIconRadiusPx * scaleFactor, scaledPadding); } } diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/AuthController.java b/packages/SystemUI/src/com/android/systemui/biometrics/AuthController.java index 47ff59cfc281..f10fbd3926da 100644 --- a/packages/SystemUI/src/com/android/systemui/biometrics/AuthController.java +++ b/packages/SystemUI/src/com/android/systemui/biometrics/AuthController.java @@ -31,7 +31,6 @@ 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; @@ -55,7 +54,9 @@ import android.os.Handler; import android.os.RemoteException; import android.os.UserManager; import android.util.Log; +import android.util.RotationUtils; import android.util.SparseBooleanArray; +import android.view.Display; import android.view.DisplayInfo; import android.view.MotionEvent; import android.view.WindowManager; @@ -116,8 +117,14 @@ public class AuthController extends CoreStartable implements CommandQueue.Callba @NonNull private Point mStableDisplaySize = new Point(); - @Nullable private final PointF mFaceAuthSensorLocation; - @Nullable private PointF mFingerprintLocation; + private final Display mDisplay; + private float mScaleFactor = 1f; + // sensor locations without any resolution scaling nor rotation adjustments: + @Nullable private final Point mFaceSensorLocationDefault; + @Nullable private final Point mFingerprintSensorLocationDefault; + // cached sensor locations: + @Nullable private Point mFaceSensorLocation; + @Nullable private Point mFingerprintSensorLocation; @Nullable private Rect mUdfpsBounds; private final Set<Callback> mCallbacks = new HashSet<>(); @@ -147,6 +154,7 @@ public class AuthController extends CoreStartable implements CommandQueue.Callba @NonNull private final LockPatternUtils mLockPatternUtils; @NonNull private final InteractionJankMonitor mInteractionJankMonitor; private final @Background DelayableExecutor mBackgroundExecutor; + private final DisplayInfo mCachedDisplayInfo = new DisplayInfo(); @VisibleForTesting final TaskStackListener mTaskStackListener = new TaskStackListener() { @@ -184,7 +192,6 @@ public class AuthController extends CoreStartable implements CommandQueue.Callba Log.w(TAG, "ACTION_CLOSE_SYSTEM_DIALOGS received"); mCurrentDialog.dismissWithoutCallback(true /* animate */); mCurrentDialog = null; - mOrientationListener.disable(); for (Callback cb : mCallbacks) { cb.onBiometricPromptDismissed(); @@ -218,7 +225,6 @@ public class AuthController extends CoreStartable implements CommandQueue.Callba Log.e(TAG, "Evicting client due to: " + topPackage); mCurrentDialog.dismissWithoutCallback(true /* animate */); mCurrentDialog = null; - mOrientationListener.disable(); for (Callback cb : mCallbacks) { cb.onBiometricPromptDismissed(); @@ -284,7 +290,6 @@ public class AuthController extends CoreStartable implements CommandQueue.Callba mUdfpsController.setAuthControllerUpdateUdfpsLocation(this::updateUdfpsLocation); mUdfpsController.setHalControlsIllumination(mUdfpsProps.get(0).halControlsIllumination); mUdfpsBounds = mUdfpsProps.get(0).getLocation().getRect(); - updateUdfpsLocation(); } mSidefpsProps = !sidefpsProps.isEmpty() ? sidefpsProps : null; @@ -292,8 +297,8 @@ public class AuthController extends CoreStartable implements CommandQueue.Callba mSidefpsController = mSidefpsControllerFactory.get(); } + updateSensorLocations(); mFingerprintManager.registerBiometricStateListener(mBiometricStateListener); - updateFingerprintLocation(); for (Callback cb : mCallbacks) { cb.onAllAuthenticatorsRegistered(); @@ -470,11 +475,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 getUdfpsLocation() { + @Nullable public Point getUdfpsLocation() { if (mUdfpsController == null || mUdfpsBounds == null) { return null; } - return new PointF(mUdfpsBounds.centerX(), mUdfpsBounds.centerY()); + return new Point(mUdfpsBounds.centerX(), mUdfpsBounds.centerY()); } /** @@ -488,45 +493,105 @@ public class AuthController extends CoreStartable implements CommandQueue.Callba } /** - * @return the scale factor representing the user's current resolution / the stable - * (default) resolution + * Gets the cached scale factor representing the user's current resolution / the stable + * (default) resolution. */ public float getScaleFactor() { - if (mUdfpsController == null || mUdfpsController.mOverlayParams == null) { - return 1f; - } - return mUdfpsController.mOverlayParams.getScaleFactor(); + return mScaleFactor; } /** - * @return where the fingerprint sensor exists in pixels in portrait mode. devices without an - * overridden value will use the default value even if they don't have a fingerprint sensor + * Updates the current display info and cached scale factor & sensor locations. + * Getting the display info is a relatively expensive call, so avoid superfluous calls. */ - @Nullable public PointF getFingerprintSensorLocation() { + private void updateSensorLocations() { + mDisplay.getDisplayInfo(mCachedDisplayInfo); + + final float scaleFactor = android.util.DisplayUtils.getPhysicalPixelDisplaySizeRatio( + mStableDisplaySize.x, mStableDisplaySize.y, mCachedDisplayInfo.getNaturalWidth(), + mCachedDisplayInfo.getNaturalHeight()); + if (scaleFactor == Float.POSITIVE_INFINITY) { + mScaleFactor = 1f; + } else { + mScaleFactor = scaleFactor; + } + + updateUdfpsLocation(); + updateFingerprintLocation(); + updateFaceLocation(); + } + /** + * @return where the fingerprint sensor exists in pixels in its natural orientation. + * Devices without location configs will use the default value even if they don't have a + * fingerprint sensor. + * + * May return null if the fingerprint sensor isn't available yet. + */ + @Nullable private Point getFingerprintSensorLocationInNaturalOrientation() { if (getUdfpsLocation() != null) { return getUdfpsLocation(); } - return mFingerprintLocation; + return new Point( + (int) (mFingerprintSensorLocationDefault.x * mScaleFactor), + (int) (mFingerprintSensorLocationDefault.y * mScaleFactor) + ); } /** - * @return where the face authentication sensor exists relative to the screen in pixels in - * portrait mode. + * @return where the fingerprint sensor exists in pixels exists the current device orientation. + * Devices without location configs will use the default value even if they don't have a + * fingerprint sensor. */ - @Nullable public PointF getFaceAuthSensorLocation() { - if (mFaceProps == null || mFaceAuthSensorLocation == null) { - return null; + @Nullable public Point getFingerprintSensorLocation() { + return mFingerprintSensorLocation; + } + + private void updateFingerprintLocation() { + if (mFpProps == null) { + mFingerprintSensorLocation = null; + } else { + mFingerprintSensorLocation = rotateToCurrentOrientation( + getFingerprintSensorLocationInNaturalOrientation(), + mCachedDisplayInfo); } - DisplayInfo displayInfo = new DisplayInfo(); - mContext.getDisplay().getDisplayInfo(displayInfo); - final float scaleFactor = android.util.DisplayUtils.getPhysicalPixelDisplaySizeRatio( - mStableDisplaySize.x, mStableDisplaySize.y, displayInfo.getNaturalWidth(), - displayInfo.getNaturalHeight()); - if (scaleFactor == Float.POSITIVE_INFINITY) { - return new PointF(mFaceAuthSensorLocation.x, mFaceAuthSensorLocation.y); + } + + /** + * @return where the face sensor exists in pixels in the current device orientation. Returns + * null if no face sensor exists. + */ + @Nullable public Point getFaceSensorLocation() { + return mFaceSensorLocation; + } + + private void updateFaceLocation() { + if (mFaceProps == null || mFaceSensorLocationDefault == null) { + mFaceSensorLocation = null; + } else { + mFaceSensorLocation = rotateToCurrentOrientation( + new Point( + (int) (mFaceSensorLocationDefault.x * mScaleFactor), + (int) (mFaceSensorLocationDefault.y * mScaleFactor)), + mCachedDisplayInfo + ); } - return new PointF(mFaceAuthSensorLocation.x * scaleFactor, - mFaceAuthSensorLocation.y * scaleFactor); + } + + /** + * @param inOutPoint point on the display in pixels. Going in, represents the point + * in the device's natural orientation. Going out, represents + * the point in the display's current orientation. + * @param displayInfo currently display information to use to rotate the point + */ + @VisibleForTesting + protected Point rotateToCurrentOrientation(Point inOutPoint, DisplayInfo displayInfo) { + RotationUtils.rotatePoint( + inOutPoint, + displayInfo.rotation, + displayInfo.getNaturalWidth(), + displayInfo.getNaturalHeight() + ); + return inOutPoint; } /** @@ -625,45 +690,36 @@ public class AuthController extends CoreStartable implements CommandQueue.Callba }); mFaceProps = mFaceManager != null ? mFaceManager.getSensorPropertiesInternal() : null; - int[] faceAuthLocation = context.getResources().getIntArray( com.android.systemui.R.array.config_face_auth_props); if (faceAuthLocation == null || faceAuthLocation.length < 2) { - mFaceAuthSensorLocation = null; + mFaceSensorLocationDefault = null; } else { - mFaceAuthSensorLocation = new PointF( - (float) faceAuthLocation[0], - (float) faceAuthLocation[1]); + mFaceSensorLocationDefault = new Point( + faceAuthLocation[0], + faceAuthLocation[1]); } - updateFingerprintLocation(); - - IntentFilter filter = new IntentFilter(); - filter.addAction(Intent.ACTION_CLOSE_SYSTEM_DIALOGS); - - context.registerReceiver(mBroadcastReceiver, filter, Context.RECEIVER_EXPORTED_UNAUDITED); - mSensorPrivacyManager = context.getSystemService(SensorPrivacyManager.class); - } - - private int getDisplayWidth() { - DisplayInfo displayInfo = new DisplayInfo(); - mContext.getDisplay().getDisplayInfo(displayInfo); - return displayInfo.getNaturalWidth(); - } - - private void updateFingerprintLocation() { - int xLocation = getDisplayWidth() / 2; + mDisplay = mContext.getDisplay(); + mDisplay.getDisplayInfo(mCachedDisplayInfo); + int xFpLocation = mCachedDisplayInfo.getNaturalWidth() / 2; try { - xLocation = mContext.getResources().getDimensionPixelSize( + xFpLocation = mContext.getResources().getDimensionPixelSize( com.android.systemui.R.dimen .physical_fingerprint_sensor_center_screen_location_x); } catch (Resources.NotFoundException e) { } - int yLocation = mContext.getResources().getDimensionPixelSize( - com.android.systemui.R.dimen.physical_fingerprint_sensor_center_screen_location_y); - mFingerprintLocation = new PointF( - xLocation, - yLocation); + mFingerprintSensorLocationDefault = new Point( + xFpLocation, + mContext.getResources().getDimensionPixelSize(com.android.systemui.R.dimen + .physical_fingerprint_sensor_center_screen_location_y) + ); + updateSensorLocations(); + + IntentFilter filter = new IntentFilter(); + filter.addAction(Intent.ACTION_CLOSE_SYSTEM_DIALOGS); + context.registerReceiver(mBroadcastReceiver, filter, Context.RECEIVER_EXPORTED_UNAUDITED); + mSensorPrivacyManager = context.getSystemService(SensorPrivacyManager.class); } // TODO(b/229290039): UDFPS controller should manage its dimensions on its own. Remove this. @@ -672,19 +728,14 @@ public class AuthController extends CoreStartable implements CommandQueue.Callba // 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); final Rect previousUdfpsBounds = mUdfpsBounds; mUdfpsBounds = udfpsProp.getLocation().getRect(); - mUdfpsBounds.scale(scaleFactor); + mUdfpsBounds.scale(mScaleFactor); mUdfpsController.updateOverlayParams(udfpsProp.sensorId, - new UdfpsOverlayParams(mUdfpsBounds, displayInfo.getNaturalWidth(), - displayInfo.getNaturalHeight(), scaleFactor, displayInfo.rotation)); + new UdfpsOverlayParams(mUdfpsBounds, mCachedDisplayInfo.getNaturalWidth(), + mCachedDisplayInfo.getNaturalHeight(), mScaleFactor, + mCachedDisplayInfo.rotation)); if (!Objects.equals(previousUdfpsBounds, mUdfpsBounds)) { for (Callback cb : mCallbacks) { cb.onUdfpsLocationChanged(); @@ -705,6 +756,8 @@ public class AuthController extends CoreStartable implements CommandQueue.Callba mStableDisplaySize = mDisplayManager.getStableDisplaySize(); mActivityTaskManager.registerTaskStackListener(mTaskStackListener); + mOrientationListener.enable(); + updateSensorLocations(); } @Override @@ -905,7 +958,6 @@ public class AuthController extends CoreStartable implements CommandQueue.Callba // BiometricService will have already sent the callback to the client in this case. // This avoids a round trip to SystemUI. So, just dismiss the dialog and we're done. mCurrentDialog = null; - mOrientationListener.disable(); } /** @@ -996,7 +1048,6 @@ public class AuthController extends CoreStartable implements CommandQueue.Callba } mCurrentDialog = newDialog; mCurrentDialog.show(mWindowManager, savedState); - mOrientationListener.enable(); if (!promptInfo.isAllowBackgroundAuthentication()) { mHandler.post(this::cancelIfOwnerIsNotInForeground); @@ -1015,14 +1066,12 @@ public class AuthController extends CoreStartable implements CommandQueue.Callba mReceiver = null; mCurrentDialog = null; - mOrientationListener.disable(); } @Override protected void onConfigurationChanged(Configuration newConfig) { super.onConfigurationChanged(newConfig); - updateFingerprintLocation(); - updateUdfpsLocation(); + updateSensorLocations(); // Save the state of the current dialog (buttons showing, etc) if (mCurrentDialog != null) { @@ -1030,7 +1079,6 @@ public class AuthController extends CoreStartable implements CommandQueue.Callba mCurrentDialog.onSaveState(savedState); mCurrentDialog.dismissWithoutCallback(false /* animate */); mCurrentDialog = null; - mOrientationListener.disable(); // Only show the dialog if necessary. If it was animating out, the dialog is supposed // to send its pending callback immediately. @@ -1051,8 +1099,7 @@ public class AuthController extends CoreStartable implements CommandQueue.Callba } private void onOrientationChanged() { - updateFingerprintLocation(); - updateUdfpsLocation(); + updateSensorLocations(); if (mCurrentDialog != null) { mCurrentDialog.onOrientationChanged(); } @@ -1062,6 +1109,7 @@ public class AuthController extends CoreStartable implements CommandQueue.Callba PromptInfo promptInfo, boolean requireConfirmation, int userId, int[] sensorIds, String opPackageName, boolean skipIntro, long operationId, long requestId, @BiometricMultiSensorMode int multiSensorConfig, + @NonNull WakefulnessLifecycle wakefulnessLifecycle, @NonNull UserManager userManager, @NonNull LockPatternUtils lockPatternUtils) { @@ -1075,9 +1123,7 @@ public class AuthController extends CoreStartable implements CommandQueue.Callba .setOperationId(operationId) .setRequestId(requestId) .setMultiSensorConfig(multiSensorConfig) - .setScaleFactorProvider(() -> { - return getScaleFactor(); - }) + .setScaleFactorProvider(() -> getScaleFactor()) .build(bgExecutor, sensorIds, mFpProps, mFaceProps, wakefulnessLifecycle, userManager, lockPatternUtils, mInteractionJankMonitor); } @@ -1086,8 +1132,14 @@ public class AuthController extends CoreStartable implements CommandQueue.Callba public void dump(@NonNull PrintWriter pw, @NonNull String[] args) { final AuthDialog dialog = mCurrentDialog; pw.println(" stableDisplaySize=" + mStableDisplaySize); - pw.println(" faceAuthSensorLocation=" + mFaceAuthSensorLocation); - pw.println(" fingerprintLocation=" + mFingerprintLocation); + pw.println(" mCachedDisplayInfo=" + mCachedDisplayInfo); + pw.println(" mScaleFactor=" + mScaleFactor); + pw.println(" faceAuthSensorLocationDefault=" + mFaceSensorLocationDefault); + pw.println(" faceAuthSensorLocation=" + getFaceSensorLocation()); + pw.println(" fingerprintSensorLocationDefault=" + mFingerprintSensorLocationDefault); + pw.println(" fingerprintSensorLocationInNaturalOrientation=" + + getFingerprintSensorLocationInNaturalOrientation()); + pw.println(" fingerprintSensorLocation=" + getFingerprintSensorLocation()); pw.println(" udfpsBounds=" + mUdfpsBounds); pw.println(" allFingerprintAuthenticatorsRegistered=" + mAllFingerprintAuthenticatorsRegistered); diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/AuthRippleController.kt b/packages/SystemUI/src/com/android/systemui/biometrics/AuthRippleController.kt index 38fab8ffbfad..d7bf261b4bbd 100644 --- a/packages/SystemUI/src/com/android/systemui/biometrics/AuthRippleController.kt +++ b/packages/SystemUI/src/com/android/systemui/biometrics/AuthRippleController.kt @@ -20,7 +20,7 @@ import android.animation.Animator import android.animation.AnimatorListenerAdapter import android.animation.ValueAnimator import android.content.Context -import android.graphics.PointF +import android.graphics.Point import android.hardware.biometrics.BiometricFingerprintConstants import android.hardware.biometrics.BiometricSourceType import android.util.Log @@ -79,8 +79,8 @@ class AuthRippleController @Inject constructor( @VisibleForTesting internal var startLightRevealScrimOnKeyguardFadingAway = false var lightRevealScrimAnimator: ValueAnimator? = null - var fingerprintSensorLocation: PointF? = null - private var faceSensorLocation: PointF? = null + var fingerprintSensorLocation: Point? = null + private var faceSensorLocation: Point? = null private var circleReveal: LightRevealEffect? = null private var udfpsController: UdfpsController? = null @@ -131,10 +131,10 @@ class AuthRippleController @Inject constructor( circleReveal = CircleReveal( it.x, it.y, - 0f, + 0, Math.max( - Math.max(it.x, centralSurfaces.displayWidth - it.x), - Math.max(it.y, centralSurfaces.displayHeight - it.y) + Math.max(it.x, centralSurfaces.displayWidth.toInt() - it.x), + Math.max(it.y, centralSurfaces.displayHeight.toInt() - it.y) ) ) showUnlockedRipple() @@ -148,10 +148,10 @@ class AuthRippleController @Inject constructor( circleReveal = CircleReveal( it.x, it.y, - 0f, + 0, Math.max( - Math.max(it.x, centralSurfaces.displayWidth - it.x), - Math.max(it.y, centralSurfaces.displayHeight - it.y) + Math.max(it.x, centralSurfaces.displayWidth.toInt() - it.x), + Math.max(it.y, centralSurfaces.displayHeight.toInt() - it.y) ) ) showUnlockedRipple() @@ -228,7 +228,7 @@ class AuthRippleController @Inject constructor( fun updateSensorLocation() { fingerprintSensorLocation = authController.fingerprintSensorLocation - faceSensorLocation = authController.faceAuthSensorLocation + faceSensorLocation = authController.faceSensorLocation } private fun updateRippleColor() { @@ -362,9 +362,8 @@ class AuthRippleController @Inject constructor( invalidCommand(pw) return } - pw.println("custom ripple sensorLocation=" + args[1].toFloat() + ", " + - args[2].toFloat()) - mView.setSensorLocation(PointF(args[1].toFloat(), args[2].toFloat())) + pw.println("custom ripple sensorLocation=" + args[1] + ", " + args[2]) + mView.setSensorLocation(Point(args[1].toInt(), args[2].toInt())) showUnlockedRipple() } else -> invalidCommand(pw) diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/AuthRippleView.kt b/packages/SystemUI/src/com/android/systemui/biometrics/AuthRippleView.kt index 1c574808e0e9..c93fe6ac9f34 100644 --- a/packages/SystemUI/src/com/android/systemui/biometrics/AuthRippleView.kt +++ b/packages/SystemUI/src/com/android/systemui/biometrics/AuthRippleView.kt @@ -23,7 +23,7 @@ import android.content.Context import android.graphics.Canvas import android.graphics.Color import android.graphics.Paint -import android.graphics.PointF +import android.graphics.Point import android.util.AttributeSet import android.view.View import android.view.animation.PathInterpolator @@ -68,7 +68,7 @@ class AuthRippleView(context: Context?, attrs: AttributeSet?) : View(context, at dwellShader.maxRadius = value field = value } - private var dwellOrigin: PointF = PointF() + private var dwellOrigin: Point = Point() set(value) { dwellShader.origin = value field = value @@ -78,9 +78,9 @@ class AuthRippleView(context: Context?, attrs: AttributeSet?) : View(context, at rippleShader.setMaxSize(value * 2f, value * 2f) field = value } - private var origin: PointF = PointF() + private var origin: Point = Point() set(value) { - rippleShader.setCenter(value.x, value.y) + rippleShader.setCenter(value.x.toFloat(), value.y.toFloat()) field = value } @@ -97,12 +97,12 @@ class AuthRippleView(context: Context?, attrs: AttributeSet?) : View(context, at visibility = GONE } - fun setSensorLocation(location: PointF) { + fun setSensorLocation(location: Point) { origin = location radius = maxOf(location.x, location.y, width - location.x, height - location.y).toFloat() } - fun setFingerprintSensorLocation(location: PointF, sensorRadius: Float) { + fun setFingerprintSensorLocation(location: Point, sensorRadius: Float) { origin = location radius = maxOf(location.x, location.y, width - location.x, height - location.y).toFloat() dwellOrigin = location @@ -349,13 +349,15 @@ class AuthRippleView(context: Context?, attrs: AttributeSet?) : View(context, at if (drawDwell) { val maskRadius = (1 - (1 - dwellShader.progress) * (1 - dwellShader.progress) * (1 - dwellShader.progress)) * dwellRadius * 2f - canvas?.drawCircle(dwellOrigin.x, dwellOrigin.y, maskRadius, dwellPaint) + canvas?.drawCircle(dwellOrigin.x.toFloat(), dwellOrigin.y.toFloat(), + maskRadius, dwellPaint) } if (drawRipple) { val mask = (1 - (1 - rippleShader.progress) * (1 - rippleShader.progress) * (1 - rippleShader.progress)) * radius * 2f - canvas?.drawCircle(origin.x, origin.y, mask, ripplePaint) + canvas?.drawCircle(origin.x.toFloat(), origin.y.toFloat(), + mask, ripplePaint) } } } diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/DwellRippleShader.kt b/packages/SystemUI/src/com/android/systemui/biometrics/DwellRippleShader.kt index 979fe33fb25b..e5c4fb42ffe8 100644 --- a/packages/SystemUI/src/com/android/systemui/biometrics/DwellRippleShader.kt +++ b/packages/SystemUI/src/com/android/systemui/biometrics/DwellRippleShader.kt @@ -16,7 +16,7 @@ package com.android.systemui.biometrics -import android.graphics.PointF +import android.graphics.Point import android.graphics.RuntimeShader import android.util.MathUtils @@ -94,10 +94,10 @@ class DwellRippleShader internal constructor() : RuntimeShader(SHADER) { /** * Origin coordinate of the ripple. */ - var origin: PointF = PointF() + var origin: Point = Point() set(value) { field = value - setFloatUniform("in_origin", value.x, value.y) + setFloatUniform("in_origin", value.x.toFloat(), value.y.toFloat()) } /** @@ -107,7 +107,7 @@ class DwellRippleShader internal constructor() : RuntimeShader(SHADER) { set(value) { field = value setFloatUniform("in_radius", - (1 - (1 - value) * (1 - value) * (1 - value))* maxRadius) + (1 - (1 - value) * (1 - value) * (1 - value)) * maxRadius) setFloatUniform("in_blur", MathUtils.lerp(1f, 0.7f, value)) } diff --git a/packages/SystemUI/src/com/android/systemui/decor/FaceScanningProviderFactory.kt b/packages/SystemUI/src/com/android/systemui/decor/FaceScanningProviderFactory.kt index 81d3d6caebd7..9ffa18879cd1 100644 --- a/packages/SystemUI/src/com/android/systemui/decor/FaceScanningProviderFactory.kt +++ b/packages/SystemUI/src/com/android/systemui/decor/FaceScanningProviderFactory.kt @@ -32,8 +32,8 @@ import android.widget.FrameLayout import com.android.keyguard.KeyguardUpdateMonitor import com.android.systemui.FaceScanningOverlay import com.android.systemui.biometrics.AuthController -import com.android.systemui.dagger.qualifiers.Main import com.android.systemui.dagger.SysUISingleton +import com.android.systemui.dagger.qualifiers.Main import com.android.systemui.flags.FeatureFlags import com.android.systemui.flags.Flags import com.android.systemui.plugins.statusbar.StatusBarStateController @@ -55,7 +55,7 @@ class FaceScanningProviderFactory @Inject constructor( override val hasProviders: Boolean get() { if (!featureFlags.isEnabled(Flags.FACE_SCANNING_ANIM) || - authController.faceAuthSensorLocation == null) { + authController.faceSensorLocation == null) { return false } @@ -152,7 +152,7 @@ class FaceScanningOverlayProviderImpl( layoutParams.let { lp -> lp.width = ViewGroup.LayoutParams.MATCH_PARENT lp.height = ViewGroup.LayoutParams.MATCH_PARENT - authController.faceAuthSensorLocation?.y?.let { faceAuthSensorHeight -> + authController.faceSensorLocation?.y?.let { faceAuthSensorHeight -> val faceScanningHeight = (faceAuthSensorHeight * 2).toInt() when (rotation) { Surface.ROTATION_0, Surface.ROTATION_180 -> diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/LightRevealScrim.kt b/packages/SystemUI/src/com/android/systemui/statusbar/LightRevealScrim.kt index 0a616c095551..9d2750fa7b5f 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/LightRevealScrim.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/LightRevealScrim.kt @@ -143,13 +143,13 @@ class LinearLightRevealEffect(private val isVertical: Boolean) : LightRevealEffe class CircleReveal( /** X-value of the circle center of the reveal. */ - val centerX: Float, + val centerX: Int, /** Y-value of the circle center of the reveal. */ - val centerY: Float, + val centerY: Int, /** Radius of initial state of circle reveal */ - val startRadius: Float, + val startRadius: Int, /** Radius of end state of circle reveal */ - val endRadius: Float + val endRadius: Int ) : LightRevealEffect { override fun setRevealAmountOnScrim(amount: Float, scrim: LightRevealScrim) { // reveal amount updates already have an interpolator, so we intentionally use the @@ -350,7 +350,7 @@ class LightRevealScrim(context: Context?, attrs: AttributeSet?) : View(context, * This method does not call [invalidate] - you should do so once you're done changing * properties. */ - public fun setRevealGradientBounds(left: Float, top: Float, right: Float, bottom: Float) { + fun setRevealGradientBounds(left: Float, top: Float, right: Float, bottom: Float) { revealGradientWidth = right - left revealGradientHeight = bottom - top @@ -387,4 +387,4 @@ class LightRevealScrim(context: Context?, attrs: AttributeSet?) : View(context, getColorWithAlpha(revealGradientEndColor, revealGradientEndColorAlpha), PorterDuff.Mode.MULTIPLY) } -}
\ No newline at end of file +} 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 d158892e4ec5..f47e6206c29f 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthControllerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthControllerTest.java @@ -72,6 +72,8 @@ import android.testing.AndroidTestingRunner; import android.testing.TestableContext; import android.testing.TestableLooper; import android.testing.TestableLooper.RunWithLooper; +import android.view.DisplayInfo; +import android.view.Surface; import android.view.WindowManager; import androidx.test.filters.SmallTest; @@ -685,13 +687,8 @@ public class AuthControllerTest extends SysuiTestCase { } @Test - public void testSubscribesToOrientationChangesWhenShowingDialog() { - showDialog(new int[]{1} /* sensorIds */, false /* credentialAllowed */); - + public void testSubscribesToOrientationChangesOnStart() { verify(mDisplayManager).registerDisplayListener(any(), eq(mHandler), anyLong()); - - mAuthController.hideAuthenticationDialog(REQUEST_ID); - verify(mDisplayManager).unregisterDisplayListener(any()); } @Test @@ -736,7 +733,115 @@ public class AuthControllerTest extends SysuiTestCase { order.verify(mContextListener).onDozeChanged(eq(true)); } - // Helpers + @Test + public void testGetFingerprintSensorLocationChanges_differentRotations() { + // GIVEN fp default location and mocked device dimensions + // Rotation 0, where "o" is the location of the FP sensor, if x or y = 0, it's the edge of + // the screen which is why a 1x1 width and height is represented by a 2x2 grid below: + // [* o] + // [* *] + Point fpDefaultLocation = new Point(1, 0); + final DisplayInfo displayInfo = new DisplayInfo(); + displayInfo.logicalWidth = 1; + displayInfo.logicalHeight = 1; + + // WHEN the rotation is 0, THEN no rotation applied + displayInfo.rotation = Surface.ROTATION_0; + assertEquals( + fpDefaultLocation, + mAuthController.rotateToCurrentOrientation( + new Point(fpDefaultLocation), displayInfo) + ); + + // WHEN the rotation is 270, THEN rotation is applied + // [* *] + // [* o] + displayInfo.rotation = Surface.ROTATION_270; + assertEquals( + new Point(1, 1), + mAuthController.rotateToCurrentOrientation( + new Point(fpDefaultLocation), displayInfo) + ); + + // WHEN the rotation is 180, THEN rotation is applied + // [* *] + // [o *] + displayInfo.rotation = Surface.ROTATION_180; + assertEquals( + new Point(0, 1), + mAuthController.rotateToCurrentOrientation( + new Point(fpDefaultLocation), displayInfo) + ); + + // WHEN the rotation is 90, THEN rotation is applied + // [o *] + // [* *] + displayInfo.rotation = Surface.ROTATION_90; + assertEquals( + new Point(0, 0), + mAuthController.rotateToCurrentOrientation( + new Point(fpDefaultLocation), displayInfo) + ); + } + + @Test + public void testGetFingerprintSensorLocationChanges_rotateRectangle() { + // GIVEN fp default location and mocked device dimensions + // Rotation 0, where "o" is the location of the FP sensor, if x or y = 0, it's the edge of + // the screen. + // [* * o *] + // [* * * *] + Point fpDefaultLocation = new Point(2, 0); + final DisplayInfo displayInfo = new DisplayInfo(); + displayInfo.logicalWidth = 3; + displayInfo.logicalHeight = 1; + + // WHEN the rotation is 0, THEN no rotation applied + displayInfo.rotation = Surface.ROTATION_0; + assertEquals( + fpDefaultLocation, + mAuthController.rotateToCurrentOrientation( + new Point(fpDefaultLocation), displayInfo) + ); + + // WHEN the rotation is 180, THEN rotation is applied + // [* * * *] + // [* o * *] + displayInfo.rotation = Surface.ROTATION_180; + assertEquals( + new Point(1, 1), + mAuthController.rotateToCurrentOrientation( + new Point(fpDefaultLocation), displayInfo) + ); + + // Rotation 270 & 90 have swapped logical width and heights + displayInfo.logicalWidth = 1; + displayInfo.logicalHeight = 3; + + // WHEN the rotation is 270, THEN rotation is applied + // [* *] + // [* *] + // [* o] + // [* *] + displayInfo.rotation = Surface.ROTATION_270; + assertEquals( + new Point(1, 2), + mAuthController.rotateToCurrentOrientation( + new Point(fpDefaultLocation), displayInfo) + ); + + // WHEN the rotation is 90, THEN rotation is applied + // [* *] + // [o *] + // [* *] + // [* *] + displayInfo.rotation = Surface.ROTATION_90; + assertEquals( + new Point(0, 1), + mAuthController.rotateToCurrentOrientation( + new Point(fpDefaultLocation), displayInfo) + ); + } private void showDialog(int[] sensorIds, boolean credentialAllowed) { mAuthController.showAuthenticationDialog(createTestPromptInfo(), 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 d6afd6d192ec..44ef922d2c39 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthRippleControllerTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthRippleControllerTest.kt @@ -16,7 +16,7 @@ package com.android.systemui.biometrics -import android.graphics.PointF +import android.graphics.Point import android.hardware.biometrics.BiometricSourceType import android.testing.AndroidTestingRunner import android.testing.TestableLooper.RunWithLooper @@ -31,11 +31,12 @@ import com.android.systemui.statusbar.LightRevealScrim import com.android.systemui.statusbar.NotificationShadeWindowController import com.android.systemui.statusbar.commandline.CommandRegistry import com.android.systemui.statusbar.phone.BiometricUnlockController -import com.android.systemui.statusbar.phone.KeyguardBypassController import com.android.systemui.statusbar.phone.CentralSurfaces +import com.android.systemui.statusbar.phone.KeyguardBypassController import com.android.systemui.statusbar.policy.ConfigurationController import com.android.systemui.statusbar.policy.KeyguardStateController import com.android.systemui.util.leak.RotationUtils +import javax.inject.Provider import org.junit.After import org.junit.Assert.assertFalse import org.junit.Assert.assertTrue @@ -45,15 +46,14 @@ import org.junit.runner.RunWith import org.mockito.ArgumentCaptor import org.mockito.ArgumentMatchers import org.mockito.Mock -import org.mockito.Mockito.`when` import org.mockito.Mockito.any import org.mockito.Mockito.never import org.mockito.Mockito.reset import org.mockito.Mockito.verify +import org.mockito.Mockito.`when` import org.mockito.MockitoAnnotations import org.mockito.MockitoSession import org.mockito.quality.Strictness -import javax.inject.Provider @SmallTest @RunWith(AndroidTestingRunner::class) @@ -116,7 +116,7 @@ class AuthRippleControllerTest : SysuiTestCase() { @Test fun testFingerprintTrigger_KeyguardVisible_Ripple() { // GIVEN fp exists, keyguard is visible, user doesn't need strong auth - val fpsLocation = PointF(5f, 5f) + val fpsLocation = Point(5, 5) `when`(authController.fingerprintSensorLocation).thenReturn(fpsLocation) controller.onViewAttached() `when`(keyguardUpdateMonitor.isKeyguardVisible).thenReturn(true) @@ -139,7 +139,7 @@ class AuthRippleControllerTest : SysuiTestCase() { @Test fun testFingerprintTrigger_Dreaming_Ripple() { // GIVEN fp exists, keyguard is visible, user doesn't need strong auth - val fpsLocation = PointF(5f, 5f) + val fpsLocation = Point(5, 5) `when`(authController.fingerprintSensorLocation).thenReturn(fpsLocation) controller.onViewAttached() `when`(keyguardUpdateMonitor.isKeyguardVisible).thenReturn(false) @@ -162,7 +162,7 @@ class AuthRippleControllerTest : SysuiTestCase() { @Test fun testFingerprintTrigger_KeyguardNotVisible_NotDreaming_NoRipple() { // GIVEN fp exists & user doesn't need strong auth - val fpsLocation = PointF(5f, 5f) + val fpsLocation = Point(5, 5) `when`(authController.udfpsLocation).thenReturn(fpsLocation) controller.onViewAttached() `when`(keyguardUpdateMonitor.userNeedsStrongAuth()).thenReturn(false) @@ -184,7 +184,7 @@ class AuthRippleControllerTest : SysuiTestCase() { @Test fun testFingerprintTrigger_StrongAuthRequired_NoRipple() { // GIVEN fp exists & keyguard is visible - val fpsLocation = PointF(5f, 5f) + val fpsLocation = Point(5, 5) `when`(authController.udfpsLocation).thenReturn(fpsLocation) controller.onViewAttached() `when`(keyguardUpdateMonitor.isKeyguardVisible).thenReturn(true) @@ -205,8 +205,8 @@ class AuthRippleControllerTest : SysuiTestCase() { @Test fun testFaceTriggerBypassEnabled_Ripple() { // GIVEN face auth sensor exists, keyguard is visible & strong auth isn't required - val faceLocation = PointF(5f, 5f) - `when`(authController.faceAuthSensorLocation).thenReturn(faceLocation) + val faceLocation = Point(5, 5) + `when`(authController.faceSensorLocation).thenReturn(faceLocation) controller.onViewAttached() `when`(keyguardUpdateMonitor.isKeyguardVisible).thenReturn(true) @@ -229,8 +229,8 @@ class AuthRippleControllerTest : SysuiTestCase() { @Test fun testFaceTriggerNonBypass_NoRipple() { // GIVEN face auth sensor exists - val faceLocation = PointF(5f, 5f) - `when`(authController.faceAuthSensorLocation).thenReturn(faceLocation) + val faceLocation = Point(5, 5) + `when`(authController.faceSensorLocation).thenReturn(faceLocation) controller.onViewAttached() // WHEN bypass isn't enabled & face authenticated @@ -248,7 +248,7 @@ class AuthRippleControllerTest : SysuiTestCase() { @Test fun testNullFaceSensorLocationDoesNothing() { - `when`(authController.faceAuthSensorLocation).thenReturn(null) + `when`(authController.faceSensorLocation).thenReturn(null) controller.onViewAttached() val captor = ArgumentCaptor.forClass(KeyguardUpdateMonitorCallback::class.java) @@ -293,7 +293,7 @@ class AuthRippleControllerTest : SysuiTestCase() { @Test @RunWithLooper(setAsMainLooper = true) fun testAnimatorRunWhenWakeAndUnlock_fingerprint() { - val fpsLocation = PointF(5f, 5f) + val fpsLocation = Point(5, 5) `when`(authController.fingerprintSensorLocation).thenReturn(fpsLocation) controller.onViewAttached() `when`(keyguardUpdateMonitor.isKeyguardVisible).thenReturn(true) @@ -311,8 +311,8 @@ class AuthRippleControllerTest : SysuiTestCase() { @Test @RunWithLooper(setAsMainLooper = true) fun testAnimatorRunWhenWakeAndUnlock_faceUdfpsFingerDown() { - val faceLocation = PointF(5f, 5f) - `when`(authController.faceAuthSensorLocation).thenReturn(faceLocation) + val faceLocation = Point(5, 5) + `when`(authController.faceSensorLocation).thenReturn(faceLocation) controller.onViewAttached() `when`(keyguardUpdateMonitor.isKeyguardVisible).thenReturn(true) `when`(biometricUnlockController.isWakeAndUnlock).thenReturn(true) 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 24d051508fde..cefd68dde0a0 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/LockIconViewControllerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/LockIconViewControllerTest.java @@ -30,7 +30,7 @@ import static org.mockito.Mockito.when; import android.content.Context; import android.content.res.Resources; -import android.graphics.PointF; +import android.graphics.Point; import android.graphics.Rect; import android.graphics.drawable.AnimatedStateListDrawable; import android.hardware.biometrics.BiometricSourceType; @@ -125,7 +125,7 @@ public class LockIconViewControllerTest extends SysuiTestCase { ArgumentCaptor.forClass(KeyguardUpdateMonitorCallback.class); private KeyguardUpdateMonitorCallback mKeyguardUpdateMonitorCallback; - @Captor private ArgumentCaptor<PointF> mPointCaptor; + @Captor private ArgumentCaptor<Point> mPointCaptor; @Before public void setUp() throws Exception { @@ -176,7 +176,7 @@ public class LockIconViewControllerTest extends SysuiTestCase { @Test public void testUpdateFingerprintLocationOnInit() { // GIVEN fp sensor location is available pre-attached - Pair<Float, PointF> udfps = setupUdfps(); // first = radius, second = udfps location + Pair<Float, Point> udfps = setupUdfps(); // first = radius, second = udfps location // WHEN lock icon view controller is initialized and attached mLockIconViewController.init(); @@ -191,7 +191,7 @@ public class LockIconViewControllerTest extends SysuiTestCase { @Test public void testUpdatePaddingBasedOnResolutionScale() { // GIVEN fp sensor location is available pre-attached & scaled resolution factor is 5 - Pair<Float, PointF> udfps = setupUdfps(); // first = radius, second = udfps location + Pair<Float, Point> udfps = setupUdfps(); // first = radius, second = udfps location when(mAuthController.getScaleFactor()).thenReturn(5f); // WHEN lock icon view controller is initialized and attached @@ -216,7 +216,7 @@ public class LockIconViewControllerTest extends SysuiTestCase { // GIVEN fp sensor location is available post-attached captureAuthControllerCallback(); - Pair<Float, PointF> udfps = setupUdfps(); + Pair<Float, Point> udfps = setupUdfps(); // WHEN all authenticators are registered mAuthControllerCallback.onAllAuthenticatorsRegistered(); @@ -239,7 +239,7 @@ public class LockIconViewControllerTest extends SysuiTestCase { // GIVEN fp sensor location is available post-attached captureAuthControllerCallback(); - Pair<Float, PointF> udfps = setupUdfps(); + Pair<Float, Point> udfps = setupUdfps(); // WHEN udfps location changes mAuthControllerCallback.onUdfpsLocationChanged(); @@ -419,9 +419,9 @@ public class LockIconViewControllerTest extends SysuiTestCase { verify(mLockIconView).setTranslationX(0); } - private Pair<Float, PointF> setupUdfps() { + private Pair<Float, Point> setupUdfps() { when(mKeyguardUpdateMonitor.isUdfpsSupported()).thenReturn(true); - final PointF udfpsLocation = new PointF(50, 75); + final Point udfpsLocation = new Point(50, 75); final float radius = 33f; when(mAuthController.getUdfpsLocation()).thenReturn(udfpsLocation); when(mAuthController.getUdfpsRadius()).thenReturn(radius); |