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