Add options to face and fingerprint manager internal APIs.

These options will include additional context from callers, like keyguard, that will be propogated to the HAL in follow-up changes.

Move the new Face & Fingerprint manager tests from services to core (their home project).

Fix: 246363169
Bug: 268295421
Test: atest FaceManagerTest FingerprintManagerTest
Change-Id: I5327efab56107c9aab72ca8d1e527c4330020942
This commit is contained in:
Joe Bolinger
2023-02-11 02:11:46 +00:00
parent c122093ea5
commit 684da58666
33 changed files with 1692 additions and 349 deletions

View File

@@ -0,0 +1,77 @@
/*
* Copyright (C) 2023 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.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
/**
* Common authentication options that are exposed across all modalities.
*
* @hide
*/
public interface AuthenticateOptions {
/** The user id for this operation. */
int getUserId();
/** The sensor id for this operation. */
int getSensorId();
/** The state is unknown. */
int DISPLAY_STATE_UNKNOWN = 0;
/** The display is on and showing the lockscreen (or an occluding app). */
int DISPLAY_STATE_LOCKSCREEN = 1;
/** The display is off or dozing. */
int DISPLAY_STATE_NO_UI = 2;
/** The display is showing a screensaver (dreaming). */
int DISPLAY_STATE_SCREENSAVER = 3;
/** The display is dreaming with always on display. */
int DISPLAY_STATE_AOD = 4;
/** The doze state of the device. */
@IntDef(prefix = "DISPLAY_STATE_", value = {
DISPLAY_STATE_UNKNOWN,
DISPLAY_STATE_LOCKSCREEN,
DISPLAY_STATE_NO_UI,
DISPLAY_STATE_SCREENSAVER,
DISPLAY_STATE_AOD
})
@Retention(RetentionPolicy.SOURCE)
@interface DisplayState {}
/** The current doze state of the device. */
@DisplayState
int getDisplayState();
/**
* The package name for that operation that should be used for
* {@link android.app.AppOpsManager} verification.
*/
@NonNull String getOpPackageName();
/** The attribution tag, if any. */
@Nullable String getAttributionTag();
}

View File

@@ -0,0 +1,19 @@
/*
* Copyright (C) 2023 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.face;
parcelable FaceAuthenticateOptions;

View File

@@ -0,0 +1,624 @@
/*
* Copyright (C) 2023 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.face;
import static android.os.PowerManager.WAKE_REASON_UNKNOWN;
import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.hardware.biometrics.AuthenticateOptions;
import android.os.Parcelable;
import android.os.PowerManager;
import com.android.internal.util.DataClass;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
/**
* Additional options when requesting Face authentication or detection.
*
* @hide
*/
@DataClass(
genParcelable = true,
genAidl = true,
genBuilder = true,
genSetters = true,
genEqualsHashCode = true
)
public class FaceAuthenticateOptions implements AuthenticateOptions, Parcelable {
/** The user id for this operation. */
private final int mUserId;
private static int defaultUserId() {
return 0;
}
/** The sensor id for this operation. */
private final int mSensorId;
private static int defaultSensorId() {
return -1;
}
/** The current doze state of the device. */
@AuthenticateOptions.DisplayState
private final int mDisplayState;
private static int defaultDisplayState() {
return DISPLAY_STATE_UNKNOWN;
}
public static final int AUTHENTICATE_REASON_UNKNOWN = 0;
public static final int AUTHENTICATE_REASON_STARTED_WAKING_UP = 1;
public static final int AUTHENTICATE_REASON_PRIMARY_BOUNCER_SHOWN = 2;
public static final int AUTHENTICATE_REASON_ASSISTANT_VISIBLE = 3;
public static final int AUTHENTICATE_REASON_ALTERNATE_BIOMETRIC_BOUNCER_SHOWN = 4;
public static final int AUTHENTICATE_REASON_NOTIFICATION_PANEL_CLICKED = 5;
public static final int AUTHENTICATE_REASON_OCCLUDING_APP_REQUESTED = 6;
public static final int AUTHENTICATE_REASON_PICK_UP_GESTURE_TRIGGERED = 7;
public static final int AUTHENTICATE_REASON_QS_EXPANDED = 8;
public static final int AUTHENTICATE_REASON_SWIPE_UP_ON_BOUNCER = 9;
public static final int AUTHENTICATE_REASON_UDFPS_POINTER_DOWN = 10;
/**
* The reason for this operation when requested by the system (sysui),
* otherwise AUTHENTICATE_REASON_UNKNOWN.
*
* See frameworks/base/packages/SystemUI/src/com/android/keyguard/FaceAuthReason.kt
* for more details about each reason.
*/
@AuthenticateReason
private final int mAuthenticateReason;
private static int defaultAuthenticateReason() {
return AUTHENTICATE_REASON_UNKNOWN;
}
/** A reason if this request was triggered due to a power event or WAKE_REASON_UNKNOWN. */
@PowerManager.WakeReason
private final int mWakeReason;
private static int defaultWakeReason() {
return WAKE_REASON_UNKNOWN;
}
/**
* The package name for that operation that should be used for
* {@link android.app.AppOpsManager} verification.
*
* This option may be overridden by the FingerprintManager using the caller's context.
*/
@NonNull
private String mOpPackageName;
private static String defaultOpPackageName() {
return "";
}
/**
* The attribution tag, if any.
*
* This option may be overridden by the FingerprintManager using the caller's context.
*/
@Nullable
private String mAttributionTag;
private static String defaultAttributionTag() {
return null;
}
// Code below generated by codegen v1.0.23.
//
// DO NOT MODIFY!
// CHECKSTYLE:OFF Generated code
//
// To regenerate run:
// $ codegen $ANDROID_BUILD_TOP/frameworks/base/core/java/android/hardware/face/FaceAuthenticateOptions.java
//
// To exclude the generated code from IntelliJ auto-formatting enable (one-time):
// Settings > Editor > Code Style > Formatter Control
//@formatter:off
@IntDef(prefix = "AUTHENTICATE_REASON_", value = {
AUTHENTICATE_REASON_UNKNOWN,
AUTHENTICATE_REASON_STARTED_WAKING_UP,
AUTHENTICATE_REASON_PRIMARY_BOUNCER_SHOWN,
AUTHENTICATE_REASON_ASSISTANT_VISIBLE,
AUTHENTICATE_REASON_ALTERNATE_BIOMETRIC_BOUNCER_SHOWN,
AUTHENTICATE_REASON_NOTIFICATION_PANEL_CLICKED,
AUTHENTICATE_REASON_OCCLUDING_APP_REQUESTED,
AUTHENTICATE_REASON_PICK_UP_GESTURE_TRIGGERED,
AUTHENTICATE_REASON_QS_EXPANDED,
AUTHENTICATE_REASON_SWIPE_UP_ON_BOUNCER,
AUTHENTICATE_REASON_UDFPS_POINTER_DOWN
})
@Retention(RetentionPolicy.SOURCE)
@DataClass.Generated.Member
public @interface AuthenticateReason {}
@DataClass.Generated.Member
public static String authenticateReasonToString(@AuthenticateReason int value) {
switch (value) {
case AUTHENTICATE_REASON_UNKNOWN:
return "AUTHENTICATE_REASON_UNKNOWN";
case AUTHENTICATE_REASON_STARTED_WAKING_UP:
return "AUTHENTICATE_REASON_STARTED_WAKING_UP";
case AUTHENTICATE_REASON_PRIMARY_BOUNCER_SHOWN:
return "AUTHENTICATE_REASON_PRIMARY_BOUNCER_SHOWN";
case AUTHENTICATE_REASON_ASSISTANT_VISIBLE:
return "AUTHENTICATE_REASON_ASSISTANT_VISIBLE";
case AUTHENTICATE_REASON_ALTERNATE_BIOMETRIC_BOUNCER_SHOWN:
return "AUTHENTICATE_REASON_ALTERNATE_BIOMETRIC_BOUNCER_SHOWN";
case AUTHENTICATE_REASON_NOTIFICATION_PANEL_CLICKED:
return "AUTHENTICATE_REASON_NOTIFICATION_PANEL_CLICKED";
case AUTHENTICATE_REASON_OCCLUDING_APP_REQUESTED:
return "AUTHENTICATE_REASON_OCCLUDING_APP_REQUESTED";
case AUTHENTICATE_REASON_PICK_UP_GESTURE_TRIGGERED:
return "AUTHENTICATE_REASON_PICK_UP_GESTURE_TRIGGERED";
case AUTHENTICATE_REASON_QS_EXPANDED:
return "AUTHENTICATE_REASON_QS_EXPANDED";
case AUTHENTICATE_REASON_SWIPE_UP_ON_BOUNCER:
return "AUTHENTICATE_REASON_SWIPE_UP_ON_BOUNCER";
case AUTHENTICATE_REASON_UDFPS_POINTER_DOWN:
return "AUTHENTICATE_REASON_UDFPS_POINTER_DOWN";
default: return Integer.toHexString(value);
}
}
@DataClass.Generated.Member
/* package-private */ FaceAuthenticateOptions(
int userId,
int sensorId,
@AuthenticateOptions.DisplayState int displayState,
@AuthenticateReason int authenticateReason,
@PowerManager.WakeReason int wakeReason,
@NonNull String opPackageName,
@Nullable String attributionTag) {
this.mUserId = userId;
this.mSensorId = sensorId;
this.mDisplayState = displayState;
com.android.internal.util.AnnotationValidations.validate(
AuthenticateOptions.DisplayState.class, null, mDisplayState);
this.mAuthenticateReason = authenticateReason;
if (!(mAuthenticateReason == AUTHENTICATE_REASON_UNKNOWN)
&& !(mAuthenticateReason == AUTHENTICATE_REASON_STARTED_WAKING_UP)
&& !(mAuthenticateReason == AUTHENTICATE_REASON_PRIMARY_BOUNCER_SHOWN)
&& !(mAuthenticateReason == AUTHENTICATE_REASON_ASSISTANT_VISIBLE)
&& !(mAuthenticateReason == AUTHENTICATE_REASON_ALTERNATE_BIOMETRIC_BOUNCER_SHOWN)
&& !(mAuthenticateReason == AUTHENTICATE_REASON_NOTIFICATION_PANEL_CLICKED)
&& !(mAuthenticateReason == AUTHENTICATE_REASON_OCCLUDING_APP_REQUESTED)
&& !(mAuthenticateReason == AUTHENTICATE_REASON_PICK_UP_GESTURE_TRIGGERED)
&& !(mAuthenticateReason == AUTHENTICATE_REASON_QS_EXPANDED)
&& !(mAuthenticateReason == AUTHENTICATE_REASON_SWIPE_UP_ON_BOUNCER)
&& !(mAuthenticateReason == AUTHENTICATE_REASON_UDFPS_POINTER_DOWN)) {
throw new java.lang.IllegalArgumentException(
"authenticateReason was " + mAuthenticateReason + " but must be one of: "
+ "AUTHENTICATE_REASON_UNKNOWN(" + AUTHENTICATE_REASON_UNKNOWN + "), "
+ "AUTHENTICATE_REASON_STARTED_WAKING_UP(" + AUTHENTICATE_REASON_STARTED_WAKING_UP + "), "
+ "AUTHENTICATE_REASON_PRIMARY_BOUNCER_SHOWN(" + AUTHENTICATE_REASON_PRIMARY_BOUNCER_SHOWN + "), "
+ "AUTHENTICATE_REASON_ASSISTANT_VISIBLE(" + AUTHENTICATE_REASON_ASSISTANT_VISIBLE + "), "
+ "AUTHENTICATE_REASON_ALTERNATE_BIOMETRIC_BOUNCER_SHOWN(" + AUTHENTICATE_REASON_ALTERNATE_BIOMETRIC_BOUNCER_SHOWN + "), "
+ "AUTHENTICATE_REASON_NOTIFICATION_PANEL_CLICKED(" + AUTHENTICATE_REASON_NOTIFICATION_PANEL_CLICKED + "), "
+ "AUTHENTICATE_REASON_OCCLUDING_APP_REQUESTED(" + AUTHENTICATE_REASON_OCCLUDING_APP_REQUESTED + "), "
+ "AUTHENTICATE_REASON_PICK_UP_GESTURE_TRIGGERED(" + AUTHENTICATE_REASON_PICK_UP_GESTURE_TRIGGERED + "), "
+ "AUTHENTICATE_REASON_QS_EXPANDED(" + AUTHENTICATE_REASON_QS_EXPANDED + "), "
+ "AUTHENTICATE_REASON_SWIPE_UP_ON_BOUNCER(" + AUTHENTICATE_REASON_SWIPE_UP_ON_BOUNCER + "), "
+ "AUTHENTICATE_REASON_UDFPS_POINTER_DOWN(" + AUTHENTICATE_REASON_UDFPS_POINTER_DOWN + ")");
}
this.mWakeReason = wakeReason;
com.android.internal.util.AnnotationValidations.validate(
PowerManager.WakeReason.class, null, mWakeReason);
this.mOpPackageName = opPackageName;
com.android.internal.util.AnnotationValidations.validate(
NonNull.class, null, mOpPackageName);
this.mAttributionTag = attributionTag;
// onConstructed(); // You can define this method to get a callback
}
/**
* The user id for this operation.
*/
@DataClass.Generated.Member
public int getUserId() {
return mUserId;
}
/**
* The sensor id for this operation.
*/
@DataClass.Generated.Member
public int getSensorId() {
return mSensorId;
}
/**
* The current doze state of the device.
*/
@DataClass.Generated.Member
public @AuthenticateOptions.DisplayState int getDisplayState() {
return mDisplayState;
}
/**
* The reason for this operation when requested by the system (sysui),
* otherwise AUTHENTICATE_REASON_UNKNOWN.
*
* See frameworks/base/packages/SystemUI/src/com/android/keyguard/FaceAuthReason.kt
* for more details about each reason.
*/
@DataClass.Generated.Member
public @AuthenticateReason int getAuthenticateReason() {
return mAuthenticateReason;
}
/**
* A reason if this request was triggered due to a power event or WAKE_REASON_UNKNOWN.
*/
@DataClass.Generated.Member
public @PowerManager.WakeReason int getWakeReason() {
return mWakeReason;
}
/**
* The package name for that operation that should be used for
* {@link android.app.AppOpsManager} verification.
*
* This option may be overridden by the FingerprintManager using the caller's context.
*/
@DataClass.Generated.Member
public @NonNull String getOpPackageName() {
return mOpPackageName;
}
/**
* The attribution tag, if any.
*
* This option may be overridden by the FingerprintManager using the caller's context.
*/
@DataClass.Generated.Member
public @Nullable String getAttributionTag() {
return mAttributionTag;
}
/**
* The package name for that operation that should be used for
* {@link android.app.AppOpsManager} verification.
*
* This option may be overridden by the FingerprintManager using the caller's context.
*/
@DataClass.Generated.Member
public @NonNull FaceAuthenticateOptions setOpPackageName(@NonNull String value) {
mOpPackageName = value;
com.android.internal.util.AnnotationValidations.validate(
NonNull.class, null, mOpPackageName);
return this;
}
/**
* The attribution tag, if any.
*
* This option may be overridden by the FingerprintManager using the caller's context.
*/
@DataClass.Generated.Member
public @NonNull FaceAuthenticateOptions setAttributionTag(@NonNull String value) {
mAttributionTag = value;
return this;
}
@Override
@DataClass.Generated.Member
public boolean equals(@Nullable Object o) {
// You can override field equality logic by defining either of the methods like:
// boolean fieldNameEquals(FaceAuthenticateOptions other) { ... }
// boolean fieldNameEquals(FieldType otherValue) { ... }
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
@SuppressWarnings("unchecked")
FaceAuthenticateOptions that = (FaceAuthenticateOptions) o;
//noinspection PointlessBooleanExpression
return true
&& mUserId == that.mUserId
&& mSensorId == that.mSensorId
&& mDisplayState == that.mDisplayState
&& mAuthenticateReason == that.mAuthenticateReason
&& mWakeReason == that.mWakeReason
&& java.util.Objects.equals(mOpPackageName, that.mOpPackageName)
&& java.util.Objects.equals(mAttributionTag, that.mAttributionTag);
}
@Override
@DataClass.Generated.Member
public int hashCode() {
// You can override field hashCode logic by defining methods like:
// int fieldNameHashCode() { ... }
int _hash = 1;
_hash = 31 * _hash + mUserId;
_hash = 31 * _hash + mSensorId;
_hash = 31 * _hash + mDisplayState;
_hash = 31 * _hash + mAuthenticateReason;
_hash = 31 * _hash + mWakeReason;
_hash = 31 * _hash + java.util.Objects.hashCode(mOpPackageName);
_hash = 31 * _hash + java.util.Objects.hashCode(mAttributionTag);
return _hash;
}
@Override
@DataClass.Generated.Member
public void writeToParcel(@NonNull android.os.Parcel dest, int flags) {
// You can override field parcelling by defining methods like:
// void parcelFieldName(Parcel dest, int flags) { ... }
byte flg = 0;
if (mAttributionTag != null) flg |= 0x40;
dest.writeByte(flg);
dest.writeInt(mUserId);
dest.writeInt(mSensorId);
dest.writeInt(mDisplayState);
dest.writeInt(mAuthenticateReason);
dest.writeInt(mWakeReason);
dest.writeString(mOpPackageName);
if (mAttributionTag != null) dest.writeString(mAttributionTag);
}
@Override
@DataClass.Generated.Member
public int describeContents() { return 0; }
/** @hide */
@SuppressWarnings({"unchecked", "RedundantCast"})
@DataClass.Generated.Member
protected FaceAuthenticateOptions(@NonNull android.os.Parcel in) {
// You can override field unparcelling by defining methods like:
// static FieldType unparcelFieldName(Parcel in) { ... }
byte flg = in.readByte();
int userId = in.readInt();
int sensorId = in.readInt();
int displayState = in.readInt();
int authenticateReason = in.readInt();
int wakeReason = in.readInt();
String opPackageName = in.readString();
String attributionTag = (flg & 0x40) == 0 ? null : in.readString();
this.mUserId = userId;
this.mSensorId = sensorId;
this.mDisplayState = displayState;
com.android.internal.util.AnnotationValidations.validate(
AuthenticateOptions.DisplayState.class, null, mDisplayState);
this.mAuthenticateReason = authenticateReason;
if (!(mAuthenticateReason == AUTHENTICATE_REASON_UNKNOWN)
&& !(mAuthenticateReason == AUTHENTICATE_REASON_STARTED_WAKING_UP)
&& !(mAuthenticateReason == AUTHENTICATE_REASON_PRIMARY_BOUNCER_SHOWN)
&& !(mAuthenticateReason == AUTHENTICATE_REASON_ASSISTANT_VISIBLE)
&& !(mAuthenticateReason == AUTHENTICATE_REASON_ALTERNATE_BIOMETRIC_BOUNCER_SHOWN)
&& !(mAuthenticateReason == AUTHENTICATE_REASON_NOTIFICATION_PANEL_CLICKED)
&& !(mAuthenticateReason == AUTHENTICATE_REASON_OCCLUDING_APP_REQUESTED)
&& !(mAuthenticateReason == AUTHENTICATE_REASON_PICK_UP_GESTURE_TRIGGERED)
&& !(mAuthenticateReason == AUTHENTICATE_REASON_QS_EXPANDED)
&& !(mAuthenticateReason == AUTHENTICATE_REASON_SWIPE_UP_ON_BOUNCER)
&& !(mAuthenticateReason == AUTHENTICATE_REASON_UDFPS_POINTER_DOWN)) {
throw new java.lang.IllegalArgumentException(
"authenticateReason was " + mAuthenticateReason + " but must be one of: "
+ "AUTHENTICATE_REASON_UNKNOWN(" + AUTHENTICATE_REASON_UNKNOWN + "), "
+ "AUTHENTICATE_REASON_STARTED_WAKING_UP(" + AUTHENTICATE_REASON_STARTED_WAKING_UP + "), "
+ "AUTHENTICATE_REASON_PRIMARY_BOUNCER_SHOWN(" + AUTHENTICATE_REASON_PRIMARY_BOUNCER_SHOWN + "), "
+ "AUTHENTICATE_REASON_ASSISTANT_VISIBLE(" + AUTHENTICATE_REASON_ASSISTANT_VISIBLE + "), "
+ "AUTHENTICATE_REASON_ALTERNATE_BIOMETRIC_BOUNCER_SHOWN(" + AUTHENTICATE_REASON_ALTERNATE_BIOMETRIC_BOUNCER_SHOWN + "), "
+ "AUTHENTICATE_REASON_NOTIFICATION_PANEL_CLICKED(" + AUTHENTICATE_REASON_NOTIFICATION_PANEL_CLICKED + "), "
+ "AUTHENTICATE_REASON_OCCLUDING_APP_REQUESTED(" + AUTHENTICATE_REASON_OCCLUDING_APP_REQUESTED + "), "
+ "AUTHENTICATE_REASON_PICK_UP_GESTURE_TRIGGERED(" + AUTHENTICATE_REASON_PICK_UP_GESTURE_TRIGGERED + "), "
+ "AUTHENTICATE_REASON_QS_EXPANDED(" + AUTHENTICATE_REASON_QS_EXPANDED + "), "
+ "AUTHENTICATE_REASON_SWIPE_UP_ON_BOUNCER(" + AUTHENTICATE_REASON_SWIPE_UP_ON_BOUNCER + "), "
+ "AUTHENTICATE_REASON_UDFPS_POINTER_DOWN(" + AUTHENTICATE_REASON_UDFPS_POINTER_DOWN + ")");
}
this.mWakeReason = wakeReason;
com.android.internal.util.AnnotationValidations.validate(
PowerManager.WakeReason.class, null, mWakeReason);
this.mOpPackageName = opPackageName;
com.android.internal.util.AnnotationValidations.validate(
NonNull.class, null, mOpPackageName);
this.mAttributionTag = attributionTag;
// onConstructed(); // You can define this method to get a callback
}
@DataClass.Generated.Member
public static final @NonNull Parcelable.Creator<FaceAuthenticateOptions> CREATOR
= new Parcelable.Creator<FaceAuthenticateOptions>() {
@Override
public FaceAuthenticateOptions[] newArray(int size) {
return new FaceAuthenticateOptions[size];
}
@Override
public FaceAuthenticateOptions createFromParcel(@NonNull android.os.Parcel in) {
return new FaceAuthenticateOptions(in);
}
};
/**
* A builder for {@link FaceAuthenticateOptions}
*/
@SuppressWarnings("WeakerAccess")
@DataClass.Generated.Member
public static class Builder {
private int mUserId;
private int mSensorId;
private @AuthenticateOptions.DisplayState int mDisplayState;
private @AuthenticateReason int mAuthenticateReason;
private @PowerManager.WakeReason int mWakeReason;
private @NonNull String mOpPackageName;
private @Nullable String mAttributionTag;
private long mBuilderFieldsSet = 0L;
public Builder() {
}
/**
* The user id for this operation.
*/
@DataClass.Generated.Member
public @NonNull Builder setUserId(int value) {
checkNotUsed();
mBuilderFieldsSet |= 0x1;
mUserId = value;
return this;
}
/**
* The sensor id for this operation.
*/
@DataClass.Generated.Member
public @NonNull Builder setSensorId(int value) {
checkNotUsed();
mBuilderFieldsSet |= 0x2;
mSensorId = value;
return this;
}
/**
* The current doze state of the device.
*/
@DataClass.Generated.Member
public @NonNull Builder setDisplayState(@AuthenticateOptions.DisplayState int value) {
checkNotUsed();
mBuilderFieldsSet |= 0x4;
mDisplayState = value;
return this;
}
/**
* The reason for this operation when requested by the system (sysui),
* otherwise AUTHENTICATE_REASON_UNKNOWN.
*
* See frameworks/base/packages/SystemUI/src/com/android/keyguard/FaceAuthReason.kt
* for more details about each reason.
*/
@DataClass.Generated.Member
public @NonNull Builder setAuthenticateReason(@AuthenticateReason int value) {
checkNotUsed();
mBuilderFieldsSet |= 0x8;
mAuthenticateReason = value;
return this;
}
/**
* A reason if this request was triggered due to a power event or WAKE_REASON_UNKNOWN.
*/
@DataClass.Generated.Member
public @NonNull Builder setWakeReason(@PowerManager.WakeReason int value) {
checkNotUsed();
mBuilderFieldsSet |= 0x10;
mWakeReason = value;
return this;
}
/**
* The package name for that operation that should be used for
* {@link android.app.AppOpsManager} verification.
*
* This option may be overridden by the FingerprintManager using the caller's context.
*/
@DataClass.Generated.Member
public @NonNull Builder setOpPackageName(@NonNull String value) {
checkNotUsed();
mBuilderFieldsSet |= 0x20;
mOpPackageName = value;
return this;
}
/**
* The attribution tag, if any.
*
* This option may be overridden by the FingerprintManager using the caller's context.
*/
@DataClass.Generated.Member
public @NonNull Builder setAttributionTag(@NonNull String value) {
checkNotUsed();
mBuilderFieldsSet |= 0x40;
mAttributionTag = value;
return this;
}
/** Builds the instance. This builder should not be touched after calling this! */
public @NonNull FaceAuthenticateOptions build() {
checkNotUsed();
mBuilderFieldsSet |= 0x80; // Mark builder used
if ((mBuilderFieldsSet & 0x1) == 0) {
mUserId = defaultUserId();
}
if ((mBuilderFieldsSet & 0x2) == 0) {
mSensorId = defaultSensorId();
}
if ((mBuilderFieldsSet & 0x4) == 0) {
mDisplayState = defaultDisplayState();
}
if ((mBuilderFieldsSet & 0x8) == 0) {
mAuthenticateReason = defaultAuthenticateReason();
}
if ((mBuilderFieldsSet & 0x10) == 0) {
mWakeReason = defaultWakeReason();
}
if ((mBuilderFieldsSet & 0x20) == 0) {
mOpPackageName = defaultOpPackageName();
}
if ((mBuilderFieldsSet & 0x40) == 0) {
mAttributionTag = defaultAttributionTag();
}
FaceAuthenticateOptions o = new FaceAuthenticateOptions(
mUserId,
mSensorId,
mDisplayState,
mAuthenticateReason,
mWakeReason,
mOpPackageName,
mAttributionTag);
return o;
}
private void checkNotUsed() {
if ((mBuilderFieldsSet & 0x80) != 0) {
throw new IllegalStateException(
"This Builder should not be reused. Use a new Builder instance instead");
}
}
}
@DataClass.Generated(
time = 1676508211385L,
codegenVersion = "1.0.23",
sourceFile = "frameworks/base/core/java/android/hardware/face/FaceAuthenticateOptions.java",
inputSignatures = "private final int mUserId\nprivate final int mSensorId\nprivate final @android.hardware.biometrics.AuthenticateOptions.DisplayState int mDisplayState\npublic static final int AUTHENTICATE_REASON_UNKNOWN\npublic static final int AUTHENTICATE_REASON_STARTED_WAKING_UP\npublic static final int AUTHENTICATE_REASON_PRIMARY_BOUNCER_SHOWN\npublic static final int AUTHENTICATE_REASON_ASSISTANT_VISIBLE\npublic static final int AUTHENTICATE_REASON_ALTERNATE_BIOMETRIC_BOUNCER_SHOWN\npublic static final int AUTHENTICATE_REASON_NOTIFICATION_PANEL_CLICKED\npublic static final int AUTHENTICATE_REASON_OCCLUDING_APP_REQUESTED\npublic static final int AUTHENTICATE_REASON_PICK_UP_GESTURE_TRIGGERED\npublic static final int AUTHENTICATE_REASON_QS_EXPANDED\npublic static final int AUTHENTICATE_REASON_SWIPE_UP_ON_BOUNCER\npublic static final int AUTHENTICATE_REASON_UDFPS_POINTER_DOWN\nprivate final @android.hardware.face.FaceAuthenticateOptions.AuthenticateReason int mAuthenticateReason\nprivate final @android.os.PowerManager.WakeReason int mWakeReason\nprivate @android.annotation.NonNull java.lang.String mOpPackageName\nprivate @android.annotation.Nullable java.lang.String mAttributionTag\nprivate static int defaultUserId()\nprivate static int defaultSensorId()\nprivate static int defaultDisplayState()\nprivate static int defaultAuthenticateReason()\nprivate static int defaultWakeReason()\nprivate static java.lang.String defaultOpPackageName()\nprivate static java.lang.String defaultAttributionTag()\nclass FaceAuthenticateOptions extends java.lang.Object implements [android.hardware.biometrics.AuthenticateOptions, android.os.Parcelable]\n@com.android.internal.util.DataClass(genParcelable=true, genAidl=true, genBuilder=true, genSetters=true, genEqualsHashCode=true)")
@Deprecated
private void __metadata() {}
//@formatter:on
// End of generated code
}

View File

@@ -194,18 +194,30 @@ public class FaceManager implements BiometricAuthenticator, BiometricFaceConstan
}
/**
* Request authentication of a crypto object. This call operates the face recognition hardware
* and starts capturing images. It terminates when
* @deprecated use {@link #authenticate(CryptoObject, CancellationSignal, AuthenticationCallback, Handler, FaceAuthenticateOptions)}.
*/
@Deprecated
@RequiresPermission(USE_BIOMETRIC_INTERNAL)
public void authenticate(@Nullable CryptoObject crypto, @Nullable CancellationSignal cancel,
@NonNull AuthenticationCallback callback, @Nullable Handler handler, int userId) {
authenticate(crypto, cancel, callback, handler, new FaceAuthenticateOptions.Builder()
.setUserId(userId)
.build());
}
/**
* Request authentication. This call operates the face recognition hardware and starts capturing images.
* It terminates when
* {@link AuthenticationCallback#onAuthenticationError(int, CharSequence)} or
* {@link AuthenticationCallback#onAuthenticationSucceeded(AuthenticationResult)} is called, at
* which point the object is no longer valid. The operation can be canceled by using the
* provided cancel object.
*
* @param crypto object associated with the call or null if none required.
* @param crypto object associated with the call or null if none required
* @param cancel an object that can be used to cancel authentication
* @param callback an object to receive authentication events
* @param handler an optional handler to handle callback events
* @param userId userId to authenticate for
* @param options additional options to customize this request
* @throws IllegalArgumentException if the crypto operation is not supported or is not backed
* by
* <a href="{@docRoot}training/articles/keystore.html">Android
@@ -215,8 +227,8 @@ public class FaceManager implements BiometricAuthenticator, BiometricFaceConstan
*/
@RequiresPermission(USE_BIOMETRIC_INTERNAL)
public void authenticate(@Nullable CryptoObject crypto, @Nullable CancellationSignal cancel,
@NonNull AuthenticationCallback callback, @Nullable Handler handler, int userId,
boolean isKeyguardBypassEnabled) {
@NonNull AuthenticationCallback callback, @Nullable Handler handler,
@NonNull FaceAuthenticateOptions options) {
if (callback == null) {
throw new IllegalArgumentException("Must supply an authentication callback");
}
@@ -226,6 +238,9 @@ public class FaceManager implements BiometricAuthenticator, BiometricFaceConstan
return;
}
options.setOpPackageName(mContext.getOpPackageName());
options.setAttributionTag(mContext.getAttributionTag());
if (mService != null) {
try {
useHandler(handler);
@@ -233,8 +248,8 @@ public class FaceManager implements BiometricAuthenticator, BiometricFaceConstan
mCryptoObject = crypto;
final long operationId = crypto != null ? crypto.getOpId() : 0;
Trace.beginSection("FaceManager#authenticate");
final long authId = mService.authenticate(mToken, operationId, userId,
mServiceReceiver, mContext.getOpPackageName(), isKeyguardBypassEnabled);
final long authId = mService.authenticate(
mToken, operationId, mServiceReceiver, options);
if (cancel != null) {
cancel.setOnCancelListener(new OnAuthenticationCancelListener(authId));
}
@@ -258,7 +273,7 @@ public class FaceManager implements BiometricAuthenticator, BiometricFaceConstan
*/
@RequiresPermission(USE_BIOMETRIC_INTERNAL)
public void detectFace(@NonNull CancellationSignal cancel,
@NonNull FaceDetectionCallback callback, int userId) {
@NonNull FaceDetectionCallback callback, @NonNull FaceAuthenticateOptions options) {
if (mService == null) {
return;
}
@@ -268,11 +283,13 @@ public class FaceManager implements BiometricAuthenticator, BiometricFaceConstan
return;
}
options.setOpPackageName(mContext.getOpPackageName());
options.setAttributionTag(mContext.getAttributionTag());
mFaceDetectionCallback = callback;
try {
final long authId = mService.detectFace(
mToken, userId, mServiceReceiver, mContext.getOpPackageName());
final long authId = mService.detectFace(mToken, mServiceReceiver, options);
cancel.setOnCancelListener(new OnFaceDetectionCancelListener(authId));
} catch (RemoteException e) {
Slog.w(TAG, "Remote exception when requesting finger detect", e);

View File

@@ -24,6 +24,7 @@ import android.hardware.biometrics.ITestSessionCallback;
import android.hardware.face.IFaceAuthenticatorsRegisteredCallback;
import android.hardware.face.IFaceServiceReceiver;
import android.hardware.face.Face;
import android.hardware.face.FaceAuthenticateOptions;
import android.hardware.face.FaceSensorPropertiesInternal;
import android.view.Surface;
@@ -52,14 +53,14 @@ interface IFaceService {
// Authenticate with a face. A requestId is returned that can be used to cancel this operation.
@EnforcePermission("USE_BIOMETRIC_INTERNAL")
long authenticate(IBinder token, long operationId, int userId, IFaceServiceReceiver receiver,
String opPackageName, boolean isKeyguardBypassEnabled);
long authenticate(IBinder token, long operationId, IFaceServiceReceiver receiver,
in FaceAuthenticateOptions options);
// Uses the face hardware to detect for the presence of a face, without giving details
// about accept/reject/lockout. A requestId is returned that can be used to cancel this
// operation.
@EnforcePermission("USE_BIOMETRIC_INTERNAL")
long detectFace(IBinder token, int userId, IFaceServiceReceiver receiver, String opPackageName);
long detectFace(IBinder token, IFaceServiceReceiver receiver, in FaceAuthenticateOptions options);
// This method prepares the service to start authenticating, but doesn't start authentication.
// This is protected by the MANAGE_BIOMETRIC signatuer permission. This method should only be
@@ -68,8 +69,8 @@ interface IFaceService {
// startPreparedClient().
@EnforcePermission("USE_BIOMETRIC_INTERNAL")
void prepareForAuthentication(int sensorId, boolean requireConfirmation, IBinder token,
long operationId, int userId, IBiometricSensorReceiver sensorReceiver,
String opPackageName, long requestId, int cookie,
long operationId, IBiometricSensorReceiver sensorReceiver,
in FaceAuthenticateOptions options, long requestId, int cookie,
boolean allowBackgroundAuthentication);
// Starts authentication with the previously prepared client.

View File

@@ -0,0 +1,19 @@
/*
* Copyright (C) 2023 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.fingerprint;
parcelable FingerprintAuthenticateOptions;

View File

@@ -0,0 +1,447 @@
/*
* Copyright (C) 2023 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.fingerprint;
import static android.hardware.fingerprint.FingerprintManager.SENSOR_ID_ANY;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.hardware.biometrics.AuthenticateOptions;
import android.os.Parcelable;
import com.android.internal.util.DataClass;
/**
* Additional options when requesting Fingerprint authentication or detection.
*
* @hide
*/
@DataClass(
genParcelable = true,
genAidl = true,
genBuilder = true,
genSetters = true,
genEqualsHashCode = true
)
public final class FingerprintAuthenticateOptions implements AuthenticateOptions, Parcelable {
/** The user id for this operation. */
private final int mUserId;
private static int defaultUserId() {
return 0;
}
/** The sensor id for this operation. */
private final int mSensorId;
private static int defaultSensorId() {
return SENSOR_ID_ANY;
}
/** If enrollment state should be ignored. */
private final boolean mIgnoreEnrollmentState;
private static boolean defaultIgnoreEnrollmentState() {
return false;
}
/** The current doze state of the device. */
@AuthenticateOptions.DisplayState
private final int mDisplayState;
private static int defaultDisplayState() {
return DISPLAY_STATE_UNKNOWN;
}
/**
* The package name for that operation that should be used for
* {@link android.app.AppOpsManager} verification.
*
* This option may be overridden by the FingerprintManager using the caller's context.
*/
@NonNull private String mOpPackageName;
private static String defaultOpPackageName() {
return "";
}
/**
* The attribution tag, if any.
*
* This option may be overridden by the FingerprintManager using the caller's context.
*/
@Nullable private String mAttributionTag;
private static String defaultAttributionTag() {
return null;
}
// Code below generated by codegen v1.0.23.
//
// DO NOT MODIFY!
// CHECKSTYLE:OFF Generated code
//
// To regenerate run:
// $ codegen $ANDROID_BUILD_TOP/frameworks/base/core/java/android/hardware/fingerprint/FingerprintAuthenticateOptions.java
//
// To exclude the generated code from IntelliJ auto-formatting enable (one-time):
// Settings > Editor > Code Style > Formatter Control
//@formatter:off
@DataClass.Generated.Member
/* package-private */ FingerprintAuthenticateOptions(
int userId,
int sensorId,
boolean ignoreEnrollmentState,
@AuthenticateOptions.DisplayState int displayState,
@NonNull String opPackageName,
@Nullable String attributionTag) {
this.mUserId = userId;
this.mSensorId = sensorId;
this.mIgnoreEnrollmentState = ignoreEnrollmentState;
this.mDisplayState = displayState;
com.android.internal.util.AnnotationValidations.validate(
AuthenticateOptions.DisplayState.class, null, mDisplayState);
this.mOpPackageName = opPackageName;
com.android.internal.util.AnnotationValidations.validate(
NonNull.class, null, mOpPackageName);
this.mAttributionTag = attributionTag;
// onConstructed(); // You can define this method to get a callback
}
/**
* The user id for this operation.
*/
@DataClass.Generated.Member
public int getUserId() {
return mUserId;
}
/**
* The sensor id for this operation.
*/
@DataClass.Generated.Member
public int getSensorId() {
return mSensorId;
}
/**
* If enrollment state should be ignored.
*/
@DataClass.Generated.Member
public boolean isIgnoreEnrollmentState() {
return mIgnoreEnrollmentState;
}
/**
* The current doze state of the device.
*/
@DataClass.Generated.Member
public @AuthenticateOptions.DisplayState int getDisplayState() {
return mDisplayState;
}
/**
* The package name for that operation that should be used for
* {@link android.app.AppOpsManager} verification.
*
* This option may be overridden by the FingerprintManager using the caller's context.
*/
@DataClass.Generated.Member
public @NonNull String getOpPackageName() {
return mOpPackageName;
}
/**
* The attribution tag, if any.
*
* This option may be overridden by the FingerprintManager using the caller's context.
*/
@DataClass.Generated.Member
public @Nullable String getAttributionTag() {
return mAttributionTag;
}
/**
* The package name for that operation that should be used for
* {@link android.app.AppOpsManager} verification.
*
* This option may be overridden by the FingerprintManager using the caller's context.
*/
@DataClass.Generated.Member
public @NonNull FingerprintAuthenticateOptions setOpPackageName(@NonNull String value) {
mOpPackageName = value;
com.android.internal.util.AnnotationValidations.validate(
NonNull.class, null, mOpPackageName);
return this;
}
/**
* The attribution tag, if any.
*
* This option may be overridden by the FingerprintManager using the caller's context.
*/
@DataClass.Generated.Member
public @NonNull FingerprintAuthenticateOptions setAttributionTag(@NonNull String value) {
mAttributionTag = value;
return this;
}
@Override
@DataClass.Generated.Member
public boolean equals(@Nullable Object o) {
// You can override field equality logic by defining either of the methods like:
// boolean fieldNameEquals(FingerprintAuthenticateOptions other) { ... }
// boolean fieldNameEquals(FieldType otherValue) { ... }
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
@SuppressWarnings("unchecked")
FingerprintAuthenticateOptions that = (FingerprintAuthenticateOptions) o;
//noinspection PointlessBooleanExpression
return true
&& mUserId == that.mUserId
&& mSensorId == that.mSensorId
&& mIgnoreEnrollmentState == that.mIgnoreEnrollmentState
&& mDisplayState == that.mDisplayState
&& java.util.Objects.equals(mOpPackageName, that.mOpPackageName)
&& java.util.Objects.equals(mAttributionTag, that.mAttributionTag);
}
@Override
@DataClass.Generated.Member
public int hashCode() {
// You can override field hashCode logic by defining methods like:
// int fieldNameHashCode() { ... }
int _hash = 1;
_hash = 31 * _hash + mUserId;
_hash = 31 * _hash + mSensorId;
_hash = 31 * _hash + Boolean.hashCode(mIgnoreEnrollmentState);
_hash = 31 * _hash + mDisplayState;
_hash = 31 * _hash + java.util.Objects.hashCode(mOpPackageName);
_hash = 31 * _hash + java.util.Objects.hashCode(mAttributionTag);
return _hash;
}
@Override
@DataClass.Generated.Member
public void writeToParcel(@NonNull android.os.Parcel dest, int flags) {
// You can override field parcelling by defining methods like:
// void parcelFieldName(Parcel dest, int flags) { ... }
byte flg = 0;
if (mIgnoreEnrollmentState) flg |= 0x4;
if (mAttributionTag != null) flg |= 0x20;
dest.writeByte(flg);
dest.writeInt(mUserId);
dest.writeInt(mSensorId);
dest.writeInt(mDisplayState);
dest.writeString(mOpPackageName);
if (mAttributionTag != null) dest.writeString(mAttributionTag);
}
@Override
@DataClass.Generated.Member
public int describeContents() { return 0; }
/** @hide */
@SuppressWarnings({"unchecked", "RedundantCast"})
@DataClass.Generated.Member
/* package-private */ FingerprintAuthenticateOptions(@NonNull android.os.Parcel in) {
// You can override field unparcelling by defining methods like:
// static FieldType unparcelFieldName(Parcel in) { ... }
byte flg = in.readByte();
boolean ignoreEnrollmentState = (flg & 0x4) != 0;
int userId = in.readInt();
int sensorId = in.readInt();
int displayState = in.readInt();
String opPackageName = in.readString();
String attributionTag = (flg & 0x20) == 0 ? null : in.readString();
this.mUserId = userId;
this.mSensorId = sensorId;
this.mIgnoreEnrollmentState = ignoreEnrollmentState;
this.mDisplayState = displayState;
com.android.internal.util.AnnotationValidations.validate(
AuthenticateOptions.DisplayState.class, null, mDisplayState);
this.mOpPackageName = opPackageName;
com.android.internal.util.AnnotationValidations.validate(
NonNull.class, null, mOpPackageName);
this.mAttributionTag = attributionTag;
// onConstructed(); // You can define this method to get a callback
}
@DataClass.Generated.Member
public static final @NonNull Parcelable.Creator<FingerprintAuthenticateOptions> CREATOR
= new Parcelable.Creator<FingerprintAuthenticateOptions>() {
@Override
public FingerprintAuthenticateOptions[] newArray(int size) {
return new FingerprintAuthenticateOptions[size];
}
@Override
public FingerprintAuthenticateOptions createFromParcel(@NonNull android.os.Parcel in) {
return new FingerprintAuthenticateOptions(in);
}
};
/**
* A builder for {@link FingerprintAuthenticateOptions}
*/
@SuppressWarnings("WeakerAccess")
@DataClass.Generated.Member
public static final class Builder {
private int mUserId;
private int mSensorId;
private boolean mIgnoreEnrollmentState;
private @AuthenticateOptions.DisplayState int mDisplayState;
private @NonNull String mOpPackageName;
private @Nullable String mAttributionTag;
private long mBuilderFieldsSet = 0L;
public Builder() {
}
/**
* The user id for this operation.
*/
@DataClass.Generated.Member
public @NonNull Builder setUserId(int value) {
checkNotUsed();
mBuilderFieldsSet |= 0x1;
mUserId = value;
return this;
}
/**
* The sensor id for this operation.
*/
@DataClass.Generated.Member
public @NonNull Builder setSensorId(int value) {
checkNotUsed();
mBuilderFieldsSet |= 0x2;
mSensorId = value;
return this;
}
/**
* If enrollment state should be ignored.
*/
@DataClass.Generated.Member
public @NonNull Builder setIgnoreEnrollmentState(boolean value) {
checkNotUsed();
mBuilderFieldsSet |= 0x4;
mIgnoreEnrollmentState = value;
return this;
}
/**
* The current doze state of the device.
*/
@DataClass.Generated.Member
public @NonNull Builder setDisplayState(@AuthenticateOptions.DisplayState int value) {
checkNotUsed();
mBuilderFieldsSet |= 0x8;
mDisplayState = value;
return this;
}
/**
* The package name for that operation that should be used for
* {@link android.app.AppOpsManager} verification.
*
* This option may be overridden by the FingerprintManager using the caller's context.
*/
@DataClass.Generated.Member
public @NonNull Builder setOpPackageName(@NonNull String value) {
checkNotUsed();
mBuilderFieldsSet |= 0x10;
mOpPackageName = value;
return this;
}
/**
* The attribution tag, if any.
*
* This option may be overridden by the FingerprintManager using the caller's context.
*/
@DataClass.Generated.Member
public @NonNull Builder setAttributionTag(@NonNull String value) {
checkNotUsed();
mBuilderFieldsSet |= 0x20;
mAttributionTag = value;
return this;
}
/** Builds the instance. This builder should not be touched after calling this! */
public @NonNull FingerprintAuthenticateOptions build() {
checkNotUsed();
mBuilderFieldsSet |= 0x40; // Mark builder used
if ((mBuilderFieldsSet & 0x1) == 0) {
mUserId = defaultUserId();
}
if ((mBuilderFieldsSet & 0x2) == 0) {
mSensorId = defaultSensorId();
}
if ((mBuilderFieldsSet & 0x4) == 0) {
mIgnoreEnrollmentState = defaultIgnoreEnrollmentState();
}
if ((mBuilderFieldsSet & 0x8) == 0) {
mDisplayState = defaultDisplayState();
}
if ((mBuilderFieldsSet & 0x10) == 0) {
mOpPackageName = defaultOpPackageName();
}
if ((mBuilderFieldsSet & 0x20) == 0) {
mAttributionTag = defaultAttributionTag();
}
FingerprintAuthenticateOptions o = new FingerprintAuthenticateOptions(
mUserId,
mSensorId,
mIgnoreEnrollmentState,
mDisplayState,
mOpPackageName,
mAttributionTag);
return o;
}
private void checkNotUsed() {
if ((mBuilderFieldsSet & 0x40) != 0) {
throw new IllegalStateException(
"This Builder should not be reused. Use a new Builder instance instead");
}
}
}
@DataClass.Generated(
time = 1676508212083L,
codegenVersion = "1.0.23",
sourceFile = "frameworks/base/core/java/android/hardware/fingerprint/FingerprintAuthenticateOptions.java",
inputSignatures = "private final int mUserId\nprivate final int mSensorId\nprivate final boolean mIgnoreEnrollmentState\nprivate final @android.hardware.biometrics.AuthenticateOptions.DisplayState int mDisplayState\nprivate @android.annotation.NonNull java.lang.String mOpPackageName\nprivate @android.annotation.Nullable java.lang.String mAttributionTag\nprivate static int defaultUserId()\nprivate static int defaultSensorId()\nprivate static boolean defaultIgnoreEnrollmentState()\nprivate static int defaultDisplayState()\nprivate static java.lang.String defaultOpPackageName()\nprivate static java.lang.String defaultAttributionTag()\nclass FingerprintAuthenticateOptions extends java.lang.Object implements [android.hardware.biometrics.AuthenticateOptions, android.os.Parcelable]\n@com.android.internal.util.DataClass(genParcelable=true, genAidl=true, genBuilder=true, genSetters=true, genEqualsHashCode=true)")
@Deprecated
private void __metadata() {}
//@formatter:on
// End of generated code
}

View File

@@ -577,8 +577,10 @@ public class FingerprintManager implements BiometricAuthenticator, BiometricFing
/**
* Per-user version of authenticate.
* @deprecated use {@link #authenticate(CryptoObject, CancellationSignal, AuthenticationCallback, Handler, FingerprintAuthenticateOptions)}.
* @hide
*/
@Deprecated
@RequiresPermission(anyOf = {USE_BIOMETRIC, USE_FINGERPRINT})
public void authenticate(@Nullable CryptoObject crypto, @Nullable CancellationSignal cancel,
@NonNull AuthenticationCallback callback, Handler handler, int userId) {
@@ -587,13 +589,29 @@ public class FingerprintManager implements BiometricAuthenticator, BiometricFing
/**
* Per-user and per-sensor version of authenticate.
* @deprecated use {@link #authenticate(CryptoObject, CancellationSignal, AuthenticationCallback, Handler, FingerprintAuthenticateOptions)}.
* @hide
*/
@Deprecated
@RequiresPermission(anyOf = {USE_BIOMETRIC, USE_FINGERPRINT})
public void authenticate(@Nullable CryptoObject crypto, @Nullable CancellationSignal cancel,
@NonNull AuthenticationCallback callback, Handler handler, int sensorId, int userId,
int flags) {
authenticate(crypto, cancel, callback, handler, new FingerprintAuthenticateOptions.Builder()
.setSensorId(sensorId)
.setUserId(userId)
.setIgnoreEnrollmentState(flags != 0)
.build());
}
/**
* Version of authenticate with additional options.
* @hide
*/
@RequiresPermission(anyOf = {USE_BIOMETRIC, USE_FINGERPRINT})
public void authenticate(@Nullable CryptoObject crypto, @Nullable CancellationSignal cancel,
@NonNull AuthenticationCallback callback, @NonNull Handler handler,
@NonNull FingerprintAuthenticateOptions options) {
FrameworkStatsLog.write(FrameworkStatsLog.AUTH_DEPRECATED_API_USED,
AUTH_DEPRECATED_APIUSED__DEPRECATED_API__API_FINGERPRINT_MANAGER_AUTHENTICATE,
mContext.getApplicationInfo().uid,
@@ -608,7 +626,8 @@ public class FingerprintManager implements BiometricAuthenticator, BiometricFing
return;
}
final boolean ignoreEnrollmentState = flags == 0 ? false : true;
options.setOpPackageName(mContext.getOpPackageName());
options.setAttributionTag(mContext.getAttributionTag());
if (mService != null) {
try {
@@ -616,16 +635,7 @@ public class FingerprintManager implements BiometricAuthenticator, BiometricFing
mAuthenticationCallback = callback;
mCryptoObject = crypto;
final long operationId = crypto != null ? crypto.getOpId() : 0;
final long authId =
mService.authenticate(
mToken,
operationId,
sensorId,
userId,
mServiceReceiver,
mContext.getOpPackageName(),
mContext.getAttributionTag(),
ignoreEnrollmentState);
final long authId = mService.authenticate(mToken, operationId, mServiceReceiver, options);
if (cancel != null) {
cancel.setOnCancelListener(new OnAuthenticationCancelListener(authId));
}
@@ -647,7 +657,7 @@ public class FingerprintManager implements BiometricAuthenticator, BiometricFing
*/
@RequiresPermission(USE_BIOMETRIC_INTERNAL)
public void detectFingerprint(@NonNull CancellationSignal cancel,
@NonNull FingerprintDetectionCallback callback, int userId) {
@NonNull FingerprintDetectionCallback callback, @NonNull FingerprintAuthenticateOptions options) {
if (mService == null) {
return;
}
@@ -657,11 +667,13 @@ public class FingerprintManager implements BiometricAuthenticator, BiometricFing
return;
}
options.setOpPackageName(mContext.getOpPackageName());
options.setAttributionTag(mContext.getAttributionTag());
mFingerprintDetectionCallback = callback;
try {
final long authId = mService.detectFingerprint(mToken, userId, mServiceReceiver,
mContext.getOpPackageName());
final long authId = mService.detectFingerprint(mToken, mServiceReceiver, options);
cancel.setOnCancelListener(new OnFingerprintDetectionCancelListener(authId));
} catch (RemoteException e) {
Slog.w(TAG, "Remote exception when requesting finger detect", e);

View File

@@ -29,6 +29,7 @@ import android.hardware.fingerprint.IUdfpsOverlayController;
import android.hardware.fingerprint.ISidefpsController;
import android.hardware.fingerprint.IUdfpsOverlay;
import android.hardware.fingerprint.Fingerprint;
import android.hardware.fingerprint.FingerprintAuthenticateOptions;
import android.hardware.fingerprint.FingerprintSensorPropertiesInternal;
import java.util.List;
@@ -56,16 +57,15 @@ interface IFingerprintService {
// Authenticate with a fingerprint. This is protected by USE_FINGERPRINT/USE_BIOMETRIC
// permission. This is effectively deprecated, since it only comes through FingerprintManager
// now. A requestId is returned that can be used to cancel this operation.
long authenticate(IBinder token, long operationId, int sensorId, int userId,
IFingerprintServiceReceiver receiver, String opPackageName, String attributionTag,
boolean shouldIgnoreEnrollmentState);
long authenticate(IBinder token, long operationId, IFingerprintServiceReceiver receiver,
in FingerprintAuthenticateOptions options);
// Uses the fingerprint hardware to detect for the presence of a finger, without giving details
// about accept/reject/lockout. A requestId is returned that can be used to cancel this
// operation.
@EnforcePermission("USE_BIOMETRIC_INTERNAL")
long detectFingerprint(IBinder token, int userId, IFingerprintServiceReceiver receiver,
String opPackageName);
long detectFingerprint(IBinder token, IFingerprintServiceReceiver receiver,
in FingerprintAuthenticateOptions options);
// This method prepares the service to start authenticating, but doesn't start authentication.
// This is protected by the MANAGE_BIOMETRIC signatuer permission. This method should only be

View File

@@ -0,0 +1,151 @@
/*
* Copyright (C) 2023 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.face;
import static android.hardware.biometrics.BiometricFaceConstants.FACE_ERROR_HW_UNAVAILABLE;
import static com.google.common.truth.Truth.assertThat;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.anyLong;
import static org.mockito.Mockito.eq;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import android.content.Context;
import android.content.pm.ApplicationInfo;
import android.content.res.Resources;
import android.os.CancellationSignal;
import android.os.Handler;
import android.os.IBinder;
import android.os.RemoteException;
import android.os.test.TestLooper;
import android.platform.test.annotations.Presubmit;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.ArgumentCaptor;
import org.mockito.Captor;
import org.mockito.Mock;
import org.mockito.junit.MockitoJUnit;
import org.mockito.junit.MockitoJUnitRunner;
import org.mockito.junit.MockitoRule;
import java.util.ArrayList;
import java.util.List;
@Presubmit
@RunWith(MockitoJUnitRunner.class)
public class FaceManagerTest {
private static final int USER_ID = 4;
private static final String PACKAGE_NAME = "f.m.test";
private static final String ATTRIBUTION_TAG = "blue";
@Rule
public final MockitoRule mockito = MockitoJUnit.rule();
@Mock
private Context mContext;
@Mock
private Resources mResources;
@Mock
private IFaceService mService;
@Mock
private FaceManager.AuthenticationCallback mAuthCallback;
@Captor
private ArgumentCaptor<IFaceAuthenticatorsRegisteredCallback> mCaptor;
@Captor
private ArgumentCaptor<FaceAuthenticateOptions> mOptionsCaptor;
private List<FaceSensorPropertiesInternal> mProps;
private TestLooper mLooper;
private Handler mHandler;
private FaceManager mFaceManager;
@Before
public void setUp() throws Exception {
mLooper = new TestLooper();
mHandler = new Handler(mLooper.getLooper());
when(mContext.getMainLooper()).thenReturn(mLooper.getLooper());
when(mContext.getOpPackageName()).thenReturn(PACKAGE_NAME);
when(mContext.getAttributionTag()).thenReturn(ATTRIBUTION_TAG);
when(mContext.getApplicationInfo()).thenReturn(new ApplicationInfo());
when(mContext.getResources()).thenReturn(mResources);
when(mResources.getString(anyInt())).thenReturn("string");
mFaceManager = new FaceManager(mContext, mService);
mProps = List.of(new FaceSensorPropertiesInternal(
0 /* id */,
FaceSensorProperties.STRENGTH_STRONG,
1 /* maxTemplatesAllowed */,
new ArrayList<>() /* componentInfo */,
FaceSensorProperties.TYPE_UNKNOWN,
true /* supportsFaceDetection */,
true /* supportsSelfIllumination */,
false /* resetLockoutRequiresChallenge */));
}
@Test
public void getSensorPropertiesInternal_noBinderCalls() throws RemoteException {
verify(mService).addAuthenticatorsRegisteredCallback(mCaptor.capture());
mCaptor.getValue().onAllAuthenticatorsRegistered(mProps);
List<FaceSensorPropertiesInternal> actual = mFaceManager.getSensorPropertiesInternal();
assertThat(actual).isEqualTo(mProps);
verify(mService, never()).getSensorPropertiesInternal(any());
}
@Test
public void authenticate_withOptions() throws Exception {
mFaceManager.authenticate(null, new CancellationSignal(), mAuthCallback, mHandler,
new FaceAuthenticateOptions.Builder()
.setUserId(USER_ID)
.setOpPackageName("some.thing")
.setAttributionTag(null)
.build());
verify(mService).authenticate(any(IBinder.class), eq(0L),
any(IFaceServiceReceiver.class), mOptionsCaptor.capture());
assertThat(mOptionsCaptor.getValue()).isEqualTo(
new FaceAuthenticateOptions.Builder()
.setUserId(USER_ID)
.setOpPackageName(PACKAGE_NAME)
.setAttributionTag(ATTRIBUTION_TAG)
.build()
);
}
@Test
public void authenticate_errorWhenUnavailable() throws Exception {
when(mService.authenticate(any(), anyLong(), any(), any()))
.thenThrow(new RemoteException());
mFaceManager.authenticate(null, new CancellationSignal(),
mAuthCallback, mHandler,
new FaceAuthenticateOptions.Builder().build());
verify(mAuthCallback).onAuthenticationError(eq(FACE_ERROR_HW_UNAVAILABLE), any());
}
}

View File

@@ -0,0 +1 @@
include /services/core/java/com/android/server/biometrics/OWNERS

View File

@@ -0,0 +1,152 @@
/*
* Copyright (C) 2023 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.fingerprint;
import static android.hardware.biometrics.BiometricFingerprintConstants.FINGERPRINT_ERROR_HW_UNAVAILABLE;
import static com.google.common.truth.Truth.assertThat;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.anyLong;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import android.content.Context;
import android.content.pm.ApplicationInfo;
import android.content.res.Resources;
import android.os.CancellationSignal;
import android.os.Handler;
import android.os.IBinder;
import android.os.RemoteException;
import android.os.test.TestLooper;
import android.platform.test.annotations.Presubmit;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.ArgumentCaptor;
import org.mockito.Captor;
import org.mockito.Mock;
import org.mockito.junit.MockitoJUnit;
import org.mockito.junit.MockitoJUnitRunner;
import org.mockito.junit.MockitoRule;
import java.util.ArrayList;
import java.util.List;
@Presubmit
@RunWith(MockitoJUnitRunner.class)
public class FingerprintManagerTest {
private static final int USER_ID = 9;
private static final String PACKAGE_NAME = "finger.food.test";
private static final String ATTRIBUTION_TAG = "taz";
@Rule
public final MockitoRule mockito = MockitoJUnit.rule();
@Mock
private Context mContext;
@Mock
private Resources mResources;
@Mock
private IFingerprintService mService;
@Mock
private FingerprintManager.AuthenticationCallback mAuthCallback;
@Captor
private ArgumentCaptor<IFingerprintAuthenticatorsRegisteredCallback> mCaptor;
@Captor
private ArgumentCaptor<FingerprintAuthenticateOptions> mOptionsCaptor;
private List<FingerprintSensorPropertiesInternal> mProps;
private TestLooper mLooper;
private Handler mHandler;
private FingerprintManager mFingerprintManager;
@Before
public void setUp() throws Exception {
mLooper = new TestLooper();
mHandler = new Handler(mLooper.getLooper());
when(mContext.getMainLooper()).thenReturn(mLooper.getLooper());
when(mContext.getOpPackageName()).thenReturn(PACKAGE_NAME);
when(mContext.getAttributionTag()).thenReturn(ATTRIBUTION_TAG);
when(mContext.getApplicationInfo()).thenReturn(new ApplicationInfo());
when(mContext.getResources()).thenReturn(mResources);
when(mResources.getString(anyInt())).thenReturn("string");
mFingerprintManager = new FingerprintManager(mContext, mService);
mProps = List.of(new FingerprintSensorPropertiesInternal(
0 /* sensorId */,
FingerprintSensorProperties.STRENGTH_STRONG,
1 /* maxEnrollmentsPerUser */,
new ArrayList<>() /* componentInfo */,
FingerprintSensorProperties.TYPE_UNKNOWN,
true /* halControlsIllumination */,
true /* resetLockoutRequiresHardwareAuthToken */,
new ArrayList<>() /* sensorLocations */));
}
@Test
public void getSensorPropertiesInternal_noBinderCalls() throws RemoteException {
verify(mService).addAuthenticatorsRegisteredCallback(mCaptor.capture());
mCaptor.getValue().onAllAuthenticatorsRegistered(mProps);
List<FingerprintSensorPropertiesInternal> actual =
mFingerprintManager.getSensorPropertiesInternal();
assertThat(actual).isEqualTo(mProps);
verify(mService, never()).getSensorPropertiesInternal(any());
}
@Test
public void authenticate_withOptions() throws Exception {
mFingerprintManager.authenticate(null, new CancellationSignal(), mAuthCallback, mHandler,
new FingerprintAuthenticateOptions.Builder()
.setUserId(USER_ID)
.setOpPackageName("some.thing")
.setAttributionTag(null)
.build());
verify(mService).authenticate(any(IBinder.class), eq(0L),
any(IFingerprintServiceReceiver.class), mOptionsCaptor.capture());
assertThat(mOptionsCaptor.getValue()).isEqualTo(
new FingerprintAuthenticateOptions.Builder()
.setUserId(USER_ID)
.setOpPackageName(PACKAGE_NAME)
.setAttributionTag(ATTRIBUTION_TAG)
.build()
);
}
@Test
public void authenticate_errorWhenUnavailable() throws Exception {
when(mService.authenticate(any(), anyLong(), any(), any()))
.thenThrow(new RemoteException());
mFingerprintManager.authenticate(null, new CancellationSignal(),
mAuthCallback, mHandler,
new FingerprintAuthenticateOptions.Builder().build());
verify(mAuthCallback).onAuthenticationError(eq(FINGERPRINT_ERROR_HW_UNAVAILABLE), any());
}
}

View File

@@ -0,0 +1 @@
include /services/core/java/com/android/server/biometrics/OWNERS

View File

@@ -96,8 +96,10 @@ import android.hardware.biometrics.BiometricManager;
import android.hardware.biometrics.BiometricSourceType;
import android.hardware.biometrics.IBiometricEnabledOnKeyguardCallback;
import android.hardware.biometrics.SensorProperties;
import android.hardware.face.FaceAuthenticateOptions;
import android.hardware.face.FaceManager;
import android.hardware.face.FaceSensorPropertiesInternal;
import android.hardware.fingerprint.FingerprintAuthenticateOptions;
import android.hardware.fingerprint.FingerprintManager;
import android.hardware.fingerprint.FingerprintManager.AuthenticationCallback;
import android.hardware.fingerprint.FingerprintManager.AuthenticationResult;
@@ -2942,7 +2944,9 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab
// Trigger the fingerprint success path so the bouncer can be shown
handleFingerprintAuthenticated(user, isStrongBiometric);
},
userId);
new FingerprintAuthenticateOptions.Builder()
.setUserId(userId)
.build());
} else {
mLogger.v("startListeningForFingerprint - authenticate");
mFpm.authenticate(null /* crypto */, mFingerprintCancelSignal,
@@ -2988,7 +2992,10 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab
if (supportsFaceDetection && !udfpsFingerprintAuthRunning) {
// Run face detection. (If a face is detected, show the bouncer.)
mLogger.v("startListeningForFace - detect");
mFaceManager.detectFace(mFaceCancelSignal, mFaceDetectionCallback, userId);
mFaceManager.detectFace(mFaceCancelSignal, mFaceDetectionCallback,
new FaceAuthenticateOptions.Builder()
.setUserId(userId)
.build());
} else {
// Don't run face detection. Instead, inform the user
// face auth is unavailable and how to proceed.
@@ -3007,7 +3014,7 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab
final boolean isBypassEnabled = mKeyguardBypassController != null
&& mKeyguardBypassController.isBypassEnabled();
mFaceManager.authenticate(null /* crypto */, mFaceCancelSignal,
mFaceAuthenticationCallback, null /* handler */, userId, isBypassEnabled);
mFaceAuthenticationCallback, null /* handler */, userId);
}
setFaceRunningState(BIOMETRIC_STATE_RUNNING);
}

View File

@@ -18,6 +18,7 @@ package com.android.systemui.keyguard.data.repository
import android.app.StatusBarManager
import android.content.Context
import android.hardware.face.FaceAuthenticateOptions
import android.hardware.face.FaceManager
import android.os.CancellationSignal
import com.android.internal.logging.InstanceId
@@ -235,8 +236,7 @@ constructor(
cancellationSignal,
faceAuthCallback,
null,
currentUserId,
lockscreenBypassEnabled
FaceAuthenticateOptions.Builder().setUserId(currentUserId).build()
)
}
}
@@ -255,7 +255,11 @@ constructor(
withContext(mainDispatcher) {
// We always want to invoke face detect in the main thread.
faceAuthLogger.faceDetectionStarted()
faceManager?.detectFace(cancellationSignal, detectionCallback, currentUserId)
faceManager?.detectFace(
cancellationSignal,
detectionCallback,
FaceAuthenticateOptions.Builder().setUserId(currentUserId).build()
)
}
}

View File

@@ -617,7 +617,7 @@ public class KeyguardUpdateMonitorTest extends SysuiTestCase {
verify(mFingerprintManager).authenticate(any(), any(), any(), any(), anyInt(), anyInt(),
anyInt());
verify(mFingerprintManager, never()).detectFingerprint(any(), any(), anyInt());
verify(mFingerprintManager, never()).detectFingerprint(any(), any(), any());
}
@Test
@@ -629,7 +629,7 @@ public class KeyguardUpdateMonitorTest extends SysuiTestCase {
verify(mFingerprintManager, never()).authenticate(any(), any(), any(), any(), anyInt(),
anyInt(), anyInt());
verify(mFingerprintManager, never()).detectFingerprint(any(), any(), anyInt());
verify(mFingerprintManager, never()).detectFingerprint(any(), any(), any());
}
@Test
@@ -644,7 +644,7 @@ public class KeyguardUpdateMonitorTest extends SysuiTestCase {
mTestableLooper.processAllMessages();
verify(mFingerprintManager, never()).authenticate(any(), any(), any(), any(), anyInt());
verify(mFingerprintManager).detectFingerprint(any(), any(), anyInt());
verify(mFingerprintManager).detectFingerprint(any(), any(), any());
}
@Test
@@ -733,7 +733,7 @@ public class KeyguardUpdateMonitorTest extends SysuiTestCase {
public void testTriesToAuthenticate_whenBouncer() {
setKeyguardBouncerVisibility(true);
verify(mFaceManager).authenticate(any(), any(), any(), any(), anyInt(), anyBoolean());
verify(mFaceManager).authenticate(any(), any(), any(), any(), anyInt());
verify(mFaceManager, never()).hasEnrolledTemplates(anyInt());
}
@@ -742,8 +742,7 @@ public class KeyguardUpdateMonitorTest extends SysuiTestCase {
mKeyguardUpdateMonitor.sendPrimaryBouncerChanged(
/* bouncerIsOrWillBeShowing */ true, /* bouncerFullyShown */ false);
verify(mFaceManager, never()).authenticate(any(), any(), any(), any(), anyInt(),
anyBoolean());
verify(mFaceManager, never()).authenticate(any(), any(), any(), any(), anyInt());
}
@Test
@@ -751,7 +750,7 @@ public class KeyguardUpdateMonitorTest extends SysuiTestCase {
keyguardIsVisible();
mKeyguardUpdateMonitor.dispatchStartedWakingUp(PowerManager.WAKE_REASON_POWER_BUTTON);
mTestableLooper.processAllMessages();
verify(mFaceManager).authenticate(any(), any(), any(), any(), anyInt(), anyBoolean());
verify(mFaceManager).authenticate(any(), any(), any(), any(), anyInt());
verify(mUiEventLogger).logWithInstanceIdAndPosition(
eq(FaceAuthUiEvent.FACE_AUTH_UPDATED_STARTED_WAKING_UP),
eq(0),
@@ -767,8 +766,7 @@ public class KeyguardUpdateMonitorTest extends SysuiTestCase {
mTestableLooper.processAllMessages();
keyguardIsVisible();
verify(mFaceManager, never()).authenticate(any(), any(), any(), any(), anyInt(),
anyBoolean());
verify(mFaceManager, never()).authenticate(any(), any(), any(), any(), anyInt());
}
@Test
@@ -779,8 +777,7 @@ public class KeyguardUpdateMonitorTest extends SysuiTestCase {
mKeyguardUpdateMonitor.dispatchStartedWakingUp(PowerManager.WAKE_REASON_POWER_BUTTON);
mTestableLooper.processAllMessages();
keyguardIsVisible();
verify(mFaceManager, never()).authenticate(any(), any(), any(), any(), anyInt(),
anyBoolean());
verify(mFaceManager, never()).authenticate(any(), any(), any(), any(), anyInt());
}
@Test
@@ -804,9 +801,8 @@ public class KeyguardUpdateMonitorTest extends SysuiTestCase {
mTestableLooper.processAllMessages();
// THEN face detect and authenticate are NOT triggered
verify(mFaceManager, never()).detectFace(any(), any(), anyInt());
verify(mFaceManager, never()).authenticate(any(), any(), any(), any(), anyInt(),
anyBoolean());
verify(mFaceManager, never()).detectFace(any(), any(), any());
verify(mFaceManager, never()).authenticate(any(), any(), any(), any(), anyInt());
// THEN biometric help message sent to callback
verify(keyguardUpdateMonitorCallback).onBiometricHelp(
@@ -827,9 +823,8 @@ public class KeyguardUpdateMonitorTest extends SysuiTestCase {
mTestableLooper.processAllMessages();
// FACE detect is triggered, not authenticate
verify(mFaceManager).detectFace(any(), any(), anyInt());
verify(mFaceManager, never()).authenticate(any(), any(), any(), any(), anyInt(),
anyBoolean());
verify(mFaceManager).detectFace(any(), any(), any());
verify(mFaceManager, never()).authenticate(any(), any(), any(), any(), anyInt());
// WHEN bouncer becomes visible
setKeyguardBouncerVisibility(true);
@@ -837,9 +832,8 @@ public class KeyguardUpdateMonitorTest extends SysuiTestCase {
// THEN face scanning is not run
mKeyguardUpdateMonitor.requestFaceAuth(FaceAuthApiRequestReason.UDFPS_POINTER_DOWN);
verify(mFaceManager, never()).authenticate(any(), any(), any(), any(), anyInt(),
anyBoolean());
verify(mFaceManager, never()).detectFace(any(), any(), anyInt());
verify(mFaceManager, never()).authenticate(any(), any(), any(), any(), anyInt());
verify(mFaceManager, never()).detectFace(any(), any(), any());
}
@Test
@@ -854,9 +848,8 @@ public class KeyguardUpdateMonitorTest extends SysuiTestCase {
mTestableLooper.processAllMessages();
// FACE detect and authenticate are NOT triggered
verify(mFaceManager, never()).detectFace(any(), any(), anyInt());
verify(mFaceManager, never()).authenticate(any(), any(), any(), any(), anyInt(),
anyBoolean());
verify(mFaceManager, never()).detectFace(any(), any(), any());
verify(mFaceManager, never()).authenticate(any(), any(), any(), any(), anyInt());
}
@Test
@@ -894,7 +887,7 @@ public class KeyguardUpdateMonitorTest extends SysuiTestCase {
mKeyguardUpdateMonitor.setKeyguardShowing(true, true);
mKeyguardUpdateMonitor.setAssistantVisible(true);
verify(mFaceManager).authenticate(any(), any(), any(), any(), anyInt(), anyBoolean());
verify(mFaceManager).authenticate(any(), any(), any(), any(), anyInt());
}
@Test
@@ -906,8 +899,7 @@ public class KeyguardUpdateMonitorTest extends SysuiTestCase {
any(),
any(),
any(),
anyInt(),
anyBoolean());
anyInt());
}
@Test
@@ -938,7 +930,7 @@ public class KeyguardUpdateMonitorTest extends SysuiTestCase {
KeyguardUpdateMonitor.getCurrentUser(), 0 /* flags */,
new ArrayList<>());
keyguardIsVisible();
verify(mFaceManager).authenticate(any(), any(), any(), any(), anyInt(), anyBoolean());
verify(mFaceManager).authenticate(any(), any(), any(), any(), anyInt());
}
@Test
@@ -946,7 +938,7 @@ public class KeyguardUpdateMonitorTest extends SysuiTestCase {
mKeyguardUpdateMonitor.setKeyguardShowing(true, true);
mKeyguardUpdateMonitor.setAssistantVisible(true);
verify(mFaceManager).authenticate(any(), any(), any(), any(), anyInt(), anyBoolean());
verify(mFaceManager).authenticate(any(), any(), any(), any(), anyInt());
mTestableLooper.processAllMessages();
clearInvocations(mFaceManager);
@@ -963,8 +955,7 @@ public class KeyguardUpdateMonitorTest extends SysuiTestCase {
any(),
any(),
any(),
anyInt(),
anyBoolean());
anyInt());
}
@Test
@@ -974,8 +965,7 @@ public class KeyguardUpdateMonitorTest extends SysuiTestCase {
mKeyguardUpdateMonitor.onTrustChanged(true /* enabled */, true /* newlyUnlocked */,
KeyguardUpdateMonitor.getCurrentUser(), 0 /* flags */, new ArrayList<>());
keyguardIsVisible();
verify(mFaceManager, never()).authenticate(any(), any(), any(), any(), anyInt(),
anyBoolean());
verify(mFaceManager, never()).authenticate(any(), any(), any(), any(), anyInt());
}
@Test
@@ -987,9 +977,8 @@ public class KeyguardUpdateMonitorTest extends SysuiTestCase {
keyguardIsVisible();
mTestableLooper.processAllMessages();
verify(mFaceManager, never()).authenticate(any(), any(), any(), any(), anyInt(),
anyBoolean());
verify(mFaceManager, never()).detectFace(any(), any(), anyInt());
verify(mFaceManager, never()).authenticate(any(), any(), any(), any(), anyInt());
verify(mFaceManager, never()).detectFace(any(), any(), any());
}
@Test
@@ -1019,8 +1008,7 @@ public class KeyguardUpdateMonitorTest extends SysuiTestCase {
setKeyguardBouncerVisibility(true);
mTestableLooper.processAllMessages();
verify(mFaceManager, never()).authenticate(any(), any(), any(), any(), anyInt(),
anyBoolean());
verify(mFaceManager, never()).authenticate(any(), any(), any(), any(), anyInt());
}
@Test
@@ -1147,7 +1135,7 @@ public class KeyguardUpdateMonitorTest extends SysuiTestCase {
mTestableLooper.processAllMessages();
keyguardIsVisible();
verify(mFaceManager).authenticate(any(), any(), any(), any(), anyInt(), anyBoolean());
verify(mFaceManager).authenticate(any(), any(), any(), any(), anyInt());
verify(mFingerprintManager).authenticate(any(), any(), any(), any(), anyInt(), anyInt(),
anyInt());
@@ -1599,8 +1587,7 @@ public class KeyguardUpdateMonitorTest extends SysuiTestCase {
mKeyguardUpdateMonitor.setCredentialAttempted();
verify(mFingerprintManager, never()).authenticate(any(), any(), any(),
any(), anyInt());
verify(mFaceManager, never()).authenticate(any(), any(), any(), any(), anyInt(),
anyBoolean());
verify(mFaceManager, never()).authenticate(any(), any(), any(), any(), anyInt());
}
@Test
@@ -1975,7 +1962,7 @@ public class KeyguardUpdateMonitorTest extends SysuiTestCase {
mTestableLooper.processAllMessages();
keyguardIsVisible();
verify(mFaceManager).authenticate(any(), any(), any(), any(), anyInt(), anyBoolean());
verify(mFaceManager).authenticate(any(), any(), any(), any(), anyInt());
verify(mFingerprintManager).authenticate(any(), any(), any(), any(), anyInt(), anyInt(),
anyInt());
@@ -2004,7 +1991,7 @@ public class KeyguardUpdateMonitorTest extends SysuiTestCase {
mTestableLooper.processAllMessages();
verify(mFaceManager, never()).authenticate(
any(), any(), any(), any(), anyInt(), anyBoolean());
any(), any(), any(), any(), anyInt());
}
@Test
@@ -2018,14 +2005,14 @@ public class KeyguardUpdateMonitorTest extends SysuiTestCase {
// THEN face auth isn't triggered
verify(mFaceManager, never()).authenticate(
any(), any(), any(), any(), anyInt(), anyBoolean());
any(), any(), any(), any(), anyInt());
// WHEN device wakes up from the power button
mKeyguardUpdateMonitor.dispatchStartedWakingUp(PowerManager.WAKE_REASON_POWER_BUTTON);
mTestableLooper.processAllMessages();
// THEN face auth is triggered
verify(mFaceManager).authenticate(any(), any(), any(), any(), anyInt(), anyBoolean());
verify(mFaceManager).authenticate(any(), any(), any(), any(), anyInt());
}
@Test
@@ -2195,7 +2182,7 @@ public class KeyguardUpdateMonitorTest extends SysuiTestCase {
mTestableLooper.processAllMessages();
keyguardIsVisible();
verify(mFaceManager).authenticate(any(), any(), any(), any(), anyInt(), anyBoolean());
verify(mFaceManager).authenticate(any(), any(), any(), any(), anyInt());
verify(mFingerprintManager).authenticate(any(), any(), any(), any(), anyInt(), anyInt(),
anyInt());
@@ -2228,7 +2215,7 @@ public class KeyguardUpdateMonitorTest extends SysuiTestCase {
mTestableLooper.processAllMessages();
keyguardIsVisible();
verify(mFaceManager).authenticate(any(), any(), any(), any(), anyInt(), anyBoolean());
verify(mFaceManager).authenticate(any(), any(), any(), any(), anyInt());
final CancellationSignal faceCancel = spy(mKeyguardUpdateMonitor.mFaceCancelSignal);
mKeyguardUpdateMonitor.mFaceCancelSignal = faceCancel;
@@ -2596,8 +2583,7 @@ public class KeyguardUpdateMonitorTest extends SysuiTestCase {
any(),
mAuthenticationCallbackCaptor.capture(),
any(),
anyInt(),
anyBoolean());
anyInt());
mAuthenticationCallbackCaptor.getValue()
.onAuthenticationSucceeded(
new FaceManager.AuthenticationResult(null, null, mCurrentUserId, false));

View File

@@ -21,6 +21,7 @@ import android.content.pm.UserInfo
import android.hardware.biometrics.BiometricFaceConstants.FACE_ERROR_CANCELED
import android.hardware.biometrics.BiometricFaceConstants.FACE_ERROR_LOCKOUT_PERMANENT
import android.hardware.biometrics.ComponentInfoInternal
import android.hardware.face.FaceAuthenticateOptions
import android.hardware.face.FaceManager
import android.hardware.face.FaceSensorProperties
import android.hardware.face.FaceSensorPropertiesInternal
@@ -62,7 +63,6 @@ import org.junit.runner.RunWith
import org.junit.runners.JUnit4
import org.mockito.ArgumentCaptor
import org.mockito.ArgumentMatchers.any
import org.mockito.ArgumentMatchers.anyInt
import org.mockito.ArgumentMatchers.eq
import org.mockito.Captor
import org.mockito.Mock
@@ -276,7 +276,7 @@ class KeyguardFaceAuthManagerTest : SysuiTestCase() {
underTest.detect()
verify(faceManager, never()).detectFace(any(), any(), anyInt())
verify(faceManager, never()).detectFace(any(), any(), any())
}
@Test
@@ -379,7 +379,7 @@ class KeyguardFaceAuthManagerTest : SysuiTestCase() {
.detectFace(
cancellationSignal.capture(),
detectionCallback.capture(),
eq(currentUserId)
eq(FaceAuthenticateOptions.Builder().setUserId(currentUserId).build())
)
}
@@ -390,8 +390,7 @@ class KeyguardFaceAuthManagerTest : SysuiTestCase() {
cancellationSignal.capture(),
authenticationCallback.capture(),
isNull(),
eq(currentUserId),
eq(true)
eq(FaceAuthenticateOptions.Builder().setUserId(currentUserId).build())
)
}

View File

@@ -75,7 +75,6 @@ public abstract class AuthenticationClient<T> extends AcquisitionClient<T>
private final LockoutTracker mLockoutTracker;
private final boolean mIsRestricted;
private final boolean mAllowBackgroundAuthentication;
private final boolean mIsKeyguardBypassEnabled;
// TODO: This is currently hard to maintain, as each AuthenticationClient subclass must update
// the state. We should think of a way to improve this in the future.
@State
@@ -95,7 +94,7 @@ public abstract class AuthenticationClient<T> extends AcquisitionClient<T>
@NonNull BiometricLogger biometricLogger, @NonNull BiometricContext biometricContext,
boolean isStrongBiometric, @Nullable TaskStackListener taskStackListener,
@NonNull LockoutTracker lockoutTracker, boolean allowBackgroundAuthentication,
boolean shouldVibrate, boolean isKeyguardBypassEnabled, int sensorStrength) {
boolean shouldVibrate, int sensorStrength) {
super(context, lazyDaemon, token, listener, targetUserId, owner, cookie, sensorId,
shouldVibrate, biometricLogger, biometricContext);
mIsStrongBiometric = isStrongBiometric;
@@ -107,7 +106,6 @@ public abstract class AuthenticationClient<T> extends AcquisitionClient<T>
mLockoutTracker = lockoutTracker;
mIsRestricted = restricted;
mAllowBackgroundAuthentication = allowBackgroundAuthentication;
mIsKeyguardBypassEnabled = isKeyguardBypassEnabled;
mShouldUseLockoutTracker = lockoutTracker != null;
mSensorStrength = sensorStrength;
}
@@ -374,14 +372,6 @@ public abstract class AuthenticationClient<T> extends AcquisitionClient<T>
return mState;
}
/**
* @return true if the client supports bypass (e.g. passive auth such as face), and if it's
* enabled by the user.
*/
public boolean isKeyguardBypassEnabled() {
return mIsKeyguardBypassEnabled;
}
@Override
public int getProtoEnum() {
return BiometricsProto.CM_AUTHENTICATE;

View File

@@ -23,6 +23,7 @@ import android.hardware.biometrics.IInvalidationCallback;
import android.hardware.biometrics.ITestSession;
import android.hardware.biometrics.ITestSessionCallback;
import android.hardware.biometrics.SensorPropertiesInternal;
import android.hardware.face.FaceAuthenticateOptions;
import android.hardware.face.IFaceService;
import android.os.IBinder;
import android.os.RemoteException;
@@ -64,8 +65,11 @@ public final class FaceAuthenticator extends IBiometricAuthenticator.Stub {
String opPackageName, long requestId, int cookie, boolean allowBackgroundAuthentication)
throws RemoteException {
mFaceService.prepareForAuthentication(mSensorId, requireConfirmation, token, operationId,
userId, sensorReceiver, opPackageName, requestId, cookie,
allowBackgroundAuthentication);
sensorReceiver, new FaceAuthenticateOptions.Builder()
.setUserId(userId)
.setOpPackageName(opPackageName)
.build(),
requestId, cookie, allowBackgroundAuthentication);
}
@Override

View File

@@ -35,6 +35,7 @@ import android.hardware.biometrics.ITestSessionCallback;
import android.hardware.biometrics.face.IFace;
import android.hardware.biometrics.face.SensorProps;
import android.hardware.face.Face;
import android.hardware.face.FaceAuthenticateOptions;
import android.hardware.face.FaceSensorPropertiesInternal;
import android.hardware.face.FaceServiceReceiver;
import android.hardware.face.IFaceAuthenticatorsRegisteredCallback;
@@ -238,14 +239,15 @@ public class FaceService extends SystemService {
@android.annotation.EnforcePermission(android.Manifest.permission.USE_BIOMETRIC_INTERNAL)
@Override // Binder call
public long authenticate(final IBinder token, final long operationId, int userId,
final IFaceServiceReceiver receiver, final String opPackageName,
boolean isKeyguardBypassEnabled) {
public long authenticate(final IBinder token, final long operationId,
final IFaceServiceReceiver receiver, final FaceAuthenticateOptions options) {
// TODO(b/152413782): If the sensor supports face detect and the device is encrypted or
// lockdown, something wrong happened. See similar path in FingerprintService.
super.authenticate_enforcePermission();
final int userId = options.getUserId();
final String opPackageName = options.getOpPackageName();
final boolean restricted = false; // Face APIs are private
final int statsClient = Utils.isKeyguard(getContext(), opPackageName)
? BiometricsProtoEnums.CLIENT_KEYGUARD
@@ -261,18 +263,18 @@ public class FaceService extends SystemService {
return -1;
}
return provider.second.scheduleAuthenticate(provider.first, token, operationId, userId,
0 /* cookie */,
new ClientMonitorCallbackConverter(receiver), opPackageName, restricted,
statsClient, isKeyguard, isKeyguardBypassEnabled);
return provider.second.scheduleAuthenticate(provider.first, token, operationId,
0 /* cookie */, new ClientMonitorCallbackConverter(receiver), options,
restricted, statsClient, isKeyguard);
}
@android.annotation.EnforcePermission(android.Manifest.permission.USE_BIOMETRIC_INTERNAL)
@Override // Binder call
public long detectFace(final IBinder token, final int userId,
final IFaceServiceReceiver receiver, final String opPackageName) {
public long detectFace(final IBinder token,
final IFaceServiceReceiver receiver, final FaceAuthenticateOptions options) {
super.detectFace_enforcePermission();
final String opPackageName = options.getOpPackageName();
if (!Utils.isKeyguard(getContext(), opPackageName)) {
Slog.w(TAG, "detectFace called from non-sysui package: " + opPackageName);
return -1;
@@ -284,7 +286,7 @@ public class FaceService extends SystemService {
return -1;
}
return provider.second.scheduleFaceDetect(provider.first, token, userId,
return provider.second.scheduleFaceDetect(provider.first, token, options.getUserId(),
new ClientMonitorCallbackConverter(receiver), opPackageName,
BiometricsProtoEnums.CLIENT_KEYGUARD);
}
@@ -292,9 +294,9 @@ public class FaceService extends SystemService {
@android.annotation.EnforcePermission(android.Manifest.permission.USE_BIOMETRIC_INTERNAL)
@Override // Binder call
public void prepareForAuthentication(int sensorId, boolean requireConfirmation,
IBinder token, long operationId, int userId,
IBiometricSensorReceiver sensorReceiver, String opPackageName, long requestId,
int cookie, boolean allowBackgroundAuthentication) {
IBinder token, long operationId, IBiometricSensorReceiver sensorReceiver,
FaceAuthenticateOptions options, long requestId, int cookie,
boolean allowBackgroundAuthentication) {
super.prepareForAuthentication_enforcePermission();
final ServiceProvider provider = mRegistry.getProviderForSensor(sensorId);
@@ -305,10 +307,10 @@ public class FaceService extends SystemService {
final boolean isKeyguardBypassEnabled = false; // only valid for keyguard clients
final boolean restricted = true; // BiometricPrompt is always restricted
provider.scheduleAuthenticate(sensorId, token, operationId, userId, cookie,
new ClientMonitorCallbackConverter(sensorReceiver), opPackageName, requestId,
provider.scheduleAuthenticate(sensorId, token, operationId, cookie,
new ClientMonitorCallbackConverter(sensorReceiver), options, requestId,
restricted, BiometricsProtoEnums.CLIENT_BIOMETRIC_PROMPT,
allowBackgroundAuthentication, isKeyguardBypassEnabled);
allowBackgroundAuthentication);
}
@android.annotation.EnforcePermission(android.Manifest.permission.USE_BIOMETRIC_INTERNAL)

View File

@@ -22,6 +22,7 @@ import android.hardware.biometrics.IInvalidationCallback;
import android.hardware.biometrics.ITestSession;
import android.hardware.biometrics.ITestSessionCallback;
import android.hardware.face.Face;
import android.hardware.face.FaceAuthenticateOptions;
import android.hardware.face.FaceManager;
import android.hardware.face.FaceSensorPropertiesInternal;
import android.hardware.face.IFaceServiceReceiver;
@@ -88,15 +89,15 @@ public interface ServiceProvider extends BiometricServiceProvider<FaceSensorProp
void cancelFaceDetect(int sensorId, @NonNull IBinder token, long requestId);
long scheduleAuthenticate(int sensorId, @NonNull IBinder token, long operationId, int userId,
long scheduleAuthenticate(int sensorId, @NonNull IBinder token, long operationId,
int cookie, @NonNull ClientMonitorCallbackConverter callback,
@NonNull String opPackageName, boolean restricted, int statsClient,
boolean allowBackgroundAuthentication, boolean isKeyguardBypassEnabled);
@NonNull FaceAuthenticateOptions options,
boolean restricted, int statsClient, boolean allowBackgroundAuthentication);
void scheduleAuthenticate(int sensorId, @NonNull IBinder token, long operationId, int userId,
void scheduleAuthenticate(int sensorId, @NonNull IBinder token, long operationId,
int cookie, @NonNull ClientMonitorCallbackConverter callback,
@NonNull String opPackageName, long requestId, boolean restricted, int statsClient,
boolean allowBackgroundAuthentication, boolean isKeyguardBypassEnabled);
@NonNull FaceAuthenticateOptions options, long requestId,
boolean restricted, int statsClient, boolean allowBackgroundAuthentication);
void cancelAuthentication(int sensorId, @NonNull IBinder token, long requestId);

View File

@@ -85,11 +85,11 @@ class FaceAuthenticationClient extends AuthenticationClient<AidlSession>
@NonNull BiometricLogger logger, @NonNull BiometricContext biometricContext,
boolean isStrongBiometric, @NonNull UsageStats usageStats,
@NonNull LockoutCache lockoutCache, boolean allowBackgroundAuthentication,
boolean isKeyguardBypassEnabled, @Authenticators.Types int sensorStrength) {
@Authenticators.Types int sensorStrength) {
this(context, lazyDaemon, token, requestId, listener, targetUserId, operationId,
restricted, owner, cookie, requireConfirmation, sensorId, logger, biometricContext,
isStrongBiometric, usageStats, lockoutCache /* lockoutCache */,
allowBackgroundAuthentication, isKeyguardBypassEnabled,
allowBackgroundAuthentication,
context.getSystemService(SensorPrivacyManager.class), sensorStrength);
}
@@ -102,13 +102,13 @@ class FaceAuthenticationClient extends AuthenticationClient<AidlSession>
@NonNull BiometricLogger logger, @NonNull BiometricContext biometricContext,
boolean isStrongBiometric, @NonNull UsageStats usageStats,
@NonNull LockoutCache lockoutCache, boolean allowBackgroundAuthentication,
boolean isKeyguardBypassEnabled, SensorPrivacyManager sensorPrivacyManager,
SensorPrivacyManager sensorPrivacyManager,
@Authenticators.Types int biometricStrength) {
super(context, lazyDaemon, token, listener, targetUserId, operationId, restricted,
owner, cookie, requireConfirmation, sensorId, logger, biometricContext,
isStrongBiometric, null /* taskStackListener */, null /* lockoutCache */,
allowBackgroundAuthentication, false /* shouldVibrate */,
isKeyguardBypassEnabled, biometricStrength);
biometricStrength);
setRequestId(requestId);
mUsageStats = usageStats;
mNotificationManager = context.getSystemService(NotificationManager.class);

View File

@@ -32,6 +32,7 @@ import android.hardware.biometrics.common.ComponentInfo;
import android.hardware.biometrics.face.IFace;
import android.hardware.biometrics.face.SensorProps;
import android.hardware.face.Face;
import android.hardware.face.FaceAuthenticateOptions;
import android.hardware.face.FaceSensorPropertiesInternal;
import android.hardware.face.IFaceServiceReceiver;
import android.os.Binder;
@@ -435,21 +436,21 @@ public class FaceProvider implements IBinder.DeathRecipient, ServiceProvider {
@Override
public void scheduleAuthenticate(int sensorId, @NonNull IBinder token, long operationId,
int userId, int cookie, @NonNull ClientMonitorCallbackConverter callback,
@NonNull String opPackageName, long requestId, boolean restricted, int statsClient,
boolean allowBackgroundAuthentication, boolean isKeyguardBypassEnabled) {
int cookie, @NonNull ClientMonitorCallbackConverter callback,
@NonNull FaceAuthenticateOptions options,
long requestId, boolean restricted, int statsClient,
boolean allowBackgroundAuthentication) {
mHandler.post(() -> {
final int userId = options.getUserId();
final boolean isStrongBiometric = Utils.isStrongBiometric(sensorId);
final FaceAuthenticationClient client = new FaceAuthenticationClient(
mContext, mSensors.get(sensorId).getLazySession(), token, requestId, callback,
userId, operationId, restricted, opPackageName, cookie,
userId, operationId, restricted, options.getOpPackageName(), cookie,
false /* requireConfirmation */, sensorId,
createLogger(BiometricsProtoEnums.ACTION_AUTHENTICATE, statsClient),
mBiometricContext, isStrongBiometric,
mUsageStats, mSensors.get(sensorId).getLockoutCache(),
allowBackgroundAuthentication, isKeyguardBypassEnabled,
Utils.getCurrentStrength(sensorId)
);
allowBackgroundAuthentication, Utils.getCurrentStrength(sensorId));
scheduleForSensor(sensorId, client, new ClientMonitorCallback() {
@Override
public void onClientStarted(
@@ -470,14 +471,13 @@ public class FaceProvider implements IBinder.DeathRecipient, ServiceProvider {
@Override
public long scheduleAuthenticate(int sensorId, @NonNull IBinder token, long operationId,
int userId, int cookie, @NonNull ClientMonitorCallbackConverter callback,
@NonNull String opPackageName, boolean restricted, int statsClient,
boolean allowBackgroundAuthentication, boolean isKeyguardBypassEnabled) {
int cookie, @NonNull ClientMonitorCallbackConverter callback,
@NonNull FaceAuthenticateOptions options, boolean restricted, int statsClient,
boolean allowBackgroundAuthentication) {
final long id = mRequestCounter.incrementAndGet();
scheduleAuthenticate(sensorId, token, operationId, userId, cookie, callback,
opPackageName, id, restricted, statsClient,
allowBackgroundAuthentication, isKeyguardBypassEnabled);
scheduleAuthenticate(sensorId, token, operationId, cookie, callback,
options, id, restricted, statsClient, allowBackgroundAuthentication);
return id;
}

View File

@@ -31,6 +31,7 @@ import android.hardware.biometrics.ITestSessionCallback;
import android.hardware.biometrics.face.V1_0.IBiometricsFace;
import android.hardware.biometrics.face.V1_0.IBiometricsFaceClientCallback;
import android.hardware.face.Face;
import android.hardware.face.FaceAuthenticateOptions;
import android.hardware.face.FaceSensorPropertiesInternal;
import android.hardware.face.IFaceServiceReceiver;
import android.os.Binder;
@@ -665,19 +666,20 @@ public class Face10 implements IHwBinder.DeathRecipient, ServiceProvider {
@Override
public void scheduleAuthenticate(int sensorId, @NonNull IBinder token, long operationId,
int userId, int cookie, @NonNull ClientMonitorCallbackConverter receiver,
@NonNull String opPackageName, long requestId, boolean restricted, int statsClient,
boolean allowBackgroundAuthentication, boolean isKeyguardBypassEnabled) {
int cookie, @NonNull ClientMonitorCallbackConverter receiver,
@NonNull FaceAuthenticateOptions options, long requestId, boolean restricted,
int statsClient, boolean allowBackgroundAuthentication) {
mHandler.post(() -> {
final int userId = options.getUserId();
scheduleUpdateActiveUserWithoutHandler(userId);
final boolean isStrongBiometric = Utils.isStrongBiometric(mSensorId);
final FaceAuthenticationClient client = new FaceAuthenticationClient(mContext,
mLazyDaemon, token, requestId, receiver, userId, operationId, restricted,
opPackageName, cookie, false /* requireConfirmation */, mSensorId,
options.getOpPackageName(), cookie, false /* requireConfirmation */, mSensorId,
createLogger(BiometricsProtoEnums.ACTION_AUTHENTICATE, statsClient),
mBiometricContext, isStrongBiometric, mLockoutTracker,
mUsageStats, allowBackgroundAuthentication, isKeyguardBypassEnabled,
mUsageStats, allowBackgroundAuthentication,
Utils.getCurrentStrength(mSensorId));
mScheduler.scheduleClientMonitor(client);
});
@@ -685,14 +687,13 @@ public class Face10 implements IHwBinder.DeathRecipient, ServiceProvider {
@Override
public long scheduleAuthenticate(int sensorId, @NonNull IBinder token, long operationId,
int userId, int cookie, @NonNull ClientMonitorCallbackConverter receiver,
@NonNull String opPackageName, boolean restricted, int statsClient,
boolean allowBackgroundAuthentication, boolean isKeyguardBypassEnabled) {
int cookie, @NonNull ClientMonitorCallbackConverter receiver,
@NonNull FaceAuthenticateOptions options, boolean restricted, int statsClient,
boolean allowBackgroundAuthentication) {
final long id = mRequestCounter.incrementAndGet();
scheduleAuthenticate(sensorId, token, operationId, userId, cookie, receiver,
opPackageName, id, restricted, statsClient,
allowBackgroundAuthentication, isKeyguardBypassEnabled);
scheduleAuthenticate(sensorId, token, operationId, cookie, receiver,
options, id, restricted, statsClient, allowBackgroundAuthentication);
return id;
}

View File

@@ -72,12 +72,12 @@ class FaceAuthenticationClient extends AuthenticationClient<IBiometricsFace> {
@NonNull BiometricLogger logger, @NonNull BiometricContext biometricContext,
boolean isStrongBiometric, @NonNull LockoutTracker lockoutTracker,
@NonNull UsageStats usageStats, boolean allowBackgroundAuthentication,
boolean isKeyguardBypassEnabled, @Authenticators.Types int sensorStrength) {
@Authenticators.Types int sensorStrength) {
super(context, lazyDaemon, token, listener, targetUserId, operationId, restricted,
owner, cookie, requireConfirmation, sensorId, logger, biometricContext,
isStrongBiometric, null /* taskStackListener */,
lockoutTracker, allowBackgroundAuthentication, false /* shouldVibrate */,
isKeyguardBypassEnabled, sensorStrength);
sensorStrength);
setRequestId(requestId);
mUsageStats = usageStats;
mSensorPrivacyManager = context.getSystemService(SensorPrivacyManager.class);

View File

@@ -45,6 +45,7 @@ import android.hardware.biometrics.ITestSessionCallback;
import android.hardware.biometrics.fingerprint.IFingerprint;
import android.hardware.biometrics.fingerprint.PointerContext;
import android.hardware.fingerprint.Fingerprint;
import android.hardware.fingerprint.FingerprintAuthenticateOptions;
import android.hardware.fingerprint.FingerprintManager;
import android.hardware.fingerprint.FingerprintSensorPropertiesInternal;
import android.hardware.fingerprint.FingerprintServiceReceiver;
@@ -252,15 +253,15 @@ public class FingerprintService extends SystemService {
public long authenticate(
final IBinder token,
final long operationId,
final int sensorId,
final int userId,
final IFingerprintServiceReceiver receiver,
final String opPackageName,
final String attributionTag,
boolean ignoreEnrollmentState) {
final FingerprintAuthenticateOptions options) {
final int callingUid = Binder.getCallingUid();
final int callingPid = Binder.getCallingPid();
final int callingUserId = UserHandle.getCallingUserId();
final String opPackageName = options.getOpPackageName();
final String attributionTag = options.getAttributionTag();
final int userId = options.getUserId();
final int sensorId = options.getSensorId();
if (!canUseFingerprint(
opPackageName,
@@ -314,7 +315,8 @@ public class FingerprintService extends SystemService {
&& sensorProps != null && sensorProps.isAnyUdfpsType()) {
try {
return authenticateWithPrompt(operationId, sensorProps, callingUid,
callingUserId, receiver, opPackageName, ignoreEnrollmentState);
callingUserId, receiver, opPackageName,
options.isIgnoreEnrollmentState());
} catch (PackageManager.NameNotFoundException e) {
Slog.e(TAG, "Invalid package", e);
return -1;
@@ -412,16 +414,18 @@ public class FingerprintService extends SystemService {
@android.annotation.EnforcePermission(android.Manifest.permission.USE_BIOMETRIC_INTERNAL)
@Override
public long detectFingerprint(final IBinder token, final int userId,
final IFingerprintServiceReceiver receiver, final String opPackageName) {
public long detectFingerprint(final IBinder token,
final IFingerprintServiceReceiver receiver,
final FingerprintAuthenticateOptions options) {
super.detectFingerprint_enforcePermission();
final String opPackageName = options.getOpPackageName();
if (!Utils.isKeyguard(getContext(), opPackageName)) {
Slog.w(TAG, "detectFingerprint called from non-sysui package: " + opPackageName);
return -1;
}
if (!Utils.isUserEncryptedOrLockdown(mLockPatternUtils, userId)) {
if (!Utils.isUserEncryptedOrLockdown(mLockPatternUtils, options.getUserId())) {
// If this happens, something in KeyguardUpdateMonitor is wrong. This should only
// ever be invoked when the user is encrypted or lockdown.
Slog.e(TAG, "detectFingerprint invoked when user is not encrypted or lockdown");
@@ -434,7 +438,7 @@ public class FingerprintService extends SystemService {
return -1;
}
return provider.second.scheduleFingerDetect(provider.first, token, userId,
return provider.second.scheduleFingerDetect(provider.first, token, options.getUserId(),
new ClientMonitorCallbackConverter(receiver), opPackageName,
BiometricsProtoEnums.CLIENT_KEYGUARD);
}

View File

@@ -136,7 +136,6 @@ class FingerprintAuthenticationClient extends AuthenticationClient<AidlSession>
null /* lockoutCache */,
allowBackgroundAuthentication,
false /* shouldVibrate */,
false /* isKeyguardBypassEnabled */,
biometricStrength);
setRequestId(requestId);
mSensorOverlays = new SensorOverlays(udfpsOverlayController,

View File

@@ -87,8 +87,7 @@ class FingerprintAuthenticationClient extends AuthenticationClient<IBiometricsFi
super(context, lazyDaemon, token, listener, targetUserId, operationId, restricted,
owner, cookie, requireConfirmation, sensorId, logger, biometricContext,
isStrongBiometric, taskStackListener, lockoutTracker, allowBackgroundAuthentication,
false /* shouldVibrate */, false /* isKeyguardBypassEnabled */,
sensorStrength);
false /* shouldVibrate */, sensorStrength);
setRequestId(requestId);
mLockoutFrameworkImpl = lockoutTracker;
mSensorOverlays = new SensorOverlays(udfpsOverlayController,

View File

@@ -1,86 +0,0 @@
/*
* Copyright (C) 2023 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.face;
import static com.google.common.truth.Truth.assertThat;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import android.content.Context;
import android.os.Looper;
import android.os.RemoteException;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.ArgumentCaptor;
import org.mockito.Captor;
import org.mockito.Mock;
import org.mockito.junit.MockitoJUnit;
import org.mockito.junit.MockitoJUnitRunner;
import org.mockito.junit.MockitoRule;
import java.util.ArrayList;
import java.util.List;
@RunWith(MockitoJUnitRunner.class)
public class FaceManagerTest {
@Rule
public final MockitoRule mockito = MockitoJUnit.rule();
@Mock
Context mContext;
@Mock
IFaceService mService;
@Captor
ArgumentCaptor<IFaceAuthenticatorsRegisteredCallback> mCaptor;
List<FaceSensorPropertiesInternal> mProps;
FaceManager mFaceManager;
@Before
public void setUp() throws Exception {
when(mContext.getMainLooper()).thenReturn(Looper.getMainLooper());
mFaceManager = new FaceManager(mContext, mService);
mProps = new ArrayList<>();
mProps.add(new FaceSensorPropertiesInternal(
0 /* id */,
FaceSensorProperties.STRENGTH_STRONG,
1 /* maxTemplatesAllowed */,
new ArrayList<>() /* conponentInfo */,
FaceSensorProperties.TYPE_UNKNOWN,
true /* supportsFaceDetection */,
true /* supportsSelfIllumination */,
false /* resetLockoutRequiresChallenge */));
}
@Test
public void getSensorPropertiesInternal_noBinderCalls() throws RemoteException {
verify(mService).addAuthenticatorsRegisteredCallback(mCaptor.capture());
mCaptor.getValue().onAllAuthenticatorsRegistered(mProps);
List<FaceSensorPropertiesInternal> actual = mFaceManager.getSensorPropertiesInternal();
assertThat(actual).isEqualTo(mProps);
verify(mService, never()).getSensorPropertiesInternal(any());
}
}

View File

@@ -1,88 +0,0 @@
/*
* Copyright (C) 2023 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.fingerprint;
import static com.google.common.truth.Truth.assertThat;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import android.content.Context;
import android.os.Looper;
import android.os.RemoteException;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.ArgumentCaptor;
import org.mockito.Captor;
import org.mockito.Mock;
import org.mockito.junit.MockitoJUnit;
import org.mockito.junit.MockitoJUnitRunner;
import org.mockito.junit.MockitoRule;
import java.util.ArrayList;
import java.util.List;
@RunWith(MockitoJUnitRunner.class)
public class FingerprintManagerTest {
@Rule
public final MockitoRule mockito = MockitoJUnit.rule();
@Mock
Context mContext;
@Mock
IFingerprintService mService;
@Captor
ArgumentCaptor<IFingerprintAuthenticatorsRegisteredCallback> mCaptor;
List<FingerprintSensorPropertiesInternal> mProps;
FingerprintManager mFingerprintManager;
@Before
public void setUp() throws Exception {
when(mContext.getMainLooper()).thenReturn(Looper.getMainLooper());
mFingerprintManager = new FingerprintManager(mContext, mService);
mProps = new ArrayList<>();
mProps.add(new FingerprintSensorPropertiesInternal(
0 /* sensorId */,
FingerprintSensorProperties.STRENGTH_STRONG,
1 /* maxEnrollmentsPerUser */,
new ArrayList<>() /* componentInfo */,
FingerprintSensorProperties.TYPE_UNKNOWN,
true /* halControlsIllumination */,
true /* resetLockoutRequiresHardwareAuthToken */,
new ArrayList<>() /* sensorLocations */));
}
@Test
public void getSensorPropertiesInternal_noBinderCalls() throws RemoteException {
verify(mService).addAuthenticatorsRegisteredCallback(mCaptor.capture());
mCaptor.getValue().onAllAuthenticatorsRegistered(mProps);
List<FingerprintSensorPropertiesInternal> actual =
mFingerprintManager.getSensorPropertiesInternal();
assertThat(actual).isEqualTo(mProps);
verify(mService, never()).getSensorPropertiesInternal(any());
}
}

View File

@@ -1 +1 @@
include /services/core/java/com/android/server/biometrics/OWNERS
include /services/core/java/com/android/server/biometrics/OWNERS

View File

@@ -705,7 +705,7 @@ public class BiometricSchedulerTest {
TEST_SENSOR_ID, mock(BiometricLogger.class), biometricContext,
true /* isStrongBiometric */, null /* taskStackListener */,
null /* lockoutTracker */, false /* isKeyguard */,
true /* shouldVibrate */, false /* isKeyguardBypassEnabled */,
true /* shouldVibrate */,
0 /* sensorStrength */);
}

View File

@@ -159,7 +159,7 @@ public class FaceAuthenticationClientTest {
false /* requireConfirmation */, 9 /* sensorId */,
mBiometricLogger, mBiometricContext, true /* isStrongBiometric */,
mUsageStats, null /* mLockoutCache */, false /* allowBackgroundAuthentication */,
false /* isKeyguardBypassEnabled */, null /* sensorPrivacyManager */,
null /* sensorPrivacyManager */,
0 /* biometricStrength */) {
@Override
protected ActivityTaskManager getActivityTaskManager() {