1 /* 2 * Copyright (C) 2024 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package android.hardware.face; 18 19 import static android.hardware.biometrics.BiometricFaceConstants.FACE_ACQUIRED_VENDOR; 20 import static android.hardware.biometrics.BiometricFaceConstants.FACE_ACQUIRED_VENDOR_BASE; 21 import static android.hardware.biometrics.BiometricFaceConstants.FACE_ERROR_VENDOR; 22 import static android.hardware.biometrics.BiometricFaceConstants.FACE_ERROR_VENDOR_BASE; 23 import static android.hardware.face.FaceManager.getAuthHelpMessage; 24 import static android.hardware.face.FaceManager.getEnrollHelpMessage; 25 import static android.hardware.face.FaceManager.getErrorString; 26 27 import android.content.Context; 28 import android.hardware.biometrics.CryptoObject; 29 import android.hardware.face.FaceManager.AuthenticationCallback; 30 import android.hardware.face.FaceManager.EnrollmentCallback; 31 import android.hardware.face.FaceManager.FaceDetectionCallback; 32 import android.hardware.face.FaceManager.GenerateChallengeCallback; 33 import android.hardware.face.FaceManager.GetFeatureCallback; 34 import android.hardware.face.FaceManager.RemovalCallback; 35 import android.hardware.face.FaceManager.SetFeatureCallback; 36 import android.util.Slog; 37 38 import androidx.annotation.NonNull; 39 import androidx.annotation.Nullable; 40 41 /** 42 * Encapsulates callbacks and client specific information for each face related request. 43 * @hide 44 */ 45 public class FaceCallback { 46 private static final String TAG = " FaceCallback"; 47 48 @Nullable 49 private AuthenticationCallback mAuthenticationCallback; 50 @Nullable 51 private EnrollmentCallback mEnrollmentCallback; 52 @Nullable 53 private RemovalCallback mRemovalCallback; 54 @Nullable 55 private GenerateChallengeCallback mGenerateChallengeCallback; 56 @Nullable 57 private FaceDetectionCallback mFaceDetectionCallback; 58 @Nullable 59 private SetFeatureCallback mSetFeatureCallback; 60 @Nullable 61 private GetFeatureCallback mGetFeatureCallback; 62 @Nullable 63 private Face mRemovalFace; 64 @Nullable 65 private CryptoObject mCryptoObject; 66 67 /** 68 * Construction for face authentication client callback. 69 */ FaceCallback(AuthenticationCallback authenticationCallback, CryptoObject cryptoObject)70 FaceCallback(AuthenticationCallback authenticationCallback, CryptoObject cryptoObject) { 71 mAuthenticationCallback = authenticationCallback; 72 mCryptoObject = cryptoObject; 73 } 74 75 /** 76 * Construction for face detect client callback. 77 */ FaceCallback(FaceDetectionCallback faceDetectionCallback)78 FaceCallback(FaceDetectionCallback faceDetectionCallback) { 79 mFaceDetectionCallback = faceDetectionCallback; 80 } 81 82 /** 83 * Construction for face enroll client callback. 84 */ FaceCallback(EnrollmentCallback enrollmentCallback)85 FaceCallback(EnrollmentCallback enrollmentCallback) { 86 mEnrollmentCallback = enrollmentCallback; 87 } 88 89 /** 90 * Construction for face generate challenge client callback. 91 */ FaceCallback(GenerateChallengeCallback generateChallengeCallback)92 FaceCallback(GenerateChallengeCallback generateChallengeCallback) { 93 mGenerateChallengeCallback = generateChallengeCallback; 94 } 95 96 /** 97 * Construction for face set feature client callback. 98 */ FaceCallback(SetFeatureCallback setFeatureCallback)99 FaceCallback(SetFeatureCallback setFeatureCallback) { 100 mSetFeatureCallback = setFeatureCallback; 101 } 102 103 /** 104 * Construction for face get feature client callback. 105 */ FaceCallback(GetFeatureCallback getFeatureCallback)106 FaceCallback(GetFeatureCallback getFeatureCallback) { 107 mGetFeatureCallback = getFeatureCallback; 108 } 109 110 /** 111 * Construction for single face removal client callback. 112 */ FaceCallback(RemovalCallback removalCallback, Face removalFace)113 FaceCallback(RemovalCallback removalCallback, Face removalFace) { 114 mRemovalCallback = removalCallback; 115 mRemovalFace = removalFace; 116 } 117 118 /** 119 * Construction for all face removal client callback. 120 */ FaceCallback(RemovalCallback removalCallback)121 FaceCallback(RemovalCallback removalCallback) { 122 mRemovalCallback = removalCallback; 123 } 124 125 /** 126 * Propagate set feature completed via the callback. 127 * @param success if the operation was completed successfully 128 * @param feature the feature that was set 129 */ sendSetFeatureCompleted(boolean success, int feature)130 public void sendSetFeatureCompleted(boolean success, int feature) { 131 if (mSetFeatureCallback == null) { 132 return; 133 } 134 mSetFeatureCallback.onCompleted(success, feature); 135 } 136 137 /** 138 * Propagate get feature completed via the callback. 139 * @param success if the operation was completed successfully 140 * @param features list of features available 141 * @param featureState status of the features corresponding to the previous parameter 142 */ sendGetFeatureCompleted(boolean success, int[] features, boolean[] featureState)143 public void sendGetFeatureCompleted(boolean success, int[] features, boolean[] featureState) { 144 if (mGetFeatureCallback == null) { 145 return; 146 } 147 mGetFeatureCallback.onCompleted(success, features, featureState); 148 } 149 150 /** 151 * Propagate challenge generated completed via the callback. 152 * @param sensorId id of the corresponding sensor 153 * @param userId id of the corresponding sensor 154 * @param challenge value of the challenge generated 155 */ sendChallengeGenerated(int sensorId, int userId, long challenge)156 public void sendChallengeGenerated(int sensorId, int userId, long challenge) { 157 if (mGenerateChallengeCallback == null) { 158 return; 159 } 160 mGenerateChallengeCallback.onGenerateChallengeResult(sensorId, userId, challenge); 161 } 162 163 /** 164 * Propagate face detected completed via the callback. 165 * @param sensorId id of the corresponding sensor 166 * @param userId id of the corresponding user 167 * @param isStrongBiometric if the sensor is strong or not 168 */ sendFaceDetected(int sensorId, int userId, boolean isStrongBiometric)169 public void sendFaceDetected(int sensorId, int userId, boolean isStrongBiometric) { 170 if (mFaceDetectionCallback == null) { 171 Slog.e(TAG, "sendFaceDetected, callback null"); 172 return; 173 } 174 mFaceDetectionCallback.onFaceDetected(sensorId, userId, isStrongBiometric); 175 } 176 177 /** 178 * Propagate remove face completed via the callback. 179 * @param face removed identifier 180 * @param remaining number of face enrollments remaining 181 */ sendRemovedResult(Face face, int remaining)182 public void sendRemovedResult(Face face, int remaining) { 183 if (mRemovalCallback == null) { 184 return; 185 } 186 mRemovalCallback.onRemovalSucceeded(face, remaining); 187 } 188 189 /** 190 * Propagate errors via the callback. 191 * @param context corresponding context 192 * @param errMsgId represents the framework error id 193 * @param vendorCode represents the vendor error code 194 */ sendErrorResult(Context context, int errMsgId, int vendorCode)195 public void sendErrorResult(Context context, int errMsgId, int vendorCode) { 196 // emulate HAL 2.1 behavior and send real errMsgId 197 final int clientErrMsgId = errMsgId == FACE_ERROR_VENDOR 198 ? (vendorCode + FACE_ERROR_VENDOR_BASE) : errMsgId; 199 if (mEnrollmentCallback != null) { 200 mEnrollmentCallback.onEnrollmentError(clientErrMsgId, 201 getErrorString(context, errMsgId, vendorCode)); 202 } else if (mAuthenticationCallback != null) { 203 mAuthenticationCallback.onAuthenticationError(clientErrMsgId, 204 getErrorString(context, errMsgId, vendorCode)); 205 } else if (mRemovalCallback != null) { 206 mRemovalCallback.onRemovalError(mRemovalFace, clientErrMsgId, 207 getErrorString(context, errMsgId, vendorCode)); 208 } else if (mFaceDetectionCallback != null) { 209 mFaceDetectionCallback.onDetectionError(errMsgId); 210 mFaceDetectionCallback = null; 211 } 212 } 213 214 /** 215 * Propagate enroll progress via the callback. 216 * @param remaining number of enrollment steps remaining 217 */ sendEnrollResult(int remaining)218 public void sendEnrollResult(int remaining) { 219 if (mEnrollmentCallback != null) { 220 mEnrollmentCallback.onEnrollmentProgress(remaining); 221 } 222 } 223 224 /** 225 * Propagate authentication succeeded via the callback. 226 * @param face matched identifier 227 * @param userId id of the corresponding user 228 * @param isStrongBiometric if the sensor is strong or not 229 */ sendAuthenticatedSucceeded(Face face, int userId, boolean isStrongBiometric)230 public void sendAuthenticatedSucceeded(Face face, int userId, boolean isStrongBiometric) { 231 if (mAuthenticationCallback != null) { 232 final FaceManager.AuthenticationResult result = new FaceManager.AuthenticationResult( 233 mCryptoObject, face, userId, isStrongBiometric); 234 mAuthenticationCallback.onAuthenticationSucceeded(result); 235 } 236 } 237 238 /** 239 * Propagate authentication failed via the callback. 240 */ sendAuthenticatedFailed()241 public void sendAuthenticatedFailed() { 242 if (mAuthenticationCallback != null) { 243 mAuthenticationCallback.onAuthenticationFailed(); 244 } 245 } 246 247 /** 248 * Propagate acquired result via the callback. 249 * @param context corresponding context 250 * @param acquireInfo represents the framework acquired id 251 * @param vendorCode represents the vendor acquired code 252 */ sendAcquiredResult(Context context, int acquireInfo, int vendorCode)253 public void sendAcquiredResult(Context context, int acquireInfo, int vendorCode) { 254 if (mAuthenticationCallback != null) { 255 final FaceAuthenticationFrame frame = new FaceAuthenticationFrame( 256 new FaceDataFrame(acquireInfo, vendorCode)); 257 sendAuthenticationFrame(context, frame); 258 } else if (mEnrollmentCallback != null) { 259 final FaceEnrollFrame frame = new FaceEnrollFrame( 260 null /* cell */, 261 FaceEnrollStages.UNKNOWN, 262 new FaceDataFrame(acquireInfo, vendorCode)); 263 sendEnrollmentFrame(context, frame); 264 } 265 } 266 267 /** 268 * Propagate authentication frame via the callback. 269 * @param context corresponding context 270 * @param frame authentication frame to be sent 271 */ sendAuthenticationFrame(@onNull Context context, @Nullable FaceAuthenticationFrame frame)272 public void sendAuthenticationFrame(@NonNull Context context, 273 @Nullable FaceAuthenticationFrame frame) { 274 if (frame == null) { 275 Slog.w(TAG, "Received null authentication frame"); 276 } else if (mAuthenticationCallback != null) { 277 // TODO(b/178414967): Send additional frame data to callback 278 final int acquireInfo = frame.getData().getAcquiredInfo(); 279 final int vendorCode = frame.getData().getVendorCode(); 280 final int helpCode = getHelpCode(acquireInfo, vendorCode); 281 final String helpMessage = getAuthHelpMessage(context, acquireInfo, vendorCode); 282 mAuthenticationCallback.onAuthenticationAcquired(acquireInfo); 283 284 // Ensure that only non-null help messages are sent. 285 if (helpMessage != null) { 286 mAuthenticationCallback.onAuthenticationHelp(helpCode, helpMessage); 287 } 288 } 289 } 290 291 /** 292 * Propagate enrollment via the callback. 293 * @param context corresponding context 294 * @param frame enrollment frame to be sent 295 */ sendEnrollmentFrame(Context context, @Nullable FaceEnrollFrame frame)296 public void sendEnrollmentFrame(Context context, @Nullable FaceEnrollFrame frame) { 297 if (frame == null) { 298 Slog.w(TAG, "Received null enrollment frame"); 299 } else if (mEnrollmentCallback != null) { 300 final FaceDataFrame data = frame.getData(); 301 final int acquireInfo = data.getAcquiredInfo(); 302 final int vendorCode = data.getVendorCode(); 303 final int helpCode = getHelpCode(acquireInfo, vendorCode); 304 final String helpMessage = getEnrollHelpMessage(context, acquireInfo, vendorCode); 305 mEnrollmentCallback.onEnrollmentFrame( 306 helpCode, 307 helpMessage, 308 frame.getCell(), 309 frame.getStage(), 310 data.getPan(), 311 data.getTilt(), 312 data.getDistance()); 313 } 314 } 315 getHelpCode(int acquireInfo, int vendorCode)316 private static int getHelpCode(int acquireInfo, int vendorCode) { 317 return acquireInfo == FACE_ACQUIRED_VENDOR 318 ? vendorCode + FACE_ACQUIRED_VENDOR_BASE 319 : acquireInfo; 320 } 321 } 322