1 /* 2 * Copyright (C) 2018 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.Manifest.permission.INTERACT_ACROSS_USERS; 20 import static android.Manifest.permission.MANAGE_BIOMETRIC; 21 import static android.Manifest.permission.USE_BIOMETRIC_INTERNAL; 22 import static android.hardware.biometrics.BiometricConstants.BIOMETRIC_LOCKOUT_NONE; 23 import static android.hardware.biometrics.BiometricFaceConstants.BIOMETRIC_ERROR_RE_ENROLL; 24 import static android.hardware.biometrics.BiometricFaceConstants.BIOMETRIC_ERROR_SECURITY_UPDATE_REQUIRED; 25 import static android.hardware.biometrics.BiometricFaceConstants.FACE_ACQUIRED_DARK_GLASSES_DETECTED; 26 import static android.hardware.biometrics.BiometricFaceConstants.FACE_ACQUIRED_FACE_OBSCURED; 27 import static android.hardware.biometrics.BiometricFaceConstants.FACE_ACQUIRED_GOOD; 28 import static android.hardware.biometrics.BiometricFaceConstants.FACE_ACQUIRED_INSUFFICIENT; 29 import static android.hardware.biometrics.BiometricFaceConstants.FACE_ACQUIRED_MOUTH_COVERING_DETECTED; 30 import static android.hardware.biometrics.BiometricFaceConstants.FACE_ACQUIRED_NOT_DETECTED; 31 import static android.hardware.biometrics.BiometricFaceConstants.FACE_ACQUIRED_PAN_TOO_EXTREME; 32 import static android.hardware.biometrics.BiometricFaceConstants.FACE_ACQUIRED_POOR_GAZE; 33 import static android.hardware.biometrics.BiometricFaceConstants.FACE_ACQUIRED_RECALIBRATE; 34 import static android.hardware.biometrics.BiometricFaceConstants.FACE_ACQUIRED_ROLL_TOO_EXTREME; 35 import static android.hardware.biometrics.BiometricFaceConstants.FACE_ACQUIRED_SENSOR_DIRTY; 36 import static android.hardware.biometrics.BiometricFaceConstants.FACE_ACQUIRED_START; 37 import static android.hardware.biometrics.BiometricFaceConstants.FACE_ACQUIRED_TILT_TOO_EXTREME; 38 import static android.hardware.biometrics.BiometricFaceConstants.FACE_ACQUIRED_TOO_BRIGHT; 39 import static android.hardware.biometrics.BiometricFaceConstants.FACE_ACQUIRED_TOO_CLOSE; 40 import static android.hardware.biometrics.BiometricFaceConstants.FACE_ACQUIRED_TOO_DARK; 41 import static android.hardware.biometrics.BiometricFaceConstants.FACE_ACQUIRED_TOO_DIFFERENT; 42 import static android.hardware.biometrics.BiometricFaceConstants.FACE_ACQUIRED_TOO_FAR; 43 import static android.hardware.biometrics.BiometricFaceConstants.FACE_ACQUIRED_TOO_HIGH; 44 import static android.hardware.biometrics.BiometricFaceConstants.FACE_ACQUIRED_TOO_LEFT; 45 import static android.hardware.biometrics.BiometricFaceConstants.FACE_ACQUIRED_TOO_LOW; 46 import static android.hardware.biometrics.BiometricFaceConstants.FACE_ACQUIRED_TOO_MUCH_MOTION; 47 import static android.hardware.biometrics.BiometricFaceConstants.FACE_ACQUIRED_TOO_RIGHT; 48 import static android.hardware.biometrics.BiometricFaceConstants.FACE_ACQUIRED_TOO_SIMILAR; 49 import static android.hardware.biometrics.BiometricFaceConstants.FACE_ACQUIRED_VENDOR; 50 import static android.hardware.biometrics.BiometricFaceConstants.FACE_ERROR_CANCELED; 51 import static android.hardware.biometrics.BiometricFaceConstants.FACE_ERROR_HW_NOT_PRESENT; 52 import static android.hardware.biometrics.BiometricFaceConstants.FACE_ERROR_HW_UNAVAILABLE; 53 import static android.hardware.biometrics.BiometricFaceConstants.FACE_ERROR_LOCKOUT; 54 import static android.hardware.biometrics.BiometricFaceConstants.FACE_ERROR_LOCKOUT_PERMANENT; 55 import static android.hardware.biometrics.BiometricFaceConstants.FACE_ERROR_NOT_ENROLLED; 56 import static android.hardware.biometrics.BiometricFaceConstants.FACE_ERROR_NO_SPACE; 57 import static android.hardware.biometrics.BiometricFaceConstants.FACE_ERROR_TIMEOUT; 58 import static android.hardware.biometrics.BiometricFaceConstants.FACE_ERROR_UNABLE_TO_PROCESS; 59 import static android.hardware.biometrics.BiometricFaceConstants.FACE_ERROR_USER_CANCELED; 60 import static android.hardware.biometrics.BiometricFaceConstants.FACE_ERROR_VENDOR; 61 62 import android.annotation.NonNull; 63 import android.annotation.Nullable; 64 import android.annotation.RequiresPermission; 65 import android.annotation.SystemService; 66 import android.content.Context; 67 import android.content.pm.PackageManager; 68 import android.hardware.biometrics.BiometricAuthenticator; 69 import android.hardware.biometrics.BiometricConstants; 70 import android.hardware.biometrics.BiometricStateListener; 71 import android.hardware.biometrics.CryptoObject; 72 import android.hardware.biometrics.IBiometricServiceLockoutResetCallback; 73 import android.os.Binder; 74 import android.os.CancellationSignal; 75 import android.os.CancellationSignal.OnCancelListener; 76 import android.os.Handler; 77 import android.os.HandlerExecutor; 78 import android.os.IBinder; 79 import android.os.IRemoteCallback; 80 import android.os.PowerManager; 81 import android.os.RemoteException; 82 import android.os.Trace; 83 import android.os.UserHandle; 84 import android.provider.Settings; 85 import android.util.Slog; 86 import android.view.Surface; 87 88 import com.android.internal.R; 89 90 import java.util.ArrayList; 91 import java.util.List; 92 93 /** 94 * A class that coordinates access to the face authentication hardware. 95 * @hide 96 */ 97 @SystemService(Context.FACE_SERVICE) 98 public class FaceManager implements BiometricAuthenticator { 99 100 private static final String TAG = "FaceManager"; 101 102 private final IFaceService mService; 103 private final Context mContext; 104 private final IBinder mToken = new Binder(); 105 private Handler mHandler; 106 private List<FaceSensorPropertiesInternal> mProps = new ArrayList<>(); 107 private HandlerExecutor mExecutor; 108 109 private class FaceServiceReceiver extends IFaceServiceReceiver.Stub { 110 private final FaceCallback mFaceCallback; 111 FaceServiceReceiver(FaceCallback faceCallback)112 FaceServiceReceiver(FaceCallback faceCallback) { 113 mFaceCallback = faceCallback; 114 } 115 116 @Override // binder call onEnrollResult(Face face, int remaining)117 public void onEnrollResult(Face face, int remaining) { 118 mExecutor.execute(() -> mFaceCallback.sendEnrollResult(remaining)); 119 } 120 121 @Override // binder call onAcquired(int acquireInfo, int vendorCode)122 public void onAcquired(int acquireInfo, int vendorCode) { 123 mExecutor.execute(() -> mFaceCallback.sendAcquiredResult(mContext, acquireInfo, 124 vendorCode)); 125 } 126 127 @Override // binder call onAuthenticationSucceeded(Face face, int userId, boolean isStrongBiometric)128 public void onAuthenticationSucceeded(Face face, int userId, boolean isStrongBiometric) { 129 mExecutor.execute(() -> mFaceCallback.sendAuthenticatedSucceeded(face, userId, 130 isStrongBiometric)); 131 } 132 133 @Override // binder call onFaceDetected(int sensorId, int userId, boolean isStrongBiometric)134 public void onFaceDetected(int sensorId, int userId, boolean isStrongBiometric) { 135 mExecutor.execute(() -> mFaceCallback.sendFaceDetected(sensorId, userId, 136 isStrongBiometric)); 137 } 138 139 @Override // binder call onAuthenticationFailed()140 public void onAuthenticationFailed() { 141 mExecutor.execute(mFaceCallback::sendAuthenticatedFailed); 142 } 143 144 @Override // binder call onError(int error, int vendorCode)145 public void onError(int error, int vendorCode) { 146 mExecutor.execute(() -> mFaceCallback.sendErrorResult(mContext, error, vendorCode)); 147 } 148 149 @Override // binder call onRemoved(Face face, int remaining)150 public void onRemoved(Face face, int remaining) { 151 mExecutor.execute(() -> mFaceCallback.sendRemovedResult(face, remaining)); 152 if (remaining == 0) { 153 Settings.Secure.putIntForUser(mContext.getContentResolver(), 154 Settings.Secure.FACE_UNLOCK_RE_ENROLL, 0, 155 UserHandle.USER_CURRENT); 156 } 157 } 158 159 @Override onFeatureSet(boolean success, int feature)160 public void onFeatureSet(boolean success, int feature) { 161 mExecutor.execute(() -> mFaceCallback.sendSetFeatureCompleted(success, feature)); 162 } 163 164 @Override onFeatureGet(boolean success, int[] features, boolean[] featureState)165 public void onFeatureGet(boolean success, int[] features, boolean[] featureState) { 166 mExecutor.execute(() -> mFaceCallback.sendGetFeatureCompleted(success, features, 167 featureState)); 168 } 169 170 @Override onChallengeGenerated(int sensorId, int userId, long challenge)171 public void onChallengeGenerated(int sensorId, int userId, long challenge) { 172 mExecutor.execute(() -> mFaceCallback.sendChallengeGenerated(sensorId, userId, 173 challenge)); 174 } 175 176 @Override onAuthenticationFrame(FaceAuthenticationFrame frame)177 public void onAuthenticationFrame(FaceAuthenticationFrame frame) { 178 mExecutor.execute(() -> mFaceCallback.sendAuthenticationFrame(mContext, frame)); 179 } 180 181 @Override onEnrollmentFrame(FaceEnrollFrame frame)182 public void onEnrollmentFrame(FaceEnrollFrame frame) { 183 mExecutor.execute(() -> mFaceCallback.sendEnrollmentFrame(mContext, frame)); 184 } 185 } 186 187 /** 188 * @hide 189 */ FaceManager(Context context, IFaceService service)190 public FaceManager(Context context, IFaceService service) { 191 mContext = context; 192 mService = service; 193 if (mService == null) { 194 Slog.v(TAG, "FaceAuthenticationManagerService was null"); 195 } 196 mHandler = context.getMainThreadHandler(); 197 mExecutor = new HandlerExecutor(mHandler); 198 if (context.checkCallingOrSelfPermission(USE_BIOMETRIC_INTERNAL) 199 == PackageManager.PERMISSION_GRANTED) { 200 addAuthenticatorsRegisteredCallback(new IFaceAuthenticatorsRegisteredCallback.Stub() { 201 @Override 202 public void onAllAuthenticatorsRegistered( 203 @NonNull List<FaceSensorPropertiesInternal> sensors) { 204 mProps = sensors; 205 } 206 }); 207 } 208 } 209 210 /** 211 * Use the provided handler thread for events. 212 */ useHandler(Handler handler)213 private void useHandler(Handler handler) { 214 if (handler != null) { 215 mHandler = handler; 216 mExecutor = new HandlerExecutor(mHandler); 217 } else if (mHandler != mContext.getMainThreadHandler()) { 218 mHandler = mContext.getMainThreadHandler(); 219 mExecutor = new HandlerExecutor(mHandler); 220 } 221 } 222 223 /** 224 * @deprecated use {@link #authenticate(CryptoObject, CancellationSignal, AuthenticationCallback, Handler, FaceAuthenticateOptions)}. 225 */ 226 @Deprecated 227 @RequiresPermission(USE_BIOMETRIC_INTERNAL) authenticate(@ullable CryptoObject crypto, @Nullable CancellationSignal cancel, @NonNull AuthenticationCallback callback, @Nullable Handler handler, int userId)228 public void authenticate(@Nullable CryptoObject crypto, @Nullable CancellationSignal cancel, 229 @NonNull AuthenticationCallback callback, @Nullable Handler handler, int userId) { 230 authenticate(crypto, cancel, callback, handler, new FaceAuthenticateOptions.Builder() 231 .setUserId(userId) 232 .build()); 233 } 234 235 /** 236 * Request authentication. This call operates the face recognition hardware and starts capturing images. 237 * It terminates when 238 * {@link AuthenticationCallback#onAuthenticationError(int, CharSequence)} or 239 * {@link AuthenticationCallback#onAuthenticationSucceeded(AuthenticationResult)} is called, at 240 * which point the object is no longer valid. The operation can be canceled by using the 241 * provided cancel object. 242 * 243 * @param crypto object associated with the call or null if none required 244 * @param cancel an object that can be used to cancel authentication 245 * @param callback an object to receive authentication events 246 * @param handler an optional handler to handle callback events 247 * @param options additional options to customize this request 248 * @throws IllegalArgumentException if the crypto operation is not supported or is not backed 249 * by 250 * <a href="{@docRoot}training/articles/keystore.html">Android 251 * Keystore facility</a>. 252 * @throws IllegalStateException if the crypto primitive is not initialized. 253 * @hide 254 */ 255 @RequiresPermission(USE_BIOMETRIC_INTERNAL) authenticate(@ullable CryptoObject crypto, @Nullable CancellationSignal cancel, @NonNull AuthenticationCallback callback, @Nullable Handler handler, @NonNull FaceAuthenticateOptions options)256 public void authenticate(@Nullable CryptoObject crypto, @Nullable CancellationSignal cancel, 257 @NonNull AuthenticationCallback callback, @Nullable Handler handler, 258 @NonNull FaceAuthenticateOptions options) { 259 if (callback == null) { 260 throw new IllegalArgumentException("Must supply an authentication callback"); 261 } 262 263 if (cancel != null && cancel.isCanceled()) { 264 Slog.w(TAG, "authentication already canceled"); 265 return; 266 } 267 268 options.setOpPackageName(mContext.getOpPackageName()); 269 options.setAttributionTag(mContext.getAttributionTag()); 270 271 if (mService != null) { 272 try { 273 final FaceCallback faceCallback = new FaceCallback(callback, crypto); 274 useHandler(handler); 275 final long operationId = crypto != null ? crypto.getOpId() : 0; 276 Trace.beginSection("FaceManager#authenticate"); 277 final long authId = mService.authenticate( 278 mToken, operationId, new FaceServiceReceiver(faceCallback), options); 279 if (cancel != null) { 280 cancel.setOnCancelListener(new OnAuthenticationCancelListener(authId)); 281 } 282 } catch (RemoteException e) { 283 Slog.w(TAG, "Remote exception while authenticating: ", e); 284 // Though this may not be a hardware issue, it will cause apps to give up or 285 // try again later. 286 callback.onAuthenticationError(FACE_ERROR_HW_UNAVAILABLE, 287 getErrorString(mContext, FACE_ERROR_HW_UNAVAILABLE, 288 0 /* vendorCode */)); 289 } finally { 290 Trace.endSection(); 291 } 292 } 293 } 294 295 /** 296 * Uses the face hardware to detect for the presence of a face, without giving details about 297 * accept/reject/lockout. 298 * @hide 299 */ 300 @RequiresPermission(USE_BIOMETRIC_INTERNAL) detectFace(@onNull CancellationSignal cancel, @NonNull FaceDetectionCallback callback, @NonNull FaceAuthenticateOptions options)301 public void detectFace(@NonNull CancellationSignal cancel, 302 @NonNull FaceDetectionCallback callback, @NonNull FaceAuthenticateOptions options) { 303 if (mService == null) { 304 return; 305 } 306 307 if (cancel.isCanceled()) { 308 Slog.w(TAG, "Detection already cancelled"); 309 return; 310 } 311 312 options.setOpPackageName(mContext.getOpPackageName()); 313 options.setAttributionTag(mContext.getAttributionTag()); 314 315 final FaceCallback faceCallback = new FaceCallback(callback); 316 317 try { 318 final long authId = mService.detectFace(mToken, 319 new FaceServiceReceiver(faceCallback), options); 320 cancel.setOnCancelListener(new OnFaceDetectionCancelListener(authId)); 321 } catch (RemoteException e) { 322 Slog.w(TAG, "Remote exception when requesting finger detect", e); 323 } 324 } 325 326 /** 327 * Defaults to {@link FaceManager#enroll(int, byte[], CancellationSignal, EnrollmentCallback, 328 * int[], Surface)} with {@code previewSurface} set to null. 329 * 330 * @see FaceManager#enroll(int, byte[], CancellationSignal, EnrollmentCallback, int[], Surface) 331 * @hide 332 */ 333 @RequiresPermission(MANAGE_BIOMETRIC) enroll(int userId, byte[] hardwareAuthToken, CancellationSignal cancel, EnrollmentCallback callback, int[] disabledFeatures)334 public void enroll(int userId, byte[] hardwareAuthToken, CancellationSignal cancel, 335 EnrollmentCallback callback, int[] disabledFeatures) { 336 enroll(userId, hardwareAuthToken, cancel, callback, disabledFeatures, 337 null /* previewSurface */, false /* debugConsent */, 338 (new FaceEnrollOptions.Builder()).build()); 339 340 } 341 342 /** 343 * Request face authentication enrollment. This call operates the face authentication hardware 344 * and starts capturing images. Progress will be indicated by callbacks to the 345 * {@link EnrollmentCallback} object. It terminates when 346 * {@link EnrollmentCallback#onEnrollmentError(int, CharSequence)} or 347 * {@link EnrollmentCallback#onEnrollmentProgress(int) is called with remaining == 0, at 348 * which point the object is no longer valid. The operation can be canceled by using the 349 * provided cancel object. 350 * 351 * @param hardwareAuthToken a unique token provided by a recent creation or 352 * verification of device credentials (e.g. pin, pattern or password). 353 * @param cancel an object that can be used to cancel enrollment 354 * @param userId the user to whom this face will belong to 355 * @param callback an object to receive enrollment events 356 * @param previewSurface optional camera preview surface for a single-camera device. 357 * Must be null if not used. 358 * @param debugConsent a feature flag that the user has consented to debug. 359 * @hide 360 */ 361 @RequiresPermission(MANAGE_BIOMETRIC) enroll(int userId, byte[] hardwareAuthToken, CancellationSignal cancel, EnrollmentCallback callback, int[] disabledFeatures, @Nullable Surface previewSurface, boolean debugConsent, FaceEnrollOptions options)362 public void enroll(int userId, byte[] hardwareAuthToken, CancellationSignal cancel, 363 EnrollmentCallback callback, int[] disabledFeatures, @Nullable Surface previewSurface, 364 boolean debugConsent, FaceEnrollOptions options) { 365 if (callback == null) { 366 throw new IllegalArgumentException("Must supply an enrollment callback"); 367 } 368 369 if (cancel != null && cancel.isCanceled()) { 370 Slog.w(TAG, "enrollment already canceled"); 371 return; 372 } 373 374 if (hardwareAuthToken == null) { 375 callback.onEnrollmentError(FACE_ERROR_UNABLE_TO_PROCESS, 376 getErrorString(mContext, FACE_ERROR_UNABLE_TO_PROCESS, 377 0 /* vendorCode */)); 378 return; 379 } 380 381 if (getEnrolledFaces(userId).size() 382 >= mContext.getResources().getInteger(R.integer.config_faceMaxTemplatesPerUser)) { 383 callback.onEnrollmentError(FACE_ERROR_HW_UNAVAILABLE, 384 getErrorString(mContext, FACE_ERROR_HW_UNAVAILABLE, 385 0 /* vendorCode */)); 386 return; 387 } 388 389 if (mService != null) { 390 try { 391 final FaceCallback faceCallback = new FaceCallback(callback); 392 Trace.beginSection("FaceManager#enroll"); 393 final long enrollId = mService.enroll(userId, mToken, hardwareAuthToken, 394 new FaceServiceReceiver(faceCallback), mContext.getOpPackageName(), 395 disabledFeatures, previewSurface, debugConsent, options); 396 if (cancel != null) { 397 cancel.setOnCancelListener(new OnEnrollCancelListener(enrollId)); 398 } 399 } catch (RemoteException e) { 400 Slog.w(TAG, "Remote exception in enroll: ", e); 401 // Though this may not be a hardware issue, it will cause apps to give up or 402 // try again later. 403 callback.onEnrollmentError(FACE_ERROR_HW_UNAVAILABLE, 404 getErrorString(mContext, FACE_ERROR_HW_UNAVAILABLE, 405 0 /* vendorCode */)); 406 } finally { 407 Trace.endSection(); 408 } 409 } 410 } 411 412 /** 413 * Request face authentication enrollment for a remote client, for example Android Auto. 414 * This call operates the face authentication hardware and starts capturing images. 415 * Progress will be indicated by callbacks to the 416 * {@link EnrollmentCallback} object. It terminates when 417 * {@link EnrollmentCallback#onEnrollmentError(int, CharSequence)} or 418 * {@link EnrollmentCallback#onEnrollmentProgress(int) is called with remaining == 0, at 419 * which point the object is no longer valid. The operation can be canceled by using the 420 * provided cancel object. 421 * 422 * @param hardwareAuthToken a unique token provided by a recent creation or verification of 423 * device credentials (e.g. pin, pattern or password). 424 * @param cancel an object that can be used to cancel enrollment 425 * @param userId the user to whom this face will belong to 426 * @param callback an object to receive enrollment events 427 * @hide 428 */ 429 @RequiresPermission(MANAGE_BIOMETRIC) enrollRemotely(int userId, byte[] hardwareAuthToken, CancellationSignal cancel, EnrollmentCallback callback, int[] disabledFeatures)430 public void enrollRemotely(int userId, byte[] hardwareAuthToken, CancellationSignal cancel, 431 EnrollmentCallback callback, int[] disabledFeatures) { 432 if (callback == null) { 433 throw new IllegalArgumentException("Must supply an enrollment callback"); 434 } 435 436 if (cancel != null && cancel.isCanceled()) { 437 Slog.w(TAG, "enrollRemotely is already canceled."); 438 return; 439 } 440 441 if (mService != null) { 442 try { 443 final FaceCallback faceCallback = new FaceCallback(callback); 444 Trace.beginSection("FaceManager#enrollRemotely"); 445 final long enrolId = mService.enrollRemotely(userId, mToken, hardwareAuthToken, 446 new FaceServiceReceiver(faceCallback), mContext.getOpPackageName(), 447 disabledFeatures); 448 if (cancel != null) { 449 cancel.setOnCancelListener(new OnEnrollCancelListener(enrolId)); 450 } 451 } catch (RemoteException e) { 452 Slog.w(TAG, "Remote exception in enrollRemotely: ", e); 453 // Though this may not be a hardware issue, it will cause apps to give up or 454 // try again later. 455 callback.onEnrollmentError(FACE_ERROR_HW_UNAVAILABLE, 456 getErrorString(mContext, FACE_ERROR_HW_UNAVAILABLE, 457 0 /* vendorCode */)); 458 } finally { 459 Trace.endSection(); 460 } 461 } 462 } 463 464 /** 465 * Generates a unique random challenge in the TEE. A typical use case is to have it wrapped in a 466 * HardwareAuthenticationToken, minted by Gatekeeper upon PIN/Pattern/Password verification. 467 * The HardwareAuthenticationToken can then be sent to the biometric HAL together with a 468 * request to perform sensitive operation(s) (for example enroll or setFeature), represented 469 * by the challenge. Doing this ensures that a the sensitive operation cannot be performed 470 * unless the user has entered confirmed PIN/Pattern/Password. 471 * 472 * @see com.android.server.locksettings.LockSettingsService 473 * 474 * @hide 475 */ 476 @RequiresPermission(MANAGE_BIOMETRIC) generateChallenge(int sensorId, int userId, GenerateChallengeCallback callback)477 public void generateChallenge(int sensorId, int userId, GenerateChallengeCallback callback) { 478 if (mService != null) { 479 try { 480 final FaceCallback faceCallback = new FaceCallback(callback); 481 mService.generateChallenge(mToken, sensorId, userId, 482 new FaceServiceReceiver(faceCallback), mContext.getOpPackageName()); 483 } catch (RemoteException e) { 484 throw e.rethrowFromSystemServer(); 485 } 486 } 487 } 488 489 /** 490 * Same as {@link #generateChallenge(int, int, GenerateChallengeCallback)}, but assumes the 491 * first enumerated sensor. 492 * 493 * @hide 494 */ 495 @RequiresPermission(MANAGE_BIOMETRIC) generateChallenge(int userId, GenerateChallengeCallback callback)496 public void generateChallenge(int userId, GenerateChallengeCallback callback) { 497 final List<FaceSensorPropertiesInternal> faceSensorProperties = 498 getSensorPropertiesInternal(); 499 if (faceSensorProperties.isEmpty()) { 500 Slog.e(TAG, "No sensors"); 501 return; 502 } 503 504 final int sensorId = faceSensorProperties.get(0).sensorId; 505 generateChallenge(sensorId, userId, callback); 506 } 507 508 /** 509 * Invalidates the current challenge. 510 * 511 * @hide 512 */ 513 @RequiresPermission(MANAGE_BIOMETRIC) revokeChallenge(int sensorId, int userId, long challenge)514 public void revokeChallenge(int sensorId, int userId, long challenge) { 515 if (mService != null) { 516 try { 517 mService.revokeChallenge(mToken, sensorId, userId, 518 mContext.getOpPackageName(), challenge); 519 } catch (RemoteException e) { 520 throw e.rethrowFromSystemServer(); 521 } 522 } 523 } 524 525 /** 526 * Reset the lockout when user authenticates with strong auth (e.g. PIN, pattern or password) 527 * 528 * @param sensorId Sensor ID that this operation takes effect for 529 * @param userId User ID that this operation takes effect for. 530 * @param hardwareAuthToken An opaque token returned by password confirmation. 531 * @hide 532 */ 533 @RequiresPermission(USE_BIOMETRIC_INTERNAL) resetLockout(int sensorId, int userId, @Nullable byte[] hardwareAuthToken)534 public void resetLockout(int sensorId, int userId, @Nullable byte[] hardwareAuthToken) { 535 if (mService != null) { 536 try { 537 mService.resetLockout(mToken, sensorId, userId, hardwareAuthToken, 538 mContext.getOpPackageName()); 539 } catch (RemoteException e) { 540 throw e.rethrowFromSystemServer(); 541 } 542 } 543 } 544 545 /** 546 * @hide 547 */ 548 @RequiresPermission(MANAGE_BIOMETRIC) setFeature(int userId, int feature, boolean enabled, byte[] hardwareAuthToken, SetFeatureCallback callback)549 public void setFeature(int userId, int feature, boolean enabled, byte[] hardwareAuthToken, 550 SetFeatureCallback callback) { 551 if (mService != null) { 552 try { 553 final FaceCallback faceCallback = new FaceCallback(callback); 554 mService.setFeature(mToken, userId, feature, enabled, hardwareAuthToken, 555 new FaceServiceReceiver(faceCallback), mContext.getOpPackageName()); 556 } catch (RemoteException e) { 557 throw e.rethrowFromSystemServer(); 558 } 559 } 560 } 561 562 /** 563 * @hide 564 */ 565 @RequiresPermission(MANAGE_BIOMETRIC) getFeature(int userId, int feature, GetFeatureCallback callback)566 public void getFeature(int userId, int feature, GetFeatureCallback callback) { 567 if (mService != null) { 568 try { 569 final FaceCallback faceCallback = new FaceCallback(callback); 570 mService.getFeature(mToken, userId, feature, new FaceServiceReceiver(faceCallback), 571 mContext.getOpPackageName()); 572 } catch (RemoteException e) { 573 throw e.rethrowFromSystemServer(); 574 } 575 } 576 } 577 578 /** 579 * Remove given face template from face hardware and/or protected storage. 580 * 581 * @param face the face item to remove 582 * @param userId the user who this face belongs to 583 * @param callback an optional callback to verify that face templates have been 584 * successfully removed. May be null if no callback is required. 585 * @hide 586 */ 587 @RequiresPermission(MANAGE_BIOMETRIC) remove(Face face, int userId, RemovalCallback callback)588 public void remove(Face face, int userId, RemovalCallback callback) { 589 if (mService != null) { 590 try { 591 final FaceCallback faceCallback = new FaceCallback(callback, face); 592 mService.remove(mToken, face.getBiometricId(), userId, 593 new FaceServiceReceiver(faceCallback), mContext.getOpPackageName()); 594 } catch (RemoteException e) { 595 throw e.rethrowFromSystemServer(); 596 } 597 } 598 } 599 600 /** 601 * Removes all face templates for the given user. 602 * @hide 603 */ 604 @RequiresPermission(MANAGE_BIOMETRIC) removeAll(int userId, @NonNull RemovalCallback callback)605 public void removeAll(int userId, @NonNull RemovalCallback callback) { 606 if (mService != null) { 607 try { 608 final FaceCallback faceCallback = new FaceCallback(callback); 609 mService.removeAll(mToken, userId, new FaceServiceReceiver(faceCallback), 610 mContext.getOpPackageName()); 611 } catch (RemoteException e) { 612 throw e.rethrowFromSystemServer(); 613 } 614 } 615 } 616 617 /** 618 * Obtain the enrolled face template. 619 * 620 * @return the current face item 621 * @hide 622 */ 623 @RequiresPermission(MANAGE_BIOMETRIC) getEnrolledFaces(int userId)624 public List<Face> getEnrolledFaces(int userId) { 625 final List<FaceSensorPropertiesInternal> faceSensorProperties = 626 getSensorPropertiesInternal(); 627 if (faceSensorProperties.isEmpty()) { 628 Slog.e(TAG, "No sensors"); 629 return new ArrayList<>(); 630 } 631 632 if (mService != null) { 633 try { 634 return mService.getEnrolledFaces(faceSensorProperties.get(0).sensorId, userId, 635 mContext.getOpPackageName()); 636 } catch (RemoteException e) { 637 throw e.rethrowFromSystemServer(); 638 } 639 } 640 return null; 641 } 642 643 /** 644 * Obtain the enrolled face template. 645 * 646 * @return the current face item 647 * @hide 648 */ 649 @RequiresPermission(MANAGE_BIOMETRIC) getEnrolledFaces()650 public List<Face> getEnrolledFaces() { 651 return getEnrolledFaces(UserHandle.myUserId()); 652 } 653 654 /** 655 * Determine if there is a face enrolled. 656 * 657 * @return true if a face is enrolled, false otherwise 658 * @hide 659 */ 660 @RequiresPermission(USE_BIOMETRIC_INTERNAL) hasEnrolledTemplates()661 public boolean hasEnrolledTemplates() { 662 return hasEnrolledTemplates(UserHandle.myUserId()); 663 } 664 665 /** 666 * @hide 667 */ 668 @RequiresPermission(allOf = { 669 USE_BIOMETRIC_INTERNAL, 670 INTERACT_ACROSS_USERS}) hasEnrolledTemplates(int userId)671 public boolean hasEnrolledTemplates(int userId) { 672 final List<FaceSensorPropertiesInternal> faceSensorProperties = 673 getSensorPropertiesInternal(); 674 if (faceSensorProperties.isEmpty()) { 675 Slog.e(TAG, "No sensors"); 676 return false; 677 } 678 679 if (mService != null) { 680 try { 681 return mService.hasEnrolledFaces(faceSensorProperties.get(0).sensorId, userId, 682 mContext.getOpPackageName()); 683 } catch (RemoteException e) { 684 throw e.rethrowFromSystemServer(); 685 } 686 } 687 return false; 688 } 689 690 /** 691 * Determine if face authentication sensor hardware is present and functional. 692 * 693 * @return true if hardware is present and functional, false otherwise. 694 * @hide 695 */ 696 @RequiresPermission(USE_BIOMETRIC_INTERNAL) isHardwareDetected()697 public boolean isHardwareDetected() { 698 final List<FaceSensorPropertiesInternal> faceSensorProperties = 699 getSensorPropertiesInternal(); 700 if (faceSensorProperties.isEmpty()) { 701 Slog.e(TAG, "No sensors"); 702 return false; 703 } 704 705 if (mService != null) { 706 try { 707 return mService.isHardwareDetected(faceSensorProperties.get(0).sensorId, 708 mContext.getOpPackageName()); 709 } catch (RemoteException e) { 710 throw e.rethrowFromSystemServer(); 711 } 712 } else { 713 Slog.w(TAG, "isFaceHardwareDetected(): Service not connected!"); 714 } 715 return false; 716 } 717 718 /** 719 * Retrieves a list of properties for all face authentication sensors on the device. 720 * @hide 721 */ 722 @NonNull getSensorProperties()723 public List<FaceSensorProperties> getSensorProperties() { 724 final List<FaceSensorProperties> properties = new ArrayList<>(); 725 final List<FaceSensorPropertiesInternal> internalProperties 726 = getSensorPropertiesInternal(); 727 for (FaceSensorPropertiesInternal internalProp : internalProperties) { 728 properties.add(FaceSensorProperties.from(internalProp)); 729 } 730 return properties; 731 } 732 733 /** 734 * Get statically configured sensor properties. 735 * @deprecated Generally unsafe to use, use 736 * {@link FaceManager#addAuthenticatorsRegisteredCallback} API instead. 737 * In most cases this method will work as expected, but during early boot up, it will be 738 * null/empty and there is no way for the caller to know when it's actual value is ready. 739 * @hide 740 */ 741 @RequiresPermission(USE_BIOMETRIC_INTERNAL) 742 @NonNull getSensorPropertiesInternal()743 public List<FaceSensorPropertiesInternal> getSensorPropertiesInternal() { 744 try { 745 if (!mProps.isEmpty() || mService == null) { 746 return mProps; 747 } 748 return mService.getSensorPropertiesInternal(mContext.getOpPackageName()); 749 } catch (RemoteException e) { 750 e.rethrowFromSystemServer(); 751 } 752 return mProps; 753 } 754 755 /** 756 * Forwards BiometricStateListener to FaceService. 757 * 758 * @param listener new BiometricStateListener being added 759 * @hide 760 */ registerBiometricStateListener(@onNull BiometricStateListener listener)761 public void registerBiometricStateListener(@NonNull BiometricStateListener listener) { 762 try { 763 mService.registerBiometricStateListener(listener); 764 } catch (RemoteException e) { 765 throw e.rethrowFromSystemServer(); 766 } 767 } 768 769 /** 770 * Adds a callback that gets called when the service registers all of the face 771 * authenticators (HALs). 772 * 773 * If the face authenticators are already registered when the callback is added, the 774 * callback is invoked immediately. 775 * 776 * The callback is automatically removed after it's invoked. 777 * 778 * @hide 779 */ 780 @RequiresPermission(USE_BIOMETRIC_INTERNAL) addAuthenticatorsRegisteredCallback( IFaceAuthenticatorsRegisteredCallback callback)781 public void addAuthenticatorsRegisteredCallback( 782 IFaceAuthenticatorsRegisteredCallback callback) { 783 if (mService != null) { 784 try { 785 mService.addAuthenticatorsRegisteredCallback(callback); 786 } catch (RemoteException e) { 787 throw e.rethrowFromSystemServer(); 788 } 789 } else { 790 Slog.w(TAG, "addAuthenticatorsRegisteredCallback(): Service not connected!"); 791 } 792 } 793 794 /** 795 * @hide 796 */ 797 @RequiresPermission(USE_BIOMETRIC_INTERNAL) 798 @BiometricConstants.LockoutMode getLockoutModeForUser(int sensorId, int userId)799 public int getLockoutModeForUser(int sensorId, int userId) { 800 if (mService != null) { 801 try { 802 return mService.getLockoutModeForUser(sensorId, userId); 803 } catch (RemoteException e) { 804 e.rethrowFromSystemServer(); 805 } 806 } 807 return BIOMETRIC_LOCKOUT_NONE; 808 } 809 810 /** 811 * @hide 812 */ 813 @RequiresPermission(USE_BIOMETRIC_INTERNAL) addLockoutResetCallback(final LockoutResetCallback callback)814 public void addLockoutResetCallback(final LockoutResetCallback callback) { 815 if (mService != null) { 816 try { 817 final PowerManager powerManager = mContext.getSystemService(PowerManager.class); 818 mService.addLockoutResetCallback( 819 new IBiometricServiceLockoutResetCallback.Stub() { 820 821 @Override 822 public void onLockoutReset(int sensorId, IRemoteCallback serverCallback) 823 throws RemoteException { 824 try { 825 final PowerManager.WakeLock wakeLock = powerManager.newWakeLock( 826 PowerManager.PARTIAL_WAKE_LOCK, 827 "faceLockoutResetCallback"); 828 wakeLock.acquire(); 829 mHandler.post(() -> { 830 try { 831 callback.onLockoutReset(sensorId); 832 } finally { 833 wakeLock.release(); 834 } 835 }); 836 } finally { 837 serverCallback.sendResult(null /* data */); 838 } 839 } 840 }, mContext.getOpPackageName()); 841 } catch (RemoteException e) { 842 throw e.rethrowFromSystemServer(); 843 } 844 } else { 845 Slog.w(TAG, "addLockoutResetCallback(): Service not connected!"); 846 } 847 } 848 849 /** 850 * Schedules a watchdog. 851 * 852 * @hide 853 */ 854 @RequiresPermission(USE_BIOMETRIC_INTERNAL) scheduleWatchdog()855 public void scheduleWatchdog() { 856 try { 857 mService.scheduleWatchdog(); 858 } catch (RemoteException e) { 859 throw e.rethrowFromSystemServer(); 860 } 861 } 862 cancelEnrollment(long requestId)863 private void cancelEnrollment(long requestId) { 864 if (mService != null) { 865 try { 866 mService.cancelEnrollment(mToken, requestId); 867 } catch (RemoteException e) { 868 throw e.rethrowFromSystemServer(); 869 } 870 } 871 } 872 cancelAuthentication(long requestId)873 private void cancelAuthentication(long requestId) { 874 if (mService != null) { 875 try { 876 mService.cancelAuthentication(mToken, mContext.getOpPackageName(), requestId); 877 } catch (RemoteException e) { 878 throw e.rethrowFromSystemServer(); 879 } 880 } 881 } 882 cancelFaceDetect(long requestId)883 private void cancelFaceDetect(long requestId) { 884 if (mService == null) { 885 return; 886 } 887 888 try { 889 mService.cancelFaceDetect(mToken, mContext.getOpPackageName(), requestId); 890 } catch (RemoteException e) { 891 throw e.rethrowFromSystemServer(); 892 } 893 } 894 895 /** 896 * @hide 897 */ getErrorString(Context context, int errMsg, int vendorCode)898 public static String getErrorString(Context context, int errMsg, int vendorCode) { 899 switch (errMsg) { 900 case FACE_ERROR_HW_UNAVAILABLE: 901 return context.getString( 902 com.android.internal.R.string.face_error_hw_not_available); 903 case FACE_ERROR_UNABLE_TO_PROCESS: 904 return context.getString( 905 com.android.internal.R.string.face_error_unable_to_process); 906 case FACE_ERROR_TIMEOUT: 907 return context.getString(com.android.internal.R.string.face_error_timeout); 908 case FACE_ERROR_NO_SPACE: 909 return context.getString(com.android.internal.R.string.face_error_no_space); 910 case FACE_ERROR_CANCELED: 911 return context.getString(com.android.internal.R.string.face_error_canceled); 912 case FACE_ERROR_LOCKOUT: 913 return context.getString(com.android.internal.R.string.face_error_lockout); 914 case FACE_ERROR_LOCKOUT_PERMANENT: 915 return context.getString( 916 com.android.internal.R.string.face_error_lockout_permanent); 917 case FACE_ERROR_USER_CANCELED: 918 return context.getString(com.android.internal.R.string.face_error_user_canceled); 919 case FACE_ERROR_NOT_ENROLLED: 920 return context.getString(com.android.internal.R.string.face_error_not_enrolled); 921 case FACE_ERROR_HW_NOT_PRESENT: 922 return context.getString(com.android.internal.R.string.face_error_hw_not_present); 923 case BIOMETRIC_ERROR_SECURITY_UPDATE_REQUIRED: 924 return context.getString( 925 com.android.internal.R.string.face_error_security_update_required); 926 case BIOMETRIC_ERROR_RE_ENROLL: 927 return context.getString( 928 com.android.internal.R.string.face_recalibrate_notification_content); 929 case FACE_ERROR_VENDOR: { 930 String[] msgArray = context.getResources().getStringArray( 931 com.android.internal.R.array.face_error_vendor); 932 if (vendorCode < msgArray.length) { 933 return msgArray[vendorCode]; 934 } 935 } 936 } 937 938 // This is used as a last resort in case a vendor string is missing 939 // It should not happen for anything other than FACE_ERROR_VENDOR, but 940 // warn and use the default if all else fails. 941 Slog.w(TAG, "Invalid error message: " + errMsg + ", " + vendorCode); 942 return context.getString( 943 com.android.internal.R.string.face_error_vendor_unknown); 944 } 945 946 /** 947 * Used so BiometricPrompt can map the face ones onto existing public constants. 948 * @hide 949 */ getMappedAcquiredInfo(int acquireInfo, int vendorCode)950 public static int getMappedAcquiredInfo(int acquireInfo, int vendorCode) { 951 switch (acquireInfo) { 952 case FACE_ACQUIRED_GOOD: 953 return BiometricConstants.BIOMETRIC_ACQUIRED_GOOD; 954 case FACE_ACQUIRED_INSUFFICIENT: 955 case FACE_ACQUIRED_TOO_BRIGHT: 956 case FACE_ACQUIRED_TOO_DARK: 957 return BiometricConstants.BIOMETRIC_ACQUIRED_INSUFFICIENT; 958 case FACE_ACQUIRED_TOO_CLOSE: 959 case FACE_ACQUIRED_TOO_FAR: 960 case FACE_ACQUIRED_TOO_HIGH: 961 case FACE_ACQUIRED_TOO_LOW: 962 case FACE_ACQUIRED_TOO_RIGHT: 963 case FACE_ACQUIRED_TOO_LEFT: 964 return BiometricConstants.BIOMETRIC_ACQUIRED_PARTIAL; 965 case FACE_ACQUIRED_POOR_GAZE: 966 case FACE_ACQUIRED_NOT_DETECTED: 967 case FACE_ACQUIRED_TOO_MUCH_MOTION: 968 case FACE_ACQUIRED_RECALIBRATE: 969 return BiometricConstants.BIOMETRIC_ACQUIRED_INSUFFICIENT; 970 case FACE_ACQUIRED_VENDOR: 971 return BiometricConstants.BIOMETRIC_ACQUIRED_VENDOR_BASE + vendorCode; 972 default: 973 return BiometricConstants.BIOMETRIC_ACQUIRED_GOOD; 974 } 975 } 976 977 /** 978 * Container for callback data from {@link FaceManager#authenticate(CryptoObject, 979 * CancellationSignal, int, AuthenticationCallback, Handler)}. 980 * @hide 981 */ 982 public static class AuthenticationResult { 983 private final Face mFace; 984 private final CryptoObject mCryptoObject; 985 private final int mUserId; 986 private final boolean mIsStrongBiometric; 987 988 /** 989 * Authentication result 990 * 991 * @param crypto the crypto object 992 * @param face the recognized face data, if allowed. 993 * @hide 994 */ AuthenticationResult(CryptoObject crypto, Face face, int userId, boolean isStrongBiometric)995 public AuthenticationResult(CryptoObject crypto, Face face, int userId, 996 boolean isStrongBiometric) { 997 mCryptoObject = crypto; 998 mFace = face; 999 mUserId = userId; 1000 mIsStrongBiometric = isStrongBiometric; 1001 } 1002 1003 /** 1004 * Obtain the crypto object associated with this transaction 1005 * 1006 * @return crypto object provided to {@link FaceManager#authenticate 1007 * (CryptoObject, 1008 * CancellationSignal, int, AuthenticationCallback, Handler)}. 1009 */ getCryptoObject()1010 public CryptoObject getCryptoObject() { 1011 return mCryptoObject; 1012 } 1013 1014 /** 1015 * Obtain the Face associated with this operation. Applications are strongly 1016 * discouraged from associating specific faces with specific applications or operations. 1017 * 1018 * @hide 1019 */ getFace()1020 public Face getFace() { 1021 return mFace; 1022 } 1023 1024 /** 1025 * Obtain the userId for which this face was authenticated. 1026 * 1027 * @hide 1028 */ getUserId()1029 public int getUserId() { 1030 return mUserId; 1031 } 1032 1033 /** 1034 * Check whether the strength of the face modality associated with this operation is strong 1035 * (i.e. not weak or convenience). 1036 * 1037 * @hide 1038 */ isStrongBiometric()1039 public boolean isStrongBiometric() { 1040 return mIsStrongBiometric; 1041 } 1042 } 1043 1044 /** 1045 * Callback structure provided to {@link FaceManager#authenticate(CryptoObject, 1046 * CancellationSignal, int, AuthenticationCallback, Handler)}. Users of {@link 1047 * FaceManager#authenticate(CryptoObject, CancellationSignal, 1048 * int, AuthenticationCallback, Handler) } must provide an implementation of this for listening 1049 * to face events. 1050 * @hide 1051 */ 1052 public abstract static class AuthenticationCallback 1053 extends BiometricAuthenticator.AuthenticationCallback { 1054 1055 /** 1056 * Called when an unrecoverable error has been encountered and the operation is complete. 1057 * No further callbacks will be made on this object. 1058 * 1059 * @param errorCode An integer identifying the error message 1060 * @param errString A human-readable error string that can be shown in UI 1061 */ onAuthenticationError(int errorCode, CharSequence errString)1062 public void onAuthenticationError(int errorCode, CharSequence errString) { 1063 } 1064 1065 /** 1066 * Called when a recoverable error has been encountered during authentication. The help 1067 * string is provided to give the user guidance for what went wrong, such as 1068 * "Sensor dirty, please clean it." 1069 * 1070 * @param helpCode An integer identifying the error message 1071 * @param helpString A human-readable string that can be shown in UI 1072 */ onAuthenticationHelp(int helpCode, CharSequence helpString)1073 public void onAuthenticationHelp(int helpCode, CharSequence helpString) { 1074 } 1075 1076 /** 1077 * Called when a face is recognized. 1078 * 1079 * @param result An object containing authentication-related data 1080 */ onAuthenticationSucceeded(AuthenticationResult result)1081 public void onAuthenticationSucceeded(AuthenticationResult result) { 1082 } 1083 1084 /** 1085 * Called when a face is detected but not recognized. 1086 */ onAuthenticationFailed()1087 public void onAuthenticationFailed() { 1088 } 1089 1090 /** 1091 * Called when a face image has been acquired, but wasn't processed yet. 1092 * 1093 * @param acquireInfo one of FACE_ACQUIRED_* constants 1094 * @hide 1095 */ onAuthenticationAcquired(int acquireInfo)1096 public void onAuthenticationAcquired(int acquireInfo) { 1097 } 1098 } 1099 1100 /** 1101 * @hide 1102 */ 1103 public interface FaceDetectionCallback { onFaceDetected(int sensorId, int userId, boolean isStrongBiometric)1104 void onFaceDetected(int sensorId, int userId, boolean isStrongBiometric); 1105 1106 /** 1107 * An error has occurred with face detection. 1108 * 1109 * This callback signifies that this operation has been completed, and 1110 * no more callbacks should be expected. 1111 */ onDetectionError(int errorMsgId)1112 default void onDetectionError(int errorMsgId) {} 1113 } 1114 1115 /** 1116 * Callback structure provided to {@link FaceManager#enroll(long, 1117 * EnrollmentCallback, CancellationSignal, int). Users of {@link #FaceAuthenticationManager()} 1118 * must provide an implementation of this to {@link FaceManager#enroll(long, 1119 * CancellationSignal, int, EnrollmentCallback) for listening to face enrollment events. 1120 * 1121 * @hide 1122 */ 1123 public abstract static class EnrollmentCallback { 1124 1125 /** 1126 * Called when an unrecoverable error has been encountered and the operation is complete. 1127 * No further callbacks will be made on this object. 1128 * 1129 * @param errMsgId An integer identifying the error message 1130 * @param errString A human-readable error string that can be shown in UI 1131 */ onEnrollmentError(int errMsgId, CharSequence errString)1132 public void onEnrollmentError(int errMsgId, CharSequence errString) { 1133 } 1134 1135 /** 1136 * Called when a recoverable error has been encountered during enrollment. The help 1137 * string is provided to give the user guidance for what went wrong, such as 1138 * "Image too dark, uncover light source" or what they need to do next, such as 1139 * "Rotate face up / down." 1140 * 1141 * @param helpMsgId An integer identifying the error message 1142 * @param helpString A human-readable string that can be shown in UI 1143 */ onEnrollmentHelp(int helpMsgId, CharSequence helpString)1144 public void onEnrollmentHelp(int helpMsgId, CharSequence helpString) { 1145 } 1146 1147 /** 1148 * Called each time a single frame is captured during enrollment. 1149 * 1150 * <p>For older, non-AIDL implementations, only {@code helpCode} and {@code helpMessage} are 1151 * supported. Sensible default values will be provided for all other arguments. 1152 * 1153 * @param helpCode An integer identifying the capture status for this frame. 1154 * @param helpMessage A human-readable help string that can be shown in UI. 1155 * @param cell The cell captured during this frame of enrollment, if any. 1156 * @param stage An integer representing the current stage of enrollment. 1157 * @param pan The horizontal pan of the detected face. Values in the range [-1, 1] 1158 * indicate a good capture. 1159 * @param tilt The vertical tilt of the detected face. Values in the range [-1, 1] 1160 * indicate a good capture. 1161 * @param distance The distance of the detected face from the device. Values in 1162 * the range [-1, 1] indicate a good capture. 1163 */ onEnrollmentFrame( int helpCode, @Nullable CharSequence helpMessage, @Nullable FaceEnrollCell cell, @FaceEnrollStages.FaceEnrollStage int stage, float pan, float tilt, float distance)1164 public void onEnrollmentFrame( 1165 int helpCode, 1166 @Nullable CharSequence helpMessage, 1167 @Nullable FaceEnrollCell cell, 1168 @FaceEnrollStages.FaceEnrollStage int stage, 1169 float pan, 1170 float tilt, 1171 float distance) { 1172 onEnrollmentHelp(helpCode, helpMessage); 1173 } 1174 1175 /** 1176 * Called as each enrollment step progresses. Enrollment is considered complete when 1177 * remaining reaches 0. This function will not be called if enrollment fails. See 1178 * {@link EnrollmentCallback#onEnrollmentError(int, CharSequence)} 1179 * 1180 * @param remaining The number of remaining steps 1181 */ onEnrollmentProgress(int remaining)1182 public void onEnrollmentProgress(int remaining) { 1183 } 1184 } 1185 1186 /** 1187 * Callback structure provided to {@link #remove}. Users of {@link FaceManager} 1188 * may 1189 * optionally provide an implementation of this to 1190 * {@link #remove(Face, int, RemovalCallback)} for listening to face template 1191 * removal events. 1192 * 1193 * @hide 1194 */ 1195 public abstract static class RemovalCallback { 1196 1197 /** 1198 * Called when the given face can't be removed. 1199 * 1200 * @param face The face that the call attempted to remove 1201 * @param errMsgId An associated error message id 1202 * @param errString An error message indicating why the face id can't be removed 1203 */ onRemovalError(Face face, int errMsgId, CharSequence errString)1204 public void onRemovalError(Face face, int errMsgId, CharSequence errString) { 1205 } 1206 1207 /** 1208 * Called when a given face is successfully removed. 1209 * 1210 * @param face The face template that was removed. 1211 */ onRemovalSucceeded(@ullable Face face, int remaining)1212 public void onRemovalSucceeded(@Nullable Face face, int remaining) { 1213 } 1214 } 1215 1216 /** 1217 * @hide 1218 */ 1219 public abstract static class LockoutResetCallback { 1220 1221 /** 1222 * Called when lockout period expired and clients are allowed to listen for face 1223 * authentication 1224 * again. 1225 */ onLockoutReset(int sensorId)1226 public void onLockoutReset(int sensorId) { 1227 } 1228 } 1229 1230 /** 1231 * @hide 1232 */ 1233 public abstract static class SetFeatureCallback { onCompleted(boolean success, int feature)1234 public abstract void onCompleted(boolean success, int feature); 1235 } 1236 1237 /** 1238 * @hide 1239 */ 1240 public abstract static class GetFeatureCallback { onCompleted(boolean success, int[] features, boolean[] featureState)1241 public abstract void onCompleted(boolean success, int[] features, boolean[] featureState); 1242 } 1243 1244 /** 1245 * Callback structure provided to {@link #generateChallenge(int, int, 1246 * GenerateChallengeCallback)}. 1247 * 1248 * @hide 1249 */ 1250 public interface GenerateChallengeCallback { 1251 /** 1252 * Invoked when a challenge has been generated. 1253 */ onGenerateChallengeResult(int sensorId, int userId, long challenge)1254 void onGenerateChallengeResult(int sensorId, int userId, long challenge); 1255 } 1256 1257 private class OnEnrollCancelListener implements OnCancelListener { 1258 private final long mAuthRequestId; 1259 OnEnrollCancelListener(long id)1260 private OnEnrollCancelListener(long id) { 1261 mAuthRequestId = id; 1262 } 1263 1264 @Override onCancel()1265 public void onCancel() { 1266 Slog.d(TAG, "Cancel face enrollment requested for: " + mAuthRequestId); 1267 cancelEnrollment(mAuthRequestId); 1268 } 1269 } 1270 1271 private class OnAuthenticationCancelListener implements OnCancelListener { 1272 private final long mAuthRequestId; 1273 OnAuthenticationCancelListener(long id)1274 OnAuthenticationCancelListener(long id) { 1275 mAuthRequestId = id; 1276 } 1277 1278 @Override onCancel()1279 public void onCancel() { 1280 Slog.d(TAG, "Cancel face authentication requested for: " + mAuthRequestId); 1281 cancelAuthentication(mAuthRequestId); 1282 } 1283 } 1284 1285 private class OnFaceDetectionCancelListener implements OnCancelListener { 1286 private final long mAuthRequestId; 1287 OnFaceDetectionCancelListener(long id)1288 OnFaceDetectionCancelListener(long id) { 1289 mAuthRequestId = id; 1290 } 1291 1292 @Override onCancel()1293 public void onCancel() { 1294 Slog.d(TAG, "Cancel face detect requested for: " + mAuthRequestId); 1295 cancelFaceDetect(mAuthRequestId); 1296 } 1297 } 1298 1299 /** 1300 * @hide 1301 */ 1302 @Nullable getAuthHelpMessage(Context context, int acquireInfo, int vendorCode)1303 public static String getAuthHelpMessage(Context context, int acquireInfo, int vendorCode) { 1304 switch (acquireInfo) { 1305 // No help message is needed for a good capture. 1306 case FACE_ACQUIRED_GOOD: 1307 case FACE_ACQUIRED_START: 1308 return null; 1309 1310 // Consolidate positional feedback to reduce noise during authentication. 1311 case FACE_ACQUIRED_NOT_DETECTED: 1312 return context.getString(R.string.face_acquired_not_detected); 1313 case FACE_ACQUIRED_TOO_CLOSE: 1314 return context.getString(R.string.face_acquired_too_close); 1315 case FACE_ACQUIRED_TOO_FAR: 1316 return context.getString(R.string.face_acquired_too_far); 1317 case FACE_ACQUIRED_TOO_HIGH: 1318 // TODO(b/181269243) Change back once error codes are fixed. 1319 return context.getString(R.string.face_acquired_too_low); 1320 case FACE_ACQUIRED_TOO_LOW: 1321 // TODO(b/181269243) Change back once error codes are fixed. 1322 return context.getString(R.string.face_acquired_too_high); 1323 case FACE_ACQUIRED_TOO_RIGHT: 1324 // TODO(b/181269243) Change back once error codes are fixed. 1325 return context.getString(R.string.face_acquired_too_left); 1326 case FACE_ACQUIRED_TOO_LEFT: 1327 // TODO(b/181269243) Change back once error codes are fixed. 1328 return context.getString(R.string.face_acquired_too_right); 1329 case FACE_ACQUIRED_POOR_GAZE: 1330 return context.getString(R.string.face_acquired_poor_gaze); 1331 case FACE_ACQUIRED_PAN_TOO_EXTREME: 1332 return context.getString(R.string.face_acquired_pan_too_extreme); 1333 case FACE_ACQUIRED_TILT_TOO_EXTREME: 1334 return context.getString(R.string.face_acquired_tilt_too_extreme); 1335 case FACE_ACQUIRED_ROLL_TOO_EXTREME: 1336 return context.getString(R.string.face_acquired_roll_too_extreme); 1337 case FACE_ACQUIRED_INSUFFICIENT: 1338 return context.getString(R.string.face_acquired_insufficient); 1339 case FACE_ACQUIRED_TOO_BRIGHT: 1340 return context.getString(R.string.face_acquired_too_bright); 1341 case FACE_ACQUIRED_TOO_DARK: 1342 return context.getString(R.string.face_acquired_too_dark); 1343 case FACE_ACQUIRED_TOO_MUCH_MOTION: 1344 return context.getString(R.string.face_acquired_too_much_motion); 1345 case FACE_ACQUIRED_RECALIBRATE: 1346 return context.getString(R.string.face_acquired_recalibrate); 1347 case FACE_ACQUIRED_TOO_DIFFERENT: 1348 return context.getString(R.string.face_acquired_too_different); 1349 case FACE_ACQUIRED_TOO_SIMILAR: 1350 return context.getString(R.string.face_acquired_too_similar); 1351 case FACE_ACQUIRED_FACE_OBSCURED: 1352 return context.getString(R.string.face_acquired_obscured); 1353 case FACE_ACQUIRED_SENSOR_DIRTY: 1354 return context.getString(R.string.face_acquired_sensor_dirty); 1355 case FACE_ACQUIRED_DARK_GLASSES_DETECTED: 1356 return context.getString(R.string.face_acquired_dark_glasses_detected); 1357 case FACE_ACQUIRED_MOUTH_COVERING_DETECTED: 1358 return context.getString(R.string.face_acquired_mouth_covering_detected); 1359 1360 // Find and return the appropriate vendor-specific message. 1361 case FACE_ACQUIRED_VENDOR: { 1362 String[] msgArray = context.getResources().getStringArray( 1363 R.array.face_acquired_vendor); 1364 if (vendorCode < msgArray.length) { 1365 return msgArray[vendorCode]; 1366 } 1367 } 1368 } 1369 1370 Slog.w(TAG, "Unknown authentication acquired message: " + acquireInfo + ", " + vendorCode); 1371 return null; 1372 } 1373 1374 /** 1375 * @hide 1376 */ 1377 @Nullable getEnrollHelpMessage(Context context, int acquireInfo, int vendorCode)1378 public static String getEnrollHelpMessage(Context context, int acquireInfo, int vendorCode) { 1379 switch (acquireInfo) { 1380 case FACE_ACQUIRED_GOOD: 1381 case FACE_ACQUIRED_START: 1382 return null; 1383 case FACE_ACQUIRED_INSUFFICIENT: 1384 return context.getString(R.string.face_acquired_insufficient); 1385 case FACE_ACQUIRED_TOO_BRIGHT: 1386 return context.getString(R.string.face_acquired_too_bright); 1387 case FACE_ACQUIRED_TOO_DARK: 1388 return context.getString(R.string.face_acquired_too_dark); 1389 case FACE_ACQUIRED_TOO_CLOSE: 1390 return context.getString(R.string.face_acquired_too_close); 1391 case FACE_ACQUIRED_TOO_FAR: 1392 return context.getString(R.string.face_acquired_too_far); 1393 case FACE_ACQUIRED_TOO_HIGH: 1394 // TODO(b/181269243): Change back once error codes are fixed. 1395 return context.getString(R.string.face_acquired_too_low); 1396 case FACE_ACQUIRED_TOO_LOW: 1397 // TODO(b/181269243) Change back once error codes are fixed. 1398 return context.getString(R.string.face_acquired_too_high); 1399 case FACE_ACQUIRED_TOO_RIGHT: 1400 // TODO(b/181269243) Change back once error codes are fixed. 1401 return context.getString(R.string.face_acquired_too_left); 1402 case FACE_ACQUIRED_TOO_LEFT: 1403 // TODO(b/181269243) Change back once error codes are fixed. 1404 return context.getString(R.string.face_acquired_too_right); 1405 case FACE_ACQUIRED_POOR_GAZE: 1406 return context.getString(R.string.face_acquired_poor_gaze); 1407 case FACE_ACQUIRED_NOT_DETECTED: 1408 return context.getString(R.string.face_acquired_not_detected); 1409 case FACE_ACQUIRED_TOO_MUCH_MOTION: 1410 return context.getString(R.string.face_acquired_too_much_motion); 1411 case FACE_ACQUIRED_RECALIBRATE: 1412 return context.getString(R.string.face_acquired_recalibrate); 1413 case FACE_ACQUIRED_TOO_DIFFERENT: 1414 return context.getString(R.string.face_acquired_too_different); 1415 case FACE_ACQUIRED_TOO_SIMILAR: 1416 return context.getString(R.string.face_acquired_too_similar); 1417 case FACE_ACQUIRED_PAN_TOO_EXTREME: 1418 return context.getString(R.string.face_acquired_pan_too_extreme); 1419 case FACE_ACQUIRED_TILT_TOO_EXTREME: 1420 return context.getString(R.string.face_acquired_tilt_too_extreme); 1421 case FACE_ACQUIRED_ROLL_TOO_EXTREME: 1422 return context.getString(R.string.face_acquired_roll_too_extreme); 1423 case FACE_ACQUIRED_FACE_OBSCURED: 1424 return context.getString(R.string.face_acquired_obscured); 1425 case FACE_ACQUIRED_SENSOR_DIRTY: 1426 return context.getString(R.string.face_acquired_sensor_dirty); 1427 case FACE_ACQUIRED_DARK_GLASSES_DETECTED: 1428 return context.getString(R.string.face_acquired_dark_glasses_detected); 1429 case FACE_ACQUIRED_MOUTH_COVERING_DETECTED: 1430 return context.getString(R.string.face_acquired_mouth_covering_detected); 1431 case FACE_ACQUIRED_VENDOR: { 1432 String[] msgArray = context.getResources().getStringArray( 1433 R.array.face_acquired_vendor); 1434 if (vendorCode < msgArray.length) { 1435 return msgArray[vendorCode]; 1436 } 1437 } 1438 } 1439 Slog.w(TAG, "Unknown enrollment acquired message: " + acquireInfo + ", " + vendorCode); 1440 return null; 1441 } 1442 } 1443