Merge changes I143f7e5d,I87fa7feb into tm-qpr-dev

* changes:
  Add ellipse detection to UdfpsController
  Extend UdfpsView to bottom half of screen
This commit is contained in:
Austin Delgado
2022-11-16 20:49:28 +00:00
committed by Android (Google) Code Review
13 changed files with 345 additions and 28 deletions

View File

@@ -37,6 +37,9 @@ public abstract class UdfpsAnimationView extends FrameLayout {
private float mDialogSuggestedAlpha = 1f; private float mDialogSuggestedAlpha = 1f;
private float mNotificationShadeExpansion = 0f; private float mNotificationShadeExpansion = 0f;
// Used for Udfps ellipse detection when flag is true, set by AnimationViewController
boolean mUseExpandedOverlay = false;
// mAlpha takes into consideration the status bar expansion amount and dialog suggested alpha // mAlpha takes into consideration the status bar expansion amount and dialog suggested alpha
private int mAlpha; private int mAlpha;
boolean mPauseAuth; boolean mPauseAuth;
@@ -117,6 +120,24 @@ public abstract class UdfpsAnimationView extends FrameLayout {
return (int) ((1 - percent) * 255); return (int) ((1 - percent) * 255);
} }
/**
* Converts coordinates of RectF relative to the screen to coordinates relative to this view.
*
* @param bounds RectF based off screen coordinates in current orientation
*/
RectF getBoundsRelativeToView(RectF bounds) {
int[] pos = getLocationOnScreen();
RectF output = new RectF(
bounds.left - pos[0],
bounds.top - pos[1],
bounds.right - pos[0],
bounds.bottom - pos[1]
);
return output;
}
/** /**
* Set the suggested alpha based on whether a dialog was recently shown or hidden. * Set the suggested alpha based on whether a dialog was recently shown or hidden.
* @param dialogSuggestedAlpha value from 0f to 1f. * @param dialogSuggestedAlpha value from 0f to 1f.

View File

@@ -66,6 +66,7 @@ import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.doze.DozeReceiver; import com.android.systemui.doze.DozeReceiver;
import com.android.systemui.dump.DumpManager; import com.android.systemui.dump.DumpManager;
import com.android.systemui.flags.FeatureFlags; import com.android.systemui.flags.FeatureFlags;
import com.android.systemui.flags.Flags;
import com.android.systemui.keyguard.ScreenLifecycle; import com.android.systemui.keyguard.ScreenLifecycle;
import com.android.systemui.keyguard.domain.interactor.PrimaryBouncerInteractor; import com.android.systemui.keyguard.domain.interactor.PrimaryBouncerInteractor;
import com.android.systemui.plugins.FalsingManager; import com.android.systemui.plugins.FalsingManager;
@@ -149,7 +150,7 @@ public class UdfpsController implements DozeReceiver, Dumpable {
// TODO(b/229290039): UDFPS controller should manage its dimensions on its own. Remove this. // TODO(b/229290039): UDFPS controller should manage its dimensions on its own. Remove this.
@Nullable private Runnable mAuthControllerUpdateUdfpsLocation; @Nullable private Runnable mAuthControllerUpdateUdfpsLocation;
@Nullable private final AlternateUdfpsTouchProvider mAlternateTouchProvider; @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. // Tracks the velocity of a touch to help filter out the touches that move too fast.
@Nullable private VelocityTracker mVelocityTracker; @Nullable private VelocityTracker mVelocityTracker;
@@ -164,6 +165,7 @@ public class UdfpsController implements DozeReceiver, Dumpable {
// The current request from FingerprintService. Null if no current request. // The current request from FingerprintService. Null if no current request.
@Nullable UdfpsControllerOverlay mOverlay; @Nullable UdfpsControllerOverlay mOverlay;
@Nullable private UdfpsEllipseDetection mUdfpsEllipseDetection;
// The fingerprint AOD trigger doesn't provide an ACTION_UP/ACTION_CANCEL event to tell us when // 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 // to turn off high brightness mode. To get around this limitation, the state of the AOD
@@ -320,6 +322,10 @@ public class UdfpsController implements DozeReceiver, Dumpable {
if (!mOverlayParams.equals(overlayParams)) { if (!mOverlayParams.equals(overlayParams)) {
mOverlayParams = overlayParams; mOverlayParams = overlayParams;
if (mFeatureFlags.isEnabled(Flags.UDFPS_ELLIPSE_DETECTION)) {
mUdfpsEllipseDetection.updateOverlayParams(overlayParams);
}
final boolean wasShowingAltAuth = mKeyguardViewManager.isShowingAlternateBouncer(); final boolean wasShowingAltAuth = mKeyguardViewManager.isShowingAlternateBouncer();
// When the bounds change it's always necessary to re-create the overlay's window with // When the bounds change it's always necessary to re-create the overlay's window with
@@ -459,8 +465,23 @@ public class UdfpsController implements DozeReceiver, Dumpable {
mVelocityTracker.clear(); mVelocityTracker.clear();
} }
boolean withinSensorArea = boolean withinSensorArea;
if (mFeatureFlags.isEnabled(Flags.UDFPS_NEW_TOUCH_DETECTION)) {
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);
}
} else {
// Centroid with sensor sized view
withinSensorArea =
isWithinSensorArea(udfpsView, event.getX(), event.getY(), fromUdfpsView); isWithinSensorArea(udfpsView, event.getX(), event.getY(), fromUdfpsView);
}
if (withinSensorArea) { if (withinSensorArea) {
Trace.beginAsyncSection("UdfpsController.e2e.onPointerDown", 0); Trace.beginAsyncSection("UdfpsController.e2e.onPointerDown", 0);
Log.v(TAG, "onTouch | action down"); Log.v(TAG, "onTouch | action down");
@@ -491,9 +512,25 @@ public class UdfpsController implements DozeReceiver, Dumpable {
? event.getPointerId(0) ? event.getPointerId(0)
: event.findPointerIndex(mActivePointerId); : event.findPointerIndex(mActivePointerId);
if (idx == event.getActionIndex()) { if (idx == event.getActionIndex()) {
boolean actionMoveWithinSensorArea = boolean actionMoveWithinSensorArea;
isWithinSensorArea(udfpsView, event.getX(idx), event.getY(idx), if (mFeatureFlags.isEnabled(Flags.UDFPS_NEW_TOUCH_DETECTION)) {
fromUdfpsView); 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);
}
if ((fromUdfpsView || actionMoveWithinSensorArea) if ((fromUdfpsView || actionMoveWithinSensorArea)
&& shouldTryToDismissKeyguard()) { && shouldTryToDismissKeyguard()) {
Log.v(TAG, "onTouch | dismiss keyguard ACTION_MOVE"); Log.v(TAG, "onTouch | dismiss keyguard ACTION_MOVE");
@@ -691,6 +728,10 @@ public class UdfpsController implements DozeReceiver, Dumpable {
udfpsHapticsSimulator.setUdfpsController(this); udfpsHapticsSimulator.setUdfpsController(this);
udfpsShell.setUdfpsOverlayController(mUdfpsOverlayController); udfpsShell.setUdfpsOverlayController(mUdfpsOverlayController);
if (featureFlags.isEnabled(Flags.UDFPS_ELLIPSE_DETECTION)) {
mUdfpsEllipseDetection = new UdfpsEllipseDetection(mOverlayParams);
}
} }
/** /**

View File

@@ -49,6 +49,7 @@ import com.android.systemui.R
import com.android.systemui.animation.ActivityLaunchAnimator import com.android.systemui.animation.ActivityLaunchAnimator
import com.android.systemui.dump.DumpManager import com.android.systemui.dump.DumpManager
import com.android.systemui.flags.FeatureFlags import com.android.systemui.flags.FeatureFlags
import com.android.systemui.flags.Flags
import com.android.systemui.keyguard.domain.interactor.PrimaryBouncerInteractor import com.android.systemui.keyguard.domain.interactor.PrimaryBouncerInteractor
import com.android.systemui.plugins.statusbar.StatusBarStateController import com.android.systemui.plugins.statusbar.StatusBarStateController
import com.android.systemui.shade.ShadeExpansionStateManager import com.android.systemui.shade.ShadeExpansionStateManager
@@ -103,6 +104,7 @@ class UdfpsControllerOverlay @JvmOverloads constructor(
private set private set
private var overlayParams: UdfpsOverlayParams = UdfpsOverlayParams() private var overlayParams: UdfpsOverlayParams = UdfpsOverlayParams()
private var sensorBounds: Rect = Rect()
private var overlayTouchListener: TouchExplorationStateChangeListener? = null private var overlayTouchListener: TouchExplorationStateChangeListener? = null
@@ -120,6 +122,10 @@ class UdfpsControllerOverlay @JvmOverloads constructor(
privateFlags = WindowManager.LayoutParams.PRIVATE_FLAG_TRUSTED_OVERLAY privateFlags = WindowManager.LayoutParams.PRIVATE_FLAG_TRUSTED_OVERLAY
// Avoid announcing window title. // Avoid announcing window title.
accessibilityTitle = " " accessibilityTitle = " "
if (featureFlags.isEnabled(Flags.UDFPS_NEW_TOUCH_DETECTION)) {
inputFeatures = WindowManager.LayoutParams.INPUT_FEATURE_SPY
}
} }
/** A helper if the [requestReason] was due to enrollment. */ /** A helper if the [requestReason] was due to enrollment. */
@@ -160,6 +166,7 @@ class UdfpsControllerOverlay @JvmOverloads constructor(
fun show(controller: UdfpsController, params: UdfpsOverlayParams): Boolean { fun show(controller: UdfpsController, params: UdfpsOverlayParams): Boolean {
if (overlayView == null) { if (overlayView == null) {
overlayParams = params overlayParams = params
sensorBounds = Rect(params.sensorBounds)
try { try {
overlayView = (inflater.inflate( overlayView = (inflater.inflate(
R.layout.udfps_view, null, false R.layout.udfps_view, null, false
@@ -178,6 +185,7 @@ class UdfpsControllerOverlay @JvmOverloads constructor(
} }
windowManager.addView(this, coreLayoutParams.updateDimensions(animation)) windowManager.addView(this, coreLayoutParams.updateDimensions(animation))
sensorRect = sensorBounds
touchExplorationEnabled = accessibilityManager.isTouchExplorationEnabled touchExplorationEnabled = accessibilityManager.isTouchExplorationEnabled
overlayTouchListener = TouchExplorationStateChangeListener { overlayTouchListener = TouchExplorationStateChangeListener {
if (accessibilityManager.isTouchExplorationEnabled) { if (accessibilityManager.isTouchExplorationEnabled) {
@@ -194,6 +202,7 @@ class UdfpsControllerOverlay @JvmOverloads constructor(
overlayTouchListener!! overlayTouchListener!!
) )
overlayTouchListener?.onTouchExplorationStateChanged(true) overlayTouchListener?.onTouchExplorationStateChanged(true)
useExpandedOverlay = featureFlags.isEnabled(Flags.UDFPS_NEW_TOUCH_DETECTION)
} }
} catch (e: RuntimeException) { } catch (e: RuntimeException) {
Log.e(TAG, "showUdfpsOverlay | failed to add window", e) Log.e(TAG, "showUdfpsOverlay | failed to add window", e)
@@ -225,13 +234,14 @@ class UdfpsControllerOverlay @JvmOverloads constructor(
REASON_ENROLL_ENROLLING -> { REASON_ENROLL_ENROLLING -> {
UdfpsEnrollViewController( UdfpsEnrollViewController(
view.addUdfpsView(R.layout.udfps_enroll_view) { view.addUdfpsView(R.layout.udfps_enroll_view) {
updateSensorLocation(overlayParams.sensorBounds) updateSensorLocation(sensorBounds)
}, },
enrollHelper ?: throw IllegalStateException("no enrollment helper"), enrollHelper ?: throw IllegalStateException("no enrollment helper"),
statusBarStateController, statusBarStateController,
shadeExpansionStateManager, shadeExpansionStateManager,
dialogManager, dialogManager,
dumpManager, dumpManager,
featureFlags,
overlayParams.scaleFactor overlayParams.scaleFactor
) )
} }
@@ -420,7 +430,12 @@ class UdfpsControllerOverlay @JvmOverloads constructor(
} }
// Original sensorBounds assume portrait mode. // Original sensorBounds assume portrait mode.
val rotatedSensorBounds = Rect(overlayParams.sensorBounds) var rotatedBounds =
if (featureFlags.isEnabled(Flags.UDFPS_NEW_TOUCH_DETECTION)) {
Rect(overlayParams.overlayBounds)
} else {
Rect(overlayParams.sensorBounds)
}
val rot = overlayParams.rotation val rot = overlayParams.rotation
if (rot == Surface.ROTATION_90 || rot == Surface.ROTATION_270) { if (rot == Surface.ROTATION_90 || rot == Surface.ROTATION_270) {
@@ -434,18 +449,27 @@ class UdfpsControllerOverlay @JvmOverloads constructor(
} else { } else {
Log.v(TAG, "Rotate UDFPS bounds " + Surface.rotationToString(rot)) Log.v(TAG, "Rotate UDFPS bounds " + Surface.rotationToString(rot))
RotationUtils.rotateBounds( RotationUtils.rotateBounds(
rotatedSensorBounds, rotatedBounds,
overlayParams.naturalDisplayWidth, overlayParams.naturalDisplayWidth,
overlayParams.naturalDisplayHeight, overlayParams.naturalDisplayHeight,
rot rot
) )
if (featureFlags.isEnabled(Flags.UDFPS_NEW_TOUCH_DETECTION)) {
RotationUtils.rotateBounds(
sensorBounds,
overlayParams.naturalDisplayWidth,
overlayParams.naturalDisplayHeight,
rot
)
}
} }
} }
x = rotatedSensorBounds.left - paddingX x = rotatedBounds.left - paddingX
y = rotatedSensorBounds.top - paddingY y = rotatedBounds.top - paddingY
height = rotatedSensorBounds.height() + 2 * paddingX height = rotatedBounds.height() + 2 * paddingX
width = rotatedSensorBounds.width() + 2 * paddingY width = rotatedBounds.width() + 2 * paddingY
return this return this
} }

View File

@@ -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<Point> = 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<Point> {
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)
)
}

View File

@@ -18,6 +18,7 @@ package com.android.systemui.biometrics;
import android.content.Context; import android.content.Context;
import android.graphics.Rect; import android.graphics.Rect;
import android.graphics.RectF;
import android.os.Handler; import android.os.Handler;
import android.os.Looper; import android.os.Looper;
import android.util.AttributeSet; import android.util.AttributeSet;
@@ -41,6 +42,9 @@ public class UdfpsEnrollView extends UdfpsAnimationView {
@NonNull private ImageView mFingerprintView; @NonNull private ImageView mFingerprintView;
@NonNull private ImageView mFingerprintProgressView; @NonNull private ImageView mFingerprintProgressView;
private LayoutParams mProgressParams;
private float mProgressBarRadius;
public UdfpsEnrollView(Context context, @Nullable AttributeSet attrs) { public UdfpsEnrollView(Context context, @Nullable AttributeSet attrs) {
super(context, attrs); super(context, attrs);
mFingerprintDrawable = new UdfpsEnrollDrawable(mContext, attrs); mFingerprintDrawable = new UdfpsEnrollDrawable(mContext, attrs);
@@ -56,6 +60,32 @@ public class UdfpsEnrollView extends UdfpsAnimationView {
mFingerprintProgressView.setImageDrawable(mFingerprintProgressDrawable); mFingerprintProgressView.setImageDrawable(mFingerprintProgressDrawable);
} }
@Override
void onSensorRectUpdated(RectF bounds) {
if (mUseExpandedOverlay) {
RectF converted = getBoundsRelativeToView(bounds);
mProgressParams = new LayoutParams(
(int) (converted.width() + mProgressBarRadius * 2),
(int) (converted.height() + mProgressBarRadius * 2));
mProgressParams.setMargins(
(int) (converted.left - mProgressBarRadius),
(int) (converted.top - mProgressBarRadius),
(int) (converted.right + mProgressBarRadius),
(int) (converted.bottom + mProgressBarRadius)
);
mFingerprintProgressView.setLayoutParams(mProgressParams);
super.onSensorRectUpdated(converted);
} else {
super.onSensorRectUpdated(bounds);
}
}
void setProgressBarRadius(float radius) {
mProgressBarRadius = radius;
}
@Override @Override
public UdfpsDrawable getDrawable() { public UdfpsDrawable getDrawable() {
return mFingerprintDrawable; return mFingerprintDrawable;

View File

@@ -21,6 +21,8 @@ import android.graphics.PointF;
import com.android.systemui.R; import com.android.systemui.R;
import com.android.systemui.dump.DumpManager; import com.android.systemui.dump.DumpManager;
import com.android.systemui.flags.FeatureFlags;
import com.android.systemui.flags.Flags;
import com.android.systemui.plugins.statusbar.StatusBarStateController; import com.android.systemui.plugins.statusbar.StatusBarStateController;
import com.android.systemui.shade.ShadeExpansionStateManager; import com.android.systemui.shade.ShadeExpansionStateManager;
import com.android.systemui.statusbar.phone.SystemUIDialogManager; import com.android.systemui.statusbar.phone.SystemUIDialogManager;
@@ -57,6 +59,7 @@ public class UdfpsEnrollViewController extends UdfpsAnimationViewController<Udfp
@NonNull ShadeExpansionStateManager shadeExpansionStateManager, @NonNull ShadeExpansionStateManager shadeExpansionStateManager,
@NonNull SystemUIDialogManager systemUIDialogManager, @NonNull SystemUIDialogManager systemUIDialogManager,
@NonNull DumpManager dumpManager, @NonNull DumpManager dumpManager,
@NonNull FeatureFlags featureFlags,
float scaleFactor) { float scaleFactor) {
super(view, statusBarStateController, shadeExpansionStateManager, systemUIDialogManager, super(view, statusBarStateController, shadeExpansionStateManager, systemUIDialogManager,
dumpManager); dumpManager);
@@ -64,6 +67,11 @@ public class UdfpsEnrollViewController extends UdfpsAnimationViewController<Udfp
R.integer.config_udfpsEnrollProgressBar)); R.integer.config_udfpsEnrollProgressBar));
mEnrollHelper = enrollHelper; mEnrollHelper = enrollHelper;
mView.setEnrollHelper(mEnrollHelper); mView.setEnrollHelper(mEnrollHelper);
mView.setProgressBarRadius(mEnrollProgressBarRadius);
if (featureFlags.isEnabled(Flags.UDFPS_NEW_TOUCH_DETECTION)) {
mView.mUseExpandedOverlay = true;
}
} }
@Override @Override

View File

@@ -26,6 +26,7 @@ import android.animation.ObjectAnimator;
import android.content.Context; import android.content.Context;
import android.graphics.PorterDuff; import android.graphics.PorterDuff;
import android.graphics.PorterDuffColorFilter; import android.graphics.PorterDuffColorFilter;
import android.graphics.RectF;
import android.util.AttributeSet; import android.util.AttributeSet;
import android.util.MathUtils; import android.util.MathUtils;
import android.view.View; import android.view.View;
@@ -75,6 +76,8 @@ public class UdfpsKeyguardView extends UdfpsAnimationView {
private int mAnimationType = ANIMATION_NONE; private int mAnimationType = ANIMATION_NONE;
private boolean mFullyInflated; private boolean mFullyInflated;
private LayoutParams mParams;
public UdfpsKeyguardView(Context context, @Nullable AttributeSet attrs) { public UdfpsKeyguardView(Context context, @Nullable AttributeSet attrs) {
super(context, attrs); super(context, attrs);
mFingerprintDrawable = new UdfpsFpDrawable(context); mFingerprintDrawable = new UdfpsFpDrawable(context);
@@ -239,6 +242,22 @@ public class UdfpsKeyguardView extends UdfpsAnimationView {
updateAlpha(); updateAlpha();
} }
@Override
void onSensorRectUpdated(RectF bounds) {
super.onSensorRectUpdated(bounds);
if (mUseExpandedOverlay) {
mParams = new LayoutParams((int) bounds.width(), (int) bounds.height());
RectF converted = getBoundsRelativeToView(bounds);
mParams.setMargins(
(int) converted.left,
(int) converted.top,
(int) converted.right,
(int) converted.bottom
);
}
}
/** /**
* Animates in the bg protection circle behind the fp icon to highlight the icon. * Animates in the bg protection circle behind the fp icon to highlight the icon.
*/ */
@@ -277,6 +296,7 @@ public class UdfpsKeyguardView extends UdfpsAnimationView {
pw.println(" mUdfpsRequested=" + mUdfpsRequested); pw.println(" mUdfpsRequested=" + mUdfpsRequested);
pw.println(" mInterpolatedDarkAmount=" + mInterpolatedDarkAmount); pw.println(" mInterpolatedDarkAmount=" + mInterpolatedDarkAmount);
pw.println(" mAnimationType=" + mAnimationType); pw.println(" mAnimationType=" + mAnimationType);
pw.println(" mUseExpandedOverlay=" + mUseExpandedOverlay);
} }
private final AsyncLayoutInflater.OnInflateFinishedListener mLayoutInflaterFinishListener = private final AsyncLayoutInflater.OnInflateFinishedListener mLayoutInflaterFinishListener =
@@ -291,7 +311,12 @@ public class UdfpsKeyguardView extends UdfpsAnimationView {
updatePadding(); updatePadding();
updateColor(); updateColor();
updateAlpha(); updateAlpha();
parent.addView(view);
if (mUseExpandedOverlay) {
parent.addView(view, mParams);
} else {
parent.addView(view);
}
// requires call to invalidate to update the color // requires call to invalidate to update the color
mLockScreenFp.addValueCallback( mLockScreenFp.addValueCallback(

View File

@@ -52,7 +52,6 @@ import com.android.systemui.util.time.SystemClock
import java.io.PrintWriter import java.io.PrintWriter
import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Job import kotlinx.coroutines.Job
import kotlinx.coroutines.flow.collect
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
/** Class that coordinates non-HBM animations during keyguard authentication. */ /** Class that coordinates non-HBM animations during keyguard authentication. */
@@ -82,6 +81,8 @@ constructor(
systemUIDialogManager, systemUIDialogManager,
dumpManager dumpManager
) { ) {
private val useExpandedOverlay: Boolean =
featureFlags.isEnabled(Flags.UDFPS_NEW_TOUCH_DETECTION)
private val isModernBouncerEnabled: Boolean = featureFlags.isEnabled(Flags.MODERN_BOUNCER) private val isModernBouncerEnabled: Boolean = featureFlags.isEnabled(Flags.MODERN_BOUNCER)
private var showingUdfpsBouncer = false private var showingUdfpsBouncer = false
private var udfpsRequested = false private var udfpsRequested = false
@@ -233,7 +234,13 @@ constructor(
if (transitionToFullShadeProgress != 0f) { if (transitionToFullShadeProgress != 0f) {
return return
} }
udfpsController.onTouch(event)
// Forwarding touches not needed with expanded overlay
if (useExpandedOverlay) {
return
} else {
udfpsController.onTouch(event)
}
} }
} }
@@ -322,6 +329,7 @@ constructor(
keyguardViewManager.setAlternateBouncer(mAlternateBouncer) keyguardViewManager.setAlternateBouncer(mAlternateBouncer)
lockScreenShadeTransitionController.udfpsKeyguardViewController = this lockScreenShadeTransitionController.udfpsKeyguardViewController = this
activityLaunchAnimator.addListener(activityLaunchAnimatorListener) activityLaunchAnimator.addListener(activityLaunchAnimatorListener)
view.mUseExpandedOverlay = useExpandedOverlay
} }
override fun onViewDetached() { override fun onViewDetached() {

View File

@@ -20,6 +20,7 @@ import android.graphics.Canvas
import android.graphics.Color import android.graphics.Color
import android.graphics.Paint import android.graphics.Paint
import android.graphics.PointF import android.graphics.PointF
import android.graphics.Rect
import android.graphics.RectF import android.graphics.RectF
import android.util.AttributeSet import android.util.AttributeSet
import android.util.Log import android.util.Log
@@ -38,9 +39,12 @@ class UdfpsView(
attrs: AttributeSet? attrs: AttributeSet?
) : FrameLayout(context, attrs), DozeReceiver { ) : FrameLayout(context, attrs), DozeReceiver {
// Use expanded overlay when feature flag is true, set by UdfpsViewController
var useExpandedOverlay: Boolean = false
// sensorRect may be bigger than the sensor. True sensor dimensions are defined in // sensorRect may be bigger than the sensor. True sensor dimensions are defined in
// overlayParams.sensorBounds // overlayParams.sensorBounds
private val sensorRect = RectF() var sensorRect = Rect()
private var mUdfpsDisplayMode: UdfpsDisplayModeProvider? = null private var mUdfpsDisplayMode: UdfpsDisplayModeProvider? = null
private val debugTextPaint = Paint().apply { private val debugTextPaint = Paint().apply {
isAntiAlias = true isAntiAlias = true
@@ -92,13 +96,19 @@ class UdfpsView(
val paddingX = animationViewController?.paddingX ?: 0 val paddingX = animationViewController?.paddingX ?: 0
val paddingY = animationViewController?.paddingY ?: 0 val paddingY = animationViewController?.paddingY ?: 0
sensorRect.set( // Updates sensor rect in relation to the overlay view
paddingX.toFloat(), if (useExpandedOverlay) {
paddingY.toFloat(), animationViewController?.onSensorRectUpdated(RectF(sensorRect))
(overlayParams.sensorBounds.width() + paddingX).toFloat(), } else {
(overlayParams.sensorBounds.height() + paddingY).toFloat() sensorRect.set(
) paddingX,
animationViewController?.onSensorRectUpdated(RectF(sensorRect)) paddingY,
(overlayParams.sensorBounds.width() + paddingX),
(overlayParams.sensorBounds.height() + paddingY)
)
animationViewController?.onSensorRectUpdated(RectF(sensorRect))
}
} }
fun onTouchOutsideView() { fun onTouchOutsideView() {

View File

@@ -405,4 +405,10 @@ object Flags {
// 2100 - Falsing Manager // 2100 - Falsing Manager
@JvmField val FALSING_FOR_LONG_TAPS = releasedFlag(2100, "falsing_for_long_taps") @JvmField val FALSING_FOR_LONG_TAPS = releasedFlag(2100, "falsing_for_long_taps")
// 2200 - udfps
// TODO(b/259264861): Tracking Bug
@JvmField val UDFPS_NEW_TOUCH_DETECTION = unreleasedFlag(2200, "udfps_new_touch_detection")
@JvmField val UDFPS_ELLIPSE_DEBUG_UI = unreleasedFlag(2201, "udfps_ellipse_debug")
@JvmField val UDFPS_ELLIPSE_DETECTION = unreleasedFlag(2202, "udfps_ellipse_detection")
} }

View File

@@ -94,6 +94,11 @@ public class UdfpsKeyguardViewControllerBaseTest extends SysuiTestCase {
mKeyguardStateControllerCallbackCaptor; mKeyguardStateControllerCallbackCaptor;
protected KeyguardStateController.Callback mKeyguardStateControllerCallback; protected KeyguardStateController.Callback mKeyguardStateControllerCallback;
private @Captor ArgumentCaptor<StatusBarKeyguardViewManager.KeyguardViewManagerCallback>
mKeyguardViewManagerCallbackArgumentCaptor;
protected StatusBarKeyguardViewManager.KeyguardViewManagerCallback mKeyguardViewManagerCallback;
@Before @Before
public void setUp() { public void setUp() {
MockitoAnnotations.initMocks(this); MockitoAnnotations.initMocks(this);
@@ -143,15 +148,22 @@ public class UdfpsKeyguardViewControllerBaseTest extends SysuiTestCase {
} }
public UdfpsKeyguardViewController createUdfpsKeyguardViewController() { public UdfpsKeyguardViewController createUdfpsKeyguardViewController() {
return createUdfpsKeyguardViewController(false); return createUdfpsKeyguardViewController(false, false);
}
public void captureKeyGuardViewManagerCallback() {
verify(mStatusBarKeyguardViewManager).addCallback(
mKeyguardViewManagerCallbackArgumentCaptor.capture());
mKeyguardViewManagerCallback = mKeyguardViewManagerCallbackArgumentCaptor.getValue();
} }
protected UdfpsKeyguardViewController createUdfpsKeyguardViewController( protected UdfpsKeyguardViewController createUdfpsKeyguardViewController(
boolean useModernBouncer) { boolean useModernBouncer, boolean useExpandedOverlay) {
mFeatureFlags.set(Flags.MODERN_BOUNCER, useModernBouncer); mFeatureFlags.set(Flags.MODERN_BOUNCER, useModernBouncer);
mFeatureFlags.set(Flags.UDFPS_NEW_TOUCH_DETECTION, useExpandedOverlay);
when(mStatusBarKeyguardViewManager.getPrimaryBouncer()).thenReturn( when(mStatusBarKeyguardViewManager.getPrimaryBouncer()).thenReturn(
useModernBouncer ? null : mBouncer); useModernBouncer ? null : mBouncer);
return new UdfpsKeyguardViewController( UdfpsKeyguardViewController controller = new UdfpsKeyguardViewController(
mView, mView,
mStatusBarStateController, mStatusBarStateController,
mShadeExpansionStateManager, mShadeExpansionStateManager,
@@ -168,5 +180,6 @@ public class UdfpsKeyguardViewControllerBaseTest extends SysuiTestCase {
mActivityLaunchAnimator, mActivityLaunchAnimator,
mFeatureFlags, mFeatureFlags,
mPrimaryBouncerInteractor); mPrimaryBouncerInteractor);
return controller;
} }
} }

View File

@@ -18,6 +18,7 @@ package com.android.systemui.biometrics;
import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue; import static org.junit.Assert.assertTrue;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyBoolean; import static org.mockito.ArgumentMatchers.anyBoolean;
import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.Mockito.atLeast; import static org.mockito.Mockito.atLeast;
@@ -30,6 +31,7 @@ import static org.mockito.Mockito.when;
import android.testing.AndroidTestingRunner; import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper.RunWithLooper; import android.testing.TestableLooper.RunWithLooper;
import android.view.MotionEvent;
import androidx.test.filters.SmallTest; import androidx.test.filters.SmallTest;
@@ -52,7 +54,8 @@ public class UdfpsKeyguardViewControllerTest extends UdfpsKeyguardViewController
@Override @Override
public UdfpsKeyguardViewController createUdfpsKeyguardViewController() { public UdfpsKeyguardViewController createUdfpsKeyguardViewController() {
return createUdfpsKeyguardViewController(/* useModernBouncer */ false); return createUdfpsKeyguardViewController(/* useModernBouncer */ false,
/* useExpandedOverlay */ false);
} }
@Test @Test
@@ -422,4 +425,37 @@ public class UdfpsKeyguardViewControllerTest extends UdfpsKeyguardViewController
verify(mBouncer).addBouncerExpansionCallback(mBouncerExpansionCallbackCaptor.capture()); verify(mBouncer).addBouncerExpansionCallback(mBouncerExpansionCallbackCaptor.capture());
mBouncerExpansionCallback = mBouncerExpansionCallbackCaptor.getValue(); mBouncerExpansionCallback = mBouncerExpansionCallbackCaptor.getValue();
} }
@Test
// TODO(b/259264861): Tracking Bug
public void testUdfpsExpandedOverlayOn() {
// GIVEN view is attached and useExpandedOverlay is true
mController = createUdfpsKeyguardViewController(false, true);
mController.onViewAttached();
captureKeyGuardViewManagerCallback();
// WHEN a touch is received
mKeyguardViewManagerCallback.onTouch(
MotionEvent.obtain(0, 0, 0, 0, 0, 0));
// THEN udfpsController onTouch is not called
assertTrue(mView.mUseExpandedOverlay);
verify(mUdfpsController, never()).onTouch(any());
}
@Test
// TODO(b/259264861): Tracking Bug
public void testUdfpsExpandedOverlayOff() {
// GIVEN view is attached and useExpandedOverlay is false
mController.onViewAttached();
captureKeyGuardViewManagerCallback();
// WHEN a touch is received
mKeyguardViewManagerCallback.onTouch(
MotionEvent.obtain(0, 0, 0, 0, 0, 0));
// THEN udfpsController onTouch is called
assertFalse(mView.mUseExpandedOverlay);
verify(mUdfpsController).onTouch(any());
}
} }

View File

@@ -72,7 +72,10 @@ class UdfpsKeyguardViewControllerWithCoroutinesTest : UdfpsKeyguardViewControlle
mock(KeyguardBypassController::class.java), mock(KeyguardBypassController::class.java),
mKeyguardUpdateMonitor mKeyguardUpdateMonitor
) )
return createUdfpsKeyguardViewController(/* useModernBouncer */ true) return createUdfpsKeyguardViewController(
/* useModernBouncer */ true, /* useExpandedOverlay */
false
)
} }
/** After migration, replaces LockIconViewControllerTest version */ /** After migration, replaces LockIconViewControllerTest version */