From c441a9a059a4e8b8a72cd2af7923b3e9e7ec859e Mon Sep 17 00:00:00 2001 From: Austin Delgado Date: Fri, 4 Nov 2022 13:22:57 -0700 Subject: [PATCH] Add ellipse detection to UdfpsController Enable with: adb shell cmd statusbar flag 2200 on (ExpandedOverlay) and adb shell cmd statusbar flag 2202 on (EllipseDetection) Bug: 257118043 Test: atest SystemUITests:com.android.systemui.biometrics Change-Id: I143f7e5df71d3668a79cb898f618a749eef6f263 --- .../systemui/biometrics/UdfpsController.java | 40 ++++++-- .../biometrics/UdfpsEllipseDetection.kt | 92 +++++++++++++++++++ .../biometrics/UdfpsKeyguardViewController.kt | 1 + 3 files changed, 125 insertions(+), 8 deletions(-) create mode 100644 packages/SystemUI/src/com/android/systemui/biometrics/UdfpsEllipseDetection.kt diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java index d7908db0c8b95..45595c80d36d3 100644 --- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java +++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java @@ -150,7 +150,7 @@ public class UdfpsController implements DozeReceiver, Dumpable { // TODO(b/229290039): UDFPS controller should manage its dimensions on its own. Remove this. @Nullable private Runnable mAuthControllerUpdateUdfpsLocation; @Nullable private final AlternateUdfpsTouchProvider mAlternateTouchProvider; - @Nullable private UdfpsDisplayMode mUdfpsDisplayMode; + @Nullable private UdfpsDisplayModeProvider mUdfpsDisplayMode; // Tracks the velocity of a touch to help filter out the touches that move too fast. @Nullable private VelocityTracker mVelocityTracker; @@ -165,6 +165,7 @@ public class UdfpsController implements DozeReceiver, Dumpable { // The current request from FingerprintService. Null if no current request. @Nullable UdfpsControllerOverlay mOverlay; + @Nullable private UdfpsEllipseDetection mUdfpsEllipseDetection; // The fingerprint AOD trigger doesn't provide an ACTION_UP/ACTION_CANCEL event to tell us when // to turn off high brightness mode. To get around this limitation, the state of the AOD @@ -321,6 +322,10 @@ public class UdfpsController implements DozeReceiver, Dumpable { if (!mOverlayParams.equals(overlayParams)) { mOverlayParams = overlayParams; + if (mFeatureFlags.isEnabled(Flags.UDFPS_ELLIPSE_DETECTION)) { + mUdfpsEllipseDetection.updateOverlayParams(overlayParams); + } + final boolean wasShowingAltAuth = mKeyguardViewManager.isShowingAlternateBouncer(); // When the bounds change it's always necessary to re-create the overlay's window with @@ -462,13 +467,19 @@ public class UdfpsController implements DozeReceiver, Dumpable { boolean withinSensorArea; if (mFeatureFlags.isEnabled(Flags.UDFPS_NEW_TOUCH_DETECTION)) { - withinSensorArea = + if (mFeatureFlags.isEnabled(Flags.UDFPS_ELLIPSE_DETECTION)) { + // Ellipse detection + withinSensorArea = mUdfpsEllipseDetection.isGoodEllipseOverlap(event); + } else { + // Centroid with expanded overlay + withinSensorArea = isWithinSensorArea(udfpsView, event.getRawX(), - event.getRawY(), fromUdfpsView); + event.getRawY(), fromUdfpsView); + } } else { + // Centroid with sensor sized view withinSensorArea = - isWithinSensorArea(udfpsView, event.getX(), - event.getY(), fromUdfpsView); + isWithinSensorArea(udfpsView, event.getX(), event.getY(), fromUdfpsView); } if (withinSensorArea) { @@ -503,14 +514,23 @@ public class UdfpsController implements DozeReceiver, Dumpable { if (idx == event.getActionIndex()) { boolean actionMoveWithinSensorArea; if (mFeatureFlags.isEnabled(Flags.UDFPS_NEW_TOUCH_DETECTION)) { - actionMoveWithinSensorArea = + if (mFeatureFlags.isEnabled(Flags.UDFPS_ELLIPSE_DETECTION)) { + // Ellipse detection + actionMoveWithinSensorArea = + mUdfpsEllipseDetection.isGoodEllipseOverlap(event); + } else { + // Centroid with expanded overlay + actionMoveWithinSensorArea = isWithinSensorArea(udfpsView, event.getRawX(idx), event.getRawY(idx), fromUdfpsView); + } } else { + // Centroid with sensor sized view actionMoveWithinSensorArea = - isWithinSensorArea(udfpsView, event.getX(idx), - event.getY(idx), fromUdfpsView); + isWithinSensorArea(udfpsView, event.getX(idx), + event.getY(idx), fromUdfpsView); } + if ((fromUdfpsView || actionMoveWithinSensorArea) && shouldTryToDismissKeyguard()) { Log.v(TAG, "onTouch | dismiss keyguard ACTION_MOVE"); @@ -708,6 +728,10 @@ public class UdfpsController implements DozeReceiver, Dumpable { udfpsHapticsSimulator.setUdfpsController(this); udfpsShell.setUdfpsOverlayController(mUdfpsOverlayController); + + if (featureFlags.isEnabled(Flags.UDFPS_ELLIPSE_DETECTION)) { + mUdfpsEllipseDetection = new UdfpsEllipseDetection(mOverlayParams); + } } /** diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsEllipseDetection.kt b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsEllipseDetection.kt new file mode 100644 index 0000000000000..8ae4775467df7 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsEllipseDetection.kt @@ -0,0 +1,92 @@ +/* + * Copyright (C) 2022 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.biometrics + +import android.graphics.Point +import android.graphics.Rect +import android.util.RotationUtils +import android.view.MotionEvent +import kotlin.math.cos +import kotlin.math.pow +import kotlin.math.sin + +private const val TAG = "UdfpsEllipseDetection" + +private const val NEEDED_POINTS = 2 + +class UdfpsEllipseDetection(overlayParams: UdfpsOverlayParams) { + var sensorRect = Rect() + var points: Array = emptyArray() + + init { + sensorRect = Rect(overlayParams.sensorBounds) + + points = calculateSensorPoints(sensorRect) + } + + fun updateOverlayParams(params: UdfpsOverlayParams) { + sensorRect = Rect(params.sensorBounds) + + val rot = params.rotation + RotationUtils.rotateBounds( + sensorRect, + params.naturalDisplayWidth, + params.naturalDisplayHeight, + rot + ) + + points = calculateSensorPoints(sensorRect) + } + + fun isGoodEllipseOverlap(event: MotionEvent): Boolean { + return points.count { checkPoint(event, it) } >= NEEDED_POINTS + } + + private fun checkPoint(event: MotionEvent, point: Point): Boolean { + // Calculate if sensor point is within ellipse + // Formula: ((cos(o)(xE - xS) + sin(o)(yE - yS))^2 / a^2) + ((sin(o)(xE - xS) + cos(o)(yE - + // yS))^2 / b^2) <= 1 + val a: Float = cos(event.orientation) * (point.x - event.rawX) + val b: Float = sin(event.orientation) * (point.y - event.rawY) + val c: Float = sin(event.orientation) * (point.x - event.rawX) + val d: Float = cos(event.orientation) * (point.y - event.rawY) + val result = + (a + b).pow(2) / (event.touchMinor / 2).pow(2) + + (c - d).pow(2) / (event.touchMajor / 2).pow(2) + + return result <= 1 + } +} + +fun calculateSensorPoints(sensorRect: Rect): Array { + val sensorX = sensorRect.centerX() + val sensorY = sensorRect.centerY() + val cornerOffset: Int = sensorRect.width() / 4 + val sideOffset: Int = sensorRect.width() / 3 + + return arrayOf( + Point(sensorX - cornerOffset, sensorY - cornerOffset), + Point(sensorX, sensorY - sideOffset), + Point(sensorX + cornerOffset, sensorY - cornerOffset), + Point(sensorX - sideOffset, sensorY), + Point(sensorX, sensorY), + Point(sensorX + sideOffset, sensorY), + Point(sensorX - cornerOffset, sensorY + cornerOffset), + Point(sensorX, sensorY + sideOffset), + Point(sensorX + cornerOffset, sensorY + cornerOffset) + ) +} diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsKeyguardViewController.kt b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsKeyguardViewController.kt index a20b8aa417d02..63144fcea7610 100644 --- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsKeyguardViewController.kt +++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsKeyguardViewController.kt @@ -235,6 +235,7 @@ constructor( return } + // Forwarding touches not needed with expanded overlay if (useExpandedOverlay) { return } else {