diff --git a/core/java/android/hardware/biometrics/AuthenticateOptions.java b/core/java/android/hardware/biometrics/AuthenticateOptions.java new file mode 100644 index 0000000000000..77660713275fd --- /dev/null +++ b/core/java/android/hardware/biometrics/AuthenticateOptions.java @@ -0,0 +1,77 @@ +/* + * Copyright (C) 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.hardware.biometrics; + +import android.annotation.IntDef; +import android.annotation.NonNull; +import android.annotation.Nullable; + +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; + +/** + * Common authentication options that are exposed across all modalities. + * + * @hide + */ +public interface AuthenticateOptions { + + /** The user id for this operation. */ + int getUserId(); + + /** The sensor id for this operation. */ + int getSensorId(); + + /** The state is unknown. */ + int DISPLAY_STATE_UNKNOWN = 0; + + /** The display is on and showing the lockscreen (or an occluding app). */ + int DISPLAY_STATE_LOCKSCREEN = 1; + + /** The display is off or dozing. */ + int DISPLAY_STATE_NO_UI = 2; + + /** The display is showing a screensaver (dreaming). */ + int DISPLAY_STATE_SCREENSAVER = 3; + + /** The display is dreaming with always on display. */ + int DISPLAY_STATE_AOD = 4; + + /** The doze state of the device. */ + @IntDef(prefix = "DISPLAY_STATE_", value = { + DISPLAY_STATE_UNKNOWN, + DISPLAY_STATE_LOCKSCREEN, + DISPLAY_STATE_NO_UI, + DISPLAY_STATE_SCREENSAVER, + DISPLAY_STATE_AOD + }) + @Retention(RetentionPolicy.SOURCE) + @interface DisplayState {} + + /** The current doze state of the device. */ + @DisplayState + int getDisplayState(); + + /** + * The package name for that operation that should be used for + * {@link android.app.AppOpsManager} verification. + */ + @NonNull String getOpPackageName(); + + /** The attribution tag, if any. */ + @Nullable String getAttributionTag(); +} diff --git a/core/java/android/hardware/face/FaceAuthenticateOptions.aidl b/core/java/android/hardware/face/FaceAuthenticateOptions.aidl new file mode 100644 index 0000000000000..7c72b405383c0 --- /dev/null +++ b/core/java/android/hardware/face/FaceAuthenticateOptions.aidl @@ -0,0 +1,19 @@ +/* + * Copyright (C) 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.hardware.face; + +parcelable FaceAuthenticateOptions; diff --git a/core/java/android/hardware/face/FaceAuthenticateOptions.java b/core/java/android/hardware/face/FaceAuthenticateOptions.java new file mode 100644 index 0000000000000..4009fa7682fe3 --- /dev/null +++ b/core/java/android/hardware/face/FaceAuthenticateOptions.java @@ -0,0 +1,624 @@ +/* + * Copyright (C) 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.hardware.face; + + +import static android.os.PowerManager.WAKE_REASON_UNKNOWN; + +import android.annotation.IntDef; +import android.annotation.NonNull; +import android.annotation.Nullable; +import android.hardware.biometrics.AuthenticateOptions; +import android.os.Parcelable; +import android.os.PowerManager; + +import com.android.internal.util.DataClass; + +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; + +/** + * Additional options when requesting Face authentication or detection. + * + * @hide + */ +@DataClass( + genParcelable = true, + genAidl = true, + genBuilder = true, + genSetters = true, + genEqualsHashCode = true +) +public class FaceAuthenticateOptions implements AuthenticateOptions, Parcelable { + + /** The user id for this operation. */ + private final int mUserId; + private static int defaultUserId() { + return 0; + } + + /** The sensor id for this operation. */ + private final int mSensorId; + private static int defaultSensorId() { + return -1; + } + + /** The current doze state of the device. */ + @AuthenticateOptions.DisplayState + private final int mDisplayState; + private static int defaultDisplayState() { + return DISPLAY_STATE_UNKNOWN; + } + + public static final int AUTHENTICATE_REASON_UNKNOWN = 0; + public static final int AUTHENTICATE_REASON_STARTED_WAKING_UP = 1; + public static final int AUTHENTICATE_REASON_PRIMARY_BOUNCER_SHOWN = 2; + public static final int AUTHENTICATE_REASON_ASSISTANT_VISIBLE = 3; + public static final int AUTHENTICATE_REASON_ALTERNATE_BIOMETRIC_BOUNCER_SHOWN = 4; + public static final int AUTHENTICATE_REASON_NOTIFICATION_PANEL_CLICKED = 5; + public static final int AUTHENTICATE_REASON_OCCLUDING_APP_REQUESTED = 6; + public static final int AUTHENTICATE_REASON_PICK_UP_GESTURE_TRIGGERED = 7; + public static final int AUTHENTICATE_REASON_QS_EXPANDED = 8; + public static final int AUTHENTICATE_REASON_SWIPE_UP_ON_BOUNCER = 9; + public static final int AUTHENTICATE_REASON_UDFPS_POINTER_DOWN = 10; + + /** + * The reason for this operation when requested by the system (sysui), + * otherwise AUTHENTICATE_REASON_UNKNOWN. + * + * See frameworks/base/packages/SystemUI/src/com/android/keyguard/FaceAuthReason.kt + * for more details about each reason. + */ + @AuthenticateReason + private final int mAuthenticateReason; + private static int defaultAuthenticateReason() { + return AUTHENTICATE_REASON_UNKNOWN; + } + + /** A reason if this request was triggered due to a power event or WAKE_REASON_UNKNOWN. */ + @PowerManager.WakeReason + private final int mWakeReason; + private static int defaultWakeReason() { + return WAKE_REASON_UNKNOWN; + } + + /** + * The package name for that operation that should be used for + * {@link android.app.AppOpsManager} verification. + * + * This option may be overridden by the FingerprintManager using the caller's context. + */ + @NonNull + private String mOpPackageName; + private static String defaultOpPackageName() { + return ""; + } + + /** + * The attribution tag, if any. + * + * This option may be overridden by the FingerprintManager using the caller's context. + */ + @Nullable + private String mAttributionTag; + private static String defaultAttributionTag() { + return null; + } + + + + // Code below generated by codegen v1.0.23. + // + // DO NOT MODIFY! + // CHECKSTYLE:OFF Generated code + // + // To regenerate run: + // $ codegen $ANDROID_BUILD_TOP/frameworks/base/core/java/android/hardware/face/FaceAuthenticateOptions.java + // + // To exclude the generated code from IntelliJ auto-formatting enable (one-time): + // Settings > Editor > Code Style > Formatter Control + //@formatter:off + + + @IntDef(prefix = "AUTHENTICATE_REASON_", value = { + AUTHENTICATE_REASON_UNKNOWN, + AUTHENTICATE_REASON_STARTED_WAKING_UP, + AUTHENTICATE_REASON_PRIMARY_BOUNCER_SHOWN, + AUTHENTICATE_REASON_ASSISTANT_VISIBLE, + AUTHENTICATE_REASON_ALTERNATE_BIOMETRIC_BOUNCER_SHOWN, + AUTHENTICATE_REASON_NOTIFICATION_PANEL_CLICKED, + AUTHENTICATE_REASON_OCCLUDING_APP_REQUESTED, + AUTHENTICATE_REASON_PICK_UP_GESTURE_TRIGGERED, + AUTHENTICATE_REASON_QS_EXPANDED, + AUTHENTICATE_REASON_SWIPE_UP_ON_BOUNCER, + AUTHENTICATE_REASON_UDFPS_POINTER_DOWN + }) + @Retention(RetentionPolicy.SOURCE) + @DataClass.Generated.Member + public @interface AuthenticateReason {} + + @DataClass.Generated.Member + public static String authenticateReasonToString(@AuthenticateReason int value) { + switch (value) { + case AUTHENTICATE_REASON_UNKNOWN: + return "AUTHENTICATE_REASON_UNKNOWN"; + case AUTHENTICATE_REASON_STARTED_WAKING_UP: + return "AUTHENTICATE_REASON_STARTED_WAKING_UP"; + case AUTHENTICATE_REASON_PRIMARY_BOUNCER_SHOWN: + return "AUTHENTICATE_REASON_PRIMARY_BOUNCER_SHOWN"; + case AUTHENTICATE_REASON_ASSISTANT_VISIBLE: + return "AUTHENTICATE_REASON_ASSISTANT_VISIBLE"; + case AUTHENTICATE_REASON_ALTERNATE_BIOMETRIC_BOUNCER_SHOWN: + return "AUTHENTICATE_REASON_ALTERNATE_BIOMETRIC_BOUNCER_SHOWN"; + case AUTHENTICATE_REASON_NOTIFICATION_PANEL_CLICKED: + return "AUTHENTICATE_REASON_NOTIFICATION_PANEL_CLICKED"; + case AUTHENTICATE_REASON_OCCLUDING_APP_REQUESTED: + return "AUTHENTICATE_REASON_OCCLUDING_APP_REQUESTED"; + case AUTHENTICATE_REASON_PICK_UP_GESTURE_TRIGGERED: + return "AUTHENTICATE_REASON_PICK_UP_GESTURE_TRIGGERED"; + case AUTHENTICATE_REASON_QS_EXPANDED: + return "AUTHENTICATE_REASON_QS_EXPANDED"; + case AUTHENTICATE_REASON_SWIPE_UP_ON_BOUNCER: + return "AUTHENTICATE_REASON_SWIPE_UP_ON_BOUNCER"; + case AUTHENTICATE_REASON_UDFPS_POINTER_DOWN: + return "AUTHENTICATE_REASON_UDFPS_POINTER_DOWN"; + default: return Integer.toHexString(value); + } + } + + @DataClass.Generated.Member + /* package-private */ FaceAuthenticateOptions( + int userId, + int sensorId, + @AuthenticateOptions.DisplayState int displayState, + @AuthenticateReason int authenticateReason, + @PowerManager.WakeReason int wakeReason, + @NonNull String opPackageName, + @Nullable String attributionTag) { + this.mUserId = userId; + this.mSensorId = sensorId; + this.mDisplayState = displayState; + com.android.internal.util.AnnotationValidations.validate( + AuthenticateOptions.DisplayState.class, null, mDisplayState); + this.mAuthenticateReason = authenticateReason; + + if (!(mAuthenticateReason == AUTHENTICATE_REASON_UNKNOWN) + && !(mAuthenticateReason == AUTHENTICATE_REASON_STARTED_WAKING_UP) + && !(mAuthenticateReason == AUTHENTICATE_REASON_PRIMARY_BOUNCER_SHOWN) + && !(mAuthenticateReason == AUTHENTICATE_REASON_ASSISTANT_VISIBLE) + && !(mAuthenticateReason == AUTHENTICATE_REASON_ALTERNATE_BIOMETRIC_BOUNCER_SHOWN) + && !(mAuthenticateReason == AUTHENTICATE_REASON_NOTIFICATION_PANEL_CLICKED) + && !(mAuthenticateReason == AUTHENTICATE_REASON_OCCLUDING_APP_REQUESTED) + && !(mAuthenticateReason == AUTHENTICATE_REASON_PICK_UP_GESTURE_TRIGGERED) + && !(mAuthenticateReason == AUTHENTICATE_REASON_QS_EXPANDED) + && !(mAuthenticateReason == AUTHENTICATE_REASON_SWIPE_UP_ON_BOUNCER) + && !(mAuthenticateReason == AUTHENTICATE_REASON_UDFPS_POINTER_DOWN)) { + throw new java.lang.IllegalArgumentException( + "authenticateReason was " + mAuthenticateReason + " but must be one of: " + + "AUTHENTICATE_REASON_UNKNOWN(" + AUTHENTICATE_REASON_UNKNOWN + "), " + + "AUTHENTICATE_REASON_STARTED_WAKING_UP(" + AUTHENTICATE_REASON_STARTED_WAKING_UP + "), " + + "AUTHENTICATE_REASON_PRIMARY_BOUNCER_SHOWN(" + AUTHENTICATE_REASON_PRIMARY_BOUNCER_SHOWN + "), " + + "AUTHENTICATE_REASON_ASSISTANT_VISIBLE(" + AUTHENTICATE_REASON_ASSISTANT_VISIBLE + "), " + + "AUTHENTICATE_REASON_ALTERNATE_BIOMETRIC_BOUNCER_SHOWN(" + AUTHENTICATE_REASON_ALTERNATE_BIOMETRIC_BOUNCER_SHOWN + "), " + + "AUTHENTICATE_REASON_NOTIFICATION_PANEL_CLICKED(" + AUTHENTICATE_REASON_NOTIFICATION_PANEL_CLICKED + "), " + + "AUTHENTICATE_REASON_OCCLUDING_APP_REQUESTED(" + AUTHENTICATE_REASON_OCCLUDING_APP_REQUESTED + "), " + + "AUTHENTICATE_REASON_PICK_UP_GESTURE_TRIGGERED(" + AUTHENTICATE_REASON_PICK_UP_GESTURE_TRIGGERED + "), " + + "AUTHENTICATE_REASON_QS_EXPANDED(" + AUTHENTICATE_REASON_QS_EXPANDED + "), " + + "AUTHENTICATE_REASON_SWIPE_UP_ON_BOUNCER(" + AUTHENTICATE_REASON_SWIPE_UP_ON_BOUNCER + "), " + + "AUTHENTICATE_REASON_UDFPS_POINTER_DOWN(" + AUTHENTICATE_REASON_UDFPS_POINTER_DOWN + ")"); + } + + this.mWakeReason = wakeReason; + com.android.internal.util.AnnotationValidations.validate( + PowerManager.WakeReason.class, null, mWakeReason); + this.mOpPackageName = opPackageName; + com.android.internal.util.AnnotationValidations.validate( + NonNull.class, null, mOpPackageName); + this.mAttributionTag = attributionTag; + + // onConstructed(); // You can define this method to get a callback + } + + /** + * The user id for this operation. + */ + @DataClass.Generated.Member + public int getUserId() { + return mUserId; + } + + /** + * The sensor id for this operation. + */ + @DataClass.Generated.Member + public int getSensorId() { + return mSensorId; + } + + /** + * The current doze state of the device. + */ + @DataClass.Generated.Member + public @AuthenticateOptions.DisplayState int getDisplayState() { + return mDisplayState; + } + + /** + * The reason for this operation when requested by the system (sysui), + * otherwise AUTHENTICATE_REASON_UNKNOWN. + * + * See frameworks/base/packages/SystemUI/src/com/android/keyguard/FaceAuthReason.kt + * for more details about each reason. + */ + @DataClass.Generated.Member + public @AuthenticateReason int getAuthenticateReason() { + return mAuthenticateReason; + } + + /** + * A reason if this request was triggered due to a power event or WAKE_REASON_UNKNOWN. + */ + @DataClass.Generated.Member + public @PowerManager.WakeReason int getWakeReason() { + return mWakeReason; + } + + /** + * The package name for that operation that should be used for + * {@link android.app.AppOpsManager} verification. + * + * This option may be overridden by the FingerprintManager using the caller's context. + */ + @DataClass.Generated.Member + public @NonNull String getOpPackageName() { + return mOpPackageName; + } + + /** + * The attribution tag, if any. + * + * This option may be overridden by the FingerprintManager using the caller's context. + */ + @DataClass.Generated.Member + public @Nullable String getAttributionTag() { + return mAttributionTag; + } + + /** + * The package name for that operation that should be used for + * {@link android.app.AppOpsManager} verification. + * + * This option may be overridden by the FingerprintManager using the caller's context. + */ + @DataClass.Generated.Member + public @NonNull FaceAuthenticateOptions setOpPackageName(@NonNull String value) { + mOpPackageName = value; + com.android.internal.util.AnnotationValidations.validate( + NonNull.class, null, mOpPackageName); + return this; + } + + /** + * The attribution tag, if any. + * + * This option may be overridden by the FingerprintManager using the caller's context. + */ + @DataClass.Generated.Member + public @NonNull FaceAuthenticateOptions setAttributionTag(@NonNull String value) { + mAttributionTag = value; + return this; + } + + @Override + @DataClass.Generated.Member + public boolean equals(@Nullable Object o) { + // You can override field equality logic by defining either of the methods like: + // boolean fieldNameEquals(FaceAuthenticateOptions other) { ... } + // boolean fieldNameEquals(FieldType otherValue) { ... } + + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + @SuppressWarnings("unchecked") + FaceAuthenticateOptions that = (FaceAuthenticateOptions) o; + //noinspection PointlessBooleanExpression + return true + && mUserId == that.mUserId + && mSensorId == that.mSensorId + && mDisplayState == that.mDisplayState + && mAuthenticateReason == that.mAuthenticateReason + && mWakeReason == that.mWakeReason + && java.util.Objects.equals(mOpPackageName, that.mOpPackageName) + && java.util.Objects.equals(mAttributionTag, that.mAttributionTag); + } + + @Override + @DataClass.Generated.Member + public int hashCode() { + // You can override field hashCode logic by defining methods like: + // int fieldNameHashCode() { ... } + + int _hash = 1; + _hash = 31 * _hash + mUserId; + _hash = 31 * _hash + mSensorId; + _hash = 31 * _hash + mDisplayState; + _hash = 31 * _hash + mAuthenticateReason; + _hash = 31 * _hash + mWakeReason; + _hash = 31 * _hash + java.util.Objects.hashCode(mOpPackageName); + _hash = 31 * _hash + java.util.Objects.hashCode(mAttributionTag); + return _hash; + } + + @Override + @DataClass.Generated.Member + public void writeToParcel(@NonNull android.os.Parcel dest, int flags) { + // You can override field parcelling by defining methods like: + // void parcelFieldName(Parcel dest, int flags) { ... } + + byte flg = 0; + if (mAttributionTag != null) flg |= 0x40; + dest.writeByte(flg); + dest.writeInt(mUserId); + dest.writeInt(mSensorId); + dest.writeInt(mDisplayState); + dest.writeInt(mAuthenticateReason); + dest.writeInt(mWakeReason); + dest.writeString(mOpPackageName); + if (mAttributionTag != null) dest.writeString(mAttributionTag); + } + + @Override + @DataClass.Generated.Member + public int describeContents() { return 0; } + + /** @hide */ + @SuppressWarnings({"unchecked", "RedundantCast"}) + @DataClass.Generated.Member + protected FaceAuthenticateOptions(@NonNull android.os.Parcel in) { + // You can override field unparcelling by defining methods like: + // static FieldType unparcelFieldName(Parcel in) { ... } + + byte flg = in.readByte(); + int userId = in.readInt(); + int sensorId = in.readInt(); + int displayState = in.readInt(); + int authenticateReason = in.readInt(); + int wakeReason = in.readInt(); + String opPackageName = in.readString(); + String attributionTag = (flg & 0x40) == 0 ? null : in.readString(); + + this.mUserId = userId; + this.mSensorId = sensorId; + this.mDisplayState = displayState; + com.android.internal.util.AnnotationValidations.validate( + AuthenticateOptions.DisplayState.class, null, mDisplayState); + this.mAuthenticateReason = authenticateReason; + + if (!(mAuthenticateReason == AUTHENTICATE_REASON_UNKNOWN) + && !(mAuthenticateReason == AUTHENTICATE_REASON_STARTED_WAKING_UP) + && !(mAuthenticateReason == AUTHENTICATE_REASON_PRIMARY_BOUNCER_SHOWN) + && !(mAuthenticateReason == AUTHENTICATE_REASON_ASSISTANT_VISIBLE) + && !(mAuthenticateReason == AUTHENTICATE_REASON_ALTERNATE_BIOMETRIC_BOUNCER_SHOWN) + && !(mAuthenticateReason == AUTHENTICATE_REASON_NOTIFICATION_PANEL_CLICKED) + && !(mAuthenticateReason == AUTHENTICATE_REASON_OCCLUDING_APP_REQUESTED) + && !(mAuthenticateReason == AUTHENTICATE_REASON_PICK_UP_GESTURE_TRIGGERED) + && !(mAuthenticateReason == AUTHENTICATE_REASON_QS_EXPANDED) + && !(mAuthenticateReason == AUTHENTICATE_REASON_SWIPE_UP_ON_BOUNCER) + && !(mAuthenticateReason == AUTHENTICATE_REASON_UDFPS_POINTER_DOWN)) { + throw new java.lang.IllegalArgumentException( + "authenticateReason was " + mAuthenticateReason + " but must be one of: " + + "AUTHENTICATE_REASON_UNKNOWN(" + AUTHENTICATE_REASON_UNKNOWN + "), " + + "AUTHENTICATE_REASON_STARTED_WAKING_UP(" + AUTHENTICATE_REASON_STARTED_WAKING_UP + "), " + + "AUTHENTICATE_REASON_PRIMARY_BOUNCER_SHOWN(" + AUTHENTICATE_REASON_PRIMARY_BOUNCER_SHOWN + "), " + + "AUTHENTICATE_REASON_ASSISTANT_VISIBLE(" + AUTHENTICATE_REASON_ASSISTANT_VISIBLE + "), " + + "AUTHENTICATE_REASON_ALTERNATE_BIOMETRIC_BOUNCER_SHOWN(" + AUTHENTICATE_REASON_ALTERNATE_BIOMETRIC_BOUNCER_SHOWN + "), " + + "AUTHENTICATE_REASON_NOTIFICATION_PANEL_CLICKED(" + AUTHENTICATE_REASON_NOTIFICATION_PANEL_CLICKED + "), " + + "AUTHENTICATE_REASON_OCCLUDING_APP_REQUESTED(" + AUTHENTICATE_REASON_OCCLUDING_APP_REQUESTED + "), " + + "AUTHENTICATE_REASON_PICK_UP_GESTURE_TRIGGERED(" + AUTHENTICATE_REASON_PICK_UP_GESTURE_TRIGGERED + "), " + + "AUTHENTICATE_REASON_QS_EXPANDED(" + AUTHENTICATE_REASON_QS_EXPANDED + "), " + + "AUTHENTICATE_REASON_SWIPE_UP_ON_BOUNCER(" + AUTHENTICATE_REASON_SWIPE_UP_ON_BOUNCER + "), " + + "AUTHENTICATE_REASON_UDFPS_POINTER_DOWN(" + AUTHENTICATE_REASON_UDFPS_POINTER_DOWN + ")"); + } + + this.mWakeReason = wakeReason; + com.android.internal.util.AnnotationValidations.validate( + PowerManager.WakeReason.class, null, mWakeReason); + this.mOpPackageName = opPackageName; + com.android.internal.util.AnnotationValidations.validate( + NonNull.class, null, mOpPackageName); + this.mAttributionTag = attributionTag; + + // onConstructed(); // You can define this method to get a callback + } + + @DataClass.Generated.Member + public static final @NonNull Parcelable.Creator CREATOR + = new Parcelable.Creator() { + @Override + public FaceAuthenticateOptions[] newArray(int size) { + return new FaceAuthenticateOptions[size]; + } + + @Override + public FaceAuthenticateOptions createFromParcel(@NonNull android.os.Parcel in) { + return new FaceAuthenticateOptions(in); + } + }; + + /** + * A builder for {@link FaceAuthenticateOptions} + */ + @SuppressWarnings("WeakerAccess") + @DataClass.Generated.Member + public static class Builder { + + private int mUserId; + private int mSensorId; + private @AuthenticateOptions.DisplayState int mDisplayState; + private @AuthenticateReason int mAuthenticateReason; + private @PowerManager.WakeReason int mWakeReason; + private @NonNull String mOpPackageName; + private @Nullable String mAttributionTag; + + private long mBuilderFieldsSet = 0L; + + public Builder() { + } + + /** + * The user id for this operation. + */ + @DataClass.Generated.Member + public @NonNull Builder setUserId(int value) { + checkNotUsed(); + mBuilderFieldsSet |= 0x1; + mUserId = value; + return this; + } + + /** + * The sensor id for this operation. + */ + @DataClass.Generated.Member + public @NonNull Builder setSensorId(int value) { + checkNotUsed(); + mBuilderFieldsSet |= 0x2; + mSensorId = value; + return this; + } + + /** + * The current doze state of the device. + */ + @DataClass.Generated.Member + public @NonNull Builder setDisplayState(@AuthenticateOptions.DisplayState int value) { + checkNotUsed(); + mBuilderFieldsSet |= 0x4; + mDisplayState = value; + return this; + } + + /** + * The reason for this operation when requested by the system (sysui), + * otherwise AUTHENTICATE_REASON_UNKNOWN. + * + * See frameworks/base/packages/SystemUI/src/com/android/keyguard/FaceAuthReason.kt + * for more details about each reason. + */ + @DataClass.Generated.Member + public @NonNull Builder setAuthenticateReason(@AuthenticateReason int value) { + checkNotUsed(); + mBuilderFieldsSet |= 0x8; + mAuthenticateReason = value; + return this; + } + + /** + * A reason if this request was triggered due to a power event or WAKE_REASON_UNKNOWN. + */ + @DataClass.Generated.Member + public @NonNull Builder setWakeReason(@PowerManager.WakeReason int value) { + checkNotUsed(); + mBuilderFieldsSet |= 0x10; + mWakeReason = value; + return this; + } + + /** + * The package name for that operation that should be used for + * {@link android.app.AppOpsManager} verification. + * + * This option may be overridden by the FingerprintManager using the caller's context. + */ + @DataClass.Generated.Member + public @NonNull Builder setOpPackageName(@NonNull String value) { + checkNotUsed(); + mBuilderFieldsSet |= 0x20; + mOpPackageName = value; + return this; + } + + /** + * The attribution tag, if any. + * + * This option may be overridden by the FingerprintManager using the caller's context. + */ + @DataClass.Generated.Member + public @NonNull Builder setAttributionTag(@NonNull String value) { + checkNotUsed(); + mBuilderFieldsSet |= 0x40; + mAttributionTag = value; + return this; + } + + /** Builds the instance. This builder should not be touched after calling this! */ + public @NonNull FaceAuthenticateOptions build() { + checkNotUsed(); + mBuilderFieldsSet |= 0x80; // Mark builder used + + if ((mBuilderFieldsSet & 0x1) == 0) { + mUserId = defaultUserId(); + } + if ((mBuilderFieldsSet & 0x2) == 0) { + mSensorId = defaultSensorId(); + } + if ((mBuilderFieldsSet & 0x4) == 0) { + mDisplayState = defaultDisplayState(); + } + if ((mBuilderFieldsSet & 0x8) == 0) { + mAuthenticateReason = defaultAuthenticateReason(); + } + if ((mBuilderFieldsSet & 0x10) == 0) { + mWakeReason = defaultWakeReason(); + } + if ((mBuilderFieldsSet & 0x20) == 0) { + mOpPackageName = defaultOpPackageName(); + } + if ((mBuilderFieldsSet & 0x40) == 0) { + mAttributionTag = defaultAttributionTag(); + } + FaceAuthenticateOptions o = new FaceAuthenticateOptions( + mUserId, + mSensorId, + mDisplayState, + mAuthenticateReason, + mWakeReason, + mOpPackageName, + mAttributionTag); + return o; + } + + private void checkNotUsed() { + if ((mBuilderFieldsSet & 0x80) != 0) { + throw new IllegalStateException( + "This Builder should not be reused. Use a new Builder instance instead"); + } + } + } + + @DataClass.Generated( + time = 1676508211385L, + codegenVersion = "1.0.23", + sourceFile = "frameworks/base/core/java/android/hardware/face/FaceAuthenticateOptions.java", + inputSignatures = "private final int mUserId\nprivate final int mSensorId\nprivate final @android.hardware.biometrics.AuthenticateOptions.DisplayState int mDisplayState\npublic static final int AUTHENTICATE_REASON_UNKNOWN\npublic static final int AUTHENTICATE_REASON_STARTED_WAKING_UP\npublic static final int AUTHENTICATE_REASON_PRIMARY_BOUNCER_SHOWN\npublic static final int AUTHENTICATE_REASON_ASSISTANT_VISIBLE\npublic static final int AUTHENTICATE_REASON_ALTERNATE_BIOMETRIC_BOUNCER_SHOWN\npublic static final int AUTHENTICATE_REASON_NOTIFICATION_PANEL_CLICKED\npublic static final int AUTHENTICATE_REASON_OCCLUDING_APP_REQUESTED\npublic static final int AUTHENTICATE_REASON_PICK_UP_GESTURE_TRIGGERED\npublic static final int AUTHENTICATE_REASON_QS_EXPANDED\npublic static final int AUTHENTICATE_REASON_SWIPE_UP_ON_BOUNCER\npublic static final int AUTHENTICATE_REASON_UDFPS_POINTER_DOWN\nprivate final @android.hardware.face.FaceAuthenticateOptions.AuthenticateReason int mAuthenticateReason\nprivate final @android.os.PowerManager.WakeReason int mWakeReason\nprivate @android.annotation.NonNull java.lang.String mOpPackageName\nprivate @android.annotation.Nullable java.lang.String mAttributionTag\nprivate static int defaultUserId()\nprivate static int defaultSensorId()\nprivate static int defaultDisplayState()\nprivate static int defaultAuthenticateReason()\nprivate static int defaultWakeReason()\nprivate static java.lang.String defaultOpPackageName()\nprivate static java.lang.String defaultAttributionTag()\nclass FaceAuthenticateOptions extends java.lang.Object implements [android.hardware.biometrics.AuthenticateOptions, android.os.Parcelable]\n@com.android.internal.util.DataClass(genParcelable=true, genAidl=true, genBuilder=true, genSetters=true, genEqualsHashCode=true)") + @Deprecated + private void __metadata() {} + + + //@formatter:on + // End of generated code + +} diff --git a/core/java/android/hardware/face/FaceManager.java b/core/java/android/hardware/face/FaceManager.java index 96098f8535526..55b20e17d4d79 100644 --- a/core/java/android/hardware/face/FaceManager.java +++ b/core/java/android/hardware/face/FaceManager.java @@ -194,18 +194,30 @@ public class FaceManager implements BiometricAuthenticator, BiometricFaceConstan } /** - * Request authentication of a crypto object. This call operates the face recognition hardware - * and starts capturing images. It terminates when + * @deprecated use {@link #authenticate(CryptoObject, CancellationSignal, AuthenticationCallback, Handler, FaceAuthenticateOptions)}. + */ + @Deprecated + @RequiresPermission(USE_BIOMETRIC_INTERNAL) + public void authenticate(@Nullable CryptoObject crypto, @Nullable CancellationSignal cancel, + @NonNull AuthenticationCallback callback, @Nullable Handler handler, int userId) { + authenticate(crypto, cancel, callback, handler, new FaceAuthenticateOptions.Builder() + .setUserId(userId) + .build()); + } + + /** + * Request authentication. This call operates the face recognition hardware and starts capturing images. + * It terminates when * {@link AuthenticationCallback#onAuthenticationError(int, CharSequence)} or * {@link AuthenticationCallback#onAuthenticationSucceeded(AuthenticationResult)} is called, at * which point the object is no longer valid. The operation can be canceled by using the * provided cancel object. * - * @param crypto object associated with the call or null if none required. + * @param crypto object associated with the call or null if none required * @param cancel an object that can be used to cancel authentication * @param callback an object to receive authentication events * @param handler an optional handler to handle callback events - * @param userId userId to authenticate for + * @param options additional options to customize this request * @throws IllegalArgumentException if the crypto operation is not supported or is not backed * by * Android @@ -215,8 +227,8 @@ public class FaceManager implements BiometricAuthenticator, BiometricFaceConstan */ @RequiresPermission(USE_BIOMETRIC_INTERNAL) public void authenticate(@Nullable CryptoObject crypto, @Nullable CancellationSignal cancel, - @NonNull AuthenticationCallback callback, @Nullable Handler handler, int userId, - boolean isKeyguardBypassEnabled) { + @NonNull AuthenticationCallback callback, @Nullable Handler handler, + @NonNull FaceAuthenticateOptions options) { if (callback == null) { throw new IllegalArgumentException("Must supply an authentication callback"); } @@ -226,6 +238,9 @@ public class FaceManager implements BiometricAuthenticator, BiometricFaceConstan return; } + options.setOpPackageName(mContext.getOpPackageName()); + options.setAttributionTag(mContext.getAttributionTag()); + if (mService != null) { try { useHandler(handler); @@ -233,8 +248,8 @@ public class FaceManager implements BiometricAuthenticator, BiometricFaceConstan mCryptoObject = crypto; final long operationId = crypto != null ? crypto.getOpId() : 0; Trace.beginSection("FaceManager#authenticate"); - final long authId = mService.authenticate(mToken, operationId, userId, - mServiceReceiver, mContext.getOpPackageName(), isKeyguardBypassEnabled); + final long authId = mService.authenticate( + mToken, operationId, mServiceReceiver, options); if (cancel != null) { cancel.setOnCancelListener(new OnAuthenticationCancelListener(authId)); } @@ -258,7 +273,7 @@ public class FaceManager implements BiometricAuthenticator, BiometricFaceConstan */ @RequiresPermission(USE_BIOMETRIC_INTERNAL) public void detectFace(@NonNull CancellationSignal cancel, - @NonNull FaceDetectionCallback callback, int userId) { + @NonNull FaceDetectionCallback callback, @NonNull FaceAuthenticateOptions options) { if (mService == null) { return; } @@ -268,11 +283,13 @@ public class FaceManager implements BiometricAuthenticator, BiometricFaceConstan return; } + options.setOpPackageName(mContext.getOpPackageName()); + options.setAttributionTag(mContext.getAttributionTag()); + mFaceDetectionCallback = callback; try { - final long authId = mService.detectFace( - mToken, userId, mServiceReceiver, mContext.getOpPackageName()); + final long authId = mService.detectFace(mToken, mServiceReceiver, options); cancel.setOnCancelListener(new OnFaceDetectionCancelListener(authId)); } catch (RemoteException e) { Slog.w(TAG, "Remote exception when requesting finger detect", e); diff --git a/core/java/android/hardware/face/IFaceService.aidl b/core/java/android/hardware/face/IFaceService.aidl index 5fcc31e3ea25e..2857627bf7129 100644 --- a/core/java/android/hardware/face/IFaceService.aidl +++ b/core/java/android/hardware/face/IFaceService.aidl @@ -24,6 +24,7 @@ import android.hardware.biometrics.ITestSessionCallback; import android.hardware.face.IFaceAuthenticatorsRegisteredCallback; import android.hardware.face.IFaceServiceReceiver; import android.hardware.face.Face; +import android.hardware.face.FaceAuthenticateOptions; import android.hardware.face.FaceSensorPropertiesInternal; import android.view.Surface; @@ -52,14 +53,14 @@ interface IFaceService { // Authenticate with a face. A requestId is returned that can be used to cancel this operation. @EnforcePermission("USE_BIOMETRIC_INTERNAL") - long authenticate(IBinder token, long operationId, int userId, IFaceServiceReceiver receiver, - String opPackageName, boolean isKeyguardBypassEnabled); + long authenticate(IBinder token, long operationId, IFaceServiceReceiver receiver, + in FaceAuthenticateOptions options); // Uses the face hardware to detect for the presence of a face, without giving details // about accept/reject/lockout. A requestId is returned that can be used to cancel this // operation. @EnforcePermission("USE_BIOMETRIC_INTERNAL") - long detectFace(IBinder token, int userId, IFaceServiceReceiver receiver, String opPackageName); + long detectFace(IBinder token, IFaceServiceReceiver receiver, in FaceAuthenticateOptions options); // This method prepares the service to start authenticating, but doesn't start authentication. // This is protected by the MANAGE_BIOMETRIC signatuer permission. This method should only be @@ -68,8 +69,8 @@ interface IFaceService { // startPreparedClient(). @EnforcePermission("USE_BIOMETRIC_INTERNAL") void prepareForAuthentication(int sensorId, boolean requireConfirmation, IBinder token, - long operationId, int userId, IBiometricSensorReceiver sensorReceiver, - String opPackageName, long requestId, int cookie, + long operationId, IBiometricSensorReceiver sensorReceiver, + in FaceAuthenticateOptions options, long requestId, int cookie, boolean allowBackgroundAuthentication); // Starts authentication with the previously prepared client. diff --git a/core/java/android/hardware/fingerprint/FingerprintAuthenticateOptions.aidl b/core/java/android/hardware/fingerprint/FingerprintAuthenticateOptions.aidl new file mode 100644 index 0000000000000..ad30fab89a3b5 --- /dev/null +++ b/core/java/android/hardware/fingerprint/FingerprintAuthenticateOptions.aidl @@ -0,0 +1,19 @@ +/* + * Copyright (C) 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.hardware.fingerprint; + +parcelable FingerprintAuthenticateOptions; diff --git a/core/java/android/hardware/fingerprint/FingerprintAuthenticateOptions.java b/core/java/android/hardware/fingerprint/FingerprintAuthenticateOptions.java new file mode 100644 index 0000000000000..cecb3172a8d14 --- /dev/null +++ b/core/java/android/hardware/fingerprint/FingerprintAuthenticateOptions.java @@ -0,0 +1,447 @@ +/* + * Copyright (C) 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.hardware.fingerprint; + +import static android.hardware.fingerprint.FingerprintManager.SENSOR_ID_ANY; + +import android.annotation.NonNull; +import android.annotation.Nullable; +import android.hardware.biometrics.AuthenticateOptions; +import android.os.Parcelable; + +import com.android.internal.util.DataClass; + +/** + * Additional options when requesting Fingerprint authentication or detection. + * + * @hide + */ +@DataClass( + genParcelable = true, + genAidl = true, + genBuilder = true, + genSetters = true, + genEqualsHashCode = true +) +public final class FingerprintAuthenticateOptions implements AuthenticateOptions, Parcelable { + + /** The user id for this operation. */ + private final int mUserId; + private static int defaultUserId() { + return 0; + } + + /** The sensor id for this operation. */ + private final int mSensorId; + private static int defaultSensorId() { + return SENSOR_ID_ANY; + } + + /** If enrollment state should be ignored. */ + private final boolean mIgnoreEnrollmentState; + private static boolean defaultIgnoreEnrollmentState() { + return false; + } + + /** The current doze state of the device. */ + @AuthenticateOptions.DisplayState + private final int mDisplayState; + private static int defaultDisplayState() { + return DISPLAY_STATE_UNKNOWN; + } + + /** + * The package name for that operation that should be used for + * {@link android.app.AppOpsManager} verification. + * + * This option may be overridden by the FingerprintManager using the caller's context. + */ + @NonNull private String mOpPackageName; + private static String defaultOpPackageName() { + return ""; + } + + /** + * The attribution tag, if any. + * + * This option may be overridden by the FingerprintManager using the caller's context. + */ + @Nullable private String mAttributionTag; + private static String defaultAttributionTag() { + return null; + } + + + + // Code below generated by codegen v1.0.23. + // + // DO NOT MODIFY! + // CHECKSTYLE:OFF Generated code + // + // To regenerate run: + // $ codegen $ANDROID_BUILD_TOP/frameworks/base/core/java/android/hardware/fingerprint/FingerprintAuthenticateOptions.java + // + // To exclude the generated code from IntelliJ auto-formatting enable (one-time): + // Settings > Editor > Code Style > Formatter Control + //@formatter:off + + + @DataClass.Generated.Member + /* package-private */ FingerprintAuthenticateOptions( + int userId, + int sensorId, + boolean ignoreEnrollmentState, + @AuthenticateOptions.DisplayState int displayState, + @NonNull String opPackageName, + @Nullable String attributionTag) { + this.mUserId = userId; + this.mSensorId = sensorId; + this.mIgnoreEnrollmentState = ignoreEnrollmentState; + this.mDisplayState = displayState; + com.android.internal.util.AnnotationValidations.validate( + AuthenticateOptions.DisplayState.class, null, mDisplayState); + this.mOpPackageName = opPackageName; + com.android.internal.util.AnnotationValidations.validate( + NonNull.class, null, mOpPackageName); + this.mAttributionTag = attributionTag; + + // onConstructed(); // You can define this method to get a callback + } + + /** + * The user id for this operation. + */ + @DataClass.Generated.Member + public int getUserId() { + return mUserId; + } + + /** + * The sensor id for this operation. + */ + @DataClass.Generated.Member + public int getSensorId() { + return mSensorId; + } + + /** + * If enrollment state should be ignored. + */ + @DataClass.Generated.Member + public boolean isIgnoreEnrollmentState() { + return mIgnoreEnrollmentState; + } + + /** + * The current doze state of the device. + */ + @DataClass.Generated.Member + public @AuthenticateOptions.DisplayState int getDisplayState() { + return mDisplayState; + } + + /** + * The package name for that operation that should be used for + * {@link android.app.AppOpsManager} verification. + * + * This option may be overridden by the FingerprintManager using the caller's context. + */ + @DataClass.Generated.Member + public @NonNull String getOpPackageName() { + return mOpPackageName; + } + + /** + * The attribution tag, if any. + * + * This option may be overridden by the FingerprintManager using the caller's context. + */ + @DataClass.Generated.Member + public @Nullable String getAttributionTag() { + return mAttributionTag; + } + + /** + * The package name for that operation that should be used for + * {@link android.app.AppOpsManager} verification. + * + * This option may be overridden by the FingerprintManager using the caller's context. + */ + @DataClass.Generated.Member + public @NonNull FingerprintAuthenticateOptions setOpPackageName(@NonNull String value) { + mOpPackageName = value; + com.android.internal.util.AnnotationValidations.validate( + NonNull.class, null, mOpPackageName); + return this; + } + + /** + * The attribution tag, if any. + * + * This option may be overridden by the FingerprintManager using the caller's context. + */ + @DataClass.Generated.Member + public @NonNull FingerprintAuthenticateOptions setAttributionTag(@NonNull String value) { + mAttributionTag = value; + return this; + } + + @Override + @DataClass.Generated.Member + public boolean equals(@Nullable Object o) { + // You can override field equality logic by defining either of the methods like: + // boolean fieldNameEquals(FingerprintAuthenticateOptions other) { ... } + // boolean fieldNameEquals(FieldType otherValue) { ... } + + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + @SuppressWarnings("unchecked") + FingerprintAuthenticateOptions that = (FingerprintAuthenticateOptions) o; + //noinspection PointlessBooleanExpression + return true + && mUserId == that.mUserId + && mSensorId == that.mSensorId + && mIgnoreEnrollmentState == that.mIgnoreEnrollmentState + && mDisplayState == that.mDisplayState + && java.util.Objects.equals(mOpPackageName, that.mOpPackageName) + && java.util.Objects.equals(mAttributionTag, that.mAttributionTag); + } + + @Override + @DataClass.Generated.Member + public int hashCode() { + // You can override field hashCode logic by defining methods like: + // int fieldNameHashCode() { ... } + + int _hash = 1; + _hash = 31 * _hash + mUserId; + _hash = 31 * _hash + mSensorId; + _hash = 31 * _hash + Boolean.hashCode(mIgnoreEnrollmentState); + _hash = 31 * _hash + mDisplayState; + _hash = 31 * _hash + java.util.Objects.hashCode(mOpPackageName); + _hash = 31 * _hash + java.util.Objects.hashCode(mAttributionTag); + return _hash; + } + + @Override + @DataClass.Generated.Member + public void writeToParcel(@NonNull android.os.Parcel dest, int flags) { + // You can override field parcelling by defining methods like: + // void parcelFieldName(Parcel dest, int flags) { ... } + + byte flg = 0; + if (mIgnoreEnrollmentState) flg |= 0x4; + if (mAttributionTag != null) flg |= 0x20; + dest.writeByte(flg); + dest.writeInt(mUserId); + dest.writeInt(mSensorId); + dest.writeInt(mDisplayState); + dest.writeString(mOpPackageName); + if (mAttributionTag != null) dest.writeString(mAttributionTag); + } + + @Override + @DataClass.Generated.Member + public int describeContents() { return 0; } + + /** @hide */ + @SuppressWarnings({"unchecked", "RedundantCast"}) + @DataClass.Generated.Member + /* package-private */ FingerprintAuthenticateOptions(@NonNull android.os.Parcel in) { + // You can override field unparcelling by defining methods like: + // static FieldType unparcelFieldName(Parcel in) { ... } + + byte flg = in.readByte(); + boolean ignoreEnrollmentState = (flg & 0x4) != 0; + int userId = in.readInt(); + int sensorId = in.readInt(); + int displayState = in.readInt(); + String opPackageName = in.readString(); + String attributionTag = (flg & 0x20) == 0 ? null : in.readString(); + + this.mUserId = userId; + this.mSensorId = sensorId; + this.mIgnoreEnrollmentState = ignoreEnrollmentState; + this.mDisplayState = displayState; + com.android.internal.util.AnnotationValidations.validate( + AuthenticateOptions.DisplayState.class, null, mDisplayState); + this.mOpPackageName = opPackageName; + com.android.internal.util.AnnotationValidations.validate( + NonNull.class, null, mOpPackageName); + this.mAttributionTag = attributionTag; + + // onConstructed(); // You can define this method to get a callback + } + + @DataClass.Generated.Member + public static final @NonNull Parcelable.Creator CREATOR + = new Parcelable.Creator() { + @Override + public FingerprintAuthenticateOptions[] newArray(int size) { + return new FingerprintAuthenticateOptions[size]; + } + + @Override + public FingerprintAuthenticateOptions createFromParcel(@NonNull android.os.Parcel in) { + return new FingerprintAuthenticateOptions(in); + } + }; + + /** + * A builder for {@link FingerprintAuthenticateOptions} + */ + @SuppressWarnings("WeakerAccess") + @DataClass.Generated.Member + public static final class Builder { + + private int mUserId; + private int mSensorId; + private boolean mIgnoreEnrollmentState; + private @AuthenticateOptions.DisplayState int mDisplayState; + private @NonNull String mOpPackageName; + private @Nullable String mAttributionTag; + + private long mBuilderFieldsSet = 0L; + + public Builder() { + } + + /** + * The user id for this operation. + */ + @DataClass.Generated.Member + public @NonNull Builder setUserId(int value) { + checkNotUsed(); + mBuilderFieldsSet |= 0x1; + mUserId = value; + return this; + } + + /** + * The sensor id for this operation. + */ + @DataClass.Generated.Member + public @NonNull Builder setSensorId(int value) { + checkNotUsed(); + mBuilderFieldsSet |= 0x2; + mSensorId = value; + return this; + } + + /** + * If enrollment state should be ignored. + */ + @DataClass.Generated.Member + public @NonNull Builder setIgnoreEnrollmentState(boolean value) { + checkNotUsed(); + mBuilderFieldsSet |= 0x4; + mIgnoreEnrollmentState = value; + return this; + } + + /** + * The current doze state of the device. + */ + @DataClass.Generated.Member + public @NonNull Builder setDisplayState(@AuthenticateOptions.DisplayState int value) { + checkNotUsed(); + mBuilderFieldsSet |= 0x8; + mDisplayState = value; + return this; + } + + /** + * The package name for that operation that should be used for + * {@link android.app.AppOpsManager} verification. + * + * This option may be overridden by the FingerprintManager using the caller's context. + */ + @DataClass.Generated.Member + public @NonNull Builder setOpPackageName(@NonNull String value) { + checkNotUsed(); + mBuilderFieldsSet |= 0x10; + mOpPackageName = value; + return this; + } + + /** + * The attribution tag, if any. + * + * This option may be overridden by the FingerprintManager using the caller's context. + */ + @DataClass.Generated.Member + public @NonNull Builder setAttributionTag(@NonNull String value) { + checkNotUsed(); + mBuilderFieldsSet |= 0x20; + mAttributionTag = value; + return this; + } + + /** Builds the instance. This builder should not be touched after calling this! */ + public @NonNull FingerprintAuthenticateOptions build() { + checkNotUsed(); + mBuilderFieldsSet |= 0x40; // Mark builder used + + if ((mBuilderFieldsSet & 0x1) == 0) { + mUserId = defaultUserId(); + } + if ((mBuilderFieldsSet & 0x2) == 0) { + mSensorId = defaultSensorId(); + } + if ((mBuilderFieldsSet & 0x4) == 0) { + mIgnoreEnrollmentState = defaultIgnoreEnrollmentState(); + } + if ((mBuilderFieldsSet & 0x8) == 0) { + mDisplayState = defaultDisplayState(); + } + if ((mBuilderFieldsSet & 0x10) == 0) { + mOpPackageName = defaultOpPackageName(); + } + if ((mBuilderFieldsSet & 0x20) == 0) { + mAttributionTag = defaultAttributionTag(); + } + FingerprintAuthenticateOptions o = new FingerprintAuthenticateOptions( + mUserId, + mSensorId, + mIgnoreEnrollmentState, + mDisplayState, + mOpPackageName, + mAttributionTag); + return o; + } + + private void checkNotUsed() { + if ((mBuilderFieldsSet & 0x40) != 0) { + throw new IllegalStateException( + "This Builder should not be reused. Use a new Builder instance instead"); + } + } + } + + @DataClass.Generated( + time = 1676508212083L, + codegenVersion = "1.0.23", + sourceFile = "frameworks/base/core/java/android/hardware/fingerprint/FingerprintAuthenticateOptions.java", + inputSignatures = "private final int mUserId\nprivate final int mSensorId\nprivate final boolean mIgnoreEnrollmentState\nprivate final @android.hardware.biometrics.AuthenticateOptions.DisplayState int mDisplayState\nprivate @android.annotation.NonNull java.lang.String mOpPackageName\nprivate @android.annotation.Nullable java.lang.String mAttributionTag\nprivate static int defaultUserId()\nprivate static int defaultSensorId()\nprivate static boolean defaultIgnoreEnrollmentState()\nprivate static int defaultDisplayState()\nprivate static java.lang.String defaultOpPackageName()\nprivate static java.lang.String defaultAttributionTag()\nclass FingerprintAuthenticateOptions extends java.lang.Object implements [android.hardware.biometrics.AuthenticateOptions, android.os.Parcelable]\n@com.android.internal.util.DataClass(genParcelable=true, genAidl=true, genBuilder=true, genSetters=true, genEqualsHashCode=true)") + @Deprecated + private void __metadata() {} + + + //@formatter:on + // End of generated code + +} diff --git a/core/java/android/hardware/fingerprint/FingerprintManager.java b/core/java/android/hardware/fingerprint/FingerprintManager.java index d9f8f8e0e715d..eb8136e39d299 100644 --- a/core/java/android/hardware/fingerprint/FingerprintManager.java +++ b/core/java/android/hardware/fingerprint/FingerprintManager.java @@ -577,8 +577,10 @@ public class FingerprintManager implements BiometricAuthenticator, BiometricFing /** * Per-user version of authenticate. + * @deprecated use {@link #authenticate(CryptoObject, CancellationSignal, AuthenticationCallback, Handler, FingerprintAuthenticateOptions)}. * @hide */ + @Deprecated @RequiresPermission(anyOf = {USE_BIOMETRIC, USE_FINGERPRINT}) public void authenticate(@Nullable CryptoObject crypto, @Nullable CancellationSignal cancel, @NonNull AuthenticationCallback callback, Handler handler, int userId) { @@ -587,13 +589,29 @@ public class FingerprintManager implements BiometricAuthenticator, BiometricFing /** * Per-user and per-sensor version of authenticate. + * @deprecated use {@link #authenticate(CryptoObject, CancellationSignal, AuthenticationCallback, Handler, FingerprintAuthenticateOptions)}. * @hide */ + @Deprecated @RequiresPermission(anyOf = {USE_BIOMETRIC, USE_FINGERPRINT}) public void authenticate(@Nullable CryptoObject crypto, @Nullable CancellationSignal cancel, @NonNull AuthenticationCallback callback, Handler handler, int sensorId, int userId, int flags) { + authenticate(crypto, cancel, callback, handler, new FingerprintAuthenticateOptions.Builder() + .setSensorId(sensorId) + .setUserId(userId) + .setIgnoreEnrollmentState(flags != 0) + .build()); + } + /** + * Version of authenticate with additional options. + * @hide + */ + @RequiresPermission(anyOf = {USE_BIOMETRIC, USE_FINGERPRINT}) + public void authenticate(@Nullable CryptoObject crypto, @Nullable CancellationSignal cancel, + @NonNull AuthenticationCallback callback, @NonNull Handler handler, + @NonNull FingerprintAuthenticateOptions options) { FrameworkStatsLog.write(FrameworkStatsLog.AUTH_DEPRECATED_API_USED, AUTH_DEPRECATED_APIUSED__DEPRECATED_API__API_FINGERPRINT_MANAGER_AUTHENTICATE, mContext.getApplicationInfo().uid, @@ -608,7 +626,8 @@ public class FingerprintManager implements BiometricAuthenticator, BiometricFing return; } - final boolean ignoreEnrollmentState = flags == 0 ? false : true; + options.setOpPackageName(mContext.getOpPackageName()); + options.setAttributionTag(mContext.getAttributionTag()); if (mService != null) { try { @@ -616,16 +635,7 @@ public class FingerprintManager implements BiometricAuthenticator, BiometricFing mAuthenticationCallback = callback; mCryptoObject = crypto; final long operationId = crypto != null ? crypto.getOpId() : 0; - final long authId = - mService.authenticate( - mToken, - operationId, - sensorId, - userId, - mServiceReceiver, - mContext.getOpPackageName(), - mContext.getAttributionTag(), - ignoreEnrollmentState); + final long authId = mService.authenticate(mToken, operationId, mServiceReceiver, options); if (cancel != null) { cancel.setOnCancelListener(new OnAuthenticationCancelListener(authId)); } @@ -647,7 +657,7 @@ public class FingerprintManager implements BiometricAuthenticator, BiometricFing */ @RequiresPermission(USE_BIOMETRIC_INTERNAL) public void detectFingerprint(@NonNull CancellationSignal cancel, - @NonNull FingerprintDetectionCallback callback, int userId) { + @NonNull FingerprintDetectionCallback callback, @NonNull FingerprintAuthenticateOptions options) { if (mService == null) { return; } @@ -657,11 +667,13 @@ public class FingerprintManager implements BiometricAuthenticator, BiometricFing return; } + options.setOpPackageName(mContext.getOpPackageName()); + options.setAttributionTag(mContext.getAttributionTag()); + mFingerprintDetectionCallback = callback; try { - final long authId = mService.detectFingerprint(mToken, userId, mServiceReceiver, - mContext.getOpPackageName()); + final long authId = mService.detectFingerprint(mToken, mServiceReceiver, options); cancel.setOnCancelListener(new OnFingerprintDetectionCancelListener(authId)); } catch (RemoteException e) { Slog.w(TAG, "Remote exception when requesting finger detect", e); diff --git a/core/java/android/hardware/fingerprint/IFingerprintService.aidl b/core/java/android/hardware/fingerprint/IFingerprintService.aidl index 6f35713d434f1..e3ae299be7303 100644 --- a/core/java/android/hardware/fingerprint/IFingerprintService.aidl +++ b/core/java/android/hardware/fingerprint/IFingerprintService.aidl @@ -29,6 +29,7 @@ import android.hardware.fingerprint.IUdfpsOverlayController; import android.hardware.fingerprint.ISidefpsController; import android.hardware.fingerprint.IUdfpsOverlay; import android.hardware.fingerprint.Fingerprint; +import android.hardware.fingerprint.FingerprintAuthenticateOptions; import android.hardware.fingerprint.FingerprintSensorPropertiesInternal; import java.util.List; @@ -56,16 +57,15 @@ interface IFingerprintService { // Authenticate with a fingerprint. This is protected by USE_FINGERPRINT/USE_BIOMETRIC // permission. This is effectively deprecated, since it only comes through FingerprintManager // now. A requestId is returned that can be used to cancel this operation. - long authenticate(IBinder token, long operationId, int sensorId, int userId, - IFingerprintServiceReceiver receiver, String opPackageName, String attributionTag, - boolean shouldIgnoreEnrollmentState); + long authenticate(IBinder token, long operationId, IFingerprintServiceReceiver receiver, + in FingerprintAuthenticateOptions options); // Uses the fingerprint hardware to detect for the presence of a finger, without giving details // about accept/reject/lockout. A requestId is returned that can be used to cancel this // operation. @EnforcePermission("USE_BIOMETRIC_INTERNAL") - long detectFingerprint(IBinder token, int userId, IFingerprintServiceReceiver receiver, - String opPackageName); + long detectFingerprint(IBinder token, IFingerprintServiceReceiver receiver, + in FingerprintAuthenticateOptions options); // This method prepares the service to start authenticating, but doesn't start authentication. // This is protected by the MANAGE_BIOMETRIC signatuer permission. This method should only be diff --git a/core/tests/coretests/src/android/hardware/face/FaceManagerTest.java b/core/tests/coretests/src/android/hardware/face/FaceManagerTest.java new file mode 100644 index 0000000000000..9b1f0cd9e8da4 --- /dev/null +++ b/core/tests/coretests/src/android/hardware/face/FaceManagerTest.java @@ -0,0 +1,151 @@ +/* + * Copyright (C) 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.hardware.face; + +import static android.hardware.biometrics.BiometricFaceConstants.FACE_ERROR_HW_UNAVAILABLE; + +import static com.google.common.truth.Truth.assertThat; + +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyInt; +import static org.mockito.ArgumentMatchers.anyLong; +import static org.mockito.Mockito.eq; +import static org.mockito.Mockito.never; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +import android.content.Context; +import android.content.pm.ApplicationInfo; +import android.content.res.Resources; +import android.os.CancellationSignal; +import android.os.Handler; +import android.os.IBinder; +import android.os.RemoteException; +import android.os.test.TestLooper; +import android.platform.test.annotations.Presubmit; + +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.ArgumentCaptor; +import org.mockito.Captor; +import org.mockito.Mock; +import org.mockito.junit.MockitoJUnit; +import org.mockito.junit.MockitoJUnitRunner; +import org.mockito.junit.MockitoRule; + +import java.util.ArrayList; +import java.util.List; + +@Presubmit +@RunWith(MockitoJUnitRunner.class) +public class FaceManagerTest { + private static final int USER_ID = 4; + private static final String PACKAGE_NAME = "f.m.test"; + private static final String ATTRIBUTION_TAG = "blue"; + + @Rule + public final MockitoRule mockito = MockitoJUnit.rule(); + + @Mock + private Context mContext; + @Mock + private Resources mResources; + @Mock + private IFaceService mService; + @Mock + private FaceManager.AuthenticationCallback mAuthCallback; + + @Captor + private ArgumentCaptor mCaptor; + @Captor + private ArgumentCaptor mOptionsCaptor; + + private List mProps; + private TestLooper mLooper; + private Handler mHandler; + private FaceManager mFaceManager; + + @Before + public void setUp() throws Exception { + mLooper = new TestLooper(); + mHandler = new Handler(mLooper.getLooper()); + + when(mContext.getMainLooper()).thenReturn(mLooper.getLooper()); + when(mContext.getOpPackageName()).thenReturn(PACKAGE_NAME); + when(mContext.getAttributionTag()).thenReturn(ATTRIBUTION_TAG); + when(mContext.getApplicationInfo()).thenReturn(new ApplicationInfo()); + when(mContext.getResources()).thenReturn(mResources); + when(mResources.getString(anyInt())).thenReturn("string"); + + mFaceManager = new FaceManager(mContext, mService); + mProps = List.of(new FaceSensorPropertiesInternal( + 0 /* id */, + FaceSensorProperties.STRENGTH_STRONG, + 1 /* maxTemplatesAllowed */, + new ArrayList<>() /* componentInfo */, + FaceSensorProperties.TYPE_UNKNOWN, + true /* supportsFaceDetection */, + true /* supportsSelfIllumination */, + false /* resetLockoutRequiresChallenge */)); + } + + @Test + public void getSensorPropertiesInternal_noBinderCalls() throws RemoteException { + verify(mService).addAuthenticatorsRegisteredCallback(mCaptor.capture()); + + mCaptor.getValue().onAllAuthenticatorsRegistered(mProps); + List actual = mFaceManager.getSensorPropertiesInternal(); + + assertThat(actual).isEqualTo(mProps); + verify(mService, never()).getSensorPropertiesInternal(any()); + } + + @Test + public void authenticate_withOptions() throws Exception { + mFaceManager.authenticate(null, new CancellationSignal(), mAuthCallback, mHandler, + new FaceAuthenticateOptions.Builder() + .setUserId(USER_ID) + .setOpPackageName("some.thing") + .setAttributionTag(null) + .build()); + + verify(mService).authenticate(any(IBinder.class), eq(0L), + any(IFaceServiceReceiver.class), mOptionsCaptor.capture()); + + assertThat(mOptionsCaptor.getValue()).isEqualTo( + new FaceAuthenticateOptions.Builder() + .setUserId(USER_ID) + .setOpPackageName(PACKAGE_NAME) + .setAttributionTag(ATTRIBUTION_TAG) + .build() + ); + } + + @Test + public void authenticate_errorWhenUnavailable() throws Exception { + when(mService.authenticate(any(), anyLong(), any(), any())) + .thenThrow(new RemoteException()); + + mFaceManager.authenticate(null, new CancellationSignal(), + mAuthCallback, mHandler, + new FaceAuthenticateOptions.Builder().build()); + + verify(mAuthCallback).onAuthenticationError(eq(FACE_ERROR_HW_UNAVAILABLE), any()); + } +} diff --git a/core/tests/coretests/src/android/hardware/face/OWNERS b/core/tests/coretests/src/android/hardware/face/OWNERS new file mode 100644 index 0000000000000..6a2192a2c7fbc --- /dev/null +++ b/core/tests/coretests/src/android/hardware/face/OWNERS @@ -0,0 +1 @@ +include /services/core/java/com/android/server/biometrics/OWNERS diff --git a/core/tests/coretests/src/android/hardware/fingerprint/FingerprintManagerTest.java b/core/tests/coretests/src/android/hardware/fingerprint/FingerprintManagerTest.java new file mode 100644 index 0000000000000..f31903a731110 --- /dev/null +++ b/core/tests/coretests/src/android/hardware/fingerprint/FingerprintManagerTest.java @@ -0,0 +1,152 @@ +/* + * Copyright (C) 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.hardware.fingerprint; + +import static android.hardware.biometrics.BiometricFingerprintConstants.FINGERPRINT_ERROR_HW_UNAVAILABLE; + +import static com.google.common.truth.Truth.assertThat; + +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyInt; +import static org.mockito.ArgumentMatchers.anyLong; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.never; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +import android.content.Context; +import android.content.pm.ApplicationInfo; +import android.content.res.Resources; +import android.os.CancellationSignal; +import android.os.Handler; +import android.os.IBinder; +import android.os.RemoteException; +import android.os.test.TestLooper; +import android.platform.test.annotations.Presubmit; + +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.ArgumentCaptor; +import org.mockito.Captor; +import org.mockito.Mock; +import org.mockito.junit.MockitoJUnit; +import org.mockito.junit.MockitoJUnitRunner; +import org.mockito.junit.MockitoRule; + +import java.util.ArrayList; +import java.util.List; + +@Presubmit +@RunWith(MockitoJUnitRunner.class) +public class FingerprintManagerTest { + private static final int USER_ID = 9; + private static final String PACKAGE_NAME = "finger.food.test"; + private static final String ATTRIBUTION_TAG = "taz"; + + @Rule + public final MockitoRule mockito = MockitoJUnit.rule(); + + @Mock + private Context mContext; + @Mock + private Resources mResources; + @Mock + private IFingerprintService mService; + @Mock + private FingerprintManager.AuthenticationCallback mAuthCallback; + + @Captor + private ArgumentCaptor mCaptor; + @Captor + private ArgumentCaptor mOptionsCaptor; + + private List mProps; + private TestLooper mLooper; + private Handler mHandler; + private FingerprintManager mFingerprintManager; + + @Before + public void setUp() throws Exception { + mLooper = new TestLooper(); + mHandler = new Handler(mLooper.getLooper()); + + when(mContext.getMainLooper()).thenReturn(mLooper.getLooper()); + when(mContext.getOpPackageName()).thenReturn(PACKAGE_NAME); + when(mContext.getAttributionTag()).thenReturn(ATTRIBUTION_TAG); + when(mContext.getApplicationInfo()).thenReturn(new ApplicationInfo()); + when(mContext.getResources()).thenReturn(mResources); + when(mResources.getString(anyInt())).thenReturn("string"); + + mFingerprintManager = new FingerprintManager(mContext, mService); + mProps = List.of(new FingerprintSensorPropertiesInternal( + 0 /* sensorId */, + FingerprintSensorProperties.STRENGTH_STRONG, + 1 /* maxEnrollmentsPerUser */, + new ArrayList<>() /* componentInfo */, + FingerprintSensorProperties.TYPE_UNKNOWN, + true /* halControlsIllumination */, + true /* resetLockoutRequiresHardwareAuthToken */, + new ArrayList<>() /* sensorLocations */)); + } + + @Test + public void getSensorPropertiesInternal_noBinderCalls() throws RemoteException { + verify(mService).addAuthenticatorsRegisteredCallback(mCaptor.capture()); + + mCaptor.getValue().onAllAuthenticatorsRegistered(mProps); + List actual = + mFingerprintManager.getSensorPropertiesInternal(); + + assertThat(actual).isEqualTo(mProps); + verify(mService, never()).getSensorPropertiesInternal(any()); + } + + @Test + public void authenticate_withOptions() throws Exception { + mFingerprintManager.authenticate(null, new CancellationSignal(), mAuthCallback, mHandler, + new FingerprintAuthenticateOptions.Builder() + .setUserId(USER_ID) + .setOpPackageName("some.thing") + .setAttributionTag(null) + .build()); + + verify(mService).authenticate(any(IBinder.class), eq(0L), + any(IFingerprintServiceReceiver.class), mOptionsCaptor.capture()); + + assertThat(mOptionsCaptor.getValue()).isEqualTo( + new FingerprintAuthenticateOptions.Builder() + .setUserId(USER_ID) + .setOpPackageName(PACKAGE_NAME) + .setAttributionTag(ATTRIBUTION_TAG) + .build() + ); + } + + @Test + public void authenticate_errorWhenUnavailable() throws Exception { + when(mService.authenticate(any(), anyLong(), any(), any())) + .thenThrow(new RemoteException()); + + mFingerprintManager.authenticate(null, new CancellationSignal(), + mAuthCallback, mHandler, + new FingerprintAuthenticateOptions.Builder().build()); + + verify(mAuthCallback).onAuthenticationError(eq(FINGERPRINT_ERROR_HW_UNAVAILABLE), any()); + } +} diff --git a/core/tests/coretests/src/android/hardware/fingerprint/OWNERS b/core/tests/coretests/src/android/hardware/fingerprint/OWNERS new file mode 100644 index 0000000000000..6a2192a2c7fbc --- /dev/null +++ b/core/tests/coretests/src/android/hardware/fingerprint/OWNERS @@ -0,0 +1 @@ +include /services/core/java/com/android/server/biometrics/OWNERS diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java index 17ce0b9573477..83c22b8ab300e 100644 --- a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java @@ -96,8 +96,10 @@ import android.hardware.biometrics.BiometricManager; import android.hardware.biometrics.BiometricSourceType; import android.hardware.biometrics.IBiometricEnabledOnKeyguardCallback; import android.hardware.biometrics.SensorProperties; +import android.hardware.face.FaceAuthenticateOptions; import android.hardware.face.FaceManager; import android.hardware.face.FaceSensorPropertiesInternal; +import android.hardware.fingerprint.FingerprintAuthenticateOptions; import android.hardware.fingerprint.FingerprintManager; import android.hardware.fingerprint.FingerprintManager.AuthenticationCallback; import android.hardware.fingerprint.FingerprintManager.AuthenticationResult; @@ -2942,7 +2944,9 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab // Trigger the fingerprint success path so the bouncer can be shown handleFingerprintAuthenticated(user, isStrongBiometric); }, - userId); + new FingerprintAuthenticateOptions.Builder() + .setUserId(userId) + .build()); } else { mLogger.v("startListeningForFingerprint - authenticate"); mFpm.authenticate(null /* crypto */, mFingerprintCancelSignal, @@ -2988,7 +2992,10 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab if (supportsFaceDetection && !udfpsFingerprintAuthRunning) { // Run face detection. (If a face is detected, show the bouncer.) mLogger.v("startListeningForFace - detect"); - mFaceManager.detectFace(mFaceCancelSignal, mFaceDetectionCallback, userId); + mFaceManager.detectFace(mFaceCancelSignal, mFaceDetectionCallback, + new FaceAuthenticateOptions.Builder() + .setUserId(userId) + .build()); } else { // Don't run face detection. Instead, inform the user // face auth is unavailable and how to proceed. @@ -3007,7 +3014,7 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab final boolean isBypassEnabled = mKeyguardBypassController != null && mKeyguardBypassController.isBypassEnabled(); mFaceManager.authenticate(null /* crypto */, mFaceCancelSignal, - mFaceAuthenticationCallback, null /* handler */, userId, isBypassEnabled); + mFaceAuthenticationCallback, null /* handler */, userId); } setFaceRunningState(BIOMETRIC_STATE_RUNNING); } diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardFaceAuthManager.kt b/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardFaceAuthManager.kt index 2069891a23e02..a3268405a830e 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardFaceAuthManager.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardFaceAuthManager.kt @@ -18,6 +18,7 @@ package com.android.systemui.keyguard.data.repository import android.app.StatusBarManager import android.content.Context +import android.hardware.face.FaceAuthenticateOptions import android.hardware.face.FaceManager import android.os.CancellationSignal import com.android.internal.logging.InstanceId @@ -235,8 +236,7 @@ constructor( cancellationSignal, faceAuthCallback, null, - currentUserId, - lockscreenBypassEnabled + FaceAuthenticateOptions.Builder().setUserId(currentUserId).build() ) } } @@ -255,7 +255,11 @@ constructor( withContext(mainDispatcher) { // We always want to invoke face detect in the main thread. faceAuthLogger.faceDetectionStarted() - faceManager?.detectFace(cancellationSignal, detectionCallback, currentUserId) + faceManager?.detectFace( + cancellationSignal, + detectionCallback, + FaceAuthenticateOptions.Builder().setUserId(currentUserId).build() + ) } } diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java index e5d0692aaac27..a1e4f70352d6a 100644 --- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java +++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java @@ -617,7 +617,7 @@ public class KeyguardUpdateMonitorTest extends SysuiTestCase { verify(mFingerprintManager).authenticate(any(), any(), any(), any(), anyInt(), anyInt(), anyInt()); - verify(mFingerprintManager, never()).detectFingerprint(any(), any(), anyInt()); + verify(mFingerprintManager, never()).detectFingerprint(any(), any(), any()); } @Test @@ -629,7 +629,7 @@ public class KeyguardUpdateMonitorTest extends SysuiTestCase { verify(mFingerprintManager, never()).authenticate(any(), any(), any(), any(), anyInt(), anyInt(), anyInt()); - verify(mFingerprintManager, never()).detectFingerprint(any(), any(), anyInt()); + verify(mFingerprintManager, never()).detectFingerprint(any(), any(), any()); } @Test @@ -644,7 +644,7 @@ public class KeyguardUpdateMonitorTest extends SysuiTestCase { mTestableLooper.processAllMessages(); verify(mFingerprintManager, never()).authenticate(any(), any(), any(), any(), anyInt()); - verify(mFingerprintManager).detectFingerprint(any(), any(), anyInt()); + verify(mFingerprintManager).detectFingerprint(any(), any(), any()); } @Test @@ -733,7 +733,7 @@ public class KeyguardUpdateMonitorTest extends SysuiTestCase { public void testTriesToAuthenticate_whenBouncer() { setKeyguardBouncerVisibility(true); - verify(mFaceManager).authenticate(any(), any(), any(), any(), anyInt(), anyBoolean()); + verify(mFaceManager).authenticate(any(), any(), any(), any(), anyInt()); verify(mFaceManager, never()).hasEnrolledTemplates(anyInt()); } @@ -742,8 +742,7 @@ public class KeyguardUpdateMonitorTest extends SysuiTestCase { mKeyguardUpdateMonitor.sendPrimaryBouncerChanged( /* bouncerIsOrWillBeShowing */ true, /* bouncerFullyShown */ false); - verify(mFaceManager, never()).authenticate(any(), any(), any(), any(), anyInt(), - anyBoolean()); + verify(mFaceManager, never()).authenticate(any(), any(), any(), any(), anyInt()); } @Test @@ -751,7 +750,7 @@ public class KeyguardUpdateMonitorTest extends SysuiTestCase { keyguardIsVisible(); mKeyguardUpdateMonitor.dispatchStartedWakingUp(PowerManager.WAKE_REASON_POWER_BUTTON); mTestableLooper.processAllMessages(); - verify(mFaceManager).authenticate(any(), any(), any(), any(), anyInt(), anyBoolean()); + verify(mFaceManager).authenticate(any(), any(), any(), any(), anyInt()); verify(mUiEventLogger).logWithInstanceIdAndPosition( eq(FaceAuthUiEvent.FACE_AUTH_UPDATED_STARTED_WAKING_UP), eq(0), @@ -767,8 +766,7 @@ public class KeyguardUpdateMonitorTest extends SysuiTestCase { mTestableLooper.processAllMessages(); keyguardIsVisible(); - verify(mFaceManager, never()).authenticate(any(), any(), any(), any(), anyInt(), - anyBoolean()); + verify(mFaceManager, never()).authenticate(any(), any(), any(), any(), anyInt()); } @Test @@ -779,8 +777,7 @@ public class KeyguardUpdateMonitorTest extends SysuiTestCase { mKeyguardUpdateMonitor.dispatchStartedWakingUp(PowerManager.WAKE_REASON_POWER_BUTTON); mTestableLooper.processAllMessages(); keyguardIsVisible(); - verify(mFaceManager, never()).authenticate(any(), any(), any(), any(), anyInt(), - anyBoolean()); + verify(mFaceManager, never()).authenticate(any(), any(), any(), any(), anyInt()); } @Test @@ -804,9 +801,8 @@ public class KeyguardUpdateMonitorTest extends SysuiTestCase { mTestableLooper.processAllMessages(); // THEN face detect and authenticate are NOT triggered - verify(mFaceManager, never()).detectFace(any(), any(), anyInt()); - verify(mFaceManager, never()).authenticate(any(), any(), any(), any(), anyInt(), - anyBoolean()); + verify(mFaceManager, never()).detectFace(any(), any(), any()); + verify(mFaceManager, never()).authenticate(any(), any(), any(), any(), anyInt()); // THEN biometric help message sent to callback verify(keyguardUpdateMonitorCallback).onBiometricHelp( @@ -827,9 +823,8 @@ public class KeyguardUpdateMonitorTest extends SysuiTestCase { mTestableLooper.processAllMessages(); // FACE detect is triggered, not authenticate - verify(mFaceManager).detectFace(any(), any(), anyInt()); - verify(mFaceManager, never()).authenticate(any(), any(), any(), any(), anyInt(), - anyBoolean()); + verify(mFaceManager).detectFace(any(), any(), any()); + verify(mFaceManager, never()).authenticate(any(), any(), any(), any(), anyInt()); // WHEN bouncer becomes visible setKeyguardBouncerVisibility(true); @@ -837,9 +832,8 @@ public class KeyguardUpdateMonitorTest extends SysuiTestCase { // THEN face scanning is not run mKeyguardUpdateMonitor.requestFaceAuth(FaceAuthApiRequestReason.UDFPS_POINTER_DOWN); - verify(mFaceManager, never()).authenticate(any(), any(), any(), any(), anyInt(), - anyBoolean()); - verify(mFaceManager, never()).detectFace(any(), any(), anyInt()); + verify(mFaceManager, never()).authenticate(any(), any(), any(), any(), anyInt()); + verify(mFaceManager, never()).detectFace(any(), any(), any()); } @Test @@ -854,9 +848,8 @@ public class KeyguardUpdateMonitorTest extends SysuiTestCase { mTestableLooper.processAllMessages(); // FACE detect and authenticate are NOT triggered - verify(mFaceManager, never()).detectFace(any(), any(), anyInt()); - verify(mFaceManager, never()).authenticate(any(), any(), any(), any(), anyInt(), - anyBoolean()); + verify(mFaceManager, never()).detectFace(any(), any(), any()); + verify(mFaceManager, never()).authenticate(any(), any(), any(), any(), anyInt()); } @Test @@ -894,7 +887,7 @@ public class KeyguardUpdateMonitorTest extends SysuiTestCase { mKeyguardUpdateMonitor.setKeyguardShowing(true, true); mKeyguardUpdateMonitor.setAssistantVisible(true); - verify(mFaceManager).authenticate(any(), any(), any(), any(), anyInt(), anyBoolean()); + verify(mFaceManager).authenticate(any(), any(), any(), any(), anyInt()); } @Test @@ -906,8 +899,7 @@ public class KeyguardUpdateMonitorTest extends SysuiTestCase { any(), any(), any(), - anyInt(), - anyBoolean()); + anyInt()); } @Test @@ -938,7 +930,7 @@ public class KeyguardUpdateMonitorTest extends SysuiTestCase { KeyguardUpdateMonitor.getCurrentUser(), 0 /* flags */, new ArrayList<>()); keyguardIsVisible(); - verify(mFaceManager).authenticate(any(), any(), any(), any(), anyInt(), anyBoolean()); + verify(mFaceManager).authenticate(any(), any(), any(), any(), anyInt()); } @Test @@ -946,7 +938,7 @@ public class KeyguardUpdateMonitorTest extends SysuiTestCase { mKeyguardUpdateMonitor.setKeyguardShowing(true, true); mKeyguardUpdateMonitor.setAssistantVisible(true); - verify(mFaceManager).authenticate(any(), any(), any(), any(), anyInt(), anyBoolean()); + verify(mFaceManager).authenticate(any(), any(), any(), any(), anyInt()); mTestableLooper.processAllMessages(); clearInvocations(mFaceManager); @@ -963,8 +955,7 @@ public class KeyguardUpdateMonitorTest extends SysuiTestCase { any(), any(), any(), - anyInt(), - anyBoolean()); + anyInt()); } @Test @@ -974,8 +965,7 @@ public class KeyguardUpdateMonitorTest extends SysuiTestCase { mKeyguardUpdateMonitor.onTrustChanged(true /* enabled */, true /* newlyUnlocked */, KeyguardUpdateMonitor.getCurrentUser(), 0 /* flags */, new ArrayList<>()); keyguardIsVisible(); - verify(mFaceManager, never()).authenticate(any(), any(), any(), any(), anyInt(), - anyBoolean()); + verify(mFaceManager, never()).authenticate(any(), any(), any(), any(), anyInt()); } @Test @@ -987,9 +977,8 @@ public class KeyguardUpdateMonitorTest extends SysuiTestCase { keyguardIsVisible(); mTestableLooper.processAllMessages(); - verify(mFaceManager, never()).authenticate(any(), any(), any(), any(), anyInt(), - anyBoolean()); - verify(mFaceManager, never()).detectFace(any(), any(), anyInt()); + verify(mFaceManager, never()).authenticate(any(), any(), any(), any(), anyInt()); + verify(mFaceManager, never()).detectFace(any(), any(), any()); } @Test @@ -1019,8 +1008,7 @@ public class KeyguardUpdateMonitorTest extends SysuiTestCase { setKeyguardBouncerVisibility(true); mTestableLooper.processAllMessages(); - verify(mFaceManager, never()).authenticate(any(), any(), any(), any(), anyInt(), - anyBoolean()); + verify(mFaceManager, never()).authenticate(any(), any(), any(), any(), anyInt()); } @Test @@ -1147,7 +1135,7 @@ public class KeyguardUpdateMonitorTest extends SysuiTestCase { mTestableLooper.processAllMessages(); keyguardIsVisible(); - verify(mFaceManager).authenticate(any(), any(), any(), any(), anyInt(), anyBoolean()); + verify(mFaceManager).authenticate(any(), any(), any(), any(), anyInt()); verify(mFingerprintManager).authenticate(any(), any(), any(), any(), anyInt(), anyInt(), anyInt()); @@ -1599,8 +1587,7 @@ public class KeyguardUpdateMonitorTest extends SysuiTestCase { mKeyguardUpdateMonitor.setCredentialAttempted(); verify(mFingerprintManager, never()).authenticate(any(), any(), any(), any(), anyInt()); - verify(mFaceManager, never()).authenticate(any(), any(), any(), any(), anyInt(), - anyBoolean()); + verify(mFaceManager, never()).authenticate(any(), any(), any(), any(), anyInt()); } @Test @@ -1975,7 +1962,7 @@ public class KeyguardUpdateMonitorTest extends SysuiTestCase { mTestableLooper.processAllMessages(); keyguardIsVisible(); - verify(mFaceManager).authenticate(any(), any(), any(), any(), anyInt(), anyBoolean()); + verify(mFaceManager).authenticate(any(), any(), any(), any(), anyInt()); verify(mFingerprintManager).authenticate(any(), any(), any(), any(), anyInt(), anyInt(), anyInt()); @@ -2004,7 +1991,7 @@ public class KeyguardUpdateMonitorTest extends SysuiTestCase { mTestableLooper.processAllMessages(); verify(mFaceManager, never()).authenticate( - any(), any(), any(), any(), anyInt(), anyBoolean()); + any(), any(), any(), any(), anyInt()); } @Test @@ -2018,14 +2005,14 @@ public class KeyguardUpdateMonitorTest extends SysuiTestCase { // THEN face auth isn't triggered verify(mFaceManager, never()).authenticate( - any(), any(), any(), any(), anyInt(), anyBoolean()); + any(), any(), any(), any(), anyInt()); // WHEN device wakes up from the power button mKeyguardUpdateMonitor.dispatchStartedWakingUp(PowerManager.WAKE_REASON_POWER_BUTTON); mTestableLooper.processAllMessages(); // THEN face auth is triggered - verify(mFaceManager).authenticate(any(), any(), any(), any(), anyInt(), anyBoolean()); + verify(mFaceManager).authenticate(any(), any(), any(), any(), anyInt()); } @Test @@ -2195,7 +2182,7 @@ public class KeyguardUpdateMonitorTest extends SysuiTestCase { mTestableLooper.processAllMessages(); keyguardIsVisible(); - verify(mFaceManager).authenticate(any(), any(), any(), any(), anyInt(), anyBoolean()); + verify(mFaceManager).authenticate(any(), any(), any(), any(), anyInt()); verify(mFingerprintManager).authenticate(any(), any(), any(), any(), anyInt(), anyInt(), anyInt()); @@ -2228,7 +2215,7 @@ public class KeyguardUpdateMonitorTest extends SysuiTestCase { mTestableLooper.processAllMessages(); keyguardIsVisible(); - verify(mFaceManager).authenticate(any(), any(), any(), any(), anyInt(), anyBoolean()); + verify(mFaceManager).authenticate(any(), any(), any(), any(), anyInt()); final CancellationSignal faceCancel = spy(mKeyguardUpdateMonitor.mFaceCancelSignal); mKeyguardUpdateMonitor.mFaceCancelSignal = faceCancel; @@ -2596,8 +2583,7 @@ public class KeyguardUpdateMonitorTest extends SysuiTestCase { any(), mAuthenticationCallbackCaptor.capture(), any(), - anyInt(), - anyBoolean()); + anyInt()); mAuthenticationCallbackCaptor.getValue() .onAuthenticationSucceeded( new FaceManager.AuthenticationResult(null, null, mCurrentUserId, false)); diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/KeyguardFaceAuthManagerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/KeyguardFaceAuthManagerTest.kt index 7c604f7606810..d55370b20d093 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/KeyguardFaceAuthManagerTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/KeyguardFaceAuthManagerTest.kt @@ -21,6 +21,7 @@ import android.content.pm.UserInfo import android.hardware.biometrics.BiometricFaceConstants.FACE_ERROR_CANCELED import android.hardware.biometrics.BiometricFaceConstants.FACE_ERROR_LOCKOUT_PERMANENT import android.hardware.biometrics.ComponentInfoInternal +import android.hardware.face.FaceAuthenticateOptions import android.hardware.face.FaceManager import android.hardware.face.FaceSensorProperties import android.hardware.face.FaceSensorPropertiesInternal @@ -62,7 +63,6 @@ import org.junit.runner.RunWith import org.junit.runners.JUnit4 import org.mockito.ArgumentCaptor import org.mockito.ArgumentMatchers.any -import org.mockito.ArgumentMatchers.anyInt import org.mockito.ArgumentMatchers.eq import org.mockito.Captor import org.mockito.Mock @@ -276,7 +276,7 @@ class KeyguardFaceAuthManagerTest : SysuiTestCase() { underTest.detect() - verify(faceManager, never()).detectFace(any(), any(), anyInt()) + verify(faceManager, never()).detectFace(any(), any(), any()) } @Test @@ -379,7 +379,7 @@ class KeyguardFaceAuthManagerTest : SysuiTestCase() { .detectFace( cancellationSignal.capture(), detectionCallback.capture(), - eq(currentUserId) + eq(FaceAuthenticateOptions.Builder().setUserId(currentUserId).build()) ) } @@ -390,8 +390,7 @@ class KeyguardFaceAuthManagerTest : SysuiTestCase() { cancellationSignal.capture(), authenticationCallback.capture(), isNull(), - eq(currentUserId), - eq(true) + eq(FaceAuthenticateOptions.Builder().setUserId(currentUserId).build()) ) } diff --git a/services/core/java/com/android/server/biometrics/sensors/AuthenticationClient.java b/services/core/java/com/android/server/biometrics/sensors/AuthenticationClient.java index 57d28f95eb6a4..dce88da6f1115 100644 --- a/services/core/java/com/android/server/biometrics/sensors/AuthenticationClient.java +++ b/services/core/java/com/android/server/biometrics/sensors/AuthenticationClient.java @@ -75,7 +75,6 @@ public abstract class AuthenticationClient extends AcquisitionClient private final LockoutTracker mLockoutTracker; private final boolean mIsRestricted; private final boolean mAllowBackgroundAuthentication; - private final boolean mIsKeyguardBypassEnabled; // TODO: This is currently hard to maintain, as each AuthenticationClient subclass must update // the state. We should think of a way to improve this in the future. @State @@ -95,7 +94,7 @@ public abstract class AuthenticationClient extends AcquisitionClient @NonNull BiometricLogger biometricLogger, @NonNull BiometricContext biometricContext, boolean isStrongBiometric, @Nullable TaskStackListener taskStackListener, @NonNull LockoutTracker lockoutTracker, boolean allowBackgroundAuthentication, - boolean shouldVibrate, boolean isKeyguardBypassEnabled, int sensorStrength) { + boolean shouldVibrate, int sensorStrength) { super(context, lazyDaemon, token, listener, targetUserId, owner, cookie, sensorId, shouldVibrate, biometricLogger, biometricContext); mIsStrongBiometric = isStrongBiometric; @@ -107,7 +106,6 @@ public abstract class AuthenticationClient extends AcquisitionClient mLockoutTracker = lockoutTracker; mIsRestricted = restricted; mAllowBackgroundAuthentication = allowBackgroundAuthentication; - mIsKeyguardBypassEnabled = isKeyguardBypassEnabled; mShouldUseLockoutTracker = lockoutTracker != null; mSensorStrength = sensorStrength; } @@ -374,14 +372,6 @@ public abstract class AuthenticationClient extends AcquisitionClient return mState; } - /** - * @return true if the client supports bypass (e.g. passive auth such as face), and if it's - * enabled by the user. - */ - public boolean isKeyguardBypassEnabled() { - return mIsKeyguardBypassEnabled; - } - @Override public int getProtoEnum() { return BiometricsProto.CM_AUTHENTICATE; diff --git a/services/core/java/com/android/server/biometrics/sensors/face/FaceAuthenticator.java b/services/core/java/com/android/server/biometrics/sensors/face/FaceAuthenticator.java index b2fd46d1475d2..51829684f3ab9 100644 --- a/services/core/java/com/android/server/biometrics/sensors/face/FaceAuthenticator.java +++ b/services/core/java/com/android/server/biometrics/sensors/face/FaceAuthenticator.java @@ -23,6 +23,7 @@ import android.hardware.biometrics.IInvalidationCallback; import android.hardware.biometrics.ITestSession; import android.hardware.biometrics.ITestSessionCallback; import android.hardware.biometrics.SensorPropertiesInternal; +import android.hardware.face.FaceAuthenticateOptions; import android.hardware.face.IFaceService; import android.os.IBinder; import android.os.RemoteException; @@ -64,8 +65,11 @@ public final class FaceAuthenticator extends IBiometricAuthenticator.Stub { String opPackageName, long requestId, int cookie, boolean allowBackgroundAuthentication) throws RemoteException { mFaceService.prepareForAuthentication(mSensorId, requireConfirmation, token, operationId, - userId, sensorReceiver, opPackageName, requestId, cookie, - allowBackgroundAuthentication); + sensorReceiver, new FaceAuthenticateOptions.Builder() + .setUserId(userId) + .setOpPackageName(opPackageName) + .build(), + requestId, cookie, allowBackgroundAuthentication); } @Override 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 0248010bc9f35..1ee9f53c57749 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 @@ -35,6 +35,7 @@ import android.hardware.biometrics.ITestSessionCallback; import android.hardware.biometrics.face.IFace; import android.hardware.biometrics.face.SensorProps; import android.hardware.face.Face; +import android.hardware.face.FaceAuthenticateOptions; import android.hardware.face.FaceSensorPropertiesInternal; import android.hardware.face.FaceServiceReceiver; import android.hardware.face.IFaceAuthenticatorsRegisteredCallback; @@ -238,14 +239,15 @@ public class FaceService extends SystemService { @android.annotation.EnforcePermission(android.Manifest.permission.USE_BIOMETRIC_INTERNAL) @Override // Binder call - public long authenticate(final IBinder token, final long operationId, int userId, - final IFaceServiceReceiver receiver, final String opPackageName, - boolean isKeyguardBypassEnabled) { + public long authenticate(final IBinder token, final long operationId, + final IFaceServiceReceiver receiver, final FaceAuthenticateOptions options) { // TODO(b/152413782): If the sensor supports face detect and the device is encrypted or // lockdown, something wrong happened. See similar path in FingerprintService. super.authenticate_enforcePermission(); + final int userId = options.getUserId(); + final String opPackageName = options.getOpPackageName(); final boolean restricted = false; // Face APIs are private final int statsClient = Utils.isKeyguard(getContext(), opPackageName) ? BiometricsProtoEnums.CLIENT_KEYGUARD @@ -261,18 +263,18 @@ public class FaceService extends SystemService { return -1; } - return provider.second.scheduleAuthenticate(provider.first, token, operationId, userId, - 0 /* cookie */, - new ClientMonitorCallbackConverter(receiver), opPackageName, restricted, - statsClient, isKeyguard, isKeyguardBypassEnabled); + return provider.second.scheduleAuthenticate(provider.first, token, operationId, + 0 /* cookie */, new ClientMonitorCallbackConverter(receiver), options, + restricted, statsClient, isKeyguard); } @android.annotation.EnforcePermission(android.Manifest.permission.USE_BIOMETRIC_INTERNAL) @Override // Binder call - public long detectFace(final IBinder token, final int userId, - final IFaceServiceReceiver receiver, final String opPackageName) { + public long detectFace(final IBinder token, + final IFaceServiceReceiver receiver, final FaceAuthenticateOptions options) { super.detectFace_enforcePermission(); + final String opPackageName = options.getOpPackageName(); if (!Utils.isKeyguard(getContext(), opPackageName)) { Slog.w(TAG, "detectFace called from non-sysui package: " + opPackageName); return -1; @@ -284,7 +286,7 @@ public class FaceService extends SystemService { return -1; } - return provider.second.scheduleFaceDetect(provider.first, token, userId, + return provider.second.scheduleFaceDetect(provider.first, token, options.getUserId(), new ClientMonitorCallbackConverter(receiver), opPackageName, BiometricsProtoEnums.CLIENT_KEYGUARD); } @@ -292,9 +294,9 @@ public class FaceService extends SystemService { @android.annotation.EnforcePermission(android.Manifest.permission.USE_BIOMETRIC_INTERNAL) @Override // Binder call public void prepareForAuthentication(int sensorId, boolean requireConfirmation, - IBinder token, long operationId, int userId, - IBiometricSensorReceiver sensorReceiver, String opPackageName, long requestId, - int cookie, boolean allowBackgroundAuthentication) { + IBinder token, long operationId, IBiometricSensorReceiver sensorReceiver, + FaceAuthenticateOptions options, long requestId, int cookie, + boolean allowBackgroundAuthentication) { super.prepareForAuthentication_enforcePermission(); final ServiceProvider provider = mRegistry.getProviderForSensor(sensorId); @@ -305,10 +307,10 @@ public class FaceService extends SystemService { final boolean isKeyguardBypassEnabled = false; // only valid for keyguard clients final boolean restricted = true; // BiometricPrompt is always restricted - provider.scheduleAuthenticate(sensorId, token, operationId, userId, cookie, - new ClientMonitorCallbackConverter(sensorReceiver), opPackageName, requestId, + provider.scheduleAuthenticate(sensorId, token, operationId, cookie, + new ClientMonitorCallbackConverter(sensorReceiver), options, requestId, restricted, BiometricsProtoEnums.CLIENT_BIOMETRIC_PROMPT, - allowBackgroundAuthentication, isKeyguardBypassEnabled); + allowBackgroundAuthentication); } @android.annotation.EnforcePermission(android.Manifest.permission.USE_BIOMETRIC_INTERNAL) 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 85f95cec8377d..609c6a77e50a7 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 @@ -22,6 +22,7 @@ import android.hardware.biometrics.IInvalidationCallback; import android.hardware.biometrics.ITestSession; import android.hardware.biometrics.ITestSessionCallback; import android.hardware.face.Face; +import android.hardware.face.FaceAuthenticateOptions; import android.hardware.face.FaceManager; import android.hardware.face.FaceSensorPropertiesInternal; import android.hardware.face.IFaceServiceReceiver; @@ -88,15 +89,15 @@ public interface ServiceProvider extends BiometricServiceProvider @NonNull BiometricLogger logger, @NonNull BiometricContext biometricContext, boolean isStrongBiometric, @NonNull UsageStats usageStats, @NonNull LockoutCache lockoutCache, boolean allowBackgroundAuthentication, - boolean isKeyguardBypassEnabled, @Authenticators.Types int sensorStrength) { + @Authenticators.Types int sensorStrength) { this(context, lazyDaemon, token, requestId, listener, targetUserId, operationId, restricted, owner, cookie, requireConfirmation, sensorId, logger, biometricContext, isStrongBiometric, usageStats, lockoutCache /* lockoutCache */, - allowBackgroundAuthentication, isKeyguardBypassEnabled, + allowBackgroundAuthentication, context.getSystemService(SensorPrivacyManager.class), sensorStrength); } @@ -102,13 +102,13 @@ class FaceAuthenticationClient extends AuthenticationClient @NonNull BiometricLogger logger, @NonNull BiometricContext biometricContext, boolean isStrongBiometric, @NonNull UsageStats usageStats, @NonNull LockoutCache lockoutCache, boolean allowBackgroundAuthentication, - boolean isKeyguardBypassEnabled, SensorPrivacyManager sensorPrivacyManager, + SensorPrivacyManager sensorPrivacyManager, @Authenticators.Types int biometricStrength) { super(context, lazyDaemon, token, listener, targetUserId, operationId, restricted, owner, cookie, requireConfirmation, sensorId, logger, biometricContext, isStrongBiometric, null /* taskStackListener */, null /* lockoutCache */, allowBackgroundAuthentication, false /* shouldVibrate */, - isKeyguardBypassEnabled, biometricStrength); + biometricStrength); setRequestId(requestId); mUsageStats = usageStats; mNotificationManager = context.getSystemService(NotificationManager.class); 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 89852a14ba9b1..41e02691ddf8f 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 @@ -32,6 +32,7 @@ import android.hardware.biometrics.common.ComponentInfo; import android.hardware.biometrics.face.IFace; import android.hardware.biometrics.face.SensorProps; import android.hardware.face.Face; +import android.hardware.face.FaceAuthenticateOptions; import android.hardware.face.FaceSensorPropertiesInternal; import android.hardware.face.IFaceServiceReceiver; import android.os.Binder; @@ -435,21 +436,21 @@ public class FaceProvider implements IBinder.DeathRecipient, ServiceProvider { @Override public void scheduleAuthenticate(int sensorId, @NonNull IBinder token, long operationId, - int userId, int cookie, @NonNull ClientMonitorCallbackConverter callback, - @NonNull String opPackageName, long requestId, boolean restricted, int statsClient, - boolean allowBackgroundAuthentication, boolean isKeyguardBypassEnabled) { + int cookie, @NonNull ClientMonitorCallbackConverter callback, + @NonNull FaceAuthenticateOptions options, + long requestId, boolean restricted, int statsClient, + boolean allowBackgroundAuthentication) { mHandler.post(() -> { + final int userId = options.getUserId(); final boolean isStrongBiometric = Utils.isStrongBiometric(sensorId); final FaceAuthenticationClient client = new FaceAuthenticationClient( mContext, mSensors.get(sensorId).getLazySession(), token, requestId, callback, - userId, operationId, restricted, opPackageName, cookie, + userId, operationId, restricted, options.getOpPackageName(), cookie, false /* requireConfirmation */, sensorId, createLogger(BiometricsProtoEnums.ACTION_AUTHENTICATE, statsClient), mBiometricContext, isStrongBiometric, mUsageStats, mSensors.get(sensorId).getLockoutCache(), - allowBackgroundAuthentication, isKeyguardBypassEnabled, - Utils.getCurrentStrength(sensorId) - ); + allowBackgroundAuthentication, Utils.getCurrentStrength(sensorId)); scheduleForSensor(sensorId, client, new ClientMonitorCallback() { @Override public void onClientStarted( @@ -470,14 +471,13 @@ public class FaceProvider implements IBinder.DeathRecipient, ServiceProvider { @Override public long scheduleAuthenticate(int sensorId, @NonNull IBinder token, long operationId, - int userId, int cookie, @NonNull ClientMonitorCallbackConverter callback, - @NonNull String opPackageName, boolean restricted, int statsClient, - boolean allowBackgroundAuthentication, boolean isKeyguardBypassEnabled) { + int cookie, @NonNull ClientMonitorCallbackConverter callback, + @NonNull FaceAuthenticateOptions options, boolean restricted, int statsClient, + boolean allowBackgroundAuthentication) { final long id = mRequestCounter.incrementAndGet(); - scheduleAuthenticate(sensorId, token, operationId, userId, cookie, callback, - opPackageName, id, restricted, statsClient, - allowBackgroundAuthentication, isKeyguardBypassEnabled); + scheduleAuthenticate(sensorId, token, operationId, cookie, callback, + options, id, restricted, statsClient, allowBackgroundAuthentication); return id; } 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 1adc5e3e74b5b..7e575bc23f9c5 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 @@ -31,6 +31,7 @@ import android.hardware.biometrics.ITestSessionCallback; import android.hardware.biometrics.face.V1_0.IBiometricsFace; import android.hardware.biometrics.face.V1_0.IBiometricsFaceClientCallback; import android.hardware.face.Face; +import android.hardware.face.FaceAuthenticateOptions; import android.hardware.face.FaceSensorPropertiesInternal; import android.hardware.face.IFaceServiceReceiver; import android.os.Binder; @@ -665,19 +666,20 @@ public class Face10 implements IHwBinder.DeathRecipient, ServiceProvider { @Override public void scheduleAuthenticate(int sensorId, @NonNull IBinder token, long operationId, - int userId, int cookie, @NonNull ClientMonitorCallbackConverter receiver, - @NonNull String opPackageName, long requestId, boolean restricted, int statsClient, - boolean allowBackgroundAuthentication, boolean isKeyguardBypassEnabled) { + int cookie, @NonNull ClientMonitorCallbackConverter receiver, + @NonNull FaceAuthenticateOptions options, long requestId, boolean restricted, + int statsClient, boolean allowBackgroundAuthentication) { mHandler.post(() -> { + final int userId = options.getUserId(); scheduleUpdateActiveUserWithoutHandler(userId); final boolean isStrongBiometric = Utils.isStrongBiometric(mSensorId); final FaceAuthenticationClient client = new FaceAuthenticationClient(mContext, mLazyDaemon, token, requestId, receiver, userId, operationId, restricted, - opPackageName, cookie, false /* requireConfirmation */, mSensorId, + options.getOpPackageName(), cookie, false /* requireConfirmation */, mSensorId, createLogger(BiometricsProtoEnums.ACTION_AUTHENTICATE, statsClient), mBiometricContext, isStrongBiometric, mLockoutTracker, - mUsageStats, allowBackgroundAuthentication, isKeyguardBypassEnabled, + mUsageStats, allowBackgroundAuthentication, Utils.getCurrentStrength(mSensorId)); mScheduler.scheduleClientMonitor(client); }); @@ -685,14 +687,13 @@ public class Face10 implements IHwBinder.DeathRecipient, ServiceProvider { @Override public long scheduleAuthenticate(int sensorId, @NonNull IBinder token, long operationId, - int userId, int cookie, @NonNull ClientMonitorCallbackConverter receiver, - @NonNull String opPackageName, boolean restricted, int statsClient, - boolean allowBackgroundAuthentication, boolean isKeyguardBypassEnabled) { + int cookie, @NonNull ClientMonitorCallbackConverter receiver, + @NonNull FaceAuthenticateOptions options, boolean restricted, int statsClient, + boolean allowBackgroundAuthentication) { final long id = mRequestCounter.incrementAndGet(); - scheduleAuthenticate(sensorId, token, operationId, userId, cookie, receiver, - opPackageName, id, restricted, statsClient, - allowBackgroundAuthentication, isKeyguardBypassEnabled); + scheduleAuthenticate(sensorId, token, operationId, cookie, receiver, + options, id, restricted, statsClient, allowBackgroundAuthentication); return id; } diff --git a/services/core/java/com/android/server/biometrics/sensors/face/hidl/FaceAuthenticationClient.java b/services/core/java/com/android/server/biometrics/sensors/face/hidl/FaceAuthenticationClient.java index d4a7f085b8c5f..1c1f56ccddd5c 100644 --- a/services/core/java/com/android/server/biometrics/sensors/face/hidl/FaceAuthenticationClient.java +++ b/services/core/java/com/android/server/biometrics/sensors/face/hidl/FaceAuthenticationClient.java @@ -72,12 +72,12 @@ class FaceAuthenticationClient extends AuthenticationClient { @NonNull BiometricLogger logger, @NonNull BiometricContext biometricContext, boolean isStrongBiometric, @NonNull LockoutTracker lockoutTracker, @NonNull UsageStats usageStats, boolean allowBackgroundAuthentication, - boolean isKeyguardBypassEnabled, @Authenticators.Types int sensorStrength) { + @Authenticators.Types int sensorStrength) { super(context, lazyDaemon, token, listener, targetUserId, operationId, restricted, owner, cookie, requireConfirmation, sensorId, logger, biometricContext, isStrongBiometric, null /* taskStackListener */, lockoutTracker, allowBackgroundAuthentication, false /* shouldVibrate */, - isKeyguardBypassEnabled, sensorStrength); + sensorStrength); setRequestId(requestId); mUsageStats = usageStats; mSensorPrivacyManager = context.getSystemService(SensorPrivacyManager.class); 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 1c57151ed7bd1..affc496edc706 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 @@ -45,6 +45,7 @@ import android.hardware.biometrics.ITestSessionCallback; import android.hardware.biometrics.fingerprint.IFingerprint; import android.hardware.biometrics.fingerprint.PointerContext; import android.hardware.fingerprint.Fingerprint; +import android.hardware.fingerprint.FingerprintAuthenticateOptions; import android.hardware.fingerprint.FingerprintManager; import android.hardware.fingerprint.FingerprintSensorPropertiesInternal; import android.hardware.fingerprint.FingerprintServiceReceiver; @@ -252,15 +253,15 @@ public class FingerprintService extends SystemService { public long authenticate( final IBinder token, final long operationId, - final int sensorId, - final int userId, final IFingerprintServiceReceiver receiver, - final String opPackageName, - final String attributionTag, - boolean ignoreEnrollmentState) { + final FingerprintAuthenticateOptions options) { final int callingUid = Binder.getCallingUid(); final int callingPid = Binder.getCallingPid(); final int callingUserId = UserHandle.getCallingUserId(); + final String opPackageName = options.getOpPackageName(); + final String attributionTag = options.getAttributionTag(); + final int userId = options.getUserId(); + final int sensorId = options.getSensorId(); if (!canUseFingerprint( opPackageName, @@ -314,7 +315,8 @@ public class FingerprintService extends SystemService { && sensorProps != null && sensorProps.isAnyUdfpsType()) { try { return authenticateWithPrompt(operationId, sensorProps, callingUid, - callingUserId, receiver, opPackageName, ignoreEnrollmentState); + callingUserId, receiver, opPackageName, + options.isIgnoreEnrollmentState()); } catch (PackageManager.NameNotFoundException e) { Slog.e(TAG, "Invalid package", e); return -1; @@ -412,16 +414,18 @@ public class FingerprintService extends SystemService { @android.annotation.EnforcePermission(android.Manifest.permission.USE_BIOMETRIC_INTERNAL) @Override - public long detectFingerprint(final IBinder token, final int userId, - final IFingerprintServiceReceiver receiver, final String opPackageName) { + public long detectFingerprint(final IBinder token, + final IFingerprintServiceReceiver receiver, + final FingerprintAuthenticateOptions options) { super.detectFingerprint_enforcePermission(); + final String opPackageName = options.getOpPackageName(); if (!Utils.isKeyguard(getContext(), opPackageName)) { Slog.w(TAG, "detectFingerprint called from non-sysui package: " + opPackageName); return -1; } - if (!Utils.isUserEncryptedOrLockdown(mLockPatternUtils, userId)) { + if (!Utils.isUserEncryptedOrLockdown(mLockPatternUtils, options.getUserId())) { // If this happens, something in KeyguardUpdateMonitor is wrong. This should only // ever be invoked when the user is encrypted or lockdown. Slog.e(TAG, "detectFingerprint invoked when user is not encrypted or lockdown"); @@ -434,7 +438,7 @@ public class FingerprintService extends SystemService { return -1; } - return provider.second.scheduleFingerDetect(provider.first, token, userId, + return provider.second.scheduleFingerDetect(provider.first, token, options.getUserId(), new ClientMonitorCallbackConverter(receiver), opPackageName, BiometricsProtoEnums.CLIENT_KEYGUARD); } diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintAuthenticationClient.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintAuthenticationClient.java index a90679e755cf6..d1a7b1339179f 100644 --- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintAuthenticationClient.java +++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintAuthenticationClient.java @@ -136,7 +136,6 @@ class FingerprintAuthenticationClient extends AuthenticationClient null /* lockoutCache */, allowBackgroundAuthentication, false /* shouldVibrate */, - false /* isKeyguardBypassEnabled */, biometricStrength); setRequestId(requestId); mSensorOverlays = new SensorOverlays(udfpsOverlayController, diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/FingerprintAuthenticationClient.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/FingerprintAuthenticationClient.java index a9cc897a29370..957005a9223e6 100644 --- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/FingerprintAuthenticationClient.java +++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/FingerprintAuthenticationClient.java @@ -87,8 +87,7 @@ class FingerprintAuthenticationClient extends AuthenticationClient mCaptor; - - List mProps; - FaceManager mFaceManager; - - @Before - public void setUp() throws Exception { - when(mContext.getMainLooper()).thenReturn(Looper.getMainLooper()); - mFaceManager = new FaceManager(mContext, mService); - mProps = new ArrayList<>(); - mProps.add(new FaceSensorPropertiesInternal( - 0 /* id */, - FaceSensorProperties.STRENGTH_STRONG, - 1 /* maxTemplatesAllowed */, - new ArrayList<>() /* conponentInfo */, - FaceSensorProperties.TYPE_UNKNOWN, - true /* supportsFaceDetection */, - true /* supportsSelfIllumination */, - false /* resetLockoutRequiresChallenge */)); - } - - @Test - public void getSensorPropertiesInternal_noBinderCalls() throws RemoteException { - verify(mService).addAuthenticatorsRegisteredCallback(mCaptor.capture()); - - mCaptor.getValue().onAllAuthenticatorsRegistered(mProps); - List actual = mFaceManager.getSensorPropertiesInternal(); - - assertThat(actual).isEqualTo(mProps); - verify(mService, never()).getSensorPropertiesInternal(any()); - } -} diff --git a/services/tests/mockingservicestests/src/android/hardware/fingerprint/FingerprintManagerTest.java b/services/tests/mockingservicestests/src/android/hardware/fingerprint/FingerprintManagerTest.java deleted file mode 100644 index 558202d51b27f..0000000000000 --- a/services/tests/mockingservicestests/src/android/hardware/fingerprint/FingerprintManagerTest.java +++ /dev/null @@ -1,88 +0,0 @@ -/* - * Copyright (C) 2023 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.hardware.fingerprint; - -import static com.google.common.truth.Truth.assertThat; - -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.Mockito.never; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; - -import android.content.Context; -import android.os.Looper; -import android.os.RemoteException; - -import org.junit.Before; -import org.junit.Rule; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.mockito.ArgumentCaptor; -import org.mockito.Captor; -import org.mockito.Mock; -import org.mockito.junit.MockitoJUnit; -import org.mockito.junit.MockitoJUnitRunner; -import org.mockito.junit.MockitoRule; - -import java.util.ArrayList; -import java.util.List; - - -@RunWith(MockitoJUnitRunner.class) -public class FingerprintManagerTest { - @Rule - public final MockitoRule mockito = MockitoJUnit.rule(); - - @Mock - Context mContext; - @Mock - IFingerprintService mService; - - @Captor - ArgumentCaptor mCaptor; - - List mProps; - FingerprintManager mFingerprintManager; - - @Before - public void setUp() throws Exception { - when(mContext.getMainLooper()).thenReturn(Looper.getMainLooper()); - mFingerprintManager = new FingerprintManager(mContext, mService); - mProps = new ArrayList<>(); - mProps.add(new FingerprintSensorPropertiesInternal( - 0 /* sensorId */, - FingerprintSensorProperties.STRENGTH_STRONG, - 1 /* maxEnrollmentsPerUser */, - new ArrayList<>() /* componentInfo */, - FingerprintSensorProperties.TYPE_UNKNOWN, - true /* halControlsIllumination */, - true /* resetLockoutRequiresHardwareAuthToken */, - new ArrayList<>() /* sensorLocations */)); - } - - @Test - public void getSensorPropertiesInternal_noBinderCalls() throws RemoteException { - verify(mService).addAuthenticatorsRegisteredCallback(mCaptor.capture()); - - mCaptor.getValue().onAllAuthenticatorsRegistered(mProps); - List actual = - mFingerprintManager.getSensorPropertiesInternal(); - - assertThat(actual).isEqualTo(mProps); - verify(mService, never()).getSensorPropertiesInternal(any()); - } -} diff --git a/services/tests/mockingservicestests/src/android/hardware/fingerprint/OWNERS b/services/tests/mockingservicestests/src/android/hardware/fingerprint/OWNERS index 3edcf70d7e672..6a2192a2c7fbc 100644 --- a/services/tests/mockingservicestests/src/android/hardware/fingerprint/OWNERS +++ b/services/tests/mockingservicestests/src/android/hardware/fingerprint/OWNERS @@ -1 +1 @@ -include /services/core/java/com/android/server/biometrics/OWNERS \ No newline at end of file +include /services/core/java/com/android/server/biometrics/OWNERS 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 4c898b0c4d586..b0c3a6e26b7aa 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 @@ -705,7 +705,7 @@ public class BiometricSchedulerTest { TEST_SENSOR_ID, mock(BiometricLogger.class), biometricContext, true /* isStrongBiometric */, null /* taskStackListener */, null /* lockoutTracker */, false /* isKeyguard */, - true /* shouldVibrate */, false /* isKeyguardBypassEnabled */, + true /* shouldVibrate */, 0 /* sensorStrength */); } diff --git a/services/tests/servicestests/src/com/android/server/biometrics/sensors/face/aidl/FaceAuthenticationClientTest.java b/services/tests/servicestests/src/com/android/server/biometrics/sensors/face/aidl/FaceAuthenticationClientTest.java index 139910ba89269..184a5562a689b 100644 --- a/services/tests/servicestests/src/com/android/server/biometrics/sensors/face/aidl/FaceAuthenticationClientTest.java +++ b/services/tests/servicestests/src/com/android/server/biometrics/sensors/face/aidl/FaceAuthenticationClientTest.java @@ -159,7 +159,7 @@ public class FaceAuthenticationClientTest { false /* requireConfirmation */, 9 /* sensorId */, mBiometricLogger, mBiometricContext, true /* isStrongBiometric */, mUsageStats, null /* mLockoutCache */, false /* allowBackgroundAuthentication */, - false /* isKeyguardBypassEnabled */, null /* sensorPrivacyManager */, + null /* sensorPrivacyManager */, 0 /* biometricStrength */) { @Override protected ActivityTaskManager getActivityTaskManager() {