Update side fsp sensor position via overlay.

This is a temporary workaround and the overlay properties can be removed
when the information is available from the HAL.

Bug: 174868353
Fix: 188690214
Test: manual (enroll and verify icon location)
Change-Id: I2b6826756814727368007e55bfc88d28c4a78bea
This commit is contained in:
Joe Bolinger
2021-09-07 08:53:25 -07:00
parent 33c8a1a769
commit f2e41730bb
19 changed files with 346 additions and 105 deletions

View File

@@ -0,0 +1,19 @@
/*
* 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 android.hardware.biometrics;
// @hide
parcelable SensorLocationInternal;

View File

@@ -0,0 +1,112 @@
/*
* 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 android.hardware.biometrics;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.os.Parcel;
import android.os.Parcelable;
/**
* The location of a sensor relative to a physical display.
*
* Note that the location may change depending on other attributes of the device, such as
* fold status, which are not yet included in this class.
* @hide
*/
public class SensorLocationInternal implements Parcelable {
/** Default value to use when the sensor's location is unknown or undefined. */
public static final SensorLocationInternal DEFAULT = new SensorLocationInternal("", 0, 0, 0);
/**
* The stable display id.
*/
@NonNull
public final String displayId;
/**
* The location of the center of the sensor if applicable. For example, sensors of type
* {@link FingerprintSensorProperties#TYPE_UDFPS_OPTICAL} would report this value as the
* distance in pixels, measured from the left edge of the screen.
*/
public final int sensorLocationX;
/**
* The location of the center of the sensor if applicable. For example, sensors of type
* {@link FingerprintSensorProperties#TYPE_UDFPS_OPTICAL} would report this value as the
* distance in pixels, measured from the top edge of the screen.
*
*/
public final int sensorLocationY;
/**
* The radius of the sensor if applicable. For example, sensors of type
* {@link FingerprintSensorProperties#TYPE_UDFPS_OPTICAL} would report this value as the radius
* of the sensor, in pixels.
*/
public final int sensorRadius;
public SensorLocationInternal(@Nullable String displayId,
int sensorLocationX, int sensorLocationY, int sensorRadius) {
this.displayId = displayId != null ? displayId : "";
this.sensorLocationX = sensorLocationX;
this.sensorLocationY = sensorLocationY;
this.sensorRadius = sensorRadius;
}
protected SensorLocationInternal(Parcel in) {
displayId = in.readString16NoHelper();
sensorLocationX = in.readInt();
sensorLocationY = in.readInt();
sensorRadius = in.readInt();
}
@Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeString(displayId);
dest.writeInt(sensorLocationX);
dest.writeInt(sensorLocationY);
dest.writeInt(sensorRadius);
}
@Override
public int describeContents() {
return 0;
}
public static final Creator<SensorLocationInternal> CREATOR =
new Creator<SensorLocationInternal>() {
@Override
public SensorLocationInternal createFromParcel(Parcel in) {
return new SensorLocationInternal(in);
}
@Override
public SensorLocationInternal[] newArray(int size) {
return new SensorLocationInternal[size];
}
};
@Override
public String toString() {
return "[id: " + displayId
+ ", x: " + sensorLocationX
+ ", y: " + sensorLocationY
+ ", r: " + sensorRadius + "]";
}
}

View File

@@ -21,7 +21,9 @@ import static android.hardware.fingerprint.FingerprintSensorProperties.TYPE_UDFP
import static android.hardware.fingerprint.FingerprintSensorProperties.TYPE_UDFPS_ULTRASONIC;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.hardware.biometrics.ComponentInfoInternal;
import android.hardware.biometrics.SensorLocationInternal;
import android.hardware.biometrics.SensorProperties;
import android.hardware.biometrics.SensorPropertiesInternal;
import android.os.Parcel;
@@ -38,34 +40,14 @@ public class FingerprintSensorPropertiesInternal extends SensorPropertiesInterna
*/
public final @FingerprintSensorProperties.SensorType int sensorType;
/**
* The location of the center of the sensor if applicable. For example, sensors of type
* {@link FingerprintSensorProperties#TYPE_UDFPS_OPTICAL} would report this value as the
* distance in pixels, measured from the left edge of the screen.
*/
public final int sensorLocationX;
/**
* The location of the center of the sensor if applicable. For example, sensors of type
* {@link FingerprintSensorProperties#TYPE_UDFPS_OPTICAL} would report this value as the
* distance in pixels, measured from the top edge of the screen.
*
*/
public final int sensorLocationY;
/**
* The radius of the sensor if applicable. For example, sensors of type
* {@link FingerprintSensorProperties#TYPE_UDFPS_OPTICAL} would report this value as the radius
* of the sensor, in pixels.
*/
public final int sensorRadius;
private final List<SensorLocationInternal> mSensorLocations;
public FingerprintSensorPropertiesInternal(int sensorId,
@SensorProperties.Strength int strength, int maxEnrollmentsPerUser,
@NonNull List<ComponentInfoInternal> componentInfo,
@FingerprintSensorProperties.SensorType int sensorType,
boolean resetLockoutRequiresHardwareAuthToken, int sensorLocationX, int sensorLocationY,
int sensorRadius) {
boolean resetLockoutRequiresHardwareAuthToken,
@NonNull List<SensorLocationInternal> sensorLocations) {
// IBiometricsFingerprint@2.1 handles lockout in the framework, so the challenge is not
// required as it can only be generated/attested/verified by TEE components.
// IFingerprint@1.0 handles lockout below the HAL, but does not require a challenge. See
@@ -73,9 +55,7 @@ public class FingerprintSensorPropertiesInternal extends SensorPropertiesInterna
super(sensorId, strength, maxEnrollmentsPerUser, componentInfo,
resetLockoutRequiresHardwareAuthToken, false /* resetLockoutRequiresChallenge */);
this.sensorType = sensorType;
this.sensorLocationX = sensorLocationX;
this.sensorLocationY = sensorLocationY;
this.sensorRadius = sensorRadius;
this.mSensorLocations = List.copyOf(sensorLocations);
}
/**
@@ -88,16 +68,15 @@ public class FingerprintSensorPropertiesInternal extends SensorPropertiesInterna
boolean resetLockoutRequiresHardwareAuthToken) {
// TODO(b/179175438): Value should be provided from the HAL
this(sensorId, strength, maxEnrollmentsPerUser, componentInfo, sensorType,
resetLockoutRequiresHardwareAuthToken, 540 /* sensorLocationX */,
1636 /* sensorLocationY */, 130 /* sensorRadius */);
resetLockoutRequiresHardwareAuthToken, List.of(new SensorLocationInternal(
"" /* displayId */, 540 /* sensorLocationX */, 1636 /* sensorLocationY */,
130 /* sensorRadius */)));
}
protected FingerprintSensorPropertiesInternal(Parcel in) {
super(in);
sensorType = in.readInt();
sensorLocationX = in.readInt();
sensorLocationY = in.readInt();
sensorRadius = in.readInt();
mSensorLocations = in.createTypedArrayList(SensorLocationInternal.CREATOR);
}
public static final Creator<FingerprintSensorPropertiesInternal> CREATOR =
@@ -122,9 +101,7 @@ public class FingerprintSensorPropertiesInternal extends SensorPropertiesInterna
public void writeToParcel(Parcel dest, int flags) {
super.writeToParcel(dest, flags);
dest.writeInt(sensorType);
dest.writeInt(sensorLocationX);
dest.writeInt(sensorLocationY);
dest.writeInt(sensorRadius);
dest.writeTypedList(mSensorLocations);
}
public boolean isAnyUdfpsType() {
@@ -150,6 +127,44 @@ public class FingerprintSensorPropertiesInternal extends SensorPropertiesInterna
}
}
/**
* Get the default location.
*
* Use this method when the sensor's relationship to the displays on the device do not
* matter.
* @return
*/
@NonNull
public SensorLocationInternal getLocation() {
final SensorLocationInternal location = getLocation("" /* displayId */);
return location != null ? location : SensorLocationInternal.DEFAULT;
}
/**
* Get the location of a sensor relative to a physical display layout.
*
* @param displayId stable display id
* @return location or null if none is specified
*/
@Nullable
public SensorLocationInternal getLocation(String displayId) {
for (SensorLocationInternal location : mSensorLocations) {
if (location.displayId.equals(displayId)) {
return location;
}
}
return null;
}
/**
* Gets all locations relative to all supported display layouts.
* @return supported locations
*/
@NonNull
public List<SensorLocationInternal> getAllLocations() {
return mSensorLocations;
}
@Override
public String toString() {
return "ID: " + sensorId + ", Strength: " + sensorStrength + ", Type: " + sensorType;

View File

@@ -4576,6 +4576,20 @@
-->
</integer-array>
<!-- An array of arrays of side fingerprint sensor properties relative to each display.
Note: this value is temporary and is expected to be queried directly
from the HAL in the future. -->
<array name="config_sfps_sensor_props" translatable="false">
<!--
<array>
<item>displayId</item>
<item>sensorLocationX</item>
<item>sensorLocationY</item>
<item>sensorRadius</item>
<array>
-->
</array>
<!-- How long it takes for the HW to start illuminating after the illumination is requested. -->
<integer name="config_udfps_illumination_transition_ms">50</integer>

View File

@@ -2608,6 +2608,7 @@
<java-symbol type="array" name="config_biometric_sensors" />
<java-symbol type="bool" name="allow_test_udfps" />
<java-symbol type="array" name="config_udfps_sensor_props" />
<java-symbol type="array" name="config_sfps_sensor_props" />
<java-symbol type="integer" name="config_udfps_illumination_transition_ms" />
<java-symbol type="bool" name="config_is_powerbutton_fps" />

View File

@@ -27,6 +27,7 @@ import android.graphics.Rect;
import android.graphics.drawable.AnimatedVectorDrawable;
import android.graphics.drawable.Drawable;
import android.hardware.biometrics.BiometricSourceType;
import android.hardware.biometrics.SensorLocationInternal;
import android.hardware.fingerprint.FingerprintSensorPropertiesInternal;
import android.media.AudioAttributes;
import android.os.Process;
@@ -330,8 +331,9 @@ public class LockIconViewController extends ViewController<LockIconView> impleme
private void updateLockIconLocation() {
if (mUdfpsSupported) {
FingerprintSensorPropertiesInternal props = mAuthController.getUdfpsProps().get(0);
mView.setCenterLocation(new PointF(props.sensorLocationX, props.sensorLocationY),
props.sensorRadius);
final SensorLocationInternal location = props.getLocation();
mView.setCenterLocation(new PointF(location.sensorLocationX, location.sensorLocationY),
location.sensorRadius);
} else {
mView.setCenterLocation(
new PointF(mWidthPixels / 2,

View File

@@ -223,7 +223,7 @@ class AuthRippleController @Inject constructor(
private fun updateUdfpsDependentParams() {
authController.udfpsProps?.let {
if (it.size > 0) {
udfpsRadius = it[0].sensorRadius.toFloat()
udfpsRadius = it[0].location.sensorRadius.toFloat()
udfpsController = udfpsControllerProvider.get()
if (mView.isAttachedToWindow) {

View File

@@ -17,6 +17,7 @@ package com.android.systemui.biometrics
import android.content.Context
import android.graphics.PixelFormat
import android.graphics.Rect
import android.hardware.display.DisplayManager
import android.hardware.fingerprint.FingerprintManager
import android.hardware.fingerprint.FingerprintSensorPropertiesInternal
@@ -56,21 +57,8 @@ class SidefpsController @Inject constructor(
@VisibleForTesting
val sensorProps: FingerprintSensorPropertiesInternal = fingerprintManager
?.sensorPropertiesInternal
?.filter { it.isAnySidefpsType }
// TODO(b/188690214): remove - should directly come from HAL
?.map { props ->
FingerprintSensorPropertiesInternal(
props.sensorId,
props.sensorStrength,
props.maxEnrollmentsPerUser,
props.componentInfo,
props.sensorType,
props.resetLockoutRequiresHardwareAuthToken,
25 /* sensorLocationX */,
610 /* sensorLocationY */,
112 /* sensorRadius */
)
}?.firstOrNull() ?: throw IllegalStateException("no side fingerprint sensor")
?.firstOrNull { it.isAnySidefpsType }
?: throw IllegalStateException("no side fingerprint sensor")
@VisibleForTesting
val orientationListener = BiometricDisplayListener(
@@ -131,29 +119,49 @@ class SidefpsController @Inject constructor(
private fun createOverlayForDisplay(): View {
val view = layoutInflater.inflate(R.layout.sidefps_view, null, false)
val display = context.display!!
val isPortrait = display.isPortrait()
val size = windowManager.maximumWindowMetrics.bounds
val displayWidth = if (isPortrait) size.width() else size.height()
val displayHeight = if (isPortrait) size.height() else size.width()
val lottie = view.findViewById(R.id.sidefps_animation) as LottieAnimationView
lottie.setAnimation(display.asSideFpsAnimation())
view.rotation = display.asSideFpsAnimationRotation()
updateOverlayParams(display, lottie.composition?.bounds ?: Rect())
lottie.addLottieOnCompositionLoadedListener {
if (overlayView == view) {
updateOverlayParams(display, it.bounds)
windowManager.updateViewLayout(overlayView, overlayViewParams)
}
}
return view
}
private fun updateOverlayParams(display: Display, bounds: Rect) {
val isPortrait = display.isPortrait()
val size = windowManager.maximumWindowMetrics.bounds
val displayWidth = if (isPortrait) size.width() else size.height()
val displayHeight = if (isPortrait) size.height() else size.width()
val offsets = sensorProps.getLocation(display.uniqueId).let { location ->
if (location == null) {
Log.w(TAG, "No location specified for display: ${display.uniqueId}")
}
location ?: sensorProps.location
}
// ignore sensorLocationX and sensorRadius since it's assumed to be on the side
// of the device and centered at sensorLocationY
val (x, y) = when (display.rotation) {
Surface.ROTATION_90 -> Pair(sensorProps.sensorLocationY, 0)
Surface.ROTATION_270 -> Pair(displayHeight - sensorProps.sensorLocationY, displayWidth)
Surface.ROTATION_180 -> Pair(0, displayHeight - sensorProps.sensorLocationY)
else -> Pair(displayWidth, sensorProps.sensorLocationY)
Surface.ROTATION_90 ->
Pair(offsets.sensorLocationY, 0)
Surface.ROTATION_270 ->
Pair(displayHeight - offsets.sensorLocationY - bounds.width(), displayWidth)
Surface.ROTATION_180 ->
Pair(0, displayHeight - offsets.sensorLocationY - bounds.height())
else ->
Pair(displayWidth, offsets.sensorLocationY)
}
overlayViewParams.x = x
overlayViewParams.y = y
return view
}
}

View File

@@ -33,6 +33,7 @@ import android.graphics.PixelFormat;
import android.graphics.Point;
import android.graphics.RectF;
import android.hardware.biometrics.BiometricOverlayConstants;
import android.hardware.biometrics.SensorLocationInternal;
import android.hardware.display.DisplayManager;
import android.hardware.fingerprint.FingerprintManager;
import android.hardware.fingerprint.FingerprintSensorPropertiesInternal;
@@ -643,10 +644,11 @@ public class UdfpsController implements DozeReceiver {
// on lockscreen and for the udfps light reveal animation on keyguard.
// Keyguard is only shown in portrait mode for now, so this will need to
// be updated if that ever changes.
return new RectF(mSensorProps.sensorLocationX - mSensorProps.sensorRadius,
mSensorProps.sensorLocationY - mSensorProps.sensorRadius,
mSensorProps.sensorLocationX + mSensorProps.sensorRadius,
mSensorProps.sensorLocationY + mSensorProps.sensorRadius);
final SensorLocationInternal location = mSensorProps.getLocation();
return new RectF(location.sensorLocationX - location.sensorRadius,
location.sensorLocationY - location.sensorRadius,
location.sensorLocationX + location.sensorRadius,
location.sensorLocationY + location.sensorRadius);
}
private void updateOverlay() {
@@ -670,10 +672,11 @@ public class UdfpsController implements DozeReceiver {
}
// Default dimensions assume portrait mode.
mCoreLayoutParams.x = mSensorProps.sensorLocationX - mSensorProps.sensorRadius - paddingX;
mCoreLayoutParams.y = mSensorProps.sensorLocationY - mSensorProps.sensorRadius - paddingY;
mCoreLayoutParams.height = 2 * mSensorProps.sensorRadius + 2 * paddingX;
mCoreLayoutParams.width = 2 * mSensorProps.sensorRadius + 2 * paddingY;
final SensorLocationInternal location = mSensorProps.getLocation();
mCoreLayoutParams.x = location.sensorLocationX - location.sensorRadius - paddingX;
mCoreLayoutParams.y = location.sensorLocationY - location.sensorRadius - paddingY;
mCoreLayoutParams.height = 2 * location.sensorRadius + 2 * paddingX;
mCoreLayoutParams.width = 2 * location.sensorRadius + 2 * paddingY;
Point p = new Point();
// Gets the size based on the current rotation of the display.
@@ -686,9 +689,9 @@ public class UdfpsController implements DozeReceiver {
&& mKeyguardUpdateMonitor.isGoingToSleep()) {
break;
}
mCoreLayoutParams.x = mSensorProps.sensorLocationY - mSensorProps.sensorRadius
mCoreLayoutParams.x = location.sensorLocationY - location.sensorRadius
- paddingX;
mCoreLayoutParams.y = p.y - mSensorProps.sensorLocationX - mSensorProps.sensorRadius
mCoreLayoutParams.y = p.y - location.sensorLocationX - location.sensorRadius
- paddingY;
break;
@@ -697,9 +700,9 @@ public class UdfpsController implements DozeReceiver {
&& mKeyguardUpdateMonitor.isGoingToSleep()) {
break;
}
mCoreLayoutParams.x = p.x - mSensorProps.sensorLocationY - mSensorProps.sensorRadius
mCoreLayoutParams.x = p.x - location.sensorLocationY - location.sensorRadius
- paddingX;
mCoreLayoutParams.y = mSensorProps.sensorLocationX - mSensorProps.sensorRadius
mCoreLayoutParams.y = location.sensorLocationX - location.sensorRadius
- paddingY;
break;

View File

@@ -21,6 +21,7 @@ import android.annotation.NonNull;
import android.annotation.Nullable;
import android.graphics.Insets;
import android.graphics.Rect;
import android.hardware.biometrics.SensorLocationInternal;
import android.hardware.fingerprint.FingerprintSensorPropertiesInternal;
import android.util.Log;
import android.view.Surface;
@@ -93,7 +94,7 @@ public class UdfpsDialogMeasureAdapter {
// Go through each of the children and do the custom measurement.
int totalHeight = 0;
final int numChildren = mView.getChildCount();
final int sensorDiameter = mSensorProps.sensorRadius * 2;
final int sensorDiameter = mSensorProps.getLocation().sensorRadius * 2;
for (int i = 0; i < numChildren; i++) {
final View child = mView.getChildAt(i);
if (child.getId() == R.id.biometric_icon_frame) {
@@ -160,7 +161,7 @@ public class UdfpsDialogMeasureAdapter {
final int horizontalSpacerWidth = calculateHorizontalSpacerWidthForLandscape(
mSensorProps, displayWidth, dialogMargin, horizontalInset);
final int sensorDiameter = mSensorProps.sensorRadius * 2;
final int sensorDiameter = mSensorProps.getLocation().sensorRadius * 2;
final int remeasuredWidth = sensorDiameter + 2 * horizontalSpacerWidth;
int remeasuredHeight = 0;
@@ -257,10 +258,10 @@ public class UdfpsDialogMeasureAdapter {
@NonNull FingerprintSensorPropertiesInternal sensorProperties, int displayHeightPx,
int textIndicatorHeightPx, int buttonBarHeightPx, int dialogMarginPx,
int navbarBottomInsetPx) {
final SensorLocationInternal location = sensorProperties.getLocation();
final int sensorDistanceFromBottom = displayHeightPx
- sensorProperties.sensorLocationY
- sensorProperties.sensorRadius;
- location.sensorLocationY
- location.sensorRadius;
final int spacerHeight = sensorDistanceFromBottom
- textIndicatorHeightPx
@@ -318,10 +319,10 @@ public class UdfpsDialogMeasureAdapter {
static int calculateHorizontalSpacerWidthForLandscape(
@NonNull FingerprintSensorPropertiesInternal sensorProperties, int displayWidthPx,
int dialogMarginPx, int navbarHorizontalInsetPx) {
final SensorLocationInternal location = sensorProperties.getLocation();
final int sensorDistanceFromEdge = displayWidthPx
- sensorProperties.sensorLocationY
- sensorProperties.sensorRadius;
- location.sensorLocationY
- location.sensorRadius;
final int horizontalPadding = sensorDistanceFromEdge
- dialogMarginPx

View File

@@ -63,7 +63,7 @@ public class UdfpsEnrollView extends UdfpsAnimationView {
void updateSensorLocation(@NonNull FingerprintSensorPropertiesInternal sensorProps) {
View fingerprintAccessibilityView = findViewById(R.id.udfps_enroll_accessibility_view);
final int sensorHeight = sensorProps.sensorRadius * 2;
final int sensorHeight = sensorProps.getLocation().sensorRadius * 2;
final int sensorWidth = sensorHeight;
ViewGroup.LayoutParams params = fingerprintAccessibilityView.getLayoutParams();
params.width = sensorWidth;

View File

@@ -25,6 +25,7 @@ import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.PointF;
import android.graphics.RectF;
import android.hardware.biometrics.SensorLocationInternal;
import android.hardware.fingerprint.FingerprintSensorPropertiesInternal;
import android.os.Build;
import android.os.UserHandle;
@@ -141,11 +142,12 @@ public class UdfpsView extends FrameLayout implements DozeReceiver, UdfpsIllumin
: mAnimationViewController.getPaddingX();
int paddingY = mAnimationViewController == null ? 0
: mAnimationViewController.getPaddingY();
final SensorLocationInternal location = mSensorProps.getLocation();
mSensorRect.set(
paddingX,
paddingY,
2 * mSensorProps.sensorRadius + paddingX,
2 * mSensorProps.sensorRadius + paddingY);
2 * location.sensorRadius + paddingX,
2 * location.sensorRadius + paddingY);
if (mAnimationViewController != null) {
mAnimationViewController.onSensorRectUpdated(new RectF(mSensorRect));

View File

@@ -29,6 +29,7 @@ import static org.mockito.Mockito.verify;
import android.content.Context;
import android.hardware.biometrics.ComponentInfoInternal;
import android.hardware.biometrics.SensorLocationInternal;
import android.hardware.biometrics.SensorProperties;
import android.hardware.fingerprint.FingerprintSensorProperties;
import android.hardware.fingerprint.FingerprintSensorPropertiesInternal;
@@ -257,9 +258,10 @@ public class AuthBiometricFaceToFingerprintViewTest extends SysuiTestCase {
componentInfo,
FingerprintSensorProperties.TYPE_UDFPS_OPTICAL,
true /* resetLockoutRequiresHardwareAuthToken */,
540 /* sensorLocationX */,
1600 /* sensorLocationY */,
100 /* sensorRadius */);
List.of(new SensorLocationInternal("" /* displayId */,
540 /* sensorLocationX */,
1600 /* sensorLocationY */,
100 /* sensorRadius */)));
}
public class TestableView extends AuthBiometricFaceToFingerprintView {

View File

@@ -19,6 +19,7 @@ package com.android.systemui.biometrics;
import static org.junit.Assert.assertEquals;
import android.hardware.biometrics.ComponentInfoInternal;
import android.hardware.biometrics.SensorLocationInternal;
import android.hardware.biometrics.SensorProperties;
import android.hardware.fingerprint.FingerprintSensorProperties;
import android.hardware.fingerprint.FingerprintSensorPropertiesInternal;
@@ -61,8 +62,9 @@ public class UdfpsDialogMeasureAdapterTest extends SysuiTestCase {
0 /* sensorId */, SensorProperties.STRENGTH_STRONG, 5 /* maxEnrollmentsPerUser */,
componentInfo,
FingerprintSensorProperties.TYPE_UDFPS_OPTICAL,
true /* resetLockoutRequiresHardwareAuthToken */, sensorLocationX, sensorLocationY,
sensorRadius);
true /* resetLockoutRequiresHardwareAuthToken */,
List.of(new SensorLocationInternal("" /* displayId */,
sensorLocationX, sensorLocationY, sensorRadius)));
assertEquals(970,
UdfpsDialogMeasureAdapter.calculateBottomSpacerHeightForPortrait(
@@ -125,8 +127,9 @@ public class UdfpsDialogMeasureAdapterTest extends SysuiTestCase {
0 /* sensorId */, SensorProperties.STRENGTH_STRONG, 5 /* maxEnrollmentsPerUser */,
componentInfo,
FingerprintSensorProperties.TYPE_UDFPS_OPTICAL,
true /* resetLockoutRequiresHardwareAuthToken */, sensorLocationX, sensorLocationY,
sensorRadius);
true /* resetLockoutRequiresHardwareAuthToken */,
List.of(new SensorLocationInternal("" /* displayId */,
sensorLocationX, sensorLocationY, sensorRadius)));
assertEquals(1205,
UdfpsDialogMeasureAdapter.calculateHorizontalSpacerWidthForLandscape(

View File

@@ -25,6 +25,7 @@ import static org.mockito.Mockito.when;
import android.content.Context;
import android.content.res.Resources;
import android.graphics.PointF;
import android.hardware.biometrics.SensorLocationInternal;
import android.hardware.fingerprint.FingerprintSensorPropertiesInternal;
import android.os.Vibrator;
import android.testing.AndroidTestingRunner;
@@ -132,7 +133,8 @@ public class LockIconViewControllerTest extends SysuiTestCase {
/* component info */ new ArrayList<>(),
/* sensorType */ 3,
/* resetLockoutRequiresHwToken */ false,
(int) udfpsLocation.x, (int) udfpsLocation.y, radius);
List.of(new SensorLocationInternal("" /* displayId */,
(int) udfpsLocation.x, (int) udfpsLocation.y, radius)));
when(mAuthController.getUdfpsSensorLocation()).thenReturn(udfpsLocation);
when(mAuthController.getUdfpsProps()).thenReturn(List.of(fpProps));
@@ -165,7 +167,8 @@ public class LockIconViewControllerTest extends SysuiTestCase {
/* component info */ new ArrayList<>(),
/* sensorType */ 3,
/* resetLockoutRequiresHwToken */ false,
(int) udfpsLocation.x, (int) udfpsLocation.y, radius);
List.of(new SensorLocationInternal("" /* displayId */,
(int) udfpsLocation.x, (int) udfpsLocation.y, radius)));
when(mAuthController.getUdfpsSensorLocation()).thenReturn(udfpsLocation);
when(mAuthController.getUdfpsProps()).thenReturn(List.of(fpProps));

View File

@@ -47,6 +47,7 @@ import android.hardware.biometrics.IInvalidationCallback;
import android.hardware.biometrics.ITestSession;
import android.hardware.biometrics.ITestSessionCallback;
import android.hardware.biometrics.PromptInfo;
import android.hardware.biometrics.SensorLocationInternal;
import android.hardware.biometrics.SensorPropertiesInternal;
import android.hardware.face.FaceSensorProperties;
import android.hardware.face.FaceSensorPropertiesInternal;
@@ -766,8 +767,9 @@ public class AuthService extends SystemService {
if (isUdfps && udfpsProps.length == 3) {
return new FingerprintSensorPropertiesInternal(sensorId,
Utils.authenticatorStrengthToPropertyStrength(strength), maxEnrollmentsPerUser,
componentInfo, sensorType, resetLockoutRequiresHardwareAuthToken, udfpsProps[0],
udfpsProps[1], udfpsProps[2]);
componentInfo, sensorType, resetLockoutRequiresHardwareAuthToken,
List.of(new SensorLocationInternal("" /* display */,
udfpsProps[0], udfpsProps[1], udfpsProps[2])));
} else {
return new FingerprintSensorPropertiesInternal(sensorId,
Utils.authenticatorStrengthToPropertyStrength(strength), maxEnrollmentsPerUser,

View File

@@ -25,10 +25,12 @@ import android.app.ActivityTaskManager;
import android.app.TaskStackListener;
import android.content.Context;
import android.content.pm.UserInfo;
import android.content.res.TypedArray;
import android.hardware.biometrics.ComponentInfoInternal;
import android.hardware.biometrics.IInvalidationCallback;
import android.hardware.biometrics.ITestSession;
import android.hardware.biometrics.ITestSessionCallback;
import android.hardware.biometrics.SensorLocationInternal;
import android.hardware.biometrics.common.ComponentInfo;
import android.hardware.biometrics.fingerprint.IFingerprint;
import android.hardware.biometrics.fingerprint.SensorProps;
@@ -145,6 +147,8 @@ public class FingerprintProvider implements IBinder.DeathRecipient, ServiceProvi
mActivityTaskManager = ActivityTaskManager.getInstance();
mTaskStackListener = new BiometricTaskStackListener();
final List<SensorLocationInternal> workaroundLocations = getWorkaroundSensorProps(context);
for (SensorProps prop : props) {
final int sensorId = prop.commonProps.sensorId;
@@ -164,9 +168,12 @@ public class FingerprintProvider implements IBinder.DeathRecipient, ServiceProvi
componentInfo,
prop.sensorType,
true /* resetLockoutRequiresHardwareAuthToken */,
prop.sensorLocations[0].sensorLocationX,
prop.sensorLocations[0].sensorLocationY,
prop.sensorLocations[0].sensorRadius);
!workaroundLocations.isEmpty() ? workaroundLocations :
List.of(new SensorLocationInternal(
"" /* displayId */,
prop.sensorLocations[0].sensorLocationX,
prop.sensorLocations[0].sensorLocationY,
prop.sensorLocations[0].sensorRadius)));
final Sensor sensor = new Sensor(getTag() + "/" + sensorId, this, mContext, mHandler,
internalProp, lockoutResetDispatcher, gestureAvailabilityDispatcher);
@@ -647,4 +654,45 @@ public class FingerprintProvider implements IBinder.DeathRecipient, ServiceProvi
void setTestHalEnabled(boolean enabled) {
mTestHalEnabled = enabled;
}
// TODO(b/174868353): workaround for gaps in HAL interface (remove and get directly from HAL)
// reads values via an overlay instead of querying the HAL
@NonNull
private List<SensorLocationInternal> getWorkaroundSensorProps(@NonNull Context context) {
final List<SensorLocationInternal> sensorLocations = new ArrayList<>();
final TypedArray sfpsProps = context.getResources().obtainTypedArray(
com.android.internal.R.array.config_sfps_sensor_props);
for (int i = 0; i < sfpsProps.length(); i++) {
final int id = sfpsProps.getResourceId(i, -1);
if (id > 0) {
final SensorLocationInternal location = parseSensorLocation(
context.getResources().obtainTypedArray(id));
if (location != null) {
sensorLocations.add(location);
}
}
}
sfpsProps.recycle();
return sensorLocations;
}
@Nullable
private SensorLocationInternal parseSensorLocation(@Nullable TypedArray array) {
if (array == null) {
return null;
}
try {
return new SensorLocationInternal(
array.getString(0),
array.getInt(1, 0),
array.getInt(2, 0),
array.getInt(3, 0));
} catch (Exception e) {
Slog.w(getTag(), "malformed sensor location", e);
}
return null;
}
}

View File

@@ -426,8 +426,7 @@ public class Fingerprint21UdfpsMock extends Fingerprint21 implements TrustManage
mSensorProperties = new FingerprintSensorPropertiesInternal(sensorProps.sensorId,
sensorProps.sensorStrength, maxTemplatesAllowed, sensorProps.componentInfo,
FingerprintSensorProperties.TYPE_UDFPS_OPTICAL,
resetLockoutRequiresHardwareAuthToken, sensorProps.sensorLocationX,
sensorProps.sensorLocationY, sensorProps.sensorRadius);
resetLockoutRequiresHardwareAuthToken, sensorProps.getAllLocations());
mMockHalResultController = controller;
mUserHasTrust = new SparseBooleanArray();
mTrustManager = context.getSystemService(TrustManager.class);

View File

@@ -19,10 +19,13 @@ package com.android.server.biometrics.sensors.fingerprint.aidl;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.mockito.Mockito.anyInt;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
import android.content.Context;
import android.content.res.Resources;
import android.content.res.TypedArray;
import android.hardware.biometrics.common.CommonProps;
import android.hardware.biometrics.fingerprint.IFingerprint;
import android.hardware.biometrics.fingerprint.SensorLocation;
@@ -56,6 +59,8 @@ public class FingerprintProviderTest {
@Mock
private Context mContext;
@Mock
private Resources mResources;
@Mock
private UserManager mUserManager;
@Mock
private GestureAvailabilityDispatcher mGestureAvailabilityDispatcher;
@@ -74,19 +79,21 @@ public class FingerprintProviderTest {
public void setUp() {
MockitoAnnotations.initMocks(this);
when(mContext.getResources()).thenReturn(mResources);
when(mResources.obtainTypedArray(anyInt())).thenReturn(mock(TypedArray.class));
when(mContext.getSystemService(Context.USER_SERVICE)).thenReturn(mUserManager);
when(mUserManager.getAliveUsers()).thenReturn(new ArrayList<>());
final SensorProps sensor1 = new SensorProps();
sensor1.commonProps = new CommonProps();
sensor1.commonProps.sensorId = 0;
sensor1.sensorLocations = new SensorLocation[] {new SensorLocation()};
sensor1.sensorLocations = new SensorLocation[]{new SensorLocation()};
final SensorProps sensor2 = new SensorProps();
sensor2.commonProps = new CommonProps();
sensor2.commonProps.sensorId = 1;
sensor2.sensorLocations = new SensorLocation[] {new SensorLocation()};
sensor2.sensorLocations = new SensorLocation[]{new SensorLocation()};
mSensorProps = new SensorProps[] {sensor1, sensor2};
mSensorProps = new SensorProps[]{sensor1, sensor2};
mLockoutResetDispatcher = new LockoutResetDispatcher(mContext);