diff --git a/core/java/android/hardware/face/FaceEnrollFrame.java b/core/java/android/hardware/face/FaceEnrollFrame.java index 551139d240a32..822a57944449a 100644 --- a/core/java/android/hardware/face/FaceEnrollFrame.java +++ b/core/java/android/hardware/face/FaceEnrollFrame.java @@ -18,6 +18,7 @@ package android.hardware.face; import android.annotation.NonNull; import android.annotation.Nullable; +import android.hardware.face.FaceEnrollStages.FaceEnrollStage; import android.os.Parcel; import android.os.Parcelable; diff --git a/core/java/android/hardware/face/FaceEnrollStage.java b/core/java/android/hardware/face/FaceEnrollStages.java similarity index 59% rename from core/java/android/hardware/face/FaceEnrollStage.java rename to core/java/android/hardware/face/FaceEnrollStages.java index de717fbe46b44..de374b319ff92 100644 --- a/core/java/android/hardware/face/FaceEnrollStage.java +++ b/core/java/android/hardware/face/FaceEnrollStages.java @@ -22,53 +22,63 @@ import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; /** - * A stage that may occur during face enrollment. + * A collection of constants representing different stages of face enrollment. * * @hide */ -@Retention(RetentionPolicy.SOURCE) -@IntDef({ - FaceEnrollStage.UNKNOWN, - FaceEnrollStage.FIRST_FRAME_RECEIVED, - FaceEnrollStage.WAITING_FOR_CENTERING, - FaceEnrollStage.HOLD_STILL_IN_CENTER, - FaceEnrollStage.ENROLLING_MOVEMENT_1, - FaceEnrollStage.ENROLLING_MOVEMENT_2, - FaceEnrollStage.ENROLLMENT_FINISHED -}) -public @interface FaceEnrollStage { +public final class FaceEnrollStages { + // Prevent instantiation. + private FaceEnrollStages() {} + + /** + * A stage that may occur during face enrollment. + * + * @hide + */ + @IntDef({ + UNKNOWN, + FIRST_FRAME_RECEIVED, + WAITING_FOR_CENTERING, + HOLD_STILL_IN_CENTER, + ENROLLING_MOVEMENT_1, + ENROLLING_MOVEMENT_2, + ENROLLMENT_FINISHED + }) + @Retention(RetentionPolicy.SOURCE) + public @interface FaceEnrollStage {} + /** * The current enrollment stage is not known. */ - int UNKNOWN = -1; + public static final int UNKNOWN = 0; /** * Enrollment has just begun. No action is needed from the user yet. */ - int FIRST_FRAME_RECEIVED = 0; + public static final int FIRST_FRAME_RECEIVED = 1; /** * The user must center their face in the frame. */ - int WAITING_FOR_CENTERING = 1; + public static final int WAITING_FOR_CENTERING = 2; /** * The user must keep their face centered in the frame. */ - int HOLD_STILL_IN_CENTER = 2; + public static final int HOLD_STILL_IN_CENTER = 3; /** * The user must follow a first set of movement instructions. */ - int ENROLLING_MOVEMENT_1 = 3; + public static final int ENROLLING_MOVEMENT_1 = 4; /** * The user must follow a second set of movement instructions. */ - int ENROLLING_MOVEMENT_2 = 4; + public static final int ENROLLING_MOVEMENT_2 = 5; /** * Enrollment has completed. No more action is needed from the user. */ - int ENROLLMENT_FINISHED = 5; + public static final int ENROLLMENT_FINISHED = 6; } diff --git a/core/java/android/hardware/face/FaceManager.java b/core/java/android/hardware/face/FaceManager.java index 5f8789993a5e8..9a27a99437bc7 100644 --- a/core/java/android/hardware/face/FaceManager.java +++ b/core/java/android/hardware/face/FaceManager.java @@ -1022,6 +1022,34 @@ public class FaceManager implements BiometricAuthenticator, BiometricFaceConstan public void onEnrollmentHelp(int helpMsgId, CharSequence helpString) { } + /** + * Called each time a single frame is captured during enrollment. + * + *
For older, non-AIDL implementations, only {@code helpCode} and {@code helpMessage} are + * supported. Sensible default values will be provided for all other arguments. + * + * @param helpCode An integer identifying the capture status for this frame. + * @param helpMessage A human-readable help string that can be shown in UI. + * @param cell The cell captured during this frame of enrollment, if any. + * @param stage An integer representing the current stage of enrollment. + * @param pan The horizontal pan of the detected face. Values in the range [-1, 1] + * indicate a good capture. + * @param tilt The vertical tilt of the detected face. Values in the range [-1, 1] + * indicate a good capture. + * @param distance The distance of the detected face from the device. Values in + * the range [-1, 1] indicate a good capture. + */ + public void onEnrollmentFrame( + int helpCode, + @Nullable CharSequence helpMessage, + @Nullable FaceEnrollCell cell, + @FaceEnrollStages.FaceEnrollStage int stage, + float pan, + float tilt, + float distance) { + onEnrollmentHelp(helpCode, helpMessage); + } + /** * Called as each enrollment step progresses. Enrollment is considered complete when * remaining reaches 0. This function will not be called if enrollment fails. See @@ -1305,7 +1333,7 @@ public class FaceManager implements BiometricAuthenticator, BiometricFaceConstan } else if (mEnrollmentCallback != null) { final FaceEnrollFrame frame = new FaceEnrollFrame( null /* cell */, - FaceEnrollStage.UNKNOWN, + FaceEnrollStages.UNKNOWN, new FaceDataFrame(acquireInfo, vendorCode)); sendEnrollmentFrame(frame); } @@ -1333,12 +1361,19 @@ public class FaceManager implements BiometricAuthenticator, BiometricFaceConstan if (frame == null) { Slog.w(TAG, "Received null enrollment frame"); } else if (mEnrollmentCallback != null) { - // TODO(b/178414967): Send additional frame data to callback - final int acquireInfo = frame.getData().getAcquiredInfo(); - final int vendorCode = frame.getData().getVendorCode(); + final FaceDataFrame data = frame.getData(); + final int acquireInfo = data.getAcquiredInfo(); + final int vendorCode = data.getVendorCode(); final int helpCode = getHelpCode(acquireInfo, vendorCode); final String helpMessage = getEnrollHelpMessage(mContext, acquireInfo, vendorCode); - mEnrollmentCallback.onEnrollmentHelp(helpCode, helpMessage); + mEnrollmentCallback.onEnrollmentFrame( + helpCode, + helpMessage, + frame.getCell(), + frame.getStage(), + data.getPan(), + data.getTilt(), + data.getDistance()); } } diff --git a/services/core/java/com/android/server/biometrics/sensors/face/aidl/AidlConversionUtils.java b/services/core/java/com/android/server/biometrics/sensors/face/aidl/AidlConversionUtils.java index 5d713f35f925e..043260c840bc1 100644 --- a/services/core/java/com/android/server/biometrics/sensors/face/aidl/AidlConversionUtils.java +++ b/services/core/java/com/android/server/biometrics/sensors/face/aidl/AidlConversionUtils.java @@ -24,11 +24,14 @@ import android.hardware.biometrics.face.AuthenticationFrame; import android.hardware.biometrics.face.BaseFrame; import android.hardware.biometrics.face.Cell; import android.hardware.biometrics.face.EnrollmentFrame; +import android.hardware.biometrics.face.EnrollmentStage; import android.hardware.biometrics.face.Error; import android.hardware.face.FaceAuthenticationFrame; import android.hardware.face.FaceDataFrame; import android.hardware.face.FaceEnrollCell; import android.hardware.face.FaceEnrollFrame; +import android.hardware.face.FaceEnrollStages; +import android.hardware.face.FaceEnrollStages.FaceEnrollStage; /** * Utilities for converting from hardware to framework-defined AIDL models. @@ -38,92 +41,107 @@ final class AidlConversionUtils { private AidlConversionUtils() { } - public static @BiometricFaceConstants.FaceError int toFrameworkError(byte aidlError) { - if (aidlError == Error.UNKNOWN) { - // No framework constant available - return BiometricFaceConstants.FACE_ERROR_UNKNOWN; - } else if (aidlError == Error.HW_UNAVAILABLE) { - return BiometricFaceConstants.FACE_ERROR_HW_UNAVAILABLE; - } else if (aidlError == Error.UNABLE_TO_PROCESS) { - return BiometricFaceConstants.FACE_ERROR_UNABLE_TO_PROCESS; - } else if (aidlError == Error.TIMEOUT) { - return BiometricFaceConstants.FACE_ERROR_TIMEOUT; - } else if (aidlError == Error.NO_SPACE) { - return BiometricFaceConstants.FACE_ERROR_NO_SPACE; - } else if (aidlError == Error.CANCELED) { - return BiometricFaceConstants.FACE_ERROR_CANCELED; - } else if (aidlError == Error.UNABLE_TO_REMOVE) { - return BiometricFaceConstants.FACE_ERROR_UNABLE_TO_REMOVE; - } else if (aidlError == Error.VENDOR) { - return BiometricFaceConstants.FACE_ERROR_VENDOR; - } else if (aidlError == Error.REENROLL_REQUIRED) { - return BiometricFaceConstants.BIOMETRIC_ERROR_RE_ENROLL; - } else { - return BiometricFaceConstants.FACE_ERROR_UNKNOWN; + @BiometricFaceConstants.FaceError + public static int toFrameworkError(byte aidlError) { + switch (aidlError) { + case Error.HW_UNAVAILABLE: + return BiometricFaceConstants.FACE_ERROR_HW_UNAVAILABLE; + case Error.UNABLE_TO_PROCESS: + return BiometricFaceConstants.FACE_ERROR_UNABLE_TO_PROCESS; + case Error.TIMEOUT: + return BiometricFaceConstants.FACE_ERROR_TIMEOUT; + case Error.NO_SPACE: + return BiometricFaceConstants.FACE_ERROR_NO_SPACE; + case Error.CANCELED: + return BiometricFaceConstants.FACE_ERROR_CANCELED; + case Error.UNABLE_TO_REMOVE: + return BiometricFaceConstants.FACE_ERROR_UNABLE_TO_REMOVE; + case Error.VENDOR: + return BiometricFaceConstants.FACE_ERROR_VENDOR; + case Error.REENROLL_REQUIRED: + return BiometricFaceConstants.BIOMETRIC_ERROR_RE_ENROLL; + case Error.UNKNOWN: + default: + return BiometricFaceConstants.FACE_ERROR_UNKNOWN; } } - public static @BiometricFaceConstants.FaceAcquired int toFrameworkAcquiredInfo( - byte aidlAcquired) { - if (aidlAcquired == AcquiredInfo.UNKNOWN) { - return BiometricFaceConstants.FACE_ACQUIRED_UNKNOWN; - } else if (aidlAcquired == AcquiredInfo.GOOD) { - return BiometricFaceConstants.FACE_ACQUIRED_GOOD; - } else if (aidlAcquired == AcquiredInfo.INSUFFICIENT) { - return BiometricFaceConstants.FACE_ACQUIRED_INSUFFICIENT; - } else if (aidlAcquired == AcquiredInfo.TOO_BRIGHT) { - return BiometricFaceConstants.FACE_ACQUIRED_TOO_BRIGHT; - } else if (aidlAcquired == AcquiredInfo.TOO_DARK) { - return BiometricFaceConstants.FACE_ACQUIRED_TOO_DARK; - } else if (aidlAcquired == AcquiredInfo.TOO_CLOSE) { - return BiometricFaceConstants.FACE_ACQUIRED_TOO_CLOSE; - } else if (aidlAcquired == AcquiredInfo.TOO_FAR) { - return BiometricFaceConstants.FACE_ACQUIRED_TOO_FAR; - } else if (aidlAcquired == AcquiredInfo.FACE_TOO_HIGH) { - return BiometricFaceConstants.FACE_ACQUIRED_TOO_HIGH; - } else if (aidlAcquired == AcquiredInfo.FACE_TOO_LOW) { - return BiometricFaceConstants.FACE_ACQUIRED_TOO_LOW; - } else if (aidlAcquired == AcquiredInfo.FACE_TOO_RIGHT) { - return BiometricFaceConstants.FACE_ACQUIRED_TOO_RIGHT; - } else if (aidlAcquired == AcquiredInfo.FACE_TOO_LEFT) { - return BiometricFaceConstants.FACE_ACQUIRED_TOO_LEFT; - } else if (aidlAcquired == AcquiredInfo.POOR_GAZE) { - return BiometricFaceConstants.FACE_ACQUIRED_POOR_GAZE; - } else if (aidlAcquired == AcquiredInfo.NOT_DETECTED) { - return BiometricFaceConstants.FACE_ACQUIRED_NOT_DETECTED; - } else if (aidlAcquired == AcquiredInfo.TOO_MUCH_MOTION) { - return BiometricFaceConstants.FACE_ACQUIRED_TOO_MUCH_MOTION; - } else if (aidlAcquired == AcquiredInfo.RECALIBRATE) { - return BiometricFaceConstants.FACE_ACQUIRED_RECALIBRATE; - } else if (aidlAcquired == AcquiredInfo.TOO_DIFFERENT) { - return BiometricFaceConstants.FACE_ACQUIRED_TOO_DIFFERENT; - } else if (aidlAcquired == AcquiredInfo.TOO_SIMILAR) { - return BiometricFaceConstants.FACE_ACQUIRED_TOO_SIMILAR; - } else if (aidlAcquired == AcquiredInfo.PAN_TOO_EXTREME) { - return BiometricFaceConstants.FACE_ACQUIRED_PAN_TOO_EXTREME; - } else if (aidlAcquired == AcquiredInfo.TILT_TOO_EXTREME) { - return BiometricFaceConstants.FACE_ACQUIRED_TILT_TOO_EXTREME; - } else if (aidlAcquired == AcquiredInfo.ROLL_TOO_EXTREME) { - return BiometricFaceConstants.FACE_ACQUIRED_ROLL_TOO_EXTREME; - } else if (aidlAcquired == AcquiredInfo.FACE_OBSCURED) { - return BiometricFaceConstants.FACE_ACQUIRED_FACE_OBSCURED; - } else if (aidlAcquired == AcquiredInfo.START) { - return BiometricFaceConstants.FACE_ACQUIRED_START; - } else if (aidlAcquired == AcquiredInfo.SENSOR_DIRTY) { - return BiometricFaceConstants.FACE_ACQUIRED_SENSOR_DIRTY; - } else if (aidlAcquired == AcquiredInfo.VENDOR) { - return BiometricFaceConstants.FACE_ACQUIRED_VENDOR; - } else if (aidlAcquired == AcquiredInfo.FIRST_FRAME_RECEIVED) { - // No framework constant available - return BiometricFaceConstants.FACE_ACQUIRED_UNKNOWN; - } else if (aidlAcquired == AcquiredInfo.DARK_GLASSES_DETECTED) { - // No framework constant available - return BiometricFaceConstants.FACE_ACQUIRED_UNKNOWN; - } else if (aidlAcquired == AcquiredInfo.MOUTH_COVERING_DETECTED) { - // No framework constant available - return BiometricFaceConstants.FACE_ACQUIRED_UNKNOWN; - } else { - return BiometricFaceConstants.FACE_ACQUIRED_UNKNOWN; + @BiometricFaceConstants.FaceAcquired + public static int toFrameworkAcquiredInfo(byte aidlAcquiredInfo) { + switch (aidlAcquiredInfo) { + case AcquiredInfo.GOOD: + return BiometricFaceConstants.FACE_ACQUIRED_GOOD; + case AcquiredInfo.INSUFFICIENT: + return BiometricFaceConstants.FACE_ACQUIRED_INSUFFICIENT; + case AcquiredInfo.TOO_BRIGHT: + return BiometricFaceConstants.FACE_ACQUIRED_TOO_BRIGHT; + case AcquiredInfo.TOO_DARK: + return BiometricFaceConstants.FACE_ACQUIRED_TOO_DARK; + case AcquiredInfo.TOO_CLOSE: + return BiometricFaceConstants.FACE_ACQUIRED_TOO_CLOSE; + case AcquiredInfo.TOO_FAR: + return BiometricFaceConstants.FACE_ACQUIRED_TOO_FAR; + case AcquiredInfo.FACE_TOO_HIGH: + return BiometricFaceConstants.FACE_ACQUIRED_TOO_HIGH; + case AcquiredInfo.FACE_TOO_LOW: + return BiometricFaceConstants.FACE_ACQUIRED_TOO_LOW; + case AcquiredInfo.FACE_TOO_RIGHT: + return BiometricFaceConstants.FACE_ACQUIRED_TOO_RIGHT; + case AcquiredInfo.FACE_TOO_LEFT: + return BiometricFaceConstants.FACE_ACQUIRED_TOO_LEFT; + case AcquiredInfo.POOR_GAZE: + return BiometricFaceConstants.FACE_ACQUIRED_POOR_GAZE; + case AcquiredInfo.NOT_DETECTED: + return BiometricFaceConstants.FACE_ACQUIRED_NOT_DETECTED; + case AcquiredInfo.TOO_MUCH_MOTION: + return BiometricFaceConstants.FACE_ACQUIRED_TOO_MUCH_MOTION; + case AcquiredInfo.RECALIBRATE: + return BiometricFaceConstants.FACE_ACQUIRED_RECALIBRATE; + case AcquiredInfo.TOO_DIFFERENT: + return BiometricFaceConstants.FACE_ACQUIRED_TOO_DIFFERENT; + case AcquiredInfo.TOO_SIMILAR: + return BiometricFaceConstants.FACE_ACQUIRED_TOO_SIMILAR; + case AcquiredInfo.PAN_TOO_EXTREME: + return BiometricFaceConstants.FACE_ACQUIRED_PAN_TOO_EXTREME; + case AcquiredInfo.TILT_TOO_EXTREME: + return BiometricFaceConstants.FACE_ACQUIRED_TILT_TOO_EXTREME; + case AcquiredInfo.ROLL_TOO_EXTREME: + return BiometricFaceConstants.FACE_ACQUIRED_ROLL_TOO_EXTREME; + case AcquiredInfo.FACE_OBSCURED: + return BiometricFaceConstants.FACE_ACQUIRED_FACE_OBSCURED; + case AcquiredInfo.START: + return BiometricFaceConstants.FACE_ACQUIRED_START; + case AcquiredInfo.SENSOR_DIRTY: + return BiometricFaceConstants.FACE_ACQUIRED_SENSOR_DIRTY; + case AcquiredInfo.VENDOR: + return BiometricFaceConstants.FACE_ACQUIRED_VENDOR; + case AcquiredInfo.UNKNOWN: + case AcquiredInfo.FIRST_FRAME_RECEIVED: + case AcquiredInfo.DARK_GLASSES_DETECTED: + case AcquiredInfo.MOUTH_COVERING_DETECTED: + default: + return BiometricFaceConstants.FACE_ACQUIRED_UNKNOWN; + } + } + + @FaceEnrollStage + public static int toFrameworkEnrollmentStage(int aidlEnrollmentStage) { + switch (aidlEnrollmentStage) { + case EnrollmentStage.FIRST_FRAME_RECEIVED: + return FaceEnrollStages.FIRST_FRAME_RECEIVED; + case EnrollmentStage.WAITING_FOR_CENTERING: + return FaceEnrollStages.WAITING_FOR_CENTERING; + case EnrollmentStage.HOLD_STILL_IN_CENTER: + return FaceEnrollStages.HOLD_STILL_IN_CENTER; + case EnrollmentStage.ENROLLING_MOVEMENT_1: + return FaceEnrollStages.ENROLLING_MOVEMENT_1; + case EnrollmentStage.ENROLLING_MOVEMENT_2: + return FaceEnrollStages.ENROLLING_MOVEMENT_2; + case EnrollmentStage.ENROLLMENT_FINISHED: + return FaceEnrollStages.ENROLLMENT_FINISHED; + case EnrollmentStage.UNKNOWN: + default: + return FaceEnrollStages.UNKNOWN; } } @@ -135,7 +153,9 @@ final class AidlConversionUtils { @NonNull public static FaceEnrollFrame toFrameworkEnrollmentFrame(@NonNull EnrollmentFrame frame) { - return new FaceEnrollFrame(toFrameworkCell(frame.cell), frame.stage, + return new FaceEnrollFrame( + toFrameworkCell(frame.cell), + toFrameworkEnrollmentStage(frame.stage), toFrameworkBaseFrame(frame.data)); }