Merge "Send AIDL face enrollment frame info to clients" into sc-dev

This commit is contained in:
Curtis Belmonte
2021-04-29 17:58:28 +00:00
committed by Android (Google) Code Review
4 changed files with 174 additions and 108 deletions

View File

@@ -18,6 +18,7 @@ package android.hardware.face;
import android.annotation.NonNull; import android.annotation.NonNull;
import android.annotation.Nullable; import android.annotation.Nullable;
import android.hardware.face.FaceEnrollStages.FaceEnrollStage;
import android.os.Parcel; import android.os.Parcel;
import android.os.Parcelable; import android.os.Parcelable;

View File

@@ -21,54 +21,64 @@ import android.annotation.IntDef;
import java.lang.annotation.Retention; import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy; import java.lang.annotation.RetentionPolicy;
/**
* A collection of constants representing different stages of face enrollment.
*
* @hide
*/
public final class FaceEnrollStages {
// Prevent instantiation.
private FaceEnrollStages() {}
/** /**
* A stage that may occur during face enrollment. * A stage that may occur during face enrollment.
* *
* @hide * @hide
*/ */
@Retention(RetentionPolicy.SOURCE)
@IntDef({ @IntDef({
FaceEnrollStage.UNKNOWN, UNKNOWN,
FaceEnrollStage.FIRST_FRAME_RECEIVED, FIRST_FRAME_RECEIVED,
FaceEnrollStage.WAITING_FOR_CENTERING, WAITING_FOR_CENTERING,
FaceEnrollStage.HOLD_STILL_IN_CENTER, HOLD_STILL_IN_CENTER,
FaceEnrollStage.ENROLLING_MOVEMENT_1, ENROLLING_MOVEMENT_1,
FaceEnrollStage.ENROLLING_MOVEMENT_2, ENROLLING_MOVEMENT_2,
FaceEnrollStage.ENROLLMENT_FINISHED ENROLLMENT_FINISHED
}) })
public @interface FaceEnrollStage { @Retention(RetentionPolicy.SOURCE)
public @interface FaceEnrollStage {}
/** /**
* The current enrollment stage is not known. * 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. * 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. * 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. * 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. * 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. * 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. * Enrollment has completed. No more action is needed from the user.
*/ */
int ENROLLMENT_FINISHED = 5; public static final int ENROLLMENT_FINISHED = 6;
} }

View File

@@ -1022,6 +1022,34 @@ public class FaceManager implements BiometricAuthenticator, BiometricFaceConstan
public void onEnrollmentHelp(int helpMsgId, CharSequence helpString) { public void onEnrollmentHelp(int helpMsgId, CharSequence helpString) {
} }
/**
* Called each time a single frame is captured during enrollment.
*
* <p>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 * Called as each enrollment step progresses. Enrollment is considered complete when
* remaining reaches 0. This function will not be called if enrollment fails. See * 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) { } else if (mEnrollmentCallback != null) {
final FaceEnrollFrame frame = new FaceEnrollFrame( final FaceEnrollFrame frame = new FaceEnrollFrame(
null /* cell */, null /* cell */,
FaceEnrollStage.UNKNOWN, FaceEnrollStages.UNKNOWN,
new FaceDataFrame(acquireInfo, vendorCode)); new FaceDataFrame(acquireInfo, vendorCode));
sendEnrollmentFrame(frame); sendEnrollmentFrame(frame);
} }
@@ -1333,12 +1361,19 @@ public class FaceManager implements BiometricAuthenticator, BiometricFaceConstan
if (frame == null) { if (frame == null) {
Slog.w(TAG, "Received null enrollment frame"); Slog.w(TAG, "Received null enrollment frame");
} else if (mEnrollmentCallback != null) { } else if (mEnrollmentCallback != null) {
// TODO(b/178414967): Send additional frame data to callback final FaceDataFrame data = frame.getData();
final int acquireInfo = frame.getData().getAcquiredInfo(); final int acquireInfo = data.getAcquiredInfo();
final int vendorCode = frame.getData().getVendorCode(); final int vendorCode = data.getVendorCode();
final int helpCode = getHelpCode(acquireInfo, vendorCode); final int helpCode = getHelpCode(acquireInfo, vendorCode);
final String helpMessage = getEnrollHelpMessage(mContext, 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());
} }
} }

View File

@@ -24,11 +24,14 @@ import android.hardware.biometrics.face.AuthenticationFrame;
import android.hardware.biometrics.face.BaseFrame; import android.hardware.biometrics.face.BaseFrame;
import android.hardware.biometrics.face.Cell; import android.hardware.biometrics.face.Cell;
import android.hardware.biometrics.face.EnrollmentFrame; import android.hardware.biometrics.face.EnrollmentFrame;
import android.hardware.biometrics.face.EnrollmentStage;
import android.hardware.biometrics.face.Error; import android.hardware.biometrics.face.Error;
import android.hardware.face.FaceAuthenticationFrame; import android.hardware.face.FaceAuthenticationFrame;
import android.hardware.face.FaceDataFrame; import android.hardware.face.FaceDataFrame;
import android.hardware.face.FaceEnrollCell; import android.hardware.face.FaceEnrollCell;
import android.hardware.face.FaceEnrollFrame; 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. * Utilities for converting from hardware to framework-defined AIDL models.
@@ -38,95 +41,110 @@ final class AidlConversionUtils {
private AidlConversionUtils() { private AidlConversionUtils() {
} }
public static @BiometricFaceConstants.FaceError int toFrameworkError(byte aidlError) { @BiometricFaceConstants.FaceError
if (aidlError == Error.UNKNOWN) { public static int toFrameworkError(byte aidlError) {
// No framework constant available switch (aidlError) {
return BiometricFaceConstants.FACE_ERROR_UNKNOWN; case Error.HW_UNAVAILABLE:
} else if (aidlError == Error.HW_UNAVAILABLE) {
return BiometricFaceConstants.FACE_ERROR_HW_UNAVAILABLE; return BiometricFaceConstants.FACE_ERROR_HW_UNAVAILABLE;
} else if (aidlError == Error.UNABLE_TO_PROCESS) { case Error.UNABLE_TO_PROCESS:
return BiometricFaceConstants.FACE_ERROR_UNABLE_TO_PROCESS; return BiometricFaceConstants.FACE_ERROR_UNABLE_TO_PROCESS;
} else if (aidlError == Error.TIMEOUT) { case Error.TIMEOUT:
return BiometricFaceConstants.FACE_ERROR_TIMEOUT; return BiometricFaceConstants.FACE_ERROR_TIMEOUT;
} else if (aidlError == Error.NO_SPACE) { case Error.NO_SPACE:
return BiometricFaceConstants.FACE_ERROR_NO_SPACE; return BiometricFaceConstants.FACE_ERROR_NO_SPACE;
} else if (aidlError == Error.CANCELED) { case Error.CANCELED:
return BiometricFaceConstants.FACE_ERROR_CANCELED; return BiometricFaceConstants.FACE_ERROR_CANCELED;
} else if (aidlError == Error.UNABLE_TO_REMOVE) { case Error.UNABLE_TO_REMOVE:
return BiometricFaceConstants.FACE_ERROR_UNABLE_TO_REMOVE; return BiometricFaceConstants.FACE_ERROR_UNABLE_TO_REMOVE;
} else if (aidlError == Error.VENDOR) { case Error.VENDOR:
return BiometricFaceConstants.FACE_ERROR_VENDOR; return BiometricFaceConstants.FACE_ERROR_VENDOR;
} else if (aidlError == Error.REENROLL_REQUIRED) { case Error.REENROLL_REQUIRED:
return BiometricFaceConstants.BIOMETRIC_ERROR_RE_ENROLL; return BiometricFaceConstants.BIOMETRIC_ERROR_RE_ENROLL;
} else { case Error.UNKNOWN:
default:
return BiometricFaceConstants.FACE_ERROR_UNKNOWN; return BiometricFaceConstants.FACE_ERROR_UNKNOWN;
} }
} }
public static @BiometricFaceConstants.FaceAcquired int toFrameworkAcquiredInfo( @BiometricFaceConstants.FaceAcquired
byte aidlAcquired) { public static int toFrameworkAcquiredInfo(byte aidlAcquiredInfo) {
if (aidlAcquired == AcquiredInfo.UNKNOWN) { switch (aidlAcquiredInfo) {
return BiometricFaceConstants.FACE_ACQUIRED_UNKNOWN; case AcquiredInfo.GOOD:
} else if (aidlAcquired == AcquiredInfo.GOOD) {
return BiometricFaceConstants.FACE_ACQUIRED_GOOD; return BiometricFaceConstants.FACE_ACQUIRED_GOOD;
} else if (aidlAcquired == AcquiredInfo.INSUFFICIENT) { case AcquiredInfo.INSUFFICIENT:
return BiometricFaceConstants.FACE_ACQUIRED_INSUFFICIENT; return BiometricFaceConstants.FACE_ACQUIRED_INSUFFICIENT;
} else if (aidlAcquired == AcquiredInfo.TOO_BRIGHT) { case AcquiredInfo.TOO_BRIGHT:
return BiometricFaceConstants.FACE_ACQUIRED_TOO_BRIGHT; return BiometricFaceConstants.FACE_ACQUIRED_TOO_BRIGHT;
} else if (aidlAcquired == AcquiredInfo.TOO_DARK) { case AcquiredInfo.TOO_DARK:
return BiometricFaceConstants.FACE_ACQUIRED_TOO_DARK; return BiometricFaceConstants.FACE_ACQUIRED_TOO_DARK;
} else if (aidlAcquired == AcquiredInfo.TOO_CLOSE) { case AcquiredInfo.TOO_CLOSE:
return BiometricFaceConstants.FACE_ACQUIRED_TOO_CLOSE; return BiometricFaceConstants.FACE_ACQUIRED_TOO_CLOSE;
} else if (aidlAcquired == AcquiredInfo.TOO_FAR) { case AcquiredInfo.TOO_FAR:
return BiometricFaceConstants.FACE_ACQUIRED_TOO_FAR; return BiometricFaceConstants.FACE_ACQUIRED_TOO_FAR;
} else if (aidlAcquired == AcquiredInfo.FACE_TOO_HIGH) { case AcquiredInfo.FACE_TOO_HIGH:
return BiometricFaceConstants.FACE_ACQUIRED_TOO_HIGH; return BiometricFaceConstants.FACE_ACQUIRED_TOO_HIGH;
} else if (aidlAcquired == AcquiredInfo.FACE_TOO_LOW) { case AcquiredInfo.FACE_TOO_LOW:
return BiometricFaceConstants.FACE_ACQUIRED_TOO_LOW; return BiometricFaceConstants.FACE_ACQUIRED_TOO_LOW;
} else if (aidlAcquired == AcquiredInfo.FACE_TOO_RIGHT) { case AcquiredInfo.FACE_TOO_RIGHT:
return BiometricFaceConstants.FACE_ACQUIRED_TOO_RIGHT; return BiometricFaceConstants.FACE_ACQUIRED_TOO_RIGHT;
} else if (aidlAcquired == AcquiredInfo.FACE_TOO_LEFT) { case AcquiredInfo.FACE_TOO_LEFT:
return BiometricFaceConstants.FACE_ACQUIRED_TOO_LEFT; return BiometricFaceConstants.FACE_ACQUIRED_TOO_LEFT;
} else if (aidlAcquired == AcquiredInfo.POOR_GAZE) { case AcquiredInfo.POOR_GAZE:
return BiometricFaceConstants.FACE_ACQUIRED_POOR_GAZE; return BiometricFaceConstants.FACE_ACQUIRED_POOR_GAZE;
} else if (aidlAcquired == AcquiredInfo.NOT_DETECTED) { case AcquiredInfo.NOT_DETECTED:
return BiometricFaceConstants.FACE_ACQUIRED_NOT_DETECTED; return BiometricFaceConstants.FACE_ACQUIRED_NOT_DETECTED;
} else if (aidlAcquired == AcquiredInfo.TOO_MUCH_MOTION) { case AcquiredInfo.TOO_MUCH_MOTION:
return BiometricFaceConstants.FACE_ACQUIRED_TOO_MUCH_MOTION; return BiometricFaceConstants.FACE_ACQUIRED_TOO_MUCH_MOTION;
} else if (aidlAcquired == AcquiredInfo.RECALIBRATE) { case AcquiredInfo.RECALIBRATE:
return BiometricFaceConstants.FACE_ACQUIRED_RECALIBRATE; return BiometricFaceConstants.FACE_ACQUIRED_RECALIBRATE;
} else if (aidlAcquired == AcquiredInfo.TOO_DIFFERENT) { case AcquiredInfo.TOO_DIFFERENT:
return BiometricFaceConstants.FACE_ACQUIRED_TOO_DIFFERENT; return BiometricFaceConstants.FACE_ACQUIRED_TOO_DIFFERENT;
} else if (aidlAcquired == AcquiredInfo.TOO_SIMILAR) { case AcquiredInfo.TOO_SIMILAR:
return BiometricFaceConstants.FACE_ACQUIRED_TOO_SIMILAR; return BiometricFaceConstants.FACE_ACQUIRED_TOO_SIMILAR;
} else if (aidlAcquired == AcquiredInfo.PAN_TOO_EXTREME) { case AcquiredInfo.PAN_TOO_EXTREME:
return BiometricFaceConstants.FACE_ACQUIRED_PAN_TOO_EXTREME; return BiometricFaceConstants.FACE_ACQUIRED_PAN_TOO_EXTREME;
} else if (aidlAcquired == AcquiredInfo.TILT_TOO_EXTREME) { case AcquiredInfo.TILT_TOO_EXTREME:
return BiometricFaceConstants.FACE_ACQUIRED_TILT_TOO_EXTREME; return BiometricFaceConstants.FACE_ACQUIRED_TILT_TOO_EXTREME;
} else if (aidlAcquired == AcquiredInfo.ROLL_TOO_EXTREME) { case AcquiredInfo.ROLL_TOO_EXTREME:
return BiometricFaceConstants.FACE_ACQUIRED_ROLL_TOO_EXTREME; return BiometricFaceConstants.FACE_ACQUIRED_ROLL_TOO_EXTREME;
} else if (aidlAcquired == AcquiredInfo.FACE_OBSCURED) { case AcquiredInfo.FACE_OBSCURED:
return BiometricFaceConstants.FACE_ACQUIRED_FACE_OBSCURED; return BiometricFaceConstants.FACE_ACQUIRED_FACE_OBSCURED;
} else if (aidlAcquired == AcquiredInfo.START) { case AcquiredInfo.START:
return BiometricFaceConstants.FACE_ACQUIRED_START; return BiometricFaceConstants.FACE_ACQUIRED_START;
} else if (aidlAcquired == AcquiredInfo.SENSOR_DIRTY) { case AcquiredInfo.SENSOR_DIRTY:
return BiometricFaceConstants.FACE_ACQUIRED_SENSOR_DIRTY; return BiometricFaceConstants.FACE_ACQUIRED_SENSOR_DIRTY;
} else if (aidlAcquired == AcquiredInfo.VENDOR) { case AcquiredInfo.VENDOR:
return BiometricFaceConstants.FACE_ACQUIRED_VENDOR; return BiometricFaceConstants.FACE_ACQUIRED_VENDOR;
} else if (aidlAcquired == AcquiredInfo.FIRST_FRAME_RECEIVED) { case AcquiredInfo.UNKNOWN:
// No framework constant available case AcquiredInfo.FIRST_FRAME_RECEIVED:
return BiometricFaceConstants.FACE_ACQUIRED_UNKNOWN; case AcquiredInfo.DARK_GLASSES_DETECTED:
} else if (aidlAcquired == AcquiredInfo.DARK_GLASSES_DETECTED) { case AcquiredInfo.MOUTH_COVERING_DETECTED:
// No framework constant available default:
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; 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;
}
}
@NonNull @NonNull
public static FaceAuthenticationFrame toFrameworkAuthenticationFrame( public static FaceAuthenticationFrame toFrameworkAuthenticationFrame(
@NonNull AuthenticationFrame frame) { @NonNull AuthenticationFrame frame) {
@@ -135,7 +153,9 @@ final class AidlConversionUtils {
@NonNull @NonNull
public static FaceEnrollFrame toFrameworkEnrollmentFrame(@NonNull EnrollmentFrame frame) { 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)); toFrameworkBaseFrame(frame.data));
} }