summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author Joshua Mccloskey <joshmccloskey@google.com> 2024-02-22 01:04:06 +0000
committer Android (Google) Code Review <android-gerrit@google.com> 2024-02-22 01:04:06 +0000
commit91ba7efbe3caafd99f298e895f4eea2d6ba858d5 (patch)
tree4627891fa599a93cd69feedf2b05fc5e008b6064
parent090f31e3e2fb2201cb6593b770bfa34b17cc1c17 (diff)
parentfc2b6f3918bee422fc21d4daf20050aad7496449 (diff)
Merge "Adding biometric FRR Notification atom." into main
-rw-r--r--core/java/android/hardware/biometrics/BiometricFaceConstants.java20
-rw-r--r--core/java/android/hardware/biometrics/BiometricFingerprintConstants.java20
-rw-r--r--core/java/android/hardware/biometrics/BiometricManager.java7
-rw-r--r--core/java/android/hardware/face/FaceEnrollOptions.aidl19
-rw-r--r--core/java/android/hardware/face/FaceEnrollOptions.java259
-rw-r--r--core/java/android/hardware/face/FaceManager.java8
-rw-r--r--core/java/android/hardware/face/IFaceService.aidl3
-rw-r--r--core/java/android/hardware/fingerprint/FingerprintEnrollOptions.aidl19
-rw-r--r--core/java/android/hardware/fingerprint/FingerprintEnrollOptions.java260
-rw-r--r--core/java/android/hardware/fingerprint/FingerprintManager.java5
-rw-r--r--core/java/android/hardware/fingerprint/IFingerprintService.aidl3
-rw-r--r--core/tests/coretests/src/android/hardware/face/FaceManagerTest.java6
-rw-r--r--core/tests/coretests/src/android/hardware/fingerprint/FingerprintManagerTest.java6
-rw-r--r--services/core/java/com/android/server/biometrics/AuthenticationStatsCollector.java24
-rw-r--r--services/core/java/com/android/server/biometrics/BiometricNotificationLogger.java104
-rw-r--r--services/core/java/com/android/server/biometrics/BiometricService.java23
-rw-r--r--services/core/java/com/android/server/biometrics/log/BiometricFrameworkStatsLogger.java12
-rw-r--r--services/core/java/com/android/server/biometrics/log/BiometricLogger.java5
-rw-r--r--services/core/java/com/android/server/biometrics/sensors/BiometricNotificationUtils.java52
-rw-r--r--services/core/java/com/android/server/biometrics/sensors/EnrollClient.java9
-rw-r--r--services/core/java/com/android/server/biometrics/sensors/face/FaceService.java29
-rw-r--r--services/core/java/com/android/server/biometrics/sensors/face/FaceShellCommand.java9
-rw-r--r--services/core/java/com/android/server/biometrics/sensors/face/ServiceProvider.java3
-rw-r--r--services/core/java/com/android/server/biometrics/sensors/face/aidl/BiometricTestSessionImpl.java4
-rw-r--r--services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceEnrollClient.java9
-rw-r--r--services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceProvider.java12
-rw-r--r--services/core/java/com/android/server/biometrics/sensors/face/hidl/BiometricTestSessionImpl.java4
-rw-r--r--services/core/java/com/android/server/biometrics/sensors/face/hidl/Face10.java17
-rw-r--r--services/core/java/com/android/server/biometrics/sensors/face/hidl/FaceEnrollClient.java10
-rw-r--r--services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintService.java27
-rw-r--r--services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintShellCommand.java9
-rw-r--r--services/core/java/com/android/server/biometrics/sensors/fingerprint/ServiceProvider.java4
-rw-r--r--services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/BiometricTestSessionImpl.java7
-rw-r--r--services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintEnrollClient.java9
-rw-r--r--services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintProvider.java13
-rw-r--r--services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/BiometricTestSessionImpl.java7
-rw-r--r--services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/Fingerprint21.java19
-rw-r--r--services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/FingerprintEnrollClient.java9
-rw-r--r--services/tests/servicestests/src/com/android/server/biometrics/BiometricNotificationLoggerTest.java157
-rw-r--r--services/tests/servicestests/src/com/android/server/biometrics/BiometricServiceTest.java4
-rw-r--r--services/tests/servicestests/src/com/android/server/biometrics/log/BiometricLoggerTest.java10
-rw-r--r--services/tests/servicestests/src/com/android/server/biometrics/sensors/BiometricSchedulerTest.java2
-rw-r--r--services/tests/servicestests/src/com/android/server/biometrics/sensors/face/aidl/FaceEnrollClientTest.java19
-rw-r--r--services/tests/servicestests/src/com/android/server/biometrics/sensors/face/hidl/HidlToAidlSensorAdapterTest.java3
-rw-r--r--services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintEnrollClientTest.java19
-rw-r--r--services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/hidl/HidlToAidlSensorAdapterTest.java4
46 files changed, 1196 insertions, 87 deletions
diff --git a/core/java/android/hardware/biometrics/BiometricFaceConstants.java b/core/java/android/hardware/biometrics/BiometricFaceConstants.java
index 2b62b98529a9..2ba1d897fe34 100644
--- a/core/java/android/hardware/biometrics/BiometricFaceConstants.java
+++ b/core/java/android/hardware/biometrics/BiometricFaceConstants.java
@@ -19,6 +19,8 @@ package android.hardware.biometrics;
import android.annotation.IntDef;
import android.app.KeyguardManager;
import android.hardware.biometrics.BiometricManager.Authenticators;
+import android.hardware.face.FaceEnrollOptions;
+import android.hardware.face.FaceEnrollOptions.EnrollReason;
import android.hardware.face.FaceManager;
import java.lang.annotation.Retention;
@@ -432,4 +434,22 @@ public interface BiometricFaceConstants {
* vendor code.
*/
int FACE_ACQUIRED_VENDOR_BASE = 1000;
+
+
+ /**
+ * Converts FaceEnrollOptions.reason into BiometricsProtoEnums.enrollReason
+ */
+ public static int reasonToMetric(@EnrollReason int reason) {
+ switch (reason) {
+ case FaceEnrollOptions.ENROLL_REASON_RE_ENROLL_NOTIFICATION:
+ return BiometricsProtoEnums.ENROLLMENT_SOURCE_FRR_NOTIFICATION;
+ case FaceEnrollOptions.ENROLL_REASON_SETTINGS:
+ return BiometricsProtoEnums.ENROLLMENT_SOURCE_SETTINGS;
+ case FaceEnrollOptions.ENROLL_REASON_SUW:
+ return BiometricsProtoEnums.ENROLLMENT_SOURCE_SUW;
+ default:
+ return BiometricsProtoEnums.ENROLLMENT_SOURCE_UNKNOWN;
+ }
+
+ }
}
diff --git a/core/java/android/hardware/biometrics/BiometricFingerprintConstants.java b/core/java/android/hardware/biometrics/BiometricFingerprintConstants.java
index 5b24fb6860a2..770448bd594b 100644
--- a/core/java/android/hardware/biometrics/BiometricFingerprintConstants.java
+++ b/core/java/android/hardware/biometrics/BiometricFingerprintConstants.java
@@ -20,6 +20,8 @@ import android.annotation.IntDef;
import android.app.KeyguardManager;
import android.compat.annotation.UnsupportedAppUsage;
import android.hardware.biometrics.BiometricManager.Authenticators;
+import android.hardware.fingerprint.FingerprintEnrollOptions;
+import android.hardware.fingerprint.FingerprintEnrollOptions.EnrollReason;
import android.hardware.fingerprint.FingerprintManager;
import android.os.Build;
@@ -350,4 +352,22 @@ public interface BiometricFingerprintConstants {
return false;
}
}
+
+
+ /**
+ * Converts FaceEnrollOptions.reason into BiometricsProtoEnums.enrollReason
+ */
+ static int reasonToMetric(@EnrollReason int reason) {
+ switch(reason) {
+ case FingerprintEnrollOptions.ENROLL_REASON_RE_ENROLL_NOTIFICATION:
+ return BiometricsProtoEnums.ENROLLMENT_SOURCE_FRR_NOTIFICATION;
+ case FingerprintEnrollOptions.ENROLL_REASON_SETTINGS:
+ return BiometricsProtoEnums.ENROLLMENT_SOURCE_SETTINGS;
+ case FingerprintEnrollOptions.ENROLL_REASON_SUW:
+ return BiometricsProtoEnums.ENROLLMENT_SOURCE_SUW;
+ default:
+ return BiometricsProtoEnums.ENROLLMENT_SOURCE_UNKNOWN;
+ }
+
+ }
}
diff --git a/core/java/android/hardware/biometrics/BiometricManager.java b/core/java/android/hardware/biometrics/BiometricManager.java
index d7d1d1a7c677..fdd8b04921f5 100644
--- a/core/java/android/hardware/biometrics/BiometricManager.java
+++ b/core/java/android/hardware/biometrics/BiometricManager.java
@@ -100,6 +100,13 @@ public class BiometricManager {
Authenticators.DEVICE_CREDENTIAL | Authenticators.BIOMETRIC_STRONG;
/**
+ * Enroll reason extra that can be used by settings to understand where this request came
+ * from.
+ * @hide
+ */
+ public static final String EXTRA_ENROLL_REASON = "enroll_reason";
+
+ /**
* @hide
*/
@IntDef({BIOMETRIC_SUCCESS,
diff --git a/core/java/android/hardware/face/FaceEnrollOptions.aidl b/core/java/android/hardware/face/FaceEnrollOptions.aidl
new file mode 100644
index 000000000000..336de9db899c
--- /dev/null
+++ b/core/java/android/hardware/face/FaceEnrollOptions.aidl
@@ -0,0 +1,19 @@
+/*
+ * Copyright (C) 2024 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 FaceEnrollOptions;
diff --git a/core/java/android/hardware/face/FaceEnrollOptions.java b/core/java/android/hardware/face/FaceEnrollOptions.java
new file mode 100644
index 000000000000..440105584f74
--- /dev/null
+++ b/core/java/android/hardware/face/FaceEnrollOptions.java
@@ -0,0 +1,259 @@
+/*
+ * Copyright (C) 2024 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 android.os.Parcelable;
+
+import com.android.internal.util.DataClass;
+
+/**
+ * Additional options when requesting Face enrollment.
+ *
+ * @hide
+ */
+@DataClass(
+ genParcelable = true,
+ genAidl = true,
+ genBuilder = true,
+ genSetters = true,
+ genEqualsHashCode = true
+)
+public class FaceEnrollOptions implements Parcelable {
+ public static final int ENROLL_REASON_UNKNOWN = 0;
+ public static final int ENROLL_REASON_RE_ENROLL_NOTIFICATION = 1;
+ public static final int ENROLL_REASON_SETTINGS = 2;
+ public static final int ENROLL_REASON_SUW = 3;
+
+ /**
+ * The reason for enrollment.
+ */
+ @EnrollReason
+ private final int mEnrollReason;
+ private static int defaultEnrollReason() {
+ return ENROLL_REASON_UNKNOWN;
+ }
+
+
+
+
+ // 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/FaceEnrollOptions.java
+ //
+ // To exclude the generated code from IntelliJ auto-formatting enable (one-time):
+ // Settings > Editor > Code Style > Formatter Control
+ //@formatter:off
+
+
+ @android.annotation.IntDef(prefix = "ENROLL_REASON_", value = {
+ ENROLL_REASON_UNKNOWN,
+ ENROLL_REASON_RE_ENROLL_NOTIFICATION,
+ ENROLL_REASON_SETTINGS,
+ ENROLL_REASON_SUW
+ })
+ @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.SOURCE)
+ @DataClass.Generated.Member
+ public @interface EnrollReason {}
+
+ @DataClass.Generated.Member
+ public static String enrollReasonToString(@EnrollReason int value) {
+ switch (value) {
+ case ENROLL_REASON_UNKNOWN:
+ return "ENROLL_REASON_UNKNOWN";
+ case ENROLL_REASON_RE_ENROLL_NOTIFICATION:
+ return "ENROLL_REASON_RE_ENROLL_NOTIFICATION";
+ case ENROLL_REASON_SETTINGS:
+ return "ENROLL_REASON_SETTINGS";
+ case ENROLL_REASON_SUW:
+ return "ENROLL_REASON_SUW";
+ default: return Integer.toHexString(value);
+ }
+ }
+
+ @DataClass.Generated.Member
+ /* package-private */ FaceEnrollOptions(
+ @EnrollReason int enrollReason) {
+ this.mEnrollReason = enrollReason;
+
+ if (!(mEnrollReason == ENROLL_REASON_UNKNOWN)
+ && !(mEnrollReason == ENROLL_REASON_RE_ENROLL_NOTIFICATION)
+ && !(mEnrollReason == ENROLL_REASON_SETTINGS)
+ && !(mEnrollReason == ENROLL_REASON_SUW)) {
+ throw new java.lang.IllegalArgumentException(
+ "enrollReason was " + mEnrollReason + " but must be one of: "
+ + "ENROLL_REASON_UNKNOWN(" + ENROLL_REASON_UNKNOWN + "), "
+ + "ENROLL_REASON_RE_ENROLL_NOTIFICATION(" + ENROLL_REASON_RE_ENROLL_NOTIFICATION + "), "
+ + "ENROLL_REASON_SETTINGS(" + ENROLL_REASON_SETTINGS + "), "
+ + "ENROLL_REASON_SUW(" + ENROLL_REASON_SUW + ")");
+ }
+
+
+ // onConstructed(); // You can define this method to get a callback
+ }
+
+ /**
+ * The reason for enrollment.
+ */
+ @DataClass.Generated.Member
+ public @EnrollReason int getEnrollReason() {
+ return mEnrollReason;
+ }
+
+ @Override
+ @DataClass.Generated.Member
+ public boolean equals(@android.annotation.Nullable Object o) {
+ // You can override field equality logic by defining either of the methods like:
+ // boolean fieldNameEquals(FaceEnrollOptions other) { ... }
+ // boolean fieldNameEquals(FieldType otherValue) { ... }
+
+ if (this == o) return true;
+ if (o == null || getClass() != o.getClass()) return false;
+ @SuppressWarnings("unchecked")
+ FaceEnrollOptions that = (FaceEnrollOptions) o;
+ //noinspection PointlessBooleanExpression
+ return true
+ && mEnrollReason == that.mEnrollReason;
+ }
+
+ @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 + mEnrollReason;
+ return _hash;
+ }
+
+ @Override
+ @DataClass.Generated.Member
+ public void writeToParcel(@android.annotation.NonNull android.os.Parcel dest, int flags) {
+ // You can override field parcelling by defining methods like:
+ // void parcelFieldName(Parcel dest, int flags) { ... }
+
+ dest.writeInt(mEnrollReason);
+ }
+
+ @Override
+ @DataClass.Generated.Member
+ public int describeContents() { return 0; }
+
+ /** @hide */
+ @SuppressWarnings({"unchecked", "RedundantCast"})
+ @DataClass.Generated.Member
+ protected FaceEnrollOptions(@android.annotation.NonNull android.os.Parcel in) {
+ // You can override field unparcelling by defining methods like:
+ // static FieldType unparcelFieldName(Parcel in) { ... }
+
+ int enrollReason = in.readInt();
+
+ this.mEnrollReason = enrollReason;
+
+ if (!(mEnrollReason == ENROLL_REASON_UNKNOWN)
+ && !(mEnrollReason == ENROLL_REASON_RE_ENROLL_NOTIFICATION)
+ && !(mEnrollReason == ENROLL_REASON_SETTINGS)
+ && !(mEnrollReason == ENROLL_REASON_SUW)) {
+ throw new java.lang.IllegalArgumentException(
+ "enrollReason was " + mEnrollReason + " but must be one of: "
+ + "ENROLL_REASON_UNKNOWN(" + ENROLL_REASON_UNKNOWN + "), "
+ + "ENROLL_REASON_RE_ENROLL_NOTIFICATION(" + ENROLL_REASON_RE_ENROLL_NOTIFICATION + "), "
+ + "ENROLL_REASON_SETTINGS(" + ENROLL_REASON_SETTINGS + "), "
+ + "ENROLL_REASON_SUW(" + ENROLL_REASON_SUW + ")");
+ }
+
+
+ // onConstructed(); // You can define this method to get a callback
+ }
+
+ @DataClass.Generated.Member
+ public static final @android.annotation.NonNull Parcelable.Creator<FaceEnrollOptions> CREATOR
+ = new Parcelable.Creator<FaceEnrollOptions>() {
+ @Override
+ public FaceEnrollOptions[] newArray(int size) {
+ return new FaceEnrollOptions[size];
+ }
+
+ @Override
+ public FaceEnrollOptions createFromParcel(@android.annotation.NonNull android.os.Parcel in) {
+ return new FaceEnrollOptions(in);
+ }
+ };
+
+ /**
+ * A builder for {@link FaceEnrollOptions}
+ */
+ @SuppressWarnings("WeakerAccess")
+ @DataClass.Generated.Member
+ public static class Builder {
+
+ private @EnrollReason int mEnrollReason;
+
+ private long mBuilderFieldsSet = 0L;
+
+ public Builder() {
+ }
+
+ /**
+ * The reason for enrollment.
+ */
+ @DataClass.Generated.Member
+ public @android.annotation.NonNull Builder setEnrollReason(@EnrollReason int value) {
+ checkNotUsed();
+ mBuilderFieldsSet |= 0x1;
+ mEnrollReason = value;
+ return this;
+ }
+
+ /** Builds the instance. This builder should not be touched after calling this! */
+ public @android.annotation.NonNull FaceEnrollOptions build() {
+ checkNotUsed();
+ mBuilderFieldsSet |= 0x2; // Mark builder used
+
+ if ((mBuilderFieldsSet & 0x1) == 0) {
+ mEnrollReason = defaultEnrollReason();
+ }
+ FaceEnrollOptions o = new FaceEnrollOptions(
+ mEnrollReason);
+ return o;
+ }
+
+ private void checkNotUsed() {
+ if ((mBuilderFieldsSet & 0x2) != 0) {
+ throw new IllegalStateException(
+ "This Builder should not be reused. Use a new Builder instance instead");
+ }
+ }
+ }
+
+ @DataClass.Generated(
+ time = 1707949032303L,
+ codegenVersion = "1.0.23",
+ sourceFile = "frameworks/base/core/java/android/hardware/face/FaceEnrollOptions.java",
+ inputSignatures = "public static final int ENROLL_REASON_UNKNOWN\npublic static final int ENROLL_REASON_RE_ENROLL_NOTIFICATION\npublic static final int ENROLL_REASON_SETTINGS\npublic static final int ENROLL_REASON_SUW\nprivate final @android.hardware.face.FaceEnrollOptions.EnrollReason int mEnrollReason\nprivate static int defaultEnrollReason()\nclass FaceEnrollOptions extends java.lang.Object implements [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
+
+}
diff --git a/core/java/android/hardware/face/FaceManager.java b/core/java/android/hardware/face/FaceManager.java
index bae5e7f83569..066c45f03ec4 100644
--- a/core/java/android/hardware/face/FaceManager.java
+++ b/core/java/android/hardware/face/FaceManager.java
@@ -393,7 +393,9 @@ public class FaceManager implements BiometricAuthenticator, BiometricFaceConstan
public void enroll(int userId, byte[] hardwareAuthToken, CancellationSignal cancel,
EnrollmentCallback callback, int[] disabledFeatures) {
enroll(userId, hardwareAuthToken, cancel, callback, disabledFeatures,
- null /* previewSurface */, false /* debugConsent */);
+ null /* previewSurface */, false /* debugConsent */,
+ (new FaceEnrollOptions.Builder()).build());
+
}
/**
@@ -418,7 +420,7 @@ public class FaceManager implements BiometricAuthenticator, BiometricFaceConstan
@RequiresPermission(MANAGE_BIOMETRIC)
public void enroll(int userId, byte[] hardwareAuthToken, CancellationSignal cancel,
EnrollmentCallback callback, int[] disabledFeatures, @Nullable Surface previewSurface,
- boolean debugConsent) {
+ boolean debugConsent, FaceEnrollOptions options) {
if (callback == null) {
throw new IllegalArgumentException("Must supply an enrollment callback");
}
@@ -449,7 +451,7 @@ public class FaceManager implements BiometricAuthenticator, BiometricFaceConstan
Trace.beginSection("FaceManager#enroll");
final long enrollId = mService.enroll(userId, mToken, hardwareAuthToken,
mServiceReceiver, mContext.getOpPackageName(), disabledFeatures,
- previewSurface, debugConsent);
+ previewSurface, debugConsent, options);
if (cancel != null) {
cancel.setOnCancelListener(new OnEnrollCancelListener(enrollId));
}
diff --git a/core/java/android/hardware/face/IFaceService.aidl b/core/java/android/hardware/face/IFaceService.aidl
index 8e234fa11866..b98c0cb41ac9 100644
--- a/core/java/android/hardware/face/IFaceService.aidl
+++ b/core/java/android/hardware/face/IFaceService.aidl
@@ -26,6 +26,7 @@ import android.hardware.face.IFaceAuthenticatorsRegisteredCallback;
import android.hardware.face.IFaceServiceReceiver;
import android.hardware.face.Face;
import android.hardware.face.FaceAuthenticateOptions;
+import android.hardware.face.FaceEnrollOptions;
import android.hardware.face.FaceSensorPropertiesInternal;
import android.hardware.face.FaceSensorConfigurations;
import android.view.Surface;
@@ -100,7 +101,7 @@ interface IFaceService {
@EnforcePermission("MANAGE_BIOMETRIC")
long enroll(int userId, IBinder token, in byte [] hardwareAuthToken, IFaceServiceReceiver receiver,
String opPackageName, in int [] disabledFeatures,
- in Surface previewSurface, boolean debugConsent);
+ in Surface previewSurface, boolean debugConsent, in FaceEnrollOptions options);
// Start remote face enrollment
@EnforcePermission("MANAGE_BIOMETRIC")
diff --git a/core/java/android/hardware/fingerprint/FingerprintEnrollOptions.aidl b/core/java/android/hardware/fingerprint/FingerprintEnrollOptions.aidl
new file mode 100644
index 000000000000..77803f3e3a9b
--- /dev/null
+++ b/core/java/android/hardware/fingerprint/FingerprintEnrollOptions.aidl
@@ -0,0 +1,19 @@
+/*
+ * Copyright (C) 2024 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 FingerprintEnrollOptions; \ No newline at end of file
diff --git a/core/java/android/hardware/fingerprint/FingerprintEnrollOptions.java b/core/java/android/hardware/fingerprint/FingerprintEnrollOptions.java
new file mode 100644
index 000000000000..9f9f322a8876
--- /dev/null
+++ b/core/java/android/hardware/fingerprint/FingerprintEnrollOptions.java
@@ -0,0 +1,260 @@
+/*
+ * Copyright (C) 2024 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 android.os.Parcelable;
+
+
+import com.android.internal.util.DataClass;
+
+/**
+ * Additional options when requesting Fingerprint enrollment.
+ *
+ * @hide
+ */
+@DataClass(
+ genParcelable = true,
+ genAidl = true,
+ genBuilder = true,
+ genSetters = true,
+ genEqualsHashCode = true
+)
+public class FingerprintEnrollOptions implements Parcelable {
+ public static final int ENROLL_REASON_UNKNOWN = 0;
+ public static final int ENROLL_REASON_RE_ENROLL_NOTIFICATION = 1;
+ public static final int ENROLL_REASON_SETTINGS = 2;
+ public static final int ENROLL_REASON_SUW = 3;
+
+ /**
+ * The reason for enrollment.
+ */
+ @EnrollReason
+ private final int mEnrollReason;
+
+ private static int defaultEnrollReason() {
+ return ENROLL_REASON_UNKNOWN;
+ }
+
+
+
+ // 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/FingerprintEnrollOptions.java
+ //
+ // To exclude the generated code from IntelliJ auto-formatting enable (one-time):
+ // Settings > Editor > Code Style > Formatter Control
+ //@formatter:off
+
+
+ @android.annotation.IntDef(prefix = "ENROLL_REASON_", value = {
+ ENROLL_REASON_UNKNOWN,
+ ENROLL_REASON_RE_ENROLL_NOTIFICATION,
+ ENROLL_REASON_SETTINGS,
+ ENROLL_REASON_SUW
+ })
+ @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.SOURCE)
+ @DataClass.Generated.Member
+ public @interface EnrollReason {}
+
+ @DataClass.Generated.Member
+ public static String enrollReasonToString(@EnrollReason int value) {
+ switch (value) {
+ case ENROLL_REASON_UNKNOWN:
+ return "ENROLL_REASON_UNKNOWN";
+ case ENROLL_REASON_RE_ENROLL_NOTIFICATION:
+ return "ENROLL_REASON_RE_ENROLL_NOTIFICATION";
+ case ENROLL_REASON_SETTINGS:
+ return "ENROLL_REASON_SETTINGS";
+ case ENROLL_REASON_SUW:
+ return "ENROLL_REASON_SUW";
+ default: return Integer.toHexString(value);
+ }
+ }
+
+ @DataClass.Generated.Member
+ /* package-private */ FingerprintEnrollOptions(
+ @EnrollReason int enrollReason) {
+ this.mEnrollReason = enrollReason;
+
+ if (!(mEnrollReason == ENROLL_REASON_UNKNOWN)
+ && !(mEnrollReason == ENROLL_REASON_RE_ENROLL_NOTIFICATION)
+ && !(mEnrollReason == ENROLL_REASON_SETTINGS)
+ && !(mEnrollReason == ENROLL_REASON_SUW)) {
+ throw new java.lang.IllegalArgumentException(
+ "enrollReason was " + mEnrollReason + " but must be one of: "
+ + "ENROLL_REASON_UNKNOWN(" + ENROLL_REASON_UNKNOWN + "), "
+ + "ENROLL_REASON_RE_ENROLL_NOTIFICATION(" + ENROLL_REASON_RE_ENROLL_NOTIFICATION + "), "
+ + "ENROLL_REASON_SETTINGS(" + ENROLL_REASON_SETTINGS + "), "
+ + "ENROLL_REASON_SUW(" + ENROLL_REASON_SUW + ")");
+ }
+
+
+ // onConstructed(); // You can define this method to get a callback
+ }
+
+ /**
+ * The reason for enrollment.
+ */
+ @DataClass.Generated.Member
+ public @EnrollReason int getEnrollReason() {
+ return mEnrollReason;
+ }
+
+ @Override
+ @DataClass.Generated.Member
+ public boolean equals(@android.annotation.Nullable Object o) {
+ // You can override field equality logic by defining either of the methods like:
+ // boolean fieldNameEquals(FingerprintEnrollOptions other) { ... }
+ // boolean fieldNameEquals(FieldType otherValue) { ... }
+
+ if (this == o) return true;
+ if (o == null || getClass() != o.getClass()) return false;
+ @SuppressWarnings("unchecked")
+ FingerprintEnrollOptions that = (FingerprintEnrollOptions) o;
+ //noinspection PointlessBooleanExpression
+ return true
+ && mEnrollReason == that.mEnrollReason;
+ }
+
+ @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 + mEnrollReason;
+ return _hash;
+ }
+
+ @Override
+ @DataClass.Generated.Member
+ public void writeToParcel(@android.annotation.NonNull android.os.Parcel dest, int flags) {
+ // You can override field parcelling by defining methods like:
+ // void parcelFieldName(Parcel dest, int flags) { ... }
+
+ dest.writeInt(mEnrollReason);
+ }
+
+ @Override
+ @DataClass.Generated.Member
+ public int describeContents() { return 0; }
+
+ /** @hide */
+ @SuppressWarnings({"unchecked", "RedundantCast"})
+ @DataClass.Generated.Member
+ protected FingerprintEnrollOptions(@android.annotation.NonNull android.os.Parcel in) {
+ // You can override field unparcelling by defining methods like:
+ // static FieldType unparcelFieldName(Parcel in) { ... }
+
+ int enrollReason = in.readInt();
+
+ this.mEnrollReason = enrollReason;
+
+ if (!(mEnrollReason == ENROLL_REASON_UNKNOWN)
+ && !(mEnrollReason == ENROLL_REASON_RE_ENROLL_NOTIFICATION)
+ && !(mEnrollReason == ENROLL_REASON_SETTINGS)
+ && !(mEnrollReason == ENROLL_REASON_SUW)) {
+ throw new java.lang.IllegalArgumentException(
+ "enrollReason was " + mEnrollReason + " but must be one of: "
+ + "ENROLL_REASON_UNKNOWN(" + ENROLL_REASON_UNKNOWN + "), "
+ + "ENROLL_REASON_RE_ENROLL_NOTIFICATION(" + ENROLL_REASON_RE_ENROLL_NOTIFICATION + "), "
+ + "ENROLL_REASON_SETTINGS(" + ENROLL_REASON_SETTINGS + "), "
+ + "ENROLL_REASON_SUW(" + ENROLL_REASON_SUW + ")");
+ }
+
+
+ // onConstructed(); // You can define this method to get a callback
+ }
+
+ @DataClass.Generated.Member
+ public static final @android.annotation.NonNull Parcelable.Creator<FingerprintEnrollOptions> CREATOR
+ = new Parcelable.Creator<FingerprintEnrollOptions>() {
+ @Override
+ public FingerprintEnrollOptions[] newArray(int size) {
+ return new FingerprintEnrollOptions[size];
+ }
+
+ @Override
+ public FingerprintEnrollOptions createFromParcel(@android.annotation.NonNull android.os.Parcel in) {
+ return new FingerprintEnrollOptions(in);
+ }
+ };
+
+ /**
+ * A builder for {@link FingerprintEnrollOptions}
+ */
+ @SuppressWarnings("WeakerAccess")
+ @DataClass.Generated.Member
+ public static class Builder {
+
+ private @EnrollReason int mEnrollReason;
+
+ private long mBuilderFieldsSet = 0L;
+
+ public Builder() {
+ }
+
+ /**
+ * The reason for enrollment.
+ */
+ @DataClass.Generated.Member
+ public @android.annotation.NonNull Builder setEnrollReason(@EnrollReason int value) {
+ checkNotUsed();
+ mBuilderFieldsSet |= 0x1;
+ mEnrollReason = value;
+ return this;
+ }
+
+ /** Builds the instance. This builder should not be touched after calling this! */
+ public @android.annotation.NonNull FingerprintEnrollOptions build() {
+ checkNotUsed();
+ mBuilderFieldsSet |= 0x2; // Mark builder used
+
+ if ((mBuilderFieldsSet & 0x1) == 0) {
+ mEnrollReason = defaultEnrollReason();
+ }
+ FingerprintEnrollOptions o = new FingerprintEnrollOptions(
+ mEnrollReason);
+ return o;
+ }
+
+ private void checkNotUsed() {
+ if ((mBuilderFieldsSet & 0x2) != 0) {
+ throw new IllegalStateException(
+ "This Builder should not be reused. Use a new Builder instance instead");
+ }
+ }
+ }
+
+ @DataClass.Generated(
+ time = 1704407629121L,
+ codegenVersion = "1.0.23",
+ sourceFile = "frameworks/base/core/java/android/hardware/fingerprint/FingerprintEnrollOptions.java",
+ inputSignatures = "public static final int ENROLL_REASON_UNKNOWN\npublic static final int ENROLL_REASON_RE_ENROLL_NOTIFICATION\npublic static final int ENROLL_REASON_SETTINGS\npublic static final int ENROLL_REASON_SUW\nprivate final @android.hardware.fingerprint.FingerprintEnrollOptions.EnrollReason int mEnrollReason\nprivate static int defaultEnrollReason()\nclass FingerprintEnrollOptions extends java.lang.Object implements [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
+
+}
diff --git a/core/java/android/hardware/fingerprint/FingerprintManager.java b/core/java/android/hardware/fingerprint/FingerprintManager.java
index 5a38a34fde11..b0f69f56cba7 100644
--- a/core/java/android/hardware/fingerprint/FingerprintManager.java
+++ b/core/java/android/hardware/fingerprint/FingerprintManager.java
@@ -755,7 +755,8 @@ public class FingerprintManager implements BiometricAuthenticator, BiometricFing
*/
@RequiresPermission(MANAGE_FINGERPRINT)
public void enroll(byte [] hardwareAuthToken, CancellationSignal cancel, int userId,
- EnrollmentCallback callback, @EnrollReason int enrollReason) {
+ EnrollmentCallback callback, @EnrollReason int enrollReason,
+ FingerprintEnrollOptions options) {
if (userId == UserHandle.USER_CURRENT) {
userId = getCurrentUserId();
}
@@ -779,7 +780,7 @@ public class FingerprintManager implements BiometricAuthenticator, BiometricFing
try {
mEnrollmentCallback = callback;
final long enrollId = mService.enroll(mToken, hardwareAuthToken, userId,
- mServiceReceiver, mContext.getOpPackageName(), enrollReason);
+ mServiceReceiver, mContext.getOpPackageName(), enrollReason, options);
if (cancel != null) {
cancel.setOnCancelListener(new OnEnrollCancelListener(enrollId));
}
diff --git a/core/java/android/hardware/fingerprint/IFingerprintService.aidl b/core/java/android/hardware/fingerprint/IFingerprintService.aidl
index 606b171f36ba..8b37c24527d7 100644
--- a/core/java/android/hardware/fingerprint/IFingerprintService.aidl
+++ b/core/java/android/hardware/fingerprint/IFingerprintService.aidl
@@ -30,6 +30,7 @@ import android.hardware.fingerprint.IUdfpsOverlayController;
import android.hardware.fingerprint.ISidefpsController;
import android.hardware.fingerprint.Fingerprint;
import android.hardware.fingerprint.FingerprintAuthenticateOptions;
+import android.hardware.fingerprint.FingerprintEnrollOptions;
import android.hardware.fingerprint.FingerprintSensorPropertiesInternal;
import android.hardware.fingerprint.FingerprintSensorConfigurations;
import java.util.List;
@@ -98,7 +99,7 @@ interface IFingerprintService {
// Start fingerprint enrollment
@EnforcePermission("MANAGE_FINGERPRINT")
long enroll(IBinder token, in byte [] hardwareAuthToken, int userId, IFingerprintServiceReceiver receiver,
- String opPackageName, int enrollReason);
+ String opPackageName, int enrollReason, in FingerprintEnrollOptions options);
// Cancel enrollment in progress
@EnforcePermission("MANAGE_FINGERPRINT")
diff --git a/core/tests/coretests/src/android/hardware/face/FaceManagerTest.java b/core/tests/coretests/src/android/hardware/face/FaceManagerTest.java
index d816d0853ab6..34f5841aef72 100644
--- a/core/tests/coretests/src/android/hardware/face/FaceManagerTest.java
+++ b/core/tests/coretests/src/android/hardware/face/FaceManagerTest.java
@@ -194,13 +194,13 @@ public class FaceManagerTest {
new CancellationSignal(), mEnrollmentCallback, null /* disabledFeatures */);
verify(mService).enroll(eq(USER_ID), any(), any(), any(), anyString(), any(), any(),
- anyBoolean());
+ anyBoolean(), any());
mFaceManager.enroll(USER_ID, new byte[]{},
new CancellationSignal(), mEnrollmentCallback, null /* disabledFeatures */);
verify(mService, atMost(1 /* maxNumberOfInvocations */)).enroll(eq(USER_ID), any(), any(),
- any(), anyString(), any(), any(), anyBoolean());
+ any(), anyString(), any(), any(), anyBoolean(), any());
verify(mEnrollmentCallback).onEnrollmentError(eq(FACE_ERROR_HW_UNAVAILABLE), anyString());
}
@@ -213,7 +213,7 @@ public class FaceManagerTest {
verify(mEnrollmentCallback).onEnrollmentError(eq(FACE_ERROR_UNABLE_TO_PROCESS),
anyString());
verify(mService, never()).enroll(eq(USER_ID), any(), any(),
- any(), anyString(), any(), any(), anyBoolean());
+ any(), anyString(), any(), any(), anyBoolean(), any());
}
@Test
diff --git a/core/tests/coretests/src/android/hardware/fingerprint/FingerprintManagerTest.java b/core/tests/coretests/src/android/hardware/fingerprint/FingerprintManagerTest.java
index 70313b8c9ea7..ce7d6a95c2f4 100644
--- a/core/tests/coretests/src/android/hardware/fingerprint/FingerprintManagerTest.java
+++ b/core/tests/coretests/src/android/hardware/fingerprint/FingerprintManagerTest.java
@@ -162,11 +162,13 @@ public class FingerprintManagerTest {
mCaptor.getValue().onAllAuthenticatorsRegistered(mProps);
mFingerprintManager.enroll(null, new CancellationSignal(), USER_ID,
- mEnrollCallback, FingerprintManager.ENROLL_ENROLL);
+ mEnrollCallback, FingerprintManager.ENROLL_ENROLL,
+ (new FingerprintEnrollOptions.Builder()).build());
verify(mEnrollCallback).onEnrollmentError(eq(FINGERPRINT_ERROR_UNABLE_TO_PROCESS),
anyString());
- verify(mService, never()).enroll(any(), any(), anyInt(), any(), anyString(), anyInt());
+ verify(mService, never()).enroll(any(), any(), anyInt(), any(), anyString(), anyInt(),
+ any());
}
@Test
diff --git a/services/core/java/com/android/server/biometrics/AuthenticationStatsCollector.java b/services/core/java/com/android/server/biometrics/AuthenticationStatsCollector.java
index 5d609bca334c..526264d67318 100644
--- a/services/core/java/com/android/server/biometrics/AuthenticationStatsCollector.java
+++ b/services/core/java/com/android/server/biometrics/AuthenticationStatsCollector.java
@@ -153,7 +153,6 @@ public class AuthenticationStatsCollector {
if (authenticationStats.getTotalAttempts() < MINIMUM_ATTEMPTS) {
return;
}
-
// Don't send notification if FRR below the threshold.
if (authenticationStats.getEnrollmentNotifications() >= MAXIMUM_ENROLLMENT_NOTIFICATIONS
|| authenticationStats.getFrr() < mThreshold) {
@@ -161,6 +160,7 @@ public class AuthenticationStatsCollector {
return;
}
+
authenticationStats.resetData();
final boolean hasEnrolledFace = hasEnrolledFace(userId);
@@ -186,6 +186,28 @@ public class AuthenticationStatsCollector {
}
}
+ /**
+ * This is meant for debug purposes only, this will bypass many checks.
+ * The origination of this call should be from an adb shell command sent from
+ * FaceService.
+ *
+ * adb shell cmd face notification
+ */
+ public void sendFaceReEnrollNotification() {
+ mBiometricNotification.sendFaceEnrollNotification(mContext);
+ }
+
+ /**
+ * This is meant for debug purposes only, this will bypass many checks.
+ * The origination of this call should be from an adb shell command sent from
+ * FingerprintService.
+ *
+ * adb shell cmd fingerprint notification
+ */
+ public void sendFingerprintReEnrollNotification() {
+ mBiometricNotification.sendFpEnrollNotification(mContext);
+ }
+
private void onUserRemoved(final int userId) {
mUserAuthenticationStatsMap.remove(userId);
mAuthenticationStatsPersister.removeFrrStats(userId);
diff --git a/services/core/java/com/android/server/biometrics/BiometricNotificationLogger.java b/services/core/java/com/android/server/biometrics/BiometricNotificationLogger.java
new file mode 100644
index 000000000000..51a2b1ac2dfc
--- /dev/null
+++ b/services/core/java/com/android/server/biometrics/BiometricNotificationLogger.java
@@ -0,0 +1,104 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.biometrics;
+
+import android.hardware.biometrics.BiometricsProtoEnums;
+import android.service.notification.NotificationListenerService;
+import android.service.notification.StatusBarNotification;
+import android.util.Slog;
+
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.server.biometrics.sensors.BiometricNotificationUtils;
+import com.android.server.biometrics.log.BiometricFrameworkStatsLogger;
+
+/**
+ * A class that logs metric info related to the posting/dismissal of Biometric FRR notifications.
+ */
+public class BiometricNotificationLogger extends NotificationListenerService {
+ private static final String TAG = "FRRNotificationListener";
+ private BiometricFrameworkStatsLogger mLogger;
+
+ BiometricNotificationLogger() {
+ this(BiometricFrameworkStatsLogger.getInstance());
+ }
+
+ @VisibleForTesting
+ BiometricNotificationLogger(BiometricFrameworkStatsLogger logger) {
+ mLogger = logger;
+ }
+
+ @Override
+ public void onNotificationPosted(StatusBarNotification sbn, RankingMap map) {
+ if (sbn == null || sbn.getTag() == null) {
+ return;
+ }
+ switch (sbn.getTag()) {
+ case BiometricNotificationUtils.FACE_ENROLL_NOTIFICATION_TAG:
+ case BiometricNotificationUtils.FINGERPRINT_ENROLL_NOTIFICATION_TAG:
+ final int modality =
+ sbn.getTag() == BiometricNotificationUtils.FACE_ENROLL_NOTIFICATION_TAG
+ ? BiometricsProtoEnums.MODALITY_FACE
+ : BiometricsProtoEnums.MODALITY_FINGERPRINT;
+ Slog.d(TAG, "onNotificationPosted, tag=(" + sbn.getTag() + ")");
+ mLogger.logFrameworkNotification(
+ BiometricsProtoEnums.FRR_NOTIFICATION_ACTION_SHOWN,
+ modality
+ );
+ break;
+ default:
+ break;
+ }
+ }
+
+ @Override
+ public void onNotificationRemoved(StatusBarNotification sbn, RankingMap rankingMap,
+ int reason) {
+ if (sbn == null || sbn.getTag() == null) {
+ return;
+ }
+ switch (sbn.getTag()) {
+ case BiometricNotificationUtils.FACE_ENROLL_NOTIFICATION_TAG:
+ case BiometricNotificationUtils.FINGERPRINT_ENROLL_NOTIFICATION_TAG:
+ Slog.d(TAG, "onNotificationRemoved, tag=("
+ + sbn.getTag() + "), reason=(" + reason + ")");
+ final int modality =
+ sbn.getTag() == BiometricNotificationUtils.FACE_ENROLL_NOTIFICATION_TAG
+ ? BiometricsProtoEnums.MODALITY_FACE
+ : BiometricsProtoEnums.MODALITY_FINGERPRINT;
+ switch (reason) {
+ // REASON_CLICK = 1
+ case NotificationListenerService.REASON_CLICK:
+ mLogger.logFrameworkNotification(
+ BiometricsProtoEnums.FRR_NOTIFICATION_ACTION_CLICKED,
+ modality);
+ break;
+ // REASON_CANCEL = 2
+ case NotificationListenerService.REASON_CANCEL:
+ mLogger.logFrameworkNotification(
+ BiometricsProtoEnums.FRR_NOTIFICATION_ACTION_DISMISSED,
+ modality);
+ break;
+ default:
+ Slog.d(TAG, "unhandled reason, ignoring logging");
+ break;
+ }
+ break;
+ default:
+ break;
+ }
+ }
+}
diff --git a/services/core/java/com/android/server/biometrics/BiometricService.java b/services/core/java/com/android/server/biometrics/BiometricService.java
index fc948da260e6..894b4d5d0b36 100644
--- a/services/core/java/com/android/server/biometrics/BiometricService.java
+++ b/services/core/java/com/android/server/biometrics/BiometricService.java
@@ -32,6 +32,7 @@ import android.app.UserSwitchObserver;
import android.app.admin.DevicePolicyManager;
import android.app.trust.ITrustManager;
import android.content.ContentResolver;
+import android.content.ComponentName;
import android.content.Context;
import android.content.pm.PackageManager;
import android.content.pm.UserInfo;
@@ -143,6 +144,8 @@ public class BiometricService extends SystemService {
private final BiometricCameraManager mBiometricCameraManager;
+ private final BiometricNotificationLogger mBiometricNotificationLogger;
+
/**
* Tracks authenticatorId invalidation. For more details, see
* {@link com.android.server.biometrics.sensors.InvalidationRequesterClient}.
@@ -1100,6 +1103,10 @@ public class BiometricService extends SystemService {
return new BiometricCameraManagerImpl(context.getSystemService(CameraManager.class),
context.getSystemService(SensorPrivacyManager.class));
}
+
+ public BiometricNotificationLogger getNotificationLogger() {
+ return new BiometricNotificationLogger();
+ }
}
/**
@@ -1133,6 +1140,7 @@ public class BiometricService extends SystemService {
mBiometricCameraManager = injector.getBiometricCameraManager(context);
mKeystoreAuthorization = injector.getKeystoreAuthorizationService();
mGateKeeper = injector.getGateKeeperService();
+ mBiometricNotificationLogger = injector.getNotificationLogger();
try {
injector.getActivityManagerService().registerUserSwitchObserver(
@@ -1157,6 +1165,20 @@ public class BiometricService extends SystemService {
mInjector.publishBinderService(this, mImpl);
mBiometricStrengthController = mInjector.getBiometricStrengthController(this);
mBiometricStrengthController.startListening();
+
+ mHandler.post(new Runnable(){
+ @Override
+ public void run() {
+ try {
+ mBiometricNotificationLogger.registerAsSystemService(getContext(),
+ new ComponentName(getContext(), BiometricNotificationLogger.class),
+ UserHandle.USER_ALL);
+ } catch (RemoteException e) {
+ // Intra-process call, should never happen.
+ }
+ }
+
+ });
}
private boolean isStrongBiometric(int id) {
@@ -1508,4 +1530,5 @@ public class BiometricService extends SystemService {
pw.println("CurrentSession: " + mAuthSession);
pw.println();
}
+
}
diff --git a/services/core/java/com/android/server/biometrics/log/BiometricFrameworkStatsLogger.java b/services/core/java/com/android/server/biometrics/log/BiometricFrameworkStatsLogger.java
index 6bd48802baf5..f31b2e11b021 100644
--- a/services/core/java/com/android/server/biometrics/log/BiometricFrameworkStatsLogger.java
+++ b/services/core/java/com/android/server/biometrics/log/BiometricFrameworkStatsLogger.java
@@ -113,14 +113,16 @@ public class BiometricFrameworkStatsLogger {
/** {@see FrameworkStatsLog.BIOMETRIC_ENROLLED}. */
public void enroll(int statsModality, int statsAction, int statsClient,
- int targetUserId, long latency, boolean enrollSuccessful, float ambientLightLux) {
+ int targetUserId, long latency, boolean enrollSuccessful, float ambientLightLux,
+ int source) {
FrameworkStatsLog.write(FrameworkStatsLog.BIOMETRIC_ENROLLED,
statsModality,
targetUserId,
sanitizeLatency(latency),
enrollSuccessful,
-1, /* sensorId */
- ambientLightLux);
+ ambientLightLux,
+ source);
}
/** {@see FrameworkStatsLog.BIOMETRIC_ERROR_OCCURRED}. */
@@ -239,6 +241,12 @@ public class BiometricFrameworkStatsLogger {
-1 /* sensorId */);
}
+ /** {@see FrameworkStatsLog.BIOMETRIC_FRR_NOTIFICATION}. */
+ public void logFrameworkNotification(int action, int modality) {
+ FrameworkStatsLog.write(FrameworkStatsLog.BIOMETRIC_FRR_NOTIFICATION,
+ action, modality);
+ }
+
private long sanitizeLatency(long latency) {
if (latency < 0) {
Slog.w(TAG, "found a negative latency : " + latency);
diff --git a/services/core/java/com/android/server/biometrics/log/BiometricLogger.java b/services/core/java/com/android/server/biometrics/log/BiometricLogger.java
index dbef7178efd0..cd5d0c8dc3f2 100644
--- a/services/core/java/com/android/server/biometrics/log/BiometricLogger.java
+++ b/services/core/java/com/android/server/biometrics/log/BiometricLogger.java
@@ -252,7 +252,8 @@ public class BiometricLogger {
}
/** Log enrollment outcome. */
- public void logOnEnrolled(int targetUserId, long latency, boolean enrollSuccessful) {
+ public void logOnEnrolled(int targetUserId, long latency, boolean enrollSuccessful,
+ int source) {
if (!mShouldLogMetrics) {
return;
}
@@ -273,7 +274,7 @@ public class BiometricLogger {
}
mSink.enroll(mStatsModality, mStatsAction, mStatsClient,
- targetUserId, latency, enrollSuccessful, mALSProbe.getMostRecentLux());
+ targetUserId, latency, enrollSuccessful, mALSProbe.getMostRecentLux(), source);
}
/** Report unexpected enrollment reported by the HAL. */
diff --git a/services/core/java/com/android/server/biometrics/sensors/BiometricNotificationUtils.java b/services/core/java/com/android/server/biometrics/sensors/BiometricNotificationUtils.java
index 2aec9aefa8d1..0e22f7511af9 100644
--- a/services/core/java/com/android/server/biometrics/sensors/BiometricNotificationUtils.java
+++ b/services/core/java/com/android/server/biometrics/sensors/BiometricNotificationUtils.java
@@ -23,6 +23,9 @@ import android.app.NotificationManager;
import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent;
+import android.hardware.biometrics.BiometricManager;
+import android.hardware.face.FaceEnrollOptions;
+import android.hardware.fingerprint.FingerprintEnrollOptions;
import android.os.SystemClock;
import android.os.UserHandle;
import android.util.Slog;
@@ -36,25 +39,28 @@ public class BiometricNotificationUtils {
private static final String TAG = "BiometricNotificationUtils";
private static final String FACE_RE_ENROLL_NOTIFICATION_TAG = "FaceReEnroll";
- private static final String FACE_ENROLL_NOTIFICATION_TAG = "FaceEnroll";
- private static final String FINGERPRINT_ENROLL_NOTIFICATION_TAG = "FingerprintEnroll";
private static final String BAD_CALIBRATION_NOTIFICATION_TAG = "FingerprintBadCalibration";
private static final String KEY_RE_ENROLL_FACE = "re_enroll_face_unlock";
private static final String FACE_SETTINGS_ACTION = "android.settings.FACE_SETTINGS";
- private static final String FINGERPRINT_SETTINGS_ACTION =
- "android.settings.FINGERPRINT_SETTINGS";
private static final String FACE_ENROLL_ACTION = "android.settings.FACE_ENROLL";
private static final String FINGERPRINT_ENROLL_ACTION = "android.settings.FINGERPRINT_ENROLL";
+ private static final String FINGERPRINT_SETTINGS_ACTION =
+ "android.settings.FINGERPRINT_SETTINGS";
private static final String SETTINGS_PACKAGE = "com.android.settings";
private static final String FACE_ENROLL_CHANNEL = "FaceEnrollNotificationChannel";
private static final String FACE_RE_ENROLL_CHANNEL = "FaceReEnrollNotificationChannel";
private static final String FINGERPRINT_ENROLL_CHANNEL = "FingerprintEnrollNotificationChannel";
private static final String FINGERPRINT_BAD_CALIBRATION_CHANNEL =
"FingerprintBadCalibrationNotificationChannel";
- private static final int NOTIFICATION_ID = 1;
private static final long NOTIFICATION_INTERVAL_MS = 24 * 60 * 60 * 1000;
private static long sLastAlertTime = 0;
+ private static final String ACTION_BIOMETRIC_FRR_DISMISS = "action_biometric_frr_dismiss";
+ // Dismissal action for FRR notification.
+ private static final Intent DISMISS_FRR_INTENT = new Intent(ACTION_BIOMETRIC_FRR_DISMISS);
+ public static final int NOTIFICATION_ID = 1;
+ public static final String FACE_ENROLL_NOTIFICATION_TAG = "FaceEnroll";
+ public static final String FINGERPRINT_ENROLL_NOTIFICATION_TAG = "FingerprintEnroll";
/**
* Shows a face re-enrollment notification.
*/
@@ -71,7 +77,6 @@ public class BiometricNotificationUtils {
final Intent intent = new Intent(FACE_SETTINGS_ACTION);
intent.setPackage(SETTINGS_PACKAGE);
- intent.putExtra(KEY_RE_ENROLL_FACE, true);
final PendingIntent pendingIntent = PendingIntent.getActivityAsUser(context,
0 /* requestCode */, intent, PendingIntent.FLAG_IMMUTABLE /* flags */,
@@ -79,13 +84,14 @@ public class BiometricNotificationUtils {
showNotificationHelper(context, name, title, content, pendingIntent, FACE_RE_ENROLL_CHANNEL,
Notification.CATEGORY_SYSTEM, FACE_RE_ENROLL_NOTIFICATION_TAG,
- Notification.VISIBILITY_SECRET);
+ Notification.VISIBILITY_SECRET, false);
}
/**
* Shows a face enrollment notification.
*/
public static void showFaceEnrollNotification(@NonNull Context context) {
+ Slog.d(TAG, "Showing Face Enroll Notification");
final String name =
context.getString(R.string.device_unlock_notification_name);
@@ -96,6 +102,8 @@ public class BiometricNotificationUtils {
final Intent intent = new Intent(FACE_ENROLL_ACTION);
intent.setPackage(SETTINGS_PACKAGE);
+ intent.putExtra(BiometricManager.EXTRA_ENROLL_REASON,
+ FaceEnrollOptions.ENROLL_REASON_RE_ENROLL_NOTIFICATION);
final PendingIntent pendingIntent = PendingIntent.getActivityAsUser(context,
0 /* requestCode */, intent, PendingIntent.FLAG_IMMUTABLE /* flags */,
@@ -103,14 +111,15 @@ public class BiometricNotificationUtils {
showNotificationHelper(context, name, title, content, pendingIntent, FACE_ENROLL_CHANNEL,
Notification.CATEGORY_RECOMMENDATION, FACE_ENROLL_NOTIFICATION_TAG,
- Notification.VISIBILITY_PUBLIC);
+ Notification.VISIBILITY_PUBLIC, true);
+
}
/**
* Shows a fingerprint enrollment notification.
*/
public static void showFingerprintEnrollNotification(@NonNull Context context) {
-
+ Slog.d(TAG, "Showing Fingerprint Enroll Notification");
final String name =
context.getString(R.string.device_unlock_notification_name);
final String title =
@@ -120,6 +129,8 @@ public class BiometricNotificationUtils {
final Intent intent = new Intent(FINGERPRINT_ENROLL_ACTION);
intent.setPackage(SETTINGS_PACKAGE);
+ intent.putExtra(BiometricManager.EXTRA_ENROLL_REASON,
+ FingerprintEnrollOptions.ENROLL_REASON_RE_ENROLL_NOTIFICATION);
final PendingIntent pendingIntent = PendingIntent.getActivityAsUser(context,
0 /* requestCode */, intent, PendingIntent.FLAG_IMMUTABLE /* flags */,
@@ -127,7 +138,8 @@ public class BiometricNotificationUtils {
showNotificationHelper(context, name, title, content, pendingIntent,
Notification.CATEGORY_RECOMMENDATION, FINGERPRINT_ENROLL_CHANNEL,
- FINGERPRINT_ENROLL_NOTIFICATION_TAG, Notification.VISIBILITY_PUBLIC);
+ FINGERPRINT_ENROLL_NOTIFICATION_TAG, Notification.VISIBILITY_PUBLIC, true);
+
}
/**
@@ -162,17 +174,22 @@ public class BiometricNotificationUtils {
showNotificationHelper(context, name, title, content, pendingIntent,
Notification.CATEGORY_SYSTEM, FINGERPRINT_BAD_CALIBRATION_CHANNEL,
- BAD_CALIBRATION_NOTIFICATION_TAG, Notification.VISIBILITY_SECRET);
+ BAD_CALIBRATION_NOTIFICATION_TAG, Notification.VISIBILITY_SECRET, false);
}
private static void showNotificationHelper(Context context, String name, String title,
String content, PendingIntent pendingIntent, String category,
- String channelName, String notificationTag, int visibility) {
+ String channelName, String notificationTag, int visibility,
+ boolean listenToDismissEvent) {
+ Slog.v(TAG," listenToDismissEvent = " + listenToDismissEvent);
+ final PendingIntent dismissIntent = PendingIntent.getActivityAsUser(context,
+ 0 /* requestCode */, DISMISS_FRR_INTENT, PendingIntent.FLAG_IMMUTABLE /* flags */,
+ null /* options */, UserHandle.CURRENT);
final NotificationManager notificationManager =
context.getSystemService(NotificationManager.class);
final NotificationChannel channel = new NotificationChannel(channelName, name,
NotificationManager.IMPORTANCE_HIGH);
- final Notification notification = new Notification.Builder(context, channelName)
+ final Notification.Builder builder = new Notification.Builder(context, channelName)
.setSmallIcon(R.drawable.ic_lock)
.setContentTitle(title)
.setContentText(content)
@@ -183,12 +200,17 @@ public class BiometricNotificationUtils {
.setAutoCancel(true)
.setCategory(category)
.setContentIntent(pendingIntent)
- .setVisibility(visibility)
- .build();
+ .setVisibility(visibility);
+
+ if (listenToDismissEvent) {
+ builder.setDeleteIntent(dismissIntent);
+ }
+ final Notification notification = builder.build();
notificationManager.createNotificationChannel(channel);
notificationManager.notifyAsUser(notificationTag, NOTIFICATION_ID, notification,
UserHandle.CURRENT);
+
}
/**
diff --git a/services/core/java/com/android/server/biometrics/sensors/EnrollClient.java b/services/core/java/com/android/server/biometrics/sensors/EnrollClient.java
index 8e7004d8fde5..af6de5c7316a 100644
--- a/services/core/java/com/android/server/biometrics/sensors/EnrollClient.java
+++ b/services/core/java/com/android/server/biometrics/sensors/EnrollClient.java
@@ -45,6 +45,7 @@ public abstract class EnrollClient<T> extends AcquisitionClient<T> implements En
private long mEnrollmentStartTimeMs;
private final boolean mHasEnrollmentsBeforeStarting;
+ private final int mEnrollReason;
/**
* @return true if the user has already enrolled the maximum number of templates.
@@ -55,13 +56,15 @@ public abstract class EnrollClient<T> extends AcquisitionClient<T> implements En
@NonNull IBinder token, @NonNull ClientMonitorCallbackConverter listener, int userId,
@NonNull byte[] hardwareAuthToken, @NonNull String owner, @NonNull BiometricUtils utils,
int timeoutSec, int sensorId, boolean shouldVibrate,
- @NonNull BiometricLogger logger, @NonNull BiometricContext biometricContext) {
+ @NonNull BiometricLogger logger, @NonNull BiometricContext biometricContext,
+ int enrollReason) {
super(context, lazyDaemon, token, listener, userId, owner, 0 /* cookie */, sensorId,
shouldVibrate, logger, biometricContext);
mBiometricUtils = utils;
mHardwareAuthToken = Arrays.copyOf(hardwareAuthToken, hardwareAuthToken.length);
mTimeoutSec = timeoutSec;
mHasEnrollmentsBeforeStarting = hasEnrollments();
+ mEnrollReason = enrollReason;
}
@Override
@@ -91,7 +94,7 @@ public abstract class EnrollClient<T> extends AcquisitionClient<T> implements En
mBiometricUtils.addBiometricForUser(getContext(), getTargetUserId(), identifier);
getLogger().logOnEnrolled(getTargetUserId(),
System.currentTimeMillis() - mEnrollmentStartTimeMs,
- true /* enrollSuccessful */);
+ true /* enrollSuccessful */, mEnrollReason);
mCallback.onClientFinished(this, true /* success */);
}
notifyUserActivity();
@@ -119,7 +122,7 @@ public abstract class EnrollClient<T> extends AcquisitionClient<T> implements En
public void onError(int error, int vendorCode) {
getLogger().logOnEnrolled(getTargetUserId(),
System.currentTimeMillis() - mEnrollmentStartTimeMs,
- false /* enrollSuccessful */);
+ false /* enrollSuccessful */, mEnrollReason);
super.onError(error, vendorCode);
}
diff --git a/services/core/java/com/android/server/biometrics/sensors/face/FaceService.java b/services/core/java/com/android/server/biometrics/sensors/face/FaceService.java
index 321e951ec09b..68b4e3fb51ba 100644
--- a/services/core/java/com/android/server/biometrics/sensors/face/FaceService.java
+++ b/services/core/java/com/android/server/biometrics/sensors/face/FaceService.java
@@ -37,6 +37,7 @@ 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.FaceEnrollOptions;
import android.hardware.face.FaceSensorConfigurations;
import android.hardware.face.FaceSensorPropertiesInternal;
import android.hardware.face.FaceServiceReceiver;
@@ -44,6 +45,7 @@ import android.hardware.face.IFaceAuthenticatorsRegisteredCallback;
import android.hardware.face.IFaceService;
import android.hardware.face.IFaceServiceReceiver;
import android.os.Binder;
+import android.os.Build;
import android.os.IBinder;
import android.os.NativeHandle;
import android.os.RemoteException;
@@ -210,7 +212,8 @@ public class FaceService extends SystemService {
@Override // Binder call
public long enroll(int userId, final IBinder token, final byte[] hardwareAuthToken,
final IFaceServiceReceiver receiver, final String opPackageName,
- final int[] disabledFeatures, Surface previewSurface, boolean debugConsent) {
+ final int[] disabledFeatures, Surface previewSurface, boolean debugConsent,
+ FaceEnrollOptions options) {
super.enroll_enforcePermission();
final Pair<Integer, ServiceProvider> provider = mRegistry.getSingleProvider();
@@ -220,7 +223,8 @@ public class FaceService extends SystemService {
}
return provider.second.scheduleEnroll(provider.first, token, hardwareAuthToken, userId,
- receiver, opPackageName, disabledFeatures, previewSurface, debugConsent);
+ receiver, opPackageName, disabledFeatures, previewSurface, debugConsent,
+ options);
}
@android.annotation.EnforcePermission(android.Manifest.permission.USE_BIOMETRIC_INTERNAL)
@@ -958,4 +962,25 @@ public class FaceService extends SystemService {
}
}
}
+
+ /**
+ * This should only be called from FaceShellCommand class.
+ */
+ void sendFaceReEnrollNotification() {
+ Utils.checkPermissionOrShell(getContext(), MANAGE_FACE);
+ if (Build.IS_DEBUGGABLE) {
+ final long identity = Binder.clearCallingIdentity();
+ try {
+ final Pair<Integer, ServiceProvider> provider = mRegistry.getSingleProvider();
+ if (provider != null) {
+ FaceProvider faceProvider = (FaceProvider) provider.second;
+ faceProvider.sendFaceReEnrollNotification();
+ } else {
+ Slog.w(TAG, "Null provider for notification");
+ }
+ } finally {
+ Binder.restoreCallingIdentity(identity);
+ }
+ }
+ }
}
diff --git a/services/core/java/com/android/server/biometrics/sensors/face/FaceShellCommand.java b/services/core/java/com/android/server/biometrics/sensors/face/FaceShellCommand.java
index 187575dcd664..e167bbafc02e 100644
--- a/services/core/java/com/android/server/biometrics/sensors/face/FaceShellCommand.java
+++ b/services/core/java/com/android/server/biometrics/sensors/face/FaceShellCommand.java
@@ -42,6 +42,8 @@ public class FaceShellCommand extends ShellCommand {
return doHelp();
case "sync":
return doSync();
+ case "notification":
+ return doNotify();
default:
getOutPrintWriter().println("Unrecognized command: " + cmd);
}
@@ -59,6 +61,8 @@ public class FaceShellCommand extends ShellCommand {
pw.println(" Print this help text.");
pw.println(" sync");
pw.println(" Sync enrollments now (virtualized sensors only).");
+ pw.println(" notification");
+ pw.println(" Sends a Face re-enrollment notification");
}
private int doHelp() {
@@ -70,4 +74,9 @@ public class FaceShellCommand extends ShellCommand {
mService.syncEnrollmentsNow();
return 0;
}
+
+ private int doNotify() {
+ mService.sendFaceReEnrollNotification();
+ return 0;
+ }
}
diff --git a/services/core/java/com/android/server/biometrics/sensors/face/ServiceProvider.java b/services/core/java/com/android/server/biometrics/sensors/face/ServiceProvider.java
index 2cf64b72d01f..6f76cdae4539 100644
--- a/services/core/java/com/android/server/biometrics/sensors/face/ServiceProvider.java
+++ b/services/core/java/com/android/server/biometrics/sensors/face/ServiceProvider.java
@@ -23,6 +23,7 @@ import android.hardware.biometrics.ITestSession;
import android.hardware.biometrics.ITestSessionCallback;
import android.hardware.face.Face;
import android.hardware.face.FaceAuthenticateOptions;
+import android.hardware.face.FaceEnrollOptions;
import android.hardware.face.FaceManager;
import android.hardware.face.FaceSensorPropertiesInternal;
import android.hardware.face.IFaceServiceReceiver;
@@ -79,7 +80,7 @@ public interface ServiceProvider extends BiometricServiceProvider<FaceSensorProp
long scheduleEnroll(int sensorId, @NonNull IBinder token, @NonNull byte[] hardwareAuthToken,
int userId, @NonNull IFaceServiceReceiver receiver, @NonNull String opPackageName,
@NonNull int[] disabledFeatures, @Nullable Surface previewSurface,
- boolean debugConsent);
+ boolean debugConsent, FaceEnrollOptions options);
void cancelEnrollment(int sensorId, @NonNull IBinder token, long requestId);
diff --git a/services/core/java/com/android/server/biometrics/sensors/face/aidl/BiometricTestSessionImpl.java b/services/core/java/com/android/server/biometrics/sensors/face/aidl/BiometricTestSessionImpl.java
index d11f0991a5d4..0fdd57d64d8d 100644
--- a/services/core/java/com/android/server/biometrics/sensors/face/aidl/BiometricTestSessionImpl.java
+++ b/services/core/java/com/android/server/biometrics/sensors/face/aidl/BiometricTestSessionImpl.java
@@ -26,6 +26,7 @@ import android.hardware.biometrics.face.EnrollmentFrame;
import android.hardware.face.Face;
import android.hardware.face.FaceAuthenticationFrame;
import android.hardware.face.FaceEnrollFrame;
+import android.hardware.face.FaceEnrollOptions;
import android.hardware.face.IFaceServiceReceiver;
import android.os.Binder;
import android.os.RemoteException;
@@ -155,7 +156,8 @@ public class BiometricTestSessionImpl extends ITestSession.Stub {
mProvider.scheduleEnroll(mSensorId, new Binder(), new byte[69], userId, mReceiver,
mContext.getOpPackageName(), new int[0] /* disabledFeatures */,
- null /* previewSurface */, false /* debugConsent */);
+ null /* previewSurface */, false /* debugConsent */,
+ (new FaceEnrollOptions.Builder()).build());
}
@android.annotation.EnforcePermission(android.Manifest.permission.TEST_BIOMETRIC)
diff --git a/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceEnrollClient.java b/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceEnrollClient.java
index 5f370f23134c..781e3f491ec8 100644
--- a/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceEnrollClient.java
+++ b/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceEnrollClient.java
@@ -93,9 +93,11 @@ public class FaceEnrollClient extends EnrollClient<AidlSession> {
@NonNull BiometricUtils<Face> utils, @NonNull int[] disabledFeatures, int timeoutSec,
@Nullable Surface previewSurface, int sensorId,
@NonNull BiometricLogger logger, @NonNull BiometricContext biometricContext,
- int maxTemplatesPerUser, boolean debugConsent) {
+ int maxTemplatesPerUser, boolean debugConsent,
+ android.hardware.face.FaceEnrollOptions options) {
super(context, lazyDaemon, token, listener, userId, hardwareAuthToken, opPackageName, utils,
- timeoutSec, sensorId, false /* shouldVibrate */, logger, biometricContext);
+ timeoutSec, sensorId, false /* shouldVibrate */, logger, biometricContext,
+ BiometricFaceConstants.reasonToMetric(options.getEnrollReason()));
setRequestId(requestId);
mEnrollIgnoreList = getContext().getResources()
.getIntArray(R.array.config_face_acquire_enroll_ignorelist);
@@ -105,6 +107,9 @@ public class FaceEnrollClient extends EnrollClient<AidlSession> {
mDebugConsent = debugConsent;
mDisabledFeatures = disabledFeatures;
mPreviewSurface = previewSurface;
+ Slog.w(TAG, "EnrollOptions "
+ + android.hardware.face.FaceEnrollOptions.enrollReasonToString(
+ options.getEnrollReason()));
}
@Override
diff --git a/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceProvider.java b/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceProvider.java
index f469f6224e4c..007b7462f637 100644
--- a/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceProvider.java
+++ b/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceProvider.java
@@ -35,6 +35,7 @@ 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.FaceEnrollOptions;
import android.hardware.face.FaceSensorPropertiesInternal;
import android.hardware.face.IFaceServiceReceiver;
import android.os.Binder;
@@ -519,7 +520,7 @@ public class FaceProvider implements IBinder.DeathRecipient, ServiceProvider {
public long scheduleEnroll(int sensorId, @NonNull IBinder token,
@NonNull byte[] hardwareAuthToken, int userId, @NonNull IFaceServiceReceiver receiver,
@NonNull String opPackageName, @NonNull int[] disabledFeatures,
- @Nullable Surface previewSurface, boolean debugConsent) {
+ @Nullable Surface previewSurface, boolean debugConsent, FaceEnrollOptions options) {
final long id = mRequestCounter.incrementAndGet();
mHandler.post(() -> {
mFaceSensors.get(sensorId).scheduleFaceUpdateActiveUserClient(userId);
@@ -533,7 +534,7 @@ public class FaceProvider implements IBinder.DeathRecipient, ServiceProvider {
createLogger(BiometricsProtoEnums.ACTION_ENROLL,
BiometricsProtoEnums.CLIENT_UNKNOWN,
mAuthenticationStatsCollector),
- mBiometricContext, maxTemplatesPerUser, debugConsent);
+ mBiometricContext, maxTemplatesPerUser, debugConsent, options);
if (Flags.deHidl()) {
scheduleForSensor(sensorId, client, mBiometricStateCallback);
} else {
@@ -903,4 +904,11 @@ public class FaceProvider implements IBinder.DeathRecipient, ServiceProvider {
public boolean getTestHalEnabled() {
return mTestHalEnabled;
}
+
+ /**
+ * Sends a face re enroll notification.
+ */
+ public void sendFaceReEnrollNotification() {
+ mAuthenticationStatsCollector.sendFaceReEnrollNotification();
+ }
}
diff --git a/services/core/java/com/android/server/biometrics/sensors/face/hidl/BiometricTestSessionImpl.java b/services/core/java/com/android/server/biometrics/sensors/face/hidl/BiometricTestSessionImpl.java
index 151ffaa1cb28..0e2367a599a5 100644
--- a/services/core/java/com/android/server/biometrics/sensors/face/hidl/BiometricTestSessionImpl.java
+++ b/services/core/java/com/android/server/biometrics/sensors/face/hidl/BiometricTestSessionImpl.java
@@ -23,6 +23,7 @@ import android.hardware.biometrics.ITestSessionCallback;
import android.hardware.face.Face;
import android.hardware.face.FaceAuthenticationFrame;
import android.hardware.face.FaceEnrollFrame;
+import android.hardware.face.FaceEnrollOptions;
import android.hardware.face.IFaceServiceReceiver;
import android.os.Binder;
import android.os.RemoteException;
@@ -143,7 +144,8 @@ public class BiometricTestSessionImpl extends ITestSession.Stub {
mFace10.scheduleEnroll(mSensorId, new Binder(), new byte[69], userId, mReceiver,
mContext.getOpPackageName(), new int[0] /* disabledFeatures */,
- null /* previewSurface */, false /* debugConsent */);
+ null /* previewSurface */, false /* debugConsent */,
+ (new FaceEnrollOptions.Builder()).build());
}
@android.annotation.EnforcePermission(android.Manifest.permission.TEST_BIOMETRIC)
diff --git a/services/core/java/com/android/server/biometrics/sensors/face/hidl/Face10.java b/services/core/java/com/android/server/biometrics/sensors/face/hidl/Face10.java
index 48a676ce4937..306ddfa1e083 100644
--- a/services/core/java/com/android/server/biometrics/sensors/face/hidl/Face10.java
+++ b/services/core/java/com/android/server/biometrics/sensors/face/hidl/Face10.java
@@ -32,6 +32,7 @@ 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.FaceEnrollOptions;
import android.hardware.face.FaceSensorPropertiesInternal;
import android.hardware.face.IFaceServiceReceiver;
import android.os.Binder;
@@ -711,16 +712,17 @@ public class Face10 implements IHwBinder.DeathRecipient, ServiceProvider {
public long scheduleEnroll(int sensorId, @NonNull IBinder token,
@NonNull byte[] hardwareAuthToken, int userId, @NonNull IFaceServiceReceiver receiver,
@NonNull String opPackageName, @NonNull int[] disabledFeatures,
- @Nullable Surface previewSurface, boolean debugConsent) {
+ @Nullable Surface previewSurface, boolean debugConsent,
+ @NonNull FaceEnrollOptions options) {
final long id = mRequestCounter.incrementAndGet();
mHandler.post(() -> {
scheduleUpdateActiveUserWithoutHandler(userId);
if (Flags.deHidl()) {
scheduleEnrollAidl(token, hardwareAuthToken, userId, receiver,
- opPackageName, disabledFeatures, previewSurface, id);
+ opPackageName, disabledFeatures, previewSurface, id, options);
} else {
scheduleEnrollHidl(token, hardwareAuthToken, userId, receiver,
- opPackageName, disabledFeatures, previewSurface, id);
+ opPackageName, disabledFeatures, previewSurface, id, options);
}
});
return id;
@@ -729,7 +731,8 @@ public class Face10 implements IHwBinder.DeathRecipient, ServiceProvider {
private void scheduleEnrollAidl(@NonNull IBinder token,
@NonNull byte[] hardwareAuthToken, int userId, @NonNull IFaceServiceReceiver receiver,
@NonNull String opPackageName, @NonNull int[] disabledFeatures,
- @Nullable Surface previewSurface, long id) {
+ @Nullable Surface previewSurface, long id,
+ @NonNull FaceEnrollOptions options) {
final com.android.server.biometrics.sensors.face.aidl.FaceEnrollClient client =
new com.android.server.biometrics.sensors.face.aidl.FaceEnrollClient(
mContext, this::getSession, token,
@@ -742,7 +745,7 @@ public class Face10 implements IHwBinder.DeathRecipient, ServiceProvider {
mAuthenticationStatsCollector), mBiometricContext,
mContext.getResources().getInteger(
com.android.internal.R.integer.config_faceMaxTemplatesPerUser),
- false);
+ false, options);
mScheduler.scheduleClientMonitor(client, new ClientMonitorCallback() {
@Override
@@ -770,14 +773,14 @@ public class Face10 implements IHwBinder.DeathRecipient, ServiceProvider {
private void scheduleEnrollHidl(@NonNull IBinder token,
@NonNull byte[] hardwareAuthToken, int userId, @NonNull IFaceServiceReceiver receiver,
@NonNull String opPackageName, @NonNull int[] disabledFeatures,
- @Nullable Surface previewSurface, long id) {
+ @Nullable Surface previewSurface, long id, FaceEnrollOptions options) {
final FaceEnrollClient client = new FaceEnrollClient(mContext, mLazyDaemon, token,
new ClientMonitorCallbackConverter(receiver), userId, hardwareAuthToken,
opPackageName, id, FaceUtils.getLegacyInstance(mSensorId), disabledFeatures,
ENROLL_TIMEOUT_SEC, previewSurface, mSensorId,
createLogger(BiometricsProtoEnums.ACTION_ENROLL,
BiometricsProtoEnums.CLIENT_UNKNOWN, mAuthenticationStatsCollector),
- mBiometricContext);
+ mBiometricContext, options);
mScheduler.scheduleClientMonitor(client, new ClientMonitorCallback() {
@Override
public void onClientStarted(@NonNull BaseClientMonitor clientMonitor) {
diff --git a/services/core/java/com/android/server/biometrics/sensors/face/hidl/FaceEnrollClient.java b/services/core/java/com/android/server/biometrics/sensors/face/hidl/FaceEnrollClient.java
index 27b9c79516af..815cf9180130 100644
--- a/services/core/java/com/android/server/biometrics/sensors/face/hidl/FaceEnrollClient.java
+++ b/services/core/java/com/android/server/biometrics/sensors/face/hidl/FaceEnrollClient.java
@@ -23,6 +23,7 @@ import android.hardware.biometrics.BiometricFaceConstants;
import android.hardware.biometrics.face.V1_0.IBiometricsFace;
import android.hardware.biometrics.face.V1_0.Status;
import android.hardware.face.Face;
+import android.hardware.face.FaceEnrollOptions;
import android.hardware.face.FaceManager;
import android.os.IBinder;
import android.os.RemoteException;
@@ -61,15 +62,20 @@ public class FaceEnrollClient extends EnrollClient<IBiometricsFace> {
@NonNull byte[] hardwareAuthToken, @NonNull String owner, long requestId,
@NonNull BiometricUtils<Face> utils, @NonNull int[] disabledFeatures, int timeoutSec,
@Nullable Surface previewSurface, int sensorId,
- @NonNull BiometricLogger logger, @NonNull BiometricContext biometricContext) {
+ @NonNull BiometricLogger logger, @NonNull BiometricContext biometricContext,
+ @NonNull FaceEnrollOptions options) {
super(context, lazyDaemon, token, listener, userId, hardwareAuthToken, owner, utils,
- timeoutSec, sensorId, false /* shouldVibrate */, logger, biometricContext);
+ timeoutSec, sensorId, false /* shouldVibrate */, logger, biometricContext,
+ BiometricFaceConstants.reasonToMetric(options.getEnrollReason()));
setRequestId(requestId);
mDisabledFeatures = Arrays.copyOf(disabledFeatures, disabledFeatures.length);
mEnrollIgnoreList = getContext().getResources()
.getIntArray(R.array.config_face_acquire_enroll_ignorelist);
mEnrollIgnoreListVendor = getContext().getResources()
.getIntArray(R.array.config_face_acquire_vendor_enroll_ignorelist);
+
+ Slog.w(TAG, "EnrollOptions "
+ + FaceEnrollOptions.enrollReasonToString(options.getEnrollReason()));
}
@Override
diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintService.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintService.java
index e01d672d7e34..1ba12134ab29 100644
--- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintService.java
+++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintService.java
@@ -48,6 +48,7 @@ import android.hardware.biometrics.fingerprint.PointerContext;
import android.hardware.biometrics.fingerprint.SensorProps;
import android.hardware.fingerprint.Fingerprint;
import android.hardware.fingerprint.FingerprintAuthenticateOptions;
+import android.hardware.fingerprint.FingerprintEnrollOptions;
import android.hardware.fingerprint.FingerprintManager;
import android.hardware.fingerprint.FingerprintSensorConfigurations;
import android.hardware.fingerprint.FingerprintSensorPropertiesInternal;
@@ -239,7 +240,8 @@ public class FingerprintService extends SystemService {
@Override // Binder call
public long enroll(final IBinder token, @NonNull final byte[] hardwareAuthToken,
final int userId, final IFingerprintServiceReceiver receiver,
- final String opPackageName, @FingerprintManager.EnrollReason int enrollReason) {
+ final String opPackageName, @FingerprintManager.EnrollReason int enrollReason,
+ FingerprintEnrollOptions options) {
super.enroll_enforcePermission();
final Pair<Integer, ServiceProvider> provider = mRegistry.getSingleProvider();
@@ -249,7 +251,7 @@ public class FingerprintService extends SystemService {
}
return provider.second.scheduleEnroll(provider.first, token, hardwareAuthToken, userId,
- receiver, opPackageName, enrollReason);
+ receiver, opPackageName, enrollReason, options);
}
@android.annotation.EnforcePermission(android.Manifest.permission.MANAGE_FINGERPRINT)
@@ -1322,4 +1324,25 @@ public class FingerprintService extends SystemService {
}
}
}
+
+ /**
+ * This should only be called from FingerprintShellCommand
+ */
+ void sendFingerprintReEnrollNotification() {
+ Utils.checkPermissionOrShell(getContext(), MANAGE_FINGERPRINT);
+ if (Build.IS_DEBUGGABLE) {
+ final long identity = Binder.clearCallingIdentity();
+ try {
+ final Pair<Integer, ServiceProvider> provider = mRegistry.getSingleProvider();
+ if (provider != null) {
+ FingerprintProvider fingerprintProvider = (FingerprintProvider) provider.second;
+ fingerprintProvider.sendFingerprintReEnrollNotification();
+ } else {
+ Slog.w(TAG, "Null provider for notification");
+ }
+ } finally {
+ Binder.restoreCallingIdentity(identity);
+ }
+ }
+ }
}
diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintShellCommand.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintShellCommand.java
index dc6a63f82bb1..766b3a1f1fbf 100644
--- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintShellCommand.java
+++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintShellCommand.java
@@ -47,6 +47,8 @@ public class FingerprintShellCommand extends ShellCommand {
return doSync();
case "fingerdown":
return doSimulateVhalFingerDown();
+ case "notification":
+ return doNotify();
default:
getOutPrintWriter().println("Unrecognized command: " + cmd);
}
@@ -66,6 +68,8 @@ public class FingerprintShellCommand extends ShellCommand {
pw.println(" Sync enrollments now (virtualized sensors only).");
pw.println(" fingerdown");
pw.println(" Simulate finger down event (virtualized sensors only).");
+ pw.println(" notification");
+ pw.println(" Sends a Fingerprint re-enrollment notification");
}
private int doHelp() {
@@ -82,4 +86,9 @@ public class FingerprintShellCommand extends ShellCommand {
mService.simulateVhalFingerDown();
return 0;
}
+
+ private int doNotify() {
+ mService.sendFingerprintReEnrollNotification();
+ return 0;
+ }
}
diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/ServiceProvider.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/ServiceProvider.java
index fc37d7020a21..c2d11699b91f 100644
--- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/ServiceProvider.java
+++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/ServiceProvider.java
@@ -24,6 +24,7 @@ import android.hardware.biometrics.ITestSessionCallback;
import android.hardware.biometrics.fingerprint.PointerContext;
import android.hardware.fingerprint.Fingerprint;
import android.hardware.fingerprint.FingerprintAuthenticateOptions;
+import android.hardware.fingerprint.FingerprintEnrollOptions;
import android.hardware.fingerprint.FingerprintManager;
import android.hardware.fingerprint.FingerprintSensorPropertiesInternal;
import android.hardware.fingerprint.IFingerprintServiceReceiver;
@@ -74,7 +75,8 @@ public interface ServiceProvider extends
*/
long scheduleEnroll(int sensorId, @NonNull IBinder token, @NonNull byte[] hardwareAuthToken,
int userId, @NonNull IFingerprintServiceReceiver receiver,
- @NonNull String opPackageName, @FingerprintManager.EnrollReason int enrollReason);
+ @NonNull String opPackageName, @FingerprintManager.EnrollReason int enrollReason,
+ @NonNull FingerprintEnrollOptions options);
void cancelEnrollment(int sensorId, @NonNull IBinder token, long requestId);
diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/BiometricTestSessionImpl.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/BiometricTestSessionImpl.java
index ec1eeb138505..d64b6c29c840 100644
--- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/BiometricTestSessionImpl.java
+++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/BiometricTestSessionImpl.java
@@ -16,13 +16,12 @@
package com.android.server.biometrics.sensors.fingerprint.aidl;
-import static android.Manifest.permission.TEST_BIOMETRIC;
-
import android.annotation.NonNull;
import android.content.Context;
import android.hardware.biometrics.ITestSession;
import android.hardware.biometrics.ITestSessionCallback;
import android.hardware.fingerprint.Fingerprint;
+import android.hardware.fingerprint.FingerprintEnrollOptions;
import android.hardware.fingerprint.FingerprintManager;
import android.hardware.fingerprint.IFingerprintServiceReceiver;
import android.os.Binder;
@@ -30,7 +29,6 @@ import android.os.RemoteException;
import android.util.Slog;
import com.android.server.biometrics.HardwareAuthTokenUtils;
-import com.android.server.biometrics.Utils;
import com.android.server.biometrics.sensors.BaseClientMonitor;
import com.android.server.biometrics.sensors.BiometricStateCallback;
import com.android.server.biometrics.sensors.ClientMonitorCallback;
@@ -153,7 +151,8 @@ class BiometricTestSessionImpl extends ITestSession.Stub {
super.startEnroll_enforcePermission();
mProvider.scheduleEnroll(mSensorId, new Binder(), new byte[69], userId, mReceiver,
- mContext.getOpPackageName(), FingerprintManager.ENROLL_ENROLL);
+ mContext.getOpPackageName(), FingerprintManager.ENROLL_ENROLL,
+ (new FingerprintEnrollOptions.Builder()).build());
}
@android.annotation.EnforcePermission(android.Manifest.permission.TEST_BIOMETRIC)
diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintEnrollClient.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintEnrollClient.java
index 79975e515c70..a24ab1d022c6 100644
--- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintEnrollClient.java
+++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintEnrollClient.java
@@ -29,6 +29,7 @@ import android.hardware.biometrics.common.ICancellationSignal;
import android.hardware.biometrics.common.OperationState;
import android.hardware.biometrics.fingerprint.PointerContext;
import android.hardware.fingerprint.Fingerprint;
+import android.hardware.fingerprint.FingerprintEnrollOptions;
import android.hardware.fingerprint.FingerprintManager;
import android.hardware.fingerprint.FingerprintSensorPropertiesInternal;
import android.hardware.fingerprint.ISidefpsController;
@@ -98,11 +99,13 @@ public class FingerprintEnrollClient extends EnrollClient<AidlSession> implement
// TODO(b/288175061): remove with Flags.FLAG_SIDEFPS_CONTROLLER_REFACTOR
@Nullable ISidefpsController sidefpsController,
@NonNull AuthenticationStateListeners authenticationStateListeners,
- int maxTemplatesPerUser, @FingerprintManager.EnrollReason int enrollReason) {
+ int maxTemplatesPerUser, @FingerprintManager.EnrollReason int enrollReason,
+ @NonNull FingerprintEnrollOptions options) {
// UDFPS haptics occur when an image is acquired (instead of when the result is known)
super(context, lazyDaemon, token, listener, userId, hardwareAuthToken, owner, utils,
0 /* timeoutSec */, sensorId, shouldVibrateFor(context, sensorProps),
- logger, biometricContext);
+ logger, biometricContext,
+ BiometricFingerprintConstants.reasonToMetric(options.getEnrollReason()));
setRequestId(requestId);
mSensorProps = sensorProps;
if (sidefpsControllerRefactor()) {
@@ -120,6 +123,8 @@ public class FingerprintEnrollClient extends EnrollClient<AidlSession> implement
if (enrollReason == FingerprintManager.ENROLL_FIND_SENSOR) {
getLogger().disableMetrics();
}
+ Slog.w(TAG, "EnrollOptions "
+ + FingerprintEnrollOptions.enrollReasonToString(options.getEnrollReason()));
}
@Override
diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintProvider.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintProvider.java
index fd938ed9c389..a104cf4e1726 100644
--- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintProvider.java
+++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintProvider.java
@@ -39,6 +39,7 @@ import android.hardware.biometrics.fingerprint.PointerContext;
import android.hardware.biometrics.fingerprint.SensorProps;
import android.hardware.fingerprint.Fingerprint;
import android.hardware.fingerprint.FingerprintAuthenticateOptions;
+import android.hardware.fingerprint.FingerprintEnrollOptions;
import android.hardware.fingerprint.FingerprintManager;
import android.hardware.fingerprint.FingerprintSensorPropertiesInternal;
import android.hardware.fingerprint.IFingerprintServiceReceiver;
@@ -515,7 +516,8 @@ public class FingerprintProvider implements IBinder.DeathRecipient, ServiceProvi
public long scheduleEnroll(int sensorId, @NonNull IBinder token,
@NonNull byte[] hardwareAuthToken, int userId,
@NonNull IFingerprintServiceReceiver receiver, @NonNull String opPackageName,
- @FingerprintManager.EnrollReason int enrollReason) {
+ @FingerprintManager.EnrollReason int enrollReason,
+ @NonNull FingerprintEnrollOptions options) {
final long id = mRequestCounter.incrementAndGet();
mHandler.post(() -> {
final int maxTemplatesPerUser = mFingerprintSensors.get(sensorId).getSensorProperties()
@@ -529,7 +531,7 @@ public class FingerprintProvider implements IBinder.DeathRecipient, ServiceProvi
mBiometricContext,
mFingerprintSensors.get(sensorId).getSensorProperties(),
mUdfpsOverlayController, mSidefpsController,
- mAuthenticationStateListeners, maxTemplatesPerUser, enrollReason);
+ mAuthenticationStateListeners, maxTemplatesPerUser, enrollReason, options);
if (Flags.deHidl()) {
scheduleForSensor(sensorId, client, mBiometricStateCallback);
} else {
@@ -1021,4 +1023,11 @@ public class FingerprintProvider implements IBinder.DeathRecipient, ServiceProvi
Slog.e(getTag(), "failed hal operation ", e);
}
}
+
+ /**
+ * Sends a fingerprint enroll notification.
+ */
+ public void sendFingerprintReEnrollNotification() {
+ mAuthenticationStatsCollector.sendFingerprintReEnrollNotification();
+ }
}
diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/BiometricTestSessionImpl.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/BiometricTestSessionImpl.java
index c20a9eb958c4..fc037aeb7e17 100644
--- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/BiometricTestSessionImpl.java
+++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/BiometricTestSessionImpl.java
@@ -16,20 +16,18 @@
package com.android.server.biometrics.sensors.fingerprint.hidl;
-import static android.Manifest.permission.TEST_BIOMETRIC;
-
import android.annotation.NonNull;
import android.content.Context;
import android.hardware.biometrics.ITestSession;
import android.hardware.biometrics.ITestSessionCallback;
import android.hardware.fingerprint.Fingerprint;
+import android.hardware.fingerprint.FingerprintEnrollOptions;
import android.hardware.fingerprint.FingerprintManager;
import android.hardware.fingerprint.IFingerprintServiceReceiver;
import android.os.Binder;
import android.os.RemoteException;
import android.util.Slog;
-import com.android.server.biometrics.Utils;
import com.android.server.biometrics.sensors.BaseClientMonitor;
import com.android.server.biometrics.sensors.BiometricStateCallback;
import com.android.server.biometrics.sensors.ClientMonitorCallback;
@@ -153,7 +151,8 @@ public class BiometricTestSessionImpl extends ITestSession.Stub {
super.startEnroll_enforcePermission();
mFingerprint21.scheduleEnroll(mSensorId, new Binder(), new byte[69], userId, mReceiver,
- mContext.getOpPackageName(), FingerprintManager.ENROLL_ENROLL);
+ mContext.getOpPackageName(), FingerprintManager.ENROLL_ENROLL,
+ (new FingerprintEnrollOptions.Builder()).build());
}
@android.annotation.EnforcePermission(android.Manifest.permission.TEST_BIOMETRIC)
diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/Fingerprint21.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/Fingerprint21.java
index 4accf8f7ff30..33e448bbe612 100644
--- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/Fingerprint21.java
+++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/Fingerprint21.java
@@ -35,6 +35,7 @@ import android.hardware.biometrics.fingerprint.V2_1.IBiometricsFingerprint;
import android.hardware.biometrics.fingerprint.V2_2.IBiometricsFingerprintClientCallback;
import android.hardware.fingerprint.Fingerprint;
import android.hardware.fingerprint.FingerprintAuthenticateOptions;
+import android.hardware.fingerprint.FingerprintEnrollOptions;
import android.hardware.fingerprint.FingerprintManager;
import android.hardware.fingerprint.FingerprintSensorProperties;
import android.hardware.fingerprint.FingerprintSensorPropertiesInternal;
@@ -700,17 +701,18 @@ public class Fingerprint21 implements IHwBinder.DeathRecipient, ServiceProvider
public long scheduleEnroll(int sensorId, @NonNull IBinder token,
@NonNull byte[] hardwareAuthToken, int userId,
@NonNull IFingerprintServiceReceiver receiver, @NonNull String opPackageName,
- @FingerprintManager.EnrollReason int enrollReason) {
+ @FingerprintManager.EnrollReason int enrollReason,
+ @NonNull FingerprintEnrollOptions options) {
final long id = mRequestCounter.incrementAndGet();
mHandler.post(() -> {
scheduleUpdateActiveUserWithoutHandler(userId);
if (Flags.deHidl()) {
scheduleEnrollAidl(token, hardwareAuthToken, userId, receiver,
- opPackageName, enrollReason, id);
+ opPackageName, enrollReason, id, options);
} else {
scheduleEnrollHidl(token, hardwareAuthToken, userId, receiver,
- opPackageName, enrollReason, id);
+ opPackageName, enrollReason, id, options);
}
});
return id;
@@ -719,7 +721,8 @@ public class Fingerprint21 implements IHwBinder.DeathRecipient, ServiceProvider
private void scheduleEnrollHidl(@NonNull IBinder token,
@NonNull byte[] hardwareAuthToken, int userId,
@NonNull IFingerprintServiceReceiver receiver, @NonNull String opPackageName,
- @FingerprintManager.EnrollReason int enrollReason, long id) {
+ @FingerprintManager.EnrollReason int enrollReason, long id,
+ @NonNull FingerprintEnrollOptions options) {
final FingerprintEnrollClient client = new FingerprintEnrollClient(mContext,
mLazyDaemon, token, id, new ClientMonitorCallbackConverter(receiver),
userId, hardwareAuthToken, opPackageName,
@@ -730,7 +733,7 @@ public class Fingerprint21 implements IHwBinder.DeathRecipient, ServiceProvider
mBiometricContext, mUdfpsOverlayController,
// TODO(b/288175061): remove with Flags.FLAG_SIDEFPS_CONTROLLER_REFACTOR
mSidefpsController,
- mAuthenticationStateListeners, enrollReason);
+ mAuthenticationStateListeners, enrollReason, options);
mScheduler.scheduleClientMonitor(client, new ClientMonitorCallback() {
@Override
public void onClientStarted(@NonNull BaseClientMonitor clientMonitor) {
@@ -758,7 +761,8 @@ public class Fingerprint21 implements IHwBinder.DeathRecipient, ServiceProvider
private void scheduleEnrollAidl(@NonNull IBinder token,
@NonNull byte[] hardwareAuthToken, int userId,
@NonNull IFingerprintServiceReceiver receiver, @NonNull String opPackageName,
- @FingerprintManager.EnrollReason int enrollReason, long id) {
+ @FingerprintManager.EnrollReason int enrollReason, long id,
+ @NonNull FingerprintEnrollOptions options) {
final com.android.server.biometrics.sensors.fingerprint.aidl.FingerprintEnrollClient
client =
new com.android.server.biometrics.sensors.fingerprint.aidl.FingerprintEnrollClient(
@@ -778,8 +782,7 @@ public class Fingerprint21 implements IHwBinder.DeathRecipient, ServiceProvider
mAuthenticationStateListeners,
mContext.getResources().getInteger(
com.android.internal.R.integer.config_fingerprintMaxTemplatesPerUser),
- enrollReason);
-
+ enrollReason, options);
mScheduler.scheduleClientMonitor(client, new ClientMonitorCallback() {
@Override
public void onClientStarted(@NonNull BaseClientMonitor clientMonitor) {
diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/FingerprintEnrollClient.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/FingerprintEnrollClient.java
index 26332ff6893c..8f937fc65cbb 100644
--- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/FingerprintEnrollClient.java
+++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/FingerprintEnrollClient.java
@@ -27,6 +27,7 @@ import android.hardware.biometrics.BiometricStateListener;
import android.hardware.biometrics.fingerprint.PointerContext;
import android.hardware.biometrics.fingerprint.V2_1.IBiometricsFingerprint;
import android.hardware.fingerprint.Fingerprint;
+import android.hardware.fingerprint.FingerprintEnrollOptions;
import android.hardware.fingerprint.FingerprintManager;
import android.hardware.fingerprint.ISidefpsController;
import android.hardware.fingerprint.IUdfpsOverlayController;
@@ -75,10 +76,12 @@ public class FingerprintEnrollClient extends EnrollClient<IBiometricsFingerprint
// TODO(b/288175061): remove with Flags.FLAG_SIDEFPS_CONTROLLER_REFACTOR
@Nullable ISidefpsController sidefpsController,
@NonNull AuthenticationStateListeners authenticationStateListeners,
- @FingerprintManager.EnrollReason int enrollReason) {
+ @FingerprintManager.EnrollReason int enrollReason,
+ @NonNull FingerprintEnrollOptions options) {
super(context, lazyDaemon, token, listener, userId, hardwareAuthToken, owner, utils,
timeoutSec, sensorId, true /* shouldVibrate */, biometricLogger,
- biometricContext);
+ biometricContext,
+ BiometricFingerprintConstants.reasonToMetric(options.getEnrollReason()));
setRequestId(requestId);
if (sidefpsControllerRefactor()) {
mSensorOverlays = new SensorOverlays(udfpsOverlayController);
@@ -91,6 +94,8 @@ public class FingerprintEnrollClient extends EnrollClient<IBiometricsFingerprint
if (enrollReason == FingerprintManager.ENROLL_FIND_SENSOR) {
getLogger().disableMetrics();
}
+ Slog.w(TAG, "EnrollOptions "
+ + FingerprintEnrollOptions.enrollReasonToString(options.getEnrollReason()));
}
@Override
diff --git a/services/tests/servicestests/src/com/android/server/biometrics/BiometricNotificationLoggerTest.java b/services/tests/servicestests/src/com/android/server/biometrics/BiometricNotificationLoggerTest.java
new file mode 100644
index 000000000000..8319623eec0a
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/biometrics/BiometricNotificationLoggerTest.java
@@ -0,0 +1,157 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.biometrics;
+
+import android.hardware.biometrics.BiometricsProtoEnums;
+import android.platform.test.annotations.Presubmit;
+import android.service.notification.NotificationListenerService;
+import android.service.notification.StatusBarNotification;
+
+import com.android.server.biometrics.log.BiometricFrameworkStatsLogger;
+import com.android.server.biometrics.sensors.BiometricNotificationUtils;
+
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import androidx.test.filters.SmallTest;
+
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.mockito.Captor;
+import org.mockito.Mock;
+import org.mockito.junit.MockitoJUnit;
+import org.mockito.junit.MockitoRule;
+
+@Presubmit
+@SmallTest
+public class BiometricNotificationLoggerTest {
+ @Rule
+ public MockitoRule mockitorule = MockitoJUnit.rule();
+
+ @Mock
+ private BiometricFrameworkStatsLogger mLogger;
+ private BiometricNotificationLogger mNotificationLogger;
+
+ @Before
+ public void setUp() {
+ mNotificationLogger = new BiometricNotificationLogger(
+ mLogger);
+ }
+
+ @Test
+ public void testNotification_nullNotification_doesNothing() {
+ mNotificationLogger.onNotificationPosted(null, null);
+
+ verify(mLogger, never()).logFrameworkNotification(anyInt(), anyInt());
+ }
+
+ @Test
+ public void testNotification_emptyStringTag_doesNothing() {
+ final StatusBarNotification noti = createNotificationWithNullTag();
+ mNotificationLogger.onNotificationPosted(noti, null);
+
+ verify(mLogger, never()).logFrameworkNotification(anyInt(), anyInt());
+ }
+
+ @Test
+ public void testFaceNotification_posted() {
+ final StatusBarNotification noti = createFaceNotification();
+ mNotificationLogger.onNotificationPosted(noti, null);
+
+ verify(mLogger).logFrameworkNotification(
+ BiometricsProtoEnums.FRR_NOTIFICATION_ACTION_SHOWN,
+ BiometricsProtoEnums.MODALITY_FACE);
+ }
+
+ @Test
+ public void testFingerprintNotification_posted() {
+ final StatusBarNotification noti = createFingerprintNotification();
+ mNotificationLogger.onNotificationPosted(noti, null);
+
+ verify(mLogger).logFrameworkNotification(
+ BiometricsProtoEnums.FRR_NOTIFICATION_ACTION_SHOWN,
+ BiometricsProtoEnums.MODALITY_FINGERPRINT);
+ }
+
+ @Test
+ public void testFaceNotification_clicked() {
+ final StatusBarNotification noti = createFaceNotification();
+ mNotificationLogger.onNotificationRemoved(noti, null,
+ NotificationListenerService.REASON_CLICK);
+
+ verify(mLogger).logFrameworkNotification(
+ BiometricsProtoEnums.FRR_NOTIFICATION_ACTION_CLICKED,
+ BiometricsProtoEnums.MODALITY_FACE);
+ }
+
+ @Test
+ public void testFingerprintNotification_clicked() {
+ final StatusBarNotification noti = createFingerprintNotification();
+ mNotificationLogger.onNotificationRemoved(noti, null,
+ NotificationListenerService.REASON_CLICK);
+
+ verify(mLogger).logFrameworkNotification(
+ BiometricsProtoEnums.FRR_NOTIFICATION_ACTION_CLICKED,
+ BiometricsProtoEnums.MODALITY_FINGERPRINT);
+ }
+
+ @Test
+ public void testFaceNotification_dismissed() {
+ final StatusBarNotification noti = createFaceNotification();
+ mNotificationLogger.onNotificationRemoved(noti, null,
+ NotificationListenerService.REASON_CANCEL);
+
+ verify(mLogger).logFrameworkNotification(
+ BiometricsProtoEnums.FRR_NOTIFICATION_ACTION_DISMISSED,
+ BiometricsProtoEnums.MODALITY_FACE);
+ }
+
+ @Test
+ public void testFingerprintNotification_dismissed() {
+ final StatusBarNotification noti = createFingerprintNotification();
+ mNotificationLogger.onNotificationRemoved(noti, null,
+ NotificationListenerService.REASON_CANCEL);
+
+ verify(mLogger).logFrameworkNotification(
+ BiometricsProtoEnums.FRR_NOTIFICATION_ACTION_DISMISSED,
+ BiometricsProtoEnums.MODALITY_FINGERPRINT);
+ }
+
+ private StatusBarNotification createNotificationWithNullTag() {
+ final StatusBarNotification notification = mock(StatusBarNotification.class);
+ return notification;
+ }
+
+ private StatusBarNotification createFaceNotification() {
+ final StatusBarNotification notification = mock(StatusBarNotification.class);
+ when(notification.getTag())
+ .thenReturn(BiometricNotificationUtils.FACE_ENROLL_NOTIFICATION_TAG);
+ return notification;
+ }
+
+ private StatusBarNotification createFingerprintNotification() {
+ final StatusBarNotification notification = mock(StatusBarNotification.class);
+ when(notification.getTag())
+ .thenReturn(BiometricNotificationUtils.FINGERPRINT_ENROLL_NOTIFICATION_TAG);
+ return notification;
+ }
+
+}
diff --git a/services/tests/servicestests/src/com/android/server/biometrics/BiometricServiceTest.java b/services/tests/servicestests/src/com/android/server/biometrics/BiometricServiceTest.java
index 35ad55c0938e..49583ef5194b 100644
--- a/services/tests/servicestests/src/com/android/server/biometrics/BiometricServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/biometrics/BiometricServiceTest.java
@@ -187,6 +187,9 @@ public class BiometricServiceTest {
@Mock
private IGateKeeperService mGateKeeperService;
+ @Mock
+ private BiometricNotificationLogger mNotificationLogger;
+
BiometricContextProvider mBiometricContextProvider;
@Before
@@ -242,6 +245,7 @@ public class BiometricServiceTest {
when(mInjector.getBiometricContext(any())).thenReturn(mBiometricContextProvider);
when(mInjector.getKeystoreAuthorizationService()).thenReturn(mKeystoreAuthService);
when(mInjector.getGateKeeperService()).thenReturn(mGateKeeperService);
+ when(mInjector.getNotificationLogger()).thenReturn(mNotificationLogger);
when(mGateKeeperService.getSecureUserId(anyInt())).thenReturn(42L);
if (com.android.server.biometrics.Flags.deHidl()) {
diff --git a/services/tests/servicestests/src/com/android/server/biometrics/log/BiometricLoggerTest.java b/services/tests/servicestests/src/com/android/server/biometrics/log/BiometricLoggerTest.java
index b69b55448bcd..238a9289c05b 100644
--- a/services/tests/servicestests/src/com/android/server/biometrics/log/BiometricLoggerTest.java
+++ b/services/tests/servicestests/src/com/android/server/biometrics/log/BiometricLoggerTest.java
@@ -137,11 +137,11 @@ public class BiometricLoggerTest {
final long latency = 44;
final boolean enrollSuccessful = true;
- mLogger.logOnEnrolled(targetUserId, latency, enrollSuccessful);
+ mLogger.logOnEnrolled(targetUserId, latency, enrollSuccessful, -1);
verify(mSink).enroll(
eq(DEFAULT_MODALITY), eq(DEFAULT_ACTION), eq(DEFAULT_CLIENT),
- eq(targetUserId), eq(latency), eq(enrollSuccessful), anyFloat());
+ eq(targetUserId), eq(latency), eq(enrollSuccessful), anyFloat(), anyInt());
}
@Test
@@ -192,7 +192,8 @@ public class BiometricLoggerTest {
true/* isBiometricPrompt */);
mLogger.logOnEnrolled(2 /* targetUserId */,
10 /* latency */,
- true /* enrollSuccessful */);
+ true /* enrollSuccessful */,
+ 30 /* source */);
mLogger.logOnError(mContext, mOpContext,
4 /* error */,
0 /* vendorCode */,
@@ -205,7 +206,8 @@ public class BiometricLoggerTest {
anyInt(), anyInt(), anyInt(), anyBoolean(),
anyLong(), anyInt(), anyBoolean(), anyInt(), anyFloat());
verify(mSink, never()).enroll(
- anyInt(), anyInt(), anyInt(), anyInt(), anyLong(), anyBoolean(), anyFloat());
+ anyInt(), anyInt(), anyInt(), anyInt(), anyLong(), anyBoolean(), anyFloat(),
+ anyInt());
verify(mSink, never()).error(eq(mOpContext),
anyInt(), anyInt(), anyInt(), anyBoolean(),
anyLong(), anyInt(), anyInt(), anyInt());
diff --git a/services/tests/servicestests/src/com/android/server/biometrics/sensors/BiometricSchedulerTest.java b/services/tests/servicestests/src/com/android/server/biometrics/sensors/BiometricSchedulerTest.java
index f7480dea780b..981eba55a430 100644
--- a/services/tests/servicestests/src/com/android/server/biometrics/sensors/BiometricSchedulerTest.java
+++ b/services/tests/servicestests/src/com/android/server/biometrics/sensors/BiometricSchedulerTest.java
@@ -1139,7 +1139,7 @@ public class BiometricSchedulerTest {
super(context, lazyDaemon, token, listener, 0 /* userId */, new byte[69],
"test" /* owner */, mock(BiometricUtils.class), 5 /* timeoutSec */,
TEST_SENSOR_ID, true /* shouldVibrate */, mock(BiometricLogger.class),
- mock(BiometricContext.class));
+ mock(BiometricContext.class), 0 /* enrollReason */);
}
@Override
diff --git a/services/tests/servicestests/src/com/android/server/biometrics/sensors/face/aidl/FaceEnrollClientTest.java b/services/tests/servicestests/src/com/android/server/biometrics/sensors/face/aidl/FaceEnrollClientTest.java
index 43ed07a0bf76..02363cd66349 100644
--- a/services/tests/servicestests/src/com/android/server/biometrics/sensors/face/aidl/FaceEnrollClientTest.java
+++ b/services/tests/servicestests/src/com/android/server/biometrics/sensors/face/aidl/FaceEnrollClientTest.java
@@ -21,15 +21,20 @@ import static com.google.common.truth.Truth.assertThat;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyBoolean;
import static org.mockito.ArgumentMatchers.anyByte;
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.anyLong;
+import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.inOrder;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.same;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
+import android.hardware.biometrics.BiometricsProtoEnums;
import android.hardware.biometrics.common.OperationContext;
import android.hardware.biometrics.face.ISession;
import android.hardware.face.Face;
+import android.hardware.face.FaceEnrollOptions;
import android.os.IBinder;
import android.os.RemoteException;
import android.platform.test.annotations.Presubmit;
@@ -68,6 +73,7 @@ public class FaceEnrollClientTest {
private static final byte[] HAT = new byte[69];
private static final int USER_ID = 12;
+ private static final int ENROLL_SOURCE = FaceEnrollOptions.ENROLL_REASON_SUW;
@Rule
public final TestableContext mContext = new TestableContext(
@@ -208,6 +214,16 @@ public class FaceEnrollClientTest {
verify(mHal).enrollWithOptions(any());
}
+ @Test
+ public void testEnrollWithReasonLogsMetric() throws RemoteException {
+ final FaceEnrollClient client = createClient(4);
+ client.start(mCallback);
+ client.onEnrollResult(new Face("face", 1 /* faceId */, 20 /* deviceId */), 0);
+
+ verify(mBiometricLogger).logOnEnrolled(anyInt(), anyLong(), anyBoolean(),
+ eq(BiometricsProtoEnums.ENROLLMENT_SOURCE_SUW));
+ }
+
private FaceEnrollClient createClient() throws RemoteException {
return createClient(200 /* version */);
}
@@ -221,6 +237,7 @@ public class FaceEnrollClientTest {
mUtils, new int[0] /* disabledFeatures */, 6 /* timeoutSec */,
null /* previewSurface */, 8 /* sensorId */,
mBiometricLogger, mBiometricContext, 5 /* maxTemplatesPerUser */,
- true /* debugConsent */);
+ true /* debugConsent */,
+ (new FaceEnrollOptions.Builder()).setEnrollReason(ENROLL_SOURCE).build());
}
}
diff --git a/services/tests/servicestests/src/com/android/server/biometrics/sensors/face/hidl/HidlToAidlSensorAdapterTest.java b/services/tests/servicestests/src/com/android/server/biometrics/sensors/face/hidl/HidlToAidlSensorAdapterTest.java
index 940fe69925b5..7a778d5dd211 100644
--- a/services/tests/servicestests/src/com/android/server/biometrics/sensors/face/hidl/HidlToAidlSensorAdapterTest.java
+++ b/services/tests/servicestests/src/com/android/server/biometrics/sensors/face/hidl/HidlToAidlSensorAdapterTest.java
@@ -34,6 +34,7 @@ import android.hardware.biometrics.face.V1_0.IBiometricsFace;
import android.hardware.biometrics.face.V1_0.OptionalUint64;
import android.hardware.biometrics.face.V1_0.Status;
import android.hardware.face.Face;
+import android.hardware.face.FaceEnrollOptions;
import android.hardware.face.HidlFaceSensorConfig;
import android.os.Handler;
import android.os.RemoteException;
@@ -201,7 +202,7 @@ public class HidlToAidlSensorAdapterTest {
USER_ID, HAT, TAG, 1 /* requestId */, mBiometricUtils,
new int[]{} /* disabledFeatures */, ENROLL_TIMEOUT_SEC, null /* previewSurface */,
SENSOR_ID, mLogger, mBiometricContext, 1 /* maxTemplatesPerUser */,
- false /* debugConsent */));
+ false /* debugConsent */, (new FaceEnrollOptions.Builder()).build()));
mLooper.dispatchAll();
verify(mAidlResponseHandlerCallback).onEnrollSuccess();
diff --git a/services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintEnrollClientTest.java b/services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintEnrollClientTest.java
index 3ee54f53d44f..916f6960efc9 100644
--- a/services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintEnrollClientTest.java
+++ b/services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintEnrollClientTest.java
@@ -21,6 +21,7 @@ import static com.android.systemui.shared.Flags.FLAG_SIDEFPS_CONTROLLER_REFACTOR
import static org.mockito.ArgumentMatchers.anyBoolean;
import static org.mockito.ArgumentMatchers.anyFloat;
import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.anyLong;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.any;
import static org.mockito.Mockito.inOrder;
@@ -30,10 +31,12 @@ import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
+import android.hardware.biometrics.BiometricsProtoEnums;
import android.hardware.biometrics.common.OperationContext;
import android.hardware.biometrics.fingerprint.ISession;
import android.hardware.biometrics.fingerprint.PointerContext;
import android.hardware.fingerprint.Fingerprint;
+import android.hardware.fingerprint.FingerprintEnrollOptions;
import android.hardware.fingerprint.FingerprintManager;
import android.hardware.fingerprint.FingerprintSensorPropertiesInternal;
import android.hardware.fingerprint.ISidefpsController;
@@ -78,6 +81,8 @@ import java.util.function.Consumer;
@SmallTest
public class FingerprintEnrollClientTest {
+ private static final int ENROLL_SOURCE = FingerprintEnrollOptions.ENROLL_REASON_SUW;
+
@Rule public final SetFlagsRule mSetFlagsRule = new SetFlagsRule();
@Rule
public final CheckFlagsRule mCheckFlagsRule =
@@ -353,6 +358,16 @@ public class FingerprintEnrollClientTest {
c -> c.onEnrollResult(new Fingerprint("", 1, 1), 0));
}
+ @Test
+ public void testEnrollWithReasonLogsMetric() throws RemoteException {
+ final FingerprintEnrollClient client = createClient(4);
+ client.start(mCallback);
+ client.onEnrollResult(new Fingerprint("fingerprint", 1 /* faceId */, 20 /* deviceId */), 0);
+
+ verify(mBiometricLogger).logOnEnrolled(anyInt(), anyLong(), anyBoolean(),
+ eq(BiometricsProtoEnums.ENROLLMENT_SOURCE_SUW));
+ }
+
private void showHideOverlay_sidefpsControllerRemovalRefactor(
Consumer<FingerprintEnrollClient> block) throws RemoteException {
mSetFlagsRule.enableFlags(FLAG_SIDEFPS_CONTROLLER_REFACTOR);
@@ -382,6 +397,8 @@ public class FingerprintEnrollClientTest {
HAT, "owner", mBiometricUtils, 8 /* sensorId */,
mBiometricLogger, mBiometricContext, mSensorProps, mUdfpsOverlayController,
mSideFpsController, mAuthenticationStateListeners, 6 /* maxTemplatesPerUser */,
- FingerprintManager.ENROLL_ENROLL);
+ FingerprintManager.ENROLL_ENROLL, (new FingerprintEnrollOptions.Builder())
+ .setEnrollReason(ENROLL_SOURCE).build()
+ );
}
}
diff --git a/services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/hidl/HidlToAidlSensorAdapterTest.java b/services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/hidl/HidlToAidlSensorAdapterTest.java
index cbbc54547bf6..6c3bfe80510e 100644
--- a/services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/hidl/HidlToAidlSensorAdapterTest.java
+++ b/services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/hidl/HidlToAidlSensorAdapterTest.java
@@ -34,6 +34,7 @@ import android.app.AlarmManager;
import android.hardware.biometrics.IBiometricService;
import android.hardware.biometrics.fingerprint.V2_1.IBiometricsFingerprint;
import android.hardware.fingerprint.Fingerprint;
+import android.hardware.fingerprint.FingerprintEnrollOptions;
import android.hardware.fingerprint.HidlFingerprintSensorConfig;
import android.os.Handler;
import android.os.HandlerThread;
@@ -217,7 +218,8 @@ public class HidlToAidlSensorAdapterTest {
1 /* requestId */, null /* listener */, USER_ID, HAT, TAG, mBiometricUtils,
SENSOR_ID, mLogger, mBiometricContext,
mHidlToAidlSensorAdapter.getSensorProperties(), null, null,
- mAuthenticationStateListeners, 5 /* maxTemplatesPerUser */, ENROLL_ENROLL));
+ mAuthenticationStateListeners, 5 /* maxTemplatesPerUser */, ENROLL_ENROLL,
+ (new FingerprintEnrollOptions.Builder()).build()));
mLooper.dispatchAll();
verify(mAidlResponseHandlerCallback).onEnrollSuccess();