322 lines
12 KiB
Java
322 lines
12 KiB
Java
![]() |
/*
|
||
|
* Copyright (C) 2024 The Android Open Source Project
|
||
|
*
|
||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||
|
* you may not use this file except in compliance with the License.
|
||
|
* You may obtain a copy of the License at
|
||
|
*
|
||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||
|
*
|
||
|
* Unless required by applicable law or agreed to in writing, software
|
||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||
|
* See the License for the specific language governing permissions and
|
||
|
* limitations under the License.
|
||
|
*/
|
||
|
|
||
|
package android.hardware.face;
|
||
|
|
||
|
import static android.hardware.biometrics.BiometricFaceConstants.FACE_ACQUIRED_VENDOR;
|
||
|
import static android.hardware.biometrics.BiometricFaceConstants.FACE_ACQUIRED_VENDOR_BASE;
|
||
|
import static android.hardware.biometrics.BiometricFaceConstants.FACE_ERROR_VENDOR;
|
||
|
import static android.hardware.biometrics.BiometricFaceConstants.FACE_ERROR_VENDOR_BASE;
|
||
|
import static android.hardware.face.FaceManager.getAuthHelpMessage;
|
||
|
import static android.hardware.face.FaceManager.getEnrollHelpMessage;
|
||
|
import static android.hardware.face.FaceManager.getErrorString;
|
||
|
|
||
|
import android.content.Context;
|
||
|
import android.hardware.biometrics.CryptoObject;
|
||
|
import android.hardware.face.FaceManager.AuthenticationCallback;
|
||
|
import android.hardware.face.FaceManager.EnrollmentCallback;
|
||
|
import android.hardware.face.FaceManager.FaceDetectionCallback;
|
||
|
import android.hardware.face.FaceManager.GenerateChallengeCallback;
|
||
|
import android.hardware.face.FaceManager.GetFeatureCallback;
|
||
|
import android.hardware.face.FaceManager.RemovalCallback;
|
||
|
import android.hardware.face.FaceManager.SetFeatureCallback;
|
||
|
import android.util.Slog;
|
||
|
|
||
|
import androidx.annotation.NonNull;
|
||
|
import androidx.annotation.Nullable;
|
||
|
|
||
|
/**
|
||
|
* Encapsulates callbacks and client specific information for each face related request.
|
||
|
* @hide
|
||
|
*/
|
||
|
public class FaceCallback {
|
||
|
private static final String TAG = " FaceCallback";
|
||
|
|
||
|
@Nullable
|
||
|
private AuthenticationCallback mAuthenticationCallback;
|
||
|
@Nullable
|
||
|
private EnrollmentCallback mEnrollmentCallback;
|
||
|
@Nullable
|
||
|
private RemovalCallback mRemovalCallback;
|
||
|
@Nullable
|
||
|
private GenerateChallengeCallback mGenerateChallengeCallback;
|
||
|
@Nullable
|
||
|
private FaceDetectionCallback mFaceDetectionCallback;
|
||
|
@Nullable
|
||
|
private SetFeatureCallback mSetFeatureCallback;
|
||
|
@Nullable
|
||
|
private GetFeatureCallback mGetFeatureCallback;
|
||
|
@Nullable
|
||
|
private Face mRemovalFace;
|
||
|
@Nullable
|
||
|
private CryptoObject mCryptoObject;
|
||
|
|
||
|
/**
|
||
|
* Construction for face authentication client callback.
|
||
|
*/
|
||
|
FaceCallback(AuthenticationCallback authenticationCallback, CryptoObject cryptoObject) {
|
||
|
mAuthenticationCallback = authenticationCallback;
|
||
|
mCryptoObject = cryptoObject;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Construction for face detect client callback.
|
||
|
*/
|
||
|
FaceCallback(FaceDetectionCallback faceDetectionCallback) {
|
||
|
mFaceDetectionCallback = faceDetectionCallback;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Construction for face enroll client callback.
|
||
|
*/
|
||
|
FaceCallback(EnrollmentCallback enrollmentCallback) {
|
||
|
mEnrollmentCallback = enrollmentCallback;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Construction for face generate challenge client callback.
|
||
|
*/
|
||
|
FaceCallback(GenerateChallengeCallback generateChallengeCallback) {
|
||
|
mGenerateChallengeCallback = generateChallengeCallback;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Construction for face set feature client callback.
|
||
|
*/
|
||
|
FaceCallback(SetFeatureCallback setFeatureCallback) {
|
||
|
mSetFeatureCallback = setFeatureCallback;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Construction for face get feature client callback.
|
||
|
*/
|
||
|
FaceCallback(GetFeatureCallback getFeatureCallback) {
|
||
|
mGetFeatureCallback = getFeatureCallback;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Construction for single face removal client callback.
|
||
|
*/
|
||
|
FaceCallback(RemovalCallback removalCallback, Face removalFace) {
|
||
|
mRemovalCallback = removalCallback;
|
||
|
mRemovalFace = removalFace;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Construction for all face removal client callback.
|
||
|
*/
|
||
|
FaceCallback(RemovalCallback removalCallback) {
|
||
|
mRemovalCallback = removalCallback;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Propagate set feature completed via the callback.
|
||
|
* @param success if the operation was completed successfully
|
||
|
* @param feature the feature that was set
|
||
|
*/
|
||
|
public void sendSetFeatureCompleted(boolean success, int feature) {
|
||
|
if (mSetFeatureCallback == null) {
|
||
|
return;
|
||
|
}
|
||
|
mSetFeatureCallback.onCompleted(success, feature);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Propagate get feature completed via the callback.
|
||
|
* @param success if the operation was completed successfully
|
||
|
* @param features list of features available
|
||
|
* @param featureState status of the features corresponding to the previous parameter
|
||
|
*/
|
||
|
public void sendGetFeatureCompleted(boolean success, int[] features, boolean[] featureState) {
|
||
|
if (mGetFeatureCallback == null) {
|
||
|
return;
|
||
|
}
|
||
|
mGetFeatureCallback.onCompleted(success, features, featureState);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Propagate challenge generated completed via the callback.
|
||
|
* @param sensorId id of the corresponding sensor
|
||
|
* @param userId id of the corresponding sensor
|
||
|
* @param challenge value of the challenge generated
|
||
|
*/
|
||
|
public void sendChallengeGenerated(int sensorId, int userId, long challenge) {
|
||
|
if (mGenerateChallengeCallback == null) {
|
||
|
return;
|
||
|
}
|
||
|
mGenerateChallengeCallback.onGenerateChallengeResult(sensorId, userId, challenge);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Propagate face detected completed via the callback.
|
||
|
* @param sensorId id of the corresponding sensor
|
||
|
* @param userId id of the corresponding user
|
||
|
* @param isStrongBiometric if the sensor is strong or not
|
||
|
*/
|
||
|
public void sendFaceDetected(int sensorId, int userId, boolean isStrongBiometric) {
|
||
|
if (mFaceDetectionCallback == null) {
|
||
|
Slog.e(TAG, "sendFaceDetected, callback null");
|
||
|
return;
|
||
|
}
|
||
|
mFaceDetectionCallback.onFaceDetected(sensorId, userId, isStrongBiometric);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Propagate remove face completed via the callback.
|
||
|
* @param face removed identifier
|
||
|
* @param remaining number of face enrollments remaining
|
||
|
*/
|
||
|
public void sendRemovedResult(Face face, int remaining) {
|
||
|
if (mRemovalCallback == null) {
|
||
|
return;
|
||
|
}
|
||
|
mRemovalCallback.onRemovalSucceeded(face, remaining);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Propagate errors via the callback.
|
||
|
* @param context corresponding context
|
||
|
* @param errMsgId represents the framework error id
|
||
|
* @param vendorCode represents the vendor error code
|
||
|
*/
|
||
|
public void sendErrorResult(Context context, int errMsgId, int vendorCode) {
|
||
|
// emulate HAL 2.1 behavior and send real errMsgId
|
||
|
final int clientErrMsgId = errMsgId == FACE_ERROR_VENDOR
|
||
|
? (vendorCode + FACE_ERROR_VENDOR_BASE) : errMsgId;
|
||
|
if (mEnrollmentCallback != null) {
|
||
|
mEnrollmentCallback.onEnrollmentError(clientErrMsgId,
|
||
|
getErrorString(context, errMsgId, vendorCode));
|
||
|
} else if (mAuthenticationCallback != null) {
|
||
|
mAuthenticationCallback.onAuthenticationError(clientErrMsgId,
|
||
|
getErrorString(context, errMsgId, vendorCode));
|
||
|
} else if (mRemovalCallback != null) {
|
||
|
mRemovalCallback.onRemovalError(mRemovalFace, clientErrMsgId,
|
||
|
getErrorString(context, errMsgId, vendorCode));
|
||
|
} else if (mFaceDetectionCallback != null) {
|
||
|
mFaceDetectionCallback.onDetectionError(errMsgId);
|
||
|
mFaceDetectionCallback = null;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Propagate enroll progress via the callback.
|
||
|
* @param remaining number of enrollment steps remaining
|
||
|
*/
|
||
|
public void sendEnrollResult(int remaining) {
|
||
|
if (mEnrollmentCallback != null) {
|
||
|
mEnrollmentCallback.onEnrollmentProgress(remaining);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Propagate authentication succeeded via the callback.
|
||
|
* @param face matched identifier
|
||
|
* @param userId id of the corresponding user
|
||
|
* @param isStrongBiometric if the sensor is strong or not
|
||
|
*/
|
||
|
public void sendAuthenticatedSucceeded(Face face, int userId, boolean isStrongBiometric) {
|
||
|
if (mAuthenticationCallback != null) {
|
||
|
final FaceManager.AuthenticationResult result = new FaceManager.AuthenticationResult(
|
||
|
mCryptoObject, face, userId, isStrongBiometric);
|
||
|
mAuthenticationCallback.onAuthenticationSucceeded(result);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Propagate authentication failed via the callback.
|
||
|
*/
|
||
|
public void sendAuthenticatedFailed() {
|
||
|
if (mAuthenticationCallback != null) {
|
||
|
mAuthenticationCallback.onAuthenticationFailed();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Propagate acquired result via the callback.
|
||
|
* @param context corresponding context
|
||
|
* @param acquireInfo represents the framework acquired id
|
||
|
* @param vendorCode represents the vendor acquired code
|
||
|
*/
|
||
|
public void sendAcquiredResult(Context context, int acquireInfo, int vendorCode) {
|
||
|
if (mAuthenticationCallback != null) {
|
||
|
final FaceAuthenticationFrame frame = new FaceAuthenticationFrame(
|
||
|
new FaceDataFrame(acquireInfo, vendorCode));
|
||
|
sendAuthenticationFrame(context, frame);
|
||
|
} else if (mEnrollmentCallback != null) {
|
||
|
final FaceEnrollFrame frame = new FaceEnrollFrame(
|
||
|
null /* cell */,
|
||
|
FaceEnrollStages.UNKNOWN,
|
||
|
new FaceDataFrame(acquireInfo, vendorCode));
|
||
|
sendEnrollmentFrame(context, frame);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Propagate authentication frame via the callback.
|
||
|
* @param context corresponding context
|
||
|
* @param frame authentication frame to be sent
|
||
|
*/
|
||
|
public void sendAuthenticationFrame(@NonNull Context context,
|
||
|
@Nullable FaceAuthenticationFrame frame) {
|
||
|
if (frame == null) {
|
||
|
Slog.w(TAG, "Received null authentication frame");
|
||
|
} else if (mAuthenticationCallback != null) {
|
||
|
// TODO(b/178414967): Send additional frame data to callback
|
||
|
final int acquireInfo = frame.getData().getAcquiredInfo();
|
||
|
final int vendorCode = frame.getData().getVendorCode();
|
||
|
final int helpCode = getHelpCode(acquireInfo, vendorCode);
|
||
|
final String helpMessage = getAuthHelpMessage(context, acquireInfo, vendorCode);
|
||
|
mAuthenticationCallback.onAuthenticationAcquired(acquireInfo);
|
||
|
|
||
|
// Ensure that only non-null help messages are sent.
|
||
|
if (helpMessage != null) {
|
||
|
mAuthenticationCallback.onAuthenticationHelp(helpCode, helpMessage);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Propagate enrollment via the callback.
|
||
|
* @param context corresponding context
|
||
|
* @param frame enrollment frame to be sent
|
||
|
*/
|
||
|
public void sendEnrollmentFrame(Context context, @Nullable FaceEnrollFrame frame) {
|
||
|
if (frame == null) {
|
||
|
Slog.w(TAG, "Received null enrollment frame");
|
||
|
} else if (mEnrollmentCallback != null) {
|
||
|
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(context, acquireInfo, vendorCode);
|
||
|
mEnrollmentCallback.onEnrollmentFrame(
|
||
|
helpCode,
|
||
|
helpMessage,
|
||
|
frame.getCell(),
|
||
|
frame.getStage(),
|
||
|
data.getPan(),
|
||
|
data.getTilt(),
|
||
|
data.getDistance());
|
||
|
}
|
||
|
}
|
||
|
|
||
|
private static int getHelpCode(int acquireInfo, int vendorCode) {
|
||
|
return acquireInfo == FACE_ACQUIRED_VENDOR
|
||
|
? vendorCode + FACE_ACQUIRED_VENDOR_BASE
|
||
|
: acquireInfo;
|
||
|
}
|
||
|
}
|