Merge "Pass detailed reason to UdfpsView, split animation logic"

This commit is contained in:
Kevin Chyn
2021-01-25 18:31:52 +00:00
committed by Android (Google) Code Review
20 changed files with 409 additions and 113 deletions

View File

@@ -22,7 +22,9 @@ package android.hardware.fingerprint;
oneway interface IUdfpsOverlayController {
const int REASON_UNKNOWN = 0;
const int REASON_ENROLL = 1;
const int REASON_AUTH = 2;
const int REASON_AUTH_BP = 2; // BiometricPrompt
const int REASON_AUTH_FPM_KEYGUARD = 3; // FingerprintManager usage from Keyguard
const int REASON_AUTH_FPM_OTHER = 4; // Other FingerprintManager usage
// Shows the overlay.
void showUdfpsOverlay(int sensorId, int reason);

View File

@@ -0,0 +1,50 @@
/*
* Copyright (C) 2021 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.content.Context;
import android.graphics.RectF;
import android.graphics.drawable.Drawable;
import androidx.annotation.NonNull;
import com.android.systemui.R;
/**
* Abstract base class for animations that should be drawn when the finger is not touching the
* sensor area.
*/
public abstract class UdfpsAnimation extends Drawable {
abstract void updateColor();
@NonNull protected final Context mContext;
@NonNull protected final Drawable mFingerprintDrawable;
public UdfpsAnimation(@NonNull Context context) {
mContext = context;
mFingerprintDrawable = context.getResources().getDrawable(R.drawable.ic_fingerprint, null);
}
public void onSensorRectUpdated(@NonNull RectF sensorRect) {
int margin = (int) (sensorRect.bottom - sensorRect.top) / 5;
mFingerprintDrawable.setBounds(
(int) sensorRect.left + margin,
(int) sensorRect.top + margin,
(int) sensorRect.right - margin,
(int) sensorRect.bottom - margin);
}
}

View File

@@ -0,0 +1,88 @@
/*
* Copyright (C) 2021 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.content.Context;
import android.content.res.Configuration;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.ColorFilter;
import android.graphics.Paint;
import android.graphics.RectF;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import com.android.systemui.R;
/**
* UDFPS animations that should be shown when enrolling.
*/
public class UdfpsAnimationEnroll extends UdfpsAnimation {
private static final String TAG = "UdfpsAnimationEnroll";
@Nullable private RectF mSensorRect;
@NonNull private final Paint mSensorPaint;
UdfpsAnimationEnroll(@NonNull Context context) {
super(context);
mSensorPaint = new Paint(0 /* flags */);
mSensorPaint.setAntiAlias(true);
mSensorPaint.setColor(Color.WHITE);
mSensorPaint.setShadowLayer(UdfpsView.SENSOR_SHADOW_RADIUS, 0, 0, Color.BLACK);
mSensorPaint.setStyle(Paint.Style.FILL);
}
@Override
void updateColor() {
mFingerprintDrawable.setTint(mContext.getColor(R.color.udfps_enroll_icon));
}
@Override
public void onSensorRectUpdated(@NonNull RectF sensorRect) {
super.onSensorRectUpdated(sensorRect);
mSensorRect = sensorRect;
}
@Override
public void draw(@NonNull Canvas canvas) {
final boolean isNightMode = (mContext.getResources().getConfiguration().uiMode
& Configuration.UI_MODE_NIGHT_YES) != 0;
if (!isNightMode) {
if (mSensorRect != null) {
canvas.drawOval(mSensorRect, mSensorPaint);
}
}
mFingerprintDrawable.draw(canvas);
}
@Override
public void setAlpha(int alpha) {
}
@Override
public void setColorFilter(@Nullable ColorFilter colorFilter) {
}
@Override
public int getOpacity() {
return 0;
}
}

View File

@@ -0,0 +1,60 @@
/*
* Copyright (C) 2021 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.content.Context;
import android.graphics.Canvas;
import android.graphics.ColorFilter;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
/**
* UDFPS animations that should be shown when authenticating via FingerprintManager, excluding
* keyguard.
*/
public class UdfpsAnimationFpmOther extends UdfpsAnimation {
UdfpsAnimationFpmOther(@NonNull Context context) {
super(context);
}
@Override
void updateColor() {
}
@Override
public void draw(@NonNull Canvas canvas) {
mFingerprintDrawable.draw(canvas);
}
@Override
public void setAlpha(int alpha) {
}
@Override
public void setColorFilter(@Nullable ColorFilter colorFilter) {
}
@Override
public int getOpacity() {
return 0;
}
}

View File

@@ -0,0 +1,124 @@
/*
* Copyright (C) 2021 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 static com.android.systemui.doze.util.BurnInHelperKt.getBurnInOffset;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.ColorFilter;
import android.util.MathUtils;
import android.view.View;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import com.android.internal.graphics.ColorUtils;
import com.android.settingslib.Utils;
import com.android.systemui.R;
import com.android.systemui.doze.DozeReceiver;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
/**
* UDFPS animations that should be shown when authenticating on keyguard.
*/
public class UdfpsAnimationKeyguard extends UdfpsAnimation implements DozeReceiver,
StatusBarStateController.StateListener {
private static final String TAG = "UdfpsAnimationKeyguard";
@NonNull private final View mParent;
@NonNull private final Context mContext;
private final int mMaxBurnInOffsetX;
private final int mMaxBurnInOffsetY;
// AOD anti-burn-in offsets
private float mInterpolatedDarkAmount;
private float mBurnInOffsetX;
private float mBurnInOffsetY;
UdfpsAnimationKeyguard(@NonNull View parent, @NonNull Context context,
@NonNull StatusBarStateController statusBarStateController) {
super(context);
mParent = parent;
mContext = context;
mMaxBurnInOffsetX = context.getResources()
.getDimensionPixelSize(R.dimen.udfps_burn_in_offset_x);
mMaxBurnInOffsetY = context.getResources()
.getDimensionPixelSize(R.dimen.udfps_burn_in_offset_y);
statusBarStateController.addCallback(this);
}
private void updateAodPositionAndColor() {
mBurnInOffsetX = MathUtils.lerp(0f,
getBurnInOffset(mMaxBurnInOffsetX * 2, true /* xAxis */)
- mMaxBurnInOffsetX,
mInterpolatedDarkAmount);
mBurnInOffsetY = MathUtils.lerp(0f,
getBurnInOffset(mMaxBurnInOffsetY * 2, false /* xAxis */)
- 0.5f * mMaxBurnInOffsetY,
mInterpolatedDarkAmount);
updateColor();
mParent.postInvalidate();
}
@Override
public void dozeTimeTick() {
updateAodPositionAndColor();
}
@Override
public void onDozeAmountChanged(float linear, float eased) {
mInterpolatedDarkAmount = eased;
updateAodPositionAndColor();
}
@Override
public void draw(@NonNull Canvas canvas) {
canvas.save();
canvas.translate(mBurnInOffsetX, mBurnInOffsetY);
mFingerprintDrawable.draw(canvas);
canvas.restore();
}
@Override
public void setAlpha(int alpha) {
}
@Override
public void setColorFilter(@Nullable ColorFilter colorFilter) {
}
@Override
public int getOpacity() {
return 0;
}
@Override
public void updateColor() {
final int lockScreenIconColor = Utils.getColorAttrDefaultColor(mContext,
R.attr.wallpaperTextColor);
final int ambientDisplayIconColor = Color.WHITE;
mFingerprintDrawable.setTint(ColorUtils.blendARGB(lockScreenIconColor,
ambientDisplayIconColor, mInterpolatedDarkAmount));
}
}

View File

@@ -81,6 +81,7 @@ class UdfpsController implements DozeReceiver {
private final WindowManager mWindowManager;
private final SystemSettings mSystemSettings;
private final DelayableExecutor mFgExecutor;
private final StatusBarStateController mStatusBarStateController;
// 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;
@@ -181,6 +182,7 @@ class UdfpsController implements DozeReceiver {
mWindowManager = windowManager;
mSystemSettings = systemSettings;
mFgExecutor = fgExecutor;
mStatusBarStateController = statusBarStateController;
mSensorProps = findFirstUdfps();
// At least one UDFPS sensor exists
@@ -208,7 +210,6 @@ class UdfpsController implements DozeReceiver {
mHbmSupported = !TextUtils.isEmpty(mHbmPath);
mView.setHbmSupported(mHbmSupported);
statusBarStateController.addCallback(mView);
// This range only consists of the minimum and maximum values, which only cover
// non-high-brightness mode.
@@ -340,7 +341,7 @@ class UdfpsController implements DozeReceiver {
if (!mIsOverlayShowing) {
try {
Log.v(TAG, "showUdfpsOverlay | adding window");
mView.setShowReason(reason);
mView.setUdfpsAnimation(getUdfpsAnimationForReason(reason));
mWindowManager.addView(mView, computeLayoutParams());
mView.setOnTouchListener(mOnTouchListener);
mIsOverlayShowing = true;
@@ -353,11 +354,27 @@ class UdfpsController implements DozeReceiver {
});
}
@Nullable
private UdfpsAnimation getUdfpsAnimationForReason(int reason) {
Log.d(TAG, "getUdfpsAnimationForReason: " + reason);
switch (reason) {
case IUdfpsOverlayController.REASON_ENROLL:
return new UdfpsAnimationEnroll(mContext);
case IUdfpsOverlayController.REASON_AUTH_FPM_KEYGUARD:
return new UdfpsAnimationKeyguard(mView, mContext, mStatusBarStateController);
case IUdfpsOverlayController.REASON_AUTH_FPM_OTHER:
return new UdfpsAnimationFpmOther(mContext);
default:
Log.d(TAG, "Animation for reason " + reason + " not supported yet");
return null;
}
}
private void hideUdfpsOverlay() {
mFgExecutor.execute(() -> {
if (mIsOverlayShowing) {
Log.v(TAG, "hideUdfpsOverlay | removing window");
mView.setShowReason(IUdfpsOverlayController.REASON_UNKNOWN);
mView.setUdfpsAnimation(null);
mView.setOnTouchListener(null);
// Reset the controller back to its starting state.
onFingerUp();

View File

@@ -16,45 +16,34 @@
package com.android.systemui.biometrics;
import static com.android.systemui.doze.util.BurnInHelperKt.getBurnInOffset;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.content.Context;
import android.content.res.Configuration;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Rect;
import android.graphics.RectF;
import android.graphics.drawable.Drawable;
import android.hardware.fingerprint.FingerprintSensorPropertiesInternal;
import android.hardware.fingerprint.IUdfpsOverlayController;
import android.text.TextUtils;
import android.util.AttributeSet;
import android.util.Log;
import android.util.MathUtils;
import android.view.Surface;
import android.view.View;
import android.view.ViewTreeObserver;
import com.android.internal.graphics.ColorUtils;
import com.android.settingslib.Utils;
import com.android.systemui.R;
import com.android.systemui.doze.DozeReceiver;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
/**
* A full screen view with a configurable illumination dot and scrim.
*/
public class UdfpsView extends View implements DozeReceiver,
StatusBarStateController.StateListener {
public class UdfpsView extends View implements DozeReceiver {
private static final String TAG = "UdfpsView";
// Values in pixels.
private static final float SENSOR_SHADOW_RADIUS = 2.0f;
private static final float SENSOR_OUTLINE_WIDTH = 2.0f;
public static final float SENSOR_SHADOW_RADIUS = 2.0f;
private static final int DEBUG_TEXT_SIZE_PX = 32;
@@ -65,8 +54,7 @@ public class UdfpsView extends View implements DozeReceiver,
@NonNull private final RectF mSensorRect;
@NonNull private final Paint mSensorPaint;
private final float mSensorTouchAreaCoefficient;
private final int mMaxBurnInOffsetX;
private final int mMaxBurnInOffsetY;
// Stores rounded up values from mSensorRect. Necessary for APIs that only take Rect (not RecF).
@NonNull private final Rect mTouchableRegion;
@@ -75,17 +63,11 @@ public class UdfpsView extends View implements DozeReceiver,
// mInsetsListener to restrict the touchable region and allow the touches outside of the sensor
// to propagate to the rest of the UI.
@NonNull private final ViewTreeObserver.OnComputeInternalInsetsListener mInsetsListener;
@NonNull private final Drawable mFingerprintDrawable;
@Nullable private UdfpsAnimation mUdfpsAnimation;
// Used to obtain the sensor location.
@NonNull private FingerprintSensorPropertiesInternal mSensorProps;
// AOD anti-burn-in offsets
private float mInterpolatedDarkAmount;
private float mBurnInOffsetX;
private float mBurnInOffsetY;
private int mShowReason;
private boolean mShowScrimAndDot;
private boolean mIsHbmSupported;
@Nullable private String mDebugMessage;
@@ -110,10 +92,6 @@ public class UdfpsView extends View implements DozeReceiver,
a.recycle();
}
mMaxBurnInOffsetX = getResources()
.getDimensionPixelSize(R.dimen.udfps_burn_in_offset_x);
mMaxBurnInOffsetY = getResources()
.getDimensionPixelSize(R.dimen.udfps_burn_in_offset_y);
mScrimRect = new Rect();
mScrimPaint = new Paint(0 /* flags */);
@@ -131,8 +109,6 @@ public class UdfpsView extends View implements DozeReceiver,
mDebugTextPaint.setColor(Color.BLUE);
mDebugTextPaint.setTextSize(DEBUG_TEXT_SIZE_PX);
mFingerprintDrawable = getResources().getDrawable(R.drawable.ic_fingerprint, null);
mTouchableRegion = new Rect();
// When the device is rotated, it's important that mTouchableRegion is updated before
// this listener is called. This listener is usually called shortly after onLayout.
@@ -149,39 +125,20 @@ public class UdfpsView extends View implements DozeReceiver,
mSensorProps = properties;
}
/**
* @param reason See {@link android.hardware.fingerprint.IUdfpsOverlayController}
*/
void setShowReason(int reason) {
mShowReason = reason;
void setUdfpsAnimation(@Nullable UdfpsAnimation animation) {
mUdfpsAnimation = animation;
}
@Override
public void dozeTimeTick() {
updateAodPositionAndColor();
}
@Override
public void onDozeAmountChanged(float linear, float eased) {
mInterpolatedDarkAmount = eased;
updateAodPositionAndColor();
}
private void updateAodPositionAndColor() {
mBurnInOffsetX = MathUtils.lerp(0f,
getBurnInOffset(mMaxBurnInOffsetX * 2, true /* xAxis */)
- mMaxBurnInOffsetX,
mInterpolatedDarkAmount);
mBurnInOffsetY = MathUtils.lerp(0f,
getBurnInOffset(mMaxBurnInOffsetY * 2, false /* xAxis */)
- 0.5f * mMaxBurnInOffsetY,
mInterpolatedDarkAmount);
updateColor();
postInvalidate();
if (mUdfpsAnimation instanceof DozeReceiver) {
((DozeReceiver) mUdfpsAnimation).dozeTimeTick();
}
}
// The "h" and "w" are the display's height and width relative to its current rotation.
private void updateSensorRect(int h, int w) {
protected void updateSensorRect(int h, int w) {
// mSensorProps coordinates assume portrait mode.
mSensorRect.set(mSensorProps.sensorLocationX - mSensorProps.sensorRadius,
mSensorProps.sensorLocationY - mSensorProps.sensorRadius,
@@ -202,12 +159,9 @@ public class UdfpsView extends View implements DozeReceiver,
// Do nothing to stay in portrait mode.
}
int margin = (int) (mSensorRect.bottom - mSensorRect.top) / 5;
mFingerprintDrawable.setBounds(
(int) mSensorRect.left + margin,
(int) mSensorRect.top + margin,
(int) mSensorRect.right - margin,
(int) mSensorRect.bottom - margin);
if (mUdfpsAnimation != null) {
mUdfpsAnimation.onSensorRectUpdated(new RectF(mSensorRect));
}
}
@Override
@@ -239,14 +193,8 @@ public class UdfpsView extends View implements DozeReceiver,
}
private void updateColor() {
if (mShowReason == IUdfpsOverlayController.REASON_AUTH) {
final int lockScreenIconColor = Utils.getColorAttrDefaultColor(mContext,
com.android.systemui.R.attr.wallpaperTextColor);
final int ambientDisplayIconColor = Color.WHITE;
mFingerprintDrawable.setTint(ColorUtils.blendARGB(lockScreenIconColor,
ambientDisplayIconColor, mInterpolatedDarkAmount));
} else if (mShowReason == IUdfpsOverlayController.REASON_ENROLL) {
mFingerprintDrawable.setTint(mContext.getColor(R.color.udfps_enroll_icon));
if (mUdfpsAnimation != null) {
mUdfpsAnimation.updateColor();
}
}
@@ -266,9 +214,6 @@ public class UdfpsView extends View implements DozeReceiver,
canvas.drawRect(mScrimRect, mScrimPaint);
}
// Translation should affect everything but the scrim.
canvas.save();
canvas.translate(mBurnInOffsetX, mBurnInOffsetY);
if (!TextUtils.isEmpty(mDebugMessage)) {
canvas.drawText(mDebugMessage, 0, 160, mDebugTextPaint);
}
@@ -277,17 +222,11 @@ public class UdfpsView extends View implements DozeReceiver,
// draw dot (white circle)
canvas.drawOval(mSensorRect, mSensorPaint);
} else {
final boolean isNightMode = (getResources().getConfiguration().uiMode
& Configuration.UI_MODE_NIGHT_YES) != 0;
if (mShowReason == IUdfpsOverlayController.REASON_ENROLL && !isNightMode) {
canvas.drawOval(mSensorRect, mSensorPaint);
if (mUdfpsAnimation != null) {
mUdfpsAnimation.draw(canvas);
}
// draw fingerprint icon
mFingerprintDrawable.draw(canvas);
}
canvas.restore();
if (mShowScrimAndDot && mRunAfterShowingScrimAndDot != null) {
post(mRunAfterShowingScrimAndDot);
mRunAfterShowingScrimAndDot = null;

View File

@@ -162,7 +162,7 @@ public class UdfpsControllerTest extends SysuiTestCase {
@Test
public void showUdfpsOverlay_addsViewToWindow() throws RemoteException {
mOverlayController.showUdfpsOverlay(TEST_UDFPS_SENSOR_ID,
IUdfpsOverlayController.REASON_AUTH);
IUdfpsOverlayController.REASON_AUTH_FPM_KEYGUARD);
mFgExecutor.runAllReady();
verify(mWindowManager).addView(eq(mUdfpsView), any());
}
@@ -170,7 +170,7 @@ public class UdfpsControllerTest extends SysuiTestCase {
@Test
public void hideUdfpsOverlay_removesViewFromWindow() throws RemoteException {
mOverlayController.showUdfpsOverlay(TEST_UDFPS_SENSOR_ID,
IUdfpsOverlayController.REASON_AUTH);
IUdfpsOverlayController.REASON_AUTH_FPM_KEYGUARD);
mOverlayController.hideUdfpsOverlay(TEST_UDFPS_SENSOR_ID);
mFgExecutor.runAllReady();
verify(mWindowManager).removeView(eq(mUdfpsView));
@@ -184,7 +184,7 @@ public class UdfpsControllerTest extends SysuiTestCase {
// GIVEN that the overlay is showing
mOverlayController.showUdfpsOverlay(TEST_UDFPS_SENSOR_ID,
IUdfpsOverlayController.REASON_AUTH);
IUdfpsOverlayController.REASON_AUTH_FPM_KEYGUARD);
mFgExecutor.runAllReady();
// WHEN ACTION_DOWN is received
verify(mUdfpsView).setOnTouchListener(mTouchListenerCaptor.capture());
@@ -205,7 +205,7 @@ public class UdfpsControllerTest extends SysuiTestCase {
public void aodInterrupt() throws RemoteException {
// GIVEN that the overlay is showing
mOverlayController.showUdfpsOverlay(TEST_UDFPS_SENSOR_ID,
IUdfpsOverlayController.REASON_AUTH);
IUdfpsOverlayController.REASON_AUTH_FPM_KEYGUARD);
mFgExecutor.runAllReady();
// WHEN fingerprint is requested because of AOD interrupt
mUdfpsController.onAodInterrupt(0, 0, 2f, 3f);
@@ -223,7 +223,7 @@ public class UdfpsControllerTest extends SysuiTestCase {
public void cancelAodInterrupt() throws RemoteException {
// GIVEN AOD interrupt
mOverlayController.showUdfpsOverlay(TEST_UDFPS_SENSOR_ID,
IUdfpsOverlayController.REASON_AUTH);
IUdfpsOverlayController.REASON_AUTH_FPM_KEYGUARD);
mFgExecutor.runAllReady();
mUdfpsController.onAodInterrupt(0, 0, 0f, 0f);
// WHEN it is cancelled
@@ -236,7 +236,7 @@ public class UdfpsControllerTest extends SysuiTestCase {
public void aodInterruptTimeout() throws RemoteException {
// GIVEN AOD interrupt
mOverlayController.showUdfpsOverlay(TEST_UDFPS_SENSOR_ID,
IUdfpsOverlayController.REASON_AUTH);
IUdfpsOverlayController.REASON_AUTH_FPM_KEYGUARD);
mFgExecutor.runAllReady();
mUdfpsController.onAodInterrupt(0, 0, 0f, 0f);
// WHEN it times out

View File

@@ -50,6 +50,7 @@ import android.hardware.biometrics.IBiometricService;
import android.hardware.biometrics.PromptInfo;
import android.hardware.biometrics.SensorProperties;
import android.hardware.biometrics.SensorPropertiesInternal;
import android.hardware.fingerprint.IUdfpsOverlayController;
import android.os.Binder;
import android.os.Build;
import android.os.RemoteException;
@@ -61,6 +62,7 @@ import android.util.Slog;
import com.android.internal.R;
import com.android.internal.widget.LockPatternUtils;
import com.android.server.biometrics.sensors.AuthenticationClient;
import com.android.server.biometrics.sensors.BaseClientMonitor;
import java.util.List;
@@ -478,4 +480,14 @@ public class Utils {
throw new IllegalArgumentException("Unknown strength: " + strength);
}
}
public static int getUdfpsAuthReason(@NonNull AuthenticationClient<?> client) {
if (client.isKeyguard()) {
return IUdfpsOverlayController.REASON_AUTH_FPM_KEYGUARD;
} else if (client.isBiometricPrompt()) {
return IUdfpsOverlayController.REASON_AUTH_BP;
} else {
return IUdfpsOverlayController.REASON_AUTH_FPM_OTHER;
}
}
}

View File

@@ -53,6 +53,7 @@ public abstract class AuthenticationClient<T> extends AcquisitionClient<T>
@Nullable private final TaskStackListener mTaskStackListener;
private final LockoutTracker mLockoutTracker;
private final boolean mIsRestricted;
private final boolean mIsKeyguard;
protected final long mOperationId;
@@ -65,7 +66,7 @@ public abstract class AuthenticationClient<T> extends AcquisitionClient<T>
int targetUserId, long operationId, boolean restricted, @NonNull String owner,
int cookie, boolean requireConfirmation, int sensorId, boolean isStrongBiometric,
int statsModality, int statsClient, @Nullable TaskStackListener taskStackListener,
@NonNull LockoutTracker lockoutTracker) {
@NonNull LockoutTracker lockoutTracker, boolean isKeyguard) {
super(context, lazyDaemon, token, listener, targetUserId, owner, cookie, sensorId,
statsModality, BiometricsProtoEnums.ACTION_AUTHENTICATE, statsClient);
mIsStrongBiometric = isStrongBiometric;
@@ -75,6 +76,7 @@ public abstract class AuthenticationClient<T> extends AcquisitionClient<T>
mTaskStackListener = taskStackListener;
mLockoutTracker = lockoutTracker;
mIsRestricted = restricted;
mIsKeyguard = isKeyguard;
}
public @LockoutTracker.LockoutMode int handleFailedAttempt(int userId) {
@@ -114,6 +116,10 @@ public abstract class AuthenticationClient<T> extends AcquisitionClient<T>
return mIsRestricted;
}
public boolean isKeyguard() {
return mIsKeyguard;
}
@Override
protected boolean isCryptoOperation() {
return mOperationId != 0;

View File

@@ -67,11 +67,11 @@ class FaceAuthenticationClient extends AuthenticationClient<ISession> implements
@NonNull ClientMonitorCallbackConverter listener, int targetUserId, long operationId,
boolean restricted, String owner, int cookie, boolean requireConfirmation, int sensorId,
boolean isStrongBiometric, int statsClient, @NonNull UsageStats usageStats,
@NonNull LockoutCache lockoutCache) {
@NonNull LockoutCache lockoutCache, boolean isKeyguard) {
super(context, lazyDaemon, token, listener, targetUserId, operationId, restricted,
owner, cookie, requireConfirmation, sensorId, isStrongBiometric,
BiometricsProtoEnums.MODALITY_FACE, statsClient, null /* taskStackListener */,
lockoutCache);
lockoutCache, isKeyguard);
mUsageStats = usageStats;
mLockoutCache = lockoutCache;
mNotificationManager = context.getSystemService(NotificationManager.class);

View File

@@ -451,7 +451,7 @@ public class FaceProvider implements IBinder.DeathRecipient, ServiceProvider {
mContext, mSensors.get(sensorId).getLazySession(), token, callback, userId,
operationId, restricted, opPackageName, cookie,
false /* requireConfirmation */, sensorId, isStrongBiometric, statsClient,
mUsageStats, mSensors.get(sensorId).getLockoutCache());
mUsageStats, mSensors.get(sensorId).getLockoutCache(), isKeyguard);
mSensors.get(sensorId).getScheduler().scheduleClientMonitor(client);
} catch (RemoteException e) {
Slog.e(getTag(), "Remote exception when scheduling authenticate", e);

View File

@@ -646,7 +646,7 @@ public class Face10 implements IHwBinder.DeathRecipient, ServiceProvider {
final FaceAuthenticationClient client = new FaceAuthenticationClient(mContext,
mLazyDaemon, token, receiver, userId, operationId, restricted, opPackageName,
cookie, false /* requireConfirmation */, mSensorId, isStrongBiometric,
statsClient, mLockoutTracker, mUsageStats);
statsClient, mLockoutTracker, mUsageStats, isKeyguard);
mScheduler.scheduleClientMonitor(client);
});
}

View File

@@ -66,12 +66,12 @@ class FaceAuthenticationClient extends AuthenticationClient<IBiometricsFace> {
@NonNull LazyDaemon<IBiometricsFace> lazyDaemon, @NonNull IBinder token,
@NonNull ClientMonitorCallbackConverter listener, int targetUserId, long operationId,
boolean restricted, String owner, int cookie, boolean requireConfirmation, int sensorId,
boolean isStrongBiometric, int statsClient,
@NonNull LockoutTracker lockoutTracker, @NonNull UsageStats usageStats) {
boolean isStrongBiometric, int statsClient, @NonNull LockoutTracker lockoutTracker,
@NonNull UsageStats usageStats, boolean isKeyguard) {
super(context, lazyDaemon, token, listener, targetUserId, operationId, restricted,
owner, cookie, requireConfirmation, sensorId, isStrongBiometric,
BiometricsProtoEnums.MODALITY_FACE, statsClient, null /* taskStackListener */,
lockoutTracker);
lockoutTracker, isKeyguard);
mNotificationManager = context.getSystemService(NotificationManager.class);
mUsageStats = usageStats;

View File

@@ -30,6 +30,7 @@ import android.os.IBinder;
import android.os.RemoteException;
import android.util.Slog;
import com.android.server.biometrics.Utils;
import com.android.server.biometrics.sensors.AuthenticationClient;
import com.android.server.biometrics.sensors.ClientMonitorCallbackConverter;
import com.android.server.biometrics.sensors.LockoutCache;
@@ -58,11 +59,11 @@ class FingerprintAuthenticationClient extends AuthenticationClient<ISession> imp
boolean restricted, @NonNull String owner, int cookie, boolean requireConfirmation,
int sensorId, boolean isStrongBiometric, int statsClient,
@Nullable TaskStackListener taskStackListener, @NonNull LockoutCache lockoutCache,
@Nullable IUdfpsOverlayController udfpsOverlayController) {
@Nullable IUdfpsOverlayController udfpsOverlayController, boolean isKeyguard) {
super(context, lazyDaemon, token, listener, targetUserId, operationId, restricted, owner,
cookie, requireConfirmation, sensorId, isStrongBiometric,
BiometricsProtoEnums.MODALITY_FINGERPRINT, statsClient, taskStackListener,
lockoutCache);
lockoutCache, isKeyguard);
mLockoutCache = lockoutCache;
mUdfpsOverlayController = udfpsOverlayController;
}
@@ -87,7 +88,7 @@ class FingerprintAuthenticationClient extends AuthenticationClient<ISession> imp
@Override
protected void startHalOperation() {
UdfpsHelper.showUdfpsOverlay(getSensorId(), IUdfpsOverlayController.REASON_AUTH,
UdfpsHelper.showUdfpsOverlay(getSensorId(), Utils.getUdfpsAuthReason(this),
mUdfpsOverlayController);
try {
mCancellationSignal = getFreshDaemon().authenticate(mSequentialId, mOperationId);

View File

@@ -70,7 +70,8 @@ class FingerprintDetectClient extends AcquisitionClient<ISession> {
@Override
protected void startHalOperation() {
UdfpsHelper.showUdfpsOverlay(getSensorId(), IUdfpsOverlayController.REASON_AUTH,
UdfpsHelper.showUdfpsOverlay(getSensorId(),
IUdfpsOverlayController.REASON_AUTH_FPM_KEYGUARD,
mUdfpsOverlayController);
try {
mCancellationSignal = getFreshDaemon().detectInteraction(mSequentialId);

View File

@@ -466,7 +466,7 @@ public class FingerprintProvider implements IBinder.DeathRecipient, ServiceProvi
operationId, restricted, opPackageName, cookie,
false /* requireConfirmation */, sensorId, isStrongBiometric, statsClient,
mTaskStackListener, mSensors.get(sensorId).getLockoutCache(),
mUdfpsOverlayController);
mUdfpsOverlayController, isKeyguard);
mSensors.get(sensorId).getScheduler().scheduleClientMonitor(client);
} catch (RemoteException e) {
Slog.e(getTag(), "Remote exception when scheduling authenticate", e);

View File

@@ -30,6 +30,7 @@ import android.os.IBinder;
import android.os.RemoteException;
import android.util.Slog;
import com.android.server.biometrics.Utils;
import com.android.server.biometrics.sensors.AuthenticationClient;
import com.android.server.biometrics.sensors.ClientMonitorCallbackConverter;
import com.android.server.biometrics.sensors.LockoutTracker;
@@ -48,7 +49,6 @@ class FingerprintAuthenticationClient extends AuthenticationClient<IBiometricsFi
private static final String TAG = "Biometrics/FingerprintAuthClient";
private final boolean mIsKeyguard;
private final LockoutFrameworkImpl mLockoutFrameworkImpl;
@Nullable private final IUdfpsOverlayController mUdfpsOverlayController;
@@ -63,10 +63,9 @@ class FingerprintAuthenticationClient extends AuthenticationClient<IBiometricsFi
super(context, lazyDaemon, token, listener, targetUserId, operationId, restricted,
owner, cookie, requireConfirmation, sensorId, isStrongBiometric,
BiometricsProtoEnums.MODALITY_FINGERPRINT, statsClient, taskStackListener,
lockoutTracker);
lockoutTracker, isKeyguard);
mLockoutFrameworkImpl = lockoutTracker;
mUdfpsOverlayController = udfpsOverlayController;
mIsKeyguard = isKeyguard;
}
@Override
@@ -120,7 +119,7 @@ class FingerprintAuthenticationClient extends AuthenticationClient<IBiometricsFi
@Override
protected void startHalOperation() {
UdfpsHelper.showUdfpsOverlay(getSensorId(), IUdfpsOverlayController.REASON_AUTH,
UdfpsHelper.showUdfpsOverlay(getSensorId(), Utils.getUdfpsAuthReason(this),
mUdfpsOverlayController);
try {
// GroupId was never used. In fact, groupId is always the same as userId.
@@ -170,8 +169,4 @@ class FingerprintAuthenticationClient extends AuthenticationClient<IBiometricsFi
}
}
}
public boolean isKeyguard() {
return mIsKeyguard;
}
}

View File

@@ -83,7 +83,8 @@ class FingerprintDetectClient extends AcquisitionClient<IBiometricsFingerprint>
@Override
protected void startHalOperation() {
UdfpsHelper.showUdfpsOverlay(getSensorId(), IUdfpsOverlayController.REASON_AUTH,
UdfpsHelper.showUdfpsOverlay(getSensorId(),
IUdfpsOverlayController.REASON_AUTH_FPM_KEYGUARD,
mUdfpsOverlayController);
try {
getFreshDaemon().authenticate(0 /* operationId */, getTargetUserId());

View File

@@ -34,7 +34,6 @@ import android.hardware.biometrics.IBiometricService;
import android.os.Binder;
import android.os.IBinder;
import android.platform.test.annotations.Presubmit;
import android.util.proto.ProtoOutputStream;
import androidx.annotation.NonNull;
import androidx.test.InstrumentationRegistry;
@@ -279,7 +278,8 @@ public class BiometricSchedulerTest {
super(context, lazyDaemon, token, listener, 0 /* targetUserId */, 0 /* operationId */,
false /* restricted */, TAG, 1 /* cookie */, false /* requireConfirmation */,
TEST_SENSOR_ID, true /* isStrongBiometric */, 0 /* statsModality */,
0 /* statsClient */, null /* taskStackListener */, mock(LockoutTracker.class));
0 /* statsClient */, null /* taskStackListener */, mock(LockoutTracker.class),
false /* isKeyguard */);
}
@Override