1 /** 2 * Copyright (C) 2014 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.fingerprint; 18 19 import static android.Manifest.permission.INTERACT_ACROSS_USERS; 20 import static android.Manifest.permission.MANAGE_FINGERPRINT; 21 import static android.Manifest.permission.USE_BIOMETRIC; 22 import static android.Manifest.permission.USE_FINGERPRINT; 23 24 import android.annotation.NonNull; 25 import android.annotation.Nullable; 26 import android.annotation.RequiresFeature; 27 import android.annotation.RequiresPermission; 28 import android.annotation.SystemService; 29 import android.app.ActivityManager; 30 import android.compat.annotation.UnsupportedAppUsage; 31 import android.content.Context; 32 import android.content.pm.PackageManager; 33 import android.hardware.biometrics.BiometricAuthenticator; 34 import android.hardware.biometrics.BiometricFingerprintConstants; 35 import android.hardware.biometrics.BiometricPrompt; 36 import android.hardware.biometrics.IBiometricServiceLockoutResetCallback; 37 import android.os.Binder; 38 import android.os.CancellationSignal; 39 import android.os.CancellationSignal.OnCancelListener; 40 import android.os.Handler; 41 import android.os.IBinder; 42 import android.os.IRemoteCallback; 43 import android.os.Looper; 44 import android.os.PowerManager; 45 import android.os.RemoteException; 46 import android.os.UserHandle; 47 import android.security.identity.IdentityCredential; 48 import android.util.Slog; 49 50 import java.security.Signature; 51 import java.util.List; 52 import java.util.concurrent.Executor; 53 54 import javax.crypto.Cipher; 55 import javax.crypto.Mac; 56 57 /** 58 * A class that coordinates access to the fingerprint hardware. 59 * @deprecated See {@link BiometricPrompt} which shows a system-provided dialog upon starting 60 * authentication. In a world where devices may have different types of biometric authentication, 61 * it's much more realistic to have a system-provided authentication dialog since the method may 62 * vary by vendor/device. 63 */ 64 @Deprecated 65 @SystemService(Context.FINGERPRINT_SERVICE) 66 @RequiresFeature(PackageManager.FEATURE_FINGERPRINT) 67 public class FingerprintManager implements BiometricAuthenticator, BiometricFingerprintConstants { 68 69 private static final String TAG = "FingerprintManager"; 70 private static final boolean DEBUG = true; 71 private static final int MSG_ENROLL_RESULT = 100; 72 private static final int MSG_ACQUIRED = 101; 73 private static final int MSG_AUTHENTICATION_SUCCEEDED = 102; 74 private static final int MSG_AUTHENTICATION_FAILED = 103; 75 private static final int MSG_ERROR = 104; 76 private static final int MSG_REMOVED = 105; 77 private static final int MSG_ENUMERATED = 106; 78 79 private IFingerprintService mService; 80 private Context mContext; 81 private IBinder mToken = new Binder(); 82 private AuthenticationCallback mAuthenticationCallback; 83 private EnrollmentCallback mEnrollmentCallback; 84 private RemovalCallback mRemovalCallback; 85 private EnumerateCallback mEnumerateCallback; 86 private CryptoObject mCryptoObject; 87 private Fingerprint mRemovalFingerprint; 88 private Handler mHandler; 89 90 private class OnEnrollCancelListener implements OnCancelListener { 91 @Override onCancel()92 public void onCancel() { 93 cancelEnrollment(); 94 } 95 } 96 97 private class OnAuthenticationCancelListener implements OnCancelListener { 98 private android.hardware.biometrics.CryptoObject mCrypto; 99 OnAuthenticationCancelListener(android.hardware.biometrics.CryptoObject crypto)100 public OnAuthenticationCancelListener(android.hardware.biometrics.CryptoObject crypto) { 101 mCrypto = crypto; 102 } 103 104 @Override onCancel()105 public void onCancel() { 106 cancelAuthentication(mCrypto); 107 } 108 } 109 110 /** 111 * A wrapper class for the crypto objects supported by FingerprintManager. Currently the 112 * framework supports {@link Signature}, {@link Cipher} and {@link Mac} objects. 113 * @deprecated See {@link android.hardware.biometrics.BiometricPrompt.CryptoObject} 114 */ 115 @Deprecated 116 public static final class CryptoObject extends android.hardware.biometrics.CryptoObject { CryptoObject(@onNull Signature signature)117 public CryptoObject(@NonNull Signature signature) { 118 super(signature); 119 } 120 CryptoObject(@onNull Cipher cipher)121 public CryptoObject(@NonNull Cipher cipher) { 122 super(cipher); 123 } 124 CryptoObject(@onNull Mac mac)125 public CryptoObject(@NonNull Mac mac) { 126 super(mac); 127 } 128 129 /** 130 * Get {@link Signature} object. 131 * @return {@link Signature} object or null if this doesn't contain one. 132 */ getSignature()133 public Signature getSignature() { 134 return super.getSignature(); 135 } 136 137 /** 138 * Get {@link Cipher} object. 139 * @return {@link Cipher} object or null if this doesn't contain one. 140 */ getCipher()141 public Cipher getCipher() { 142 return super.getCipher(); 143 } 144 145 /** 146 * Get {@link Mac} object. 147 * @return {@link Mac} object or null if this doesn't contain one. 148 */ getMac()149 public Mac getMac() { 150 return super.getMac(); 151 } 152 153 /** 154 * Get {@link IdentityCredential} object. 155 * @return {@link IdentityCredential} object or null if this doesn't contain one. 156 * @hide 157 */ getIdentityCredential()158 public IdentityCredential getIdentityCredential() { 159 return super.getIdentityCredential(); 160 } 161 } 162 163 /** 164 * Container for callback data from {@link FingerprintManager#authenticate(CryptoObject, 165 * CancellationSignal, int, AuthenticationCallback, Handler)}. 166 * @deprecated See {@link android.hardware.biometrics.BiometricPrompt.AuthenticationResult} 167 */ 168 @Deprecated 169 public static class AuthenticationResult { 170 private Fingerprint mFingerprint; 171 private CryptoObject mCryptoObject; 172 private int mUserId; 173 174 /** 175 * Authentication result 176 * 177 * @param crypto the crypto object 178 * @param fingerprint the recognized fingerprint data, if allowed. 179 * @hide 180 */ AuthenticationResult(CryptoObject crypto, Fingerprint fingerprint, int userId)181 public AuthenticationResult(CryptoObject crypto, Fingerprint fingerprint, int userId) { 182 mCryptoObject = crypto; 183 mFingerprint = fingerprint; 184 mUserId = userId; 185 } 186 187 /** 188 * Obtain the crypto object associated with this transaction 189 * @return crypto object provided to {@link FingerprintManager#authenticate(CryptoObject, 190 * CancellationSignal, int, AuthenticationCallback, Handler)}. 191 */ getCryptoObject()192 public CryptoObject getCryptoObject() { return mCryptoObject; } 193 194 /** 195 * Obtain the Fingerprint associated with this operation. Applications are strongly 196 * discouraged from associating specific fingers with specific applications or operations. 197 * 198 * @hide 199 */ 200 @UnsupportedAppUsage getFingerprint()201 public Fingerprint getFingerprint() { return mFingerprint; } 202 203 /** 204 * Obtain the userId for which this fingerprint was authenticated. 205 * @hide 206 */ getUserId()207 public int getUserId() { return mUserId; } 208 }; 209 210 /** 211 * Callback structure provided to {@link FingerprintManager#authenticate(CryptoObject, 212 * CancellationSignal, int, AuthenticationCallback, Handler)}. Users of {@link 213 * FingerprintManager#authenticate(CryptoObject, CancellationSignal, 214 * int, AuthenticationCallback, Handler) } must provide an implementation of this for listening to 215 * fingerprint events. 216 * @deprecated See {@link android.hardware.biometrics.BiometricPrompt.AuthenticationCallback} 217 */ 218 @Deprecated 219 public static abstract class AuthenticationCallback 220 extends BiometricAuthenticator.AuthenticationCallback { 221 /** 222 * Called when an unrecoverable error has been encountered and the operation is complete. 223 * No further callbacks will be made on this object. 224 * @param errorCode An integer identifying the error message 225 * @param errString A human-readable error string that can be shown in UI 226 */ 227 @Override onAuthenticationError(int errorCode, CharSequence errString)228 public void onAuthenticationError(int errorCode, CharSequence errString) { } 229 230 /** 231 * Called when a recoverable error has been encountered during authentication. The help 232 * string is provided to give the user guidance for what went wrong, such as 233 * "Sensor dirty, please clean it." 234 * @param helpCode An integer identifying the error message 235 * @param helpString A human-readable string that can be shown in UI 236 */ 237 @Override onAuthenticationHelp(int helpCode, CharSequence helpString)238 public void onAuthenticationHelp(int helpCode, CharSequence helpString) { } 239 240 /** 241 * Called when a fingerprint is recognized. 242 * @param result An object containing authentication-related data 243 */ onAuthenticationSucceeded(AuthenticationResult result)244 public void onAuthenticationSucceeded(AuthenticationResult result) { } 245 246 /** 247 * Called when a fingerprint is valid but not recognized. 248 */ 249 @Override onAuthenticationFailed()250 public void onAuthenticationFailed() { } 251 252 /** 253 * Called when a fingerprint image has been acquired, but wasn't processed yet. 254 * 255 * @param acquireInfo one of FINGERPRINT_ACQUIRED_* constants 256 * @hide 257 */ 258 @Override onAuthenticationAcquired(int acquireInfo)259 public void onAuthenticationAcquired(int acquireInfo) {} 260 }; 261 262 /** 263 * Callback structure provided to {@link FingerprintManager#enroll(byte[], CancellationSignal, 264 * int, int, EnrollmentCallback)} must provide an implementation of this for listening to 265 * fingerprint events. 266 * 267 * @hide 268 */ 269 public static abstract class EnrollmentCallback { 270 /** 271 * Called when an unrecoverable error has been encountered and the operation is complete. 272 * No further callbacks will be made on this object. 273 * @param errMsgId An integer identifying the error message 274 * @param errString A human-readable error string that can be shown in UI 275 */ onEnrollmentError(int errMsgId, CharSequence errString)276 public void onEnrollmentError(int errMsgId, CharSequence errString) { } 277 278 /** 279 * Called when a recoverable error has been encountered during enrollment. The help 280 * string is provided to give the user guidance for what went wrong, such as 281 * "Sensor dirty, please clean it" or what they need to do next, such as 282 * "Touch sensor again." 283 * @param helpMsgId An integer identifying the error message 284 * @param helpString A human-readable string that can be shown in UI 285 */ onEnrollmentHelp(int helpMsgId, CharSequence helpString)286 public void onEnrollmentHelp(int helpMsgId, CharSequence helpString) { } 287 288 /** 289 * Called as each enrollment step progresses. Enrollment is considered complete when 290 * remaining reaches 0. This function will not be called if enrollment fails. See 291 * {@link EnrollmentCallback#onEnrollmentError(int, CharSequence)} 292 * @param remaining The number of remaining steps 293 */ onEnrollmentProgress(int remaining)294 public void onEnrollmentProgress(int remaining) { } 295 }; 296 297 /** 298 * Callback structure provided to {@link #remove}. Users of {@link FingerprintManager} may 299 * optionally provide an implementation of this to 300 * {@link #remove(Fingerprint, int, RemovalCallback)} for listening to fingerprint template 301 * removal events. 302 * 303 * @hide 304 */ 305 public static abstract class RemovalCallback { 306 /** 307 * Called when the given fingerprint can't be removed. 308 * @param fp The fingerprint that the call attempted to remove 309 * @param errMsgId An associated error message id 310 * @param errString An error message indicating why the fingerprint id can't be removed 311 */ onRemovalError(Fingerprint fp, int errMsgId, CharSequence errString)312 public void onRemovalError(Fingerprint fp, int errMsgId, CharSequence errString) { } 313 314 /** 315 * Called when a given fingerprint is successfully removed. 316 * @param fp The fingerprint template that was removed. 317 * @param remaining The number of fingerprints yet to be removed in this operation. If 318 * {@link #remove} is called on one fingerprint, this should be 0. If 319 * {@link #remove} is called on a group, this should be the number of remaining 320 * fingerprints in the group, and 0 after the last fingerprint is removed. 321 */ onRemovalSucceeded(Fingerprint fp, int remaining)322 public void onRemovalSucceeded(Fingerprint fp, int remaining) { } 323 }; 324 325 /** 326 * Callback structure provided to {@link FingerprintManager#enumerate(int, EnumerateCallback)}. 327 * Users of{@link #FingerprintManager} may optionally provide an implementation of this to 328 * {@link FingerprintManager#enumerate(int, EnumerateCallback)} for listening to 329 * fingerprint template removal events. 330 * 331 * @hide 332 */ 333 public static abstract class EnumerateCallback { 334 /** 335 * Called when the given fingerprint can't be removed. 336 * @param errMsgId An associated error message id 337 * @param errString An error message indicating why the fingerprint id can't be removed 338 */ onEnumerateError(int errMsgId, CharSequence errString)339 public void onEnumerateError(int errMsgId, CharSequence errString) { } 340 341 /** 342 * Called when a given fingerprint is successfully removed. 343 * @param fingerprint the fingerprint template that was removed. 344 */ onEnumerate(Fingerprint fingerprint)345 public void onEnumerate(Fingerprint fingerprint) { } 346 }; 347 348 /** 349 * @hide 350 */ 351 public static abstract class LockoutResetCallback { 352 353 /** 354 * Called when lockout period expired and clients are allowed to listen for fingerprint 355 * again. 356 */ onLockoutReset()357 public void onLockoutReset() { } 358 }; 359 360 /** 361 * Request authentication of a crypto object. This call warms up the fingerprint hardware 362 * and starts scanning for a fingerprint. It terminates when 363 * {@link AuthenticationCallback#onAuthenticationError(int, CharSequence)} or 364 * {@link AuthenticationCallback#onAuthenticationSucceeded(AuthenticationResult)} is called, at 365 * which point the object is no longer valid. The operation can be canceled by using the 366 * provided cancel object. 367 * 368 * @param crypto object associated with the call or null if none required. 369 * @param cancel an object that can be used to cancel authentication 370 * @param flags optional flags; should be 0 371 * @param callback an object to receive authentication events 372 * @param handler an optional handler to handle callback events 373 * 374 * @throws IllegalArgumentException if the crypto operation is not supported or is not backed 375 * by <a href="{@docRoot}training/articles/keystore.html">Android Keystore 376 * facility</a>. 377 * @throws IllegalStateException if the crypto primitive is not initialized. 378 * @deprecated See {@link BiometricPrompt#authenticate(CancellationSignal, Executor, 379 * BiometricPrompt.AuthenticationCallback)} and {@link BiometricPrompt#authenticate( 380 * BiometricPrompt.CryptoObject, CancellationSignal, Executor, 381 * BiometricPrompt.AuthenticationCallback)} 382 */ 383 @Deprecated 384 @RequiresPermission(anyOf = {USE_BIOMETRIC, USE_FINGERPRINT}) authenticate(@ullable CryptoObject crypto, @Nullable CancellationSignal cancel, int flags, @NonNull AuthenticationCallback callback, @Nullable Handler handler)385 public void authenticate(@Nullable CryptoObject crypto, @Nullable CancellationSignal cancel, 386 int flags, @NonNull AuthenticationCallback callback, @Nullable Handler handler) { 387 authenticate(crypto, cancel, flags, callback, handler, mContext.getUserId()); 388 } 389 390 /** 391 * Use the provided handler thread for events. 392 * @param handler 393 */ useHandler(Handler handler)394 private void useHandler(Handler handler) { 395 if (handler != null) { 396 mHandler = new MyHandler(handler.getLooper()); 397 } else if (mHandler.getLooper() != mContext.getMainLooper()){ 398 mHandler = new MyHandler(mContext.getMainLooper()); 399 } 400 } 401 402 /** 403 * Per-user version, see {@link FingerprintManager#authenticate(CryptoObject, 404 * CancellationSignal, int, AuthenticationCallback, Handler)}. This version does not 405 * display the BiometricPrompt. 406 * @param userId the user ID that the fingerprint hardware will authenticate for. 407 * @hide 408 */ 409 @RequiresPermission(anyOf = {USE_BIOMETRIC, USE_FINGERPRINT}) authenticate(@ullable CryptoObject crypto, @Nullable CancellationSignal cancel, int flags, @NonNull AuthenticationCallback callback, Handler handler, int userId)410 public void authenticate(@Nullable CryptoObject crypto, @Nullable CancellationSignal cancel, 411 int flags, @NonNull AuthenticationCallback callback, Handler handler, int userId) { 412 if (callback == null) { 413 throw new IllegalArgumentException("Must supply an authentication callback"); 414 } 415 416 if (cancel != null) { 417 if (cancel.isCanceled()) { 418 Slog.w(TAG, "authentication already canceled"); 419 return; 420 } else { 421 cancel.setOnCancelListener(new OnAuthenticationCancelListener(crypto)); 422 } 423 } 424 425 if (mService != null) try { 426 useHandler(handler); 427 mAuthenticationCallback = callback; 428 mCryptoObject = crypto; 429 long sessionId = crypto != null ? crypto.getOpId() : 0; 430 mService.authenticate(mToken, sessionId, userId, mServiceReceiver, flags, 431 mContext.getOpPackageName()); 432 } catch (RemoteException e) { 433 Slog.w(TAG, "Remote exception while authenticating: ", e); 434 if (callback != null) { 435 // Though this may not be a hardware issue, it will cause apps to give up or try 436 // again later. 437 callback.onAuthenticationError(FINGERPRINT_ERROR_HW_UNAVAILABLE, 438 getErrorString(mContext, FINGERPRINT_ERROR_HW_UNAVAILABLE, 439 0 /* vendorCode */)); 440 } 441 } 442 } 443 444 /** 445 * Request fingerprint enrollment. This call warms up the fingerprint hardware 446 * and starts scanning for fingerprints. Progress will be indicated by callbacks to the 447 * {@link EnrollmentCallback} object. It terminates when 448 * {@link EnrollmentCallback#onEnrollmentError(int, CharSequence)} or 449 * {@link EnrollmentCallback#onEnrollmentProgress(int) is called with remaining == 0, at 450 * which point the object is no longer valid. The operation can be canceled by using the 451 * provided cancel object. 452 * @param token a unique token provided by a recent creation or verification of device 453 * credentials (e.g. pin, pattern or password). 454 * @param cancel an object that can be used to cancel enrollment 455 * @param flags optional flags 456 * @param userId the user to whom this fingerprint will belong to 457 * @param callback an object to receive enrollment events 458 * @hide 459 */ 460 @RequiresPermission(MANAGE_FINGERPRINT) enroll(byte [] token, CancellationSignal cancel, int flags, int userId, EnrollmentCallback callback)461 public void enroll(byte [] token, CancellationSignal cancel, int flags, 462 int userId, EnrollmentCallback callback) { 463 if (userId == UserHandle.USER_CURRENT) { 464 userId = getCurrentUserId(); 465 } 466 if (callback == null) { 467 throw new IllegalArgumentException("Must supply an enrollment callback"); 468 } 469 470 if (cancel != null) { 471 if (cancel.isCanceled()) { 472 Slog.w(TAG, "enrollment already canceled"); 473 return; 474 } else { 475 cancel.setOnCancelListener(new OnEnrollCancelListener()); 476 } 477 } 478 479 if (mService != null) try { 480 mEnrollmentCallback = callback; 481 mService.enroll(mToken, token, userId, mServiceReceiver, flags, 482 mContext.getOpPackageName()); 483 } catch (RemoteException e) { 484 Slog.w(TAG, "Remote exception in enroll: ", e); 485 if (callback != null) { 486 // Though this may not be a hardware issue, it will cause apps to give up or try 487 // again later. 488 callback.onEnrollmentError(FINGERPRINT_ERROR_HW_UNAVAILABLE, 489 getErrorString(mContext, FINGERPRINT_ERROR_HW_UNAVAILABLE, 490 0 /* vendorCode */)); 491 } 492 } 493 } 494 495 /** 496 * Requests a pre-enrollment auth token to tie enrollment to the confirmation of 497 * existing device credentials (e.g. pin/pattern/password). 498 * @hide 499 */ 500 @RequiresPermission(MANAGE_FINGERPRINT) preEnroll()501 public long preEnroll() { 502 long result = 0; 503 if (mService != null) try { 504 result = mService.preEnroll(mToken); 505 } catch (RemoteException e) { 506 throw e.rethrowFromSystemServer(); 507 } 508 return result; 509 } 510 511 /** 512 * Finishes enrollment and cancels the current auth token. 513 * @hide 514 */ 515 @RequiresPermission(MANAGE_FINGERPRINT) postEnroll()516 public int postEnroll() { 517 int result = 0; 518 if (mService != null) try { 519 result = mService.postEnroll(mToken); 520 } catch (RemoteException e) { 521 throw e.rethrowFromSystemServer(); 522 } 523 return result; 524 } 525 526 /** 527 * Sets the active user. This is meant to be used to select the current profile for enrollment 528 * to allow separate enrolled fingers for a work profile 529 * @param userId 530 * @hide 531 */ 532 @RequiresPermission(MANAGE_FINGERPRINT) 533 @Override setActiveUser(int userId)534 public void setActiveUser(int userId) { 535 if (mService != null) try { 536 mService.setActiveUser(userId); 537 } catch (RemoteException e) { 538 throw e.rethrowFromSystemServer(); 539 } 540 } 541 542 /** 543 * Remove given fingerprint template from fingerprint hardware and/or protected storage. 544 * @param fp the fingerprint item to remove 545 * @param userId the user who this fingerprint belongs to 546 * @param callback an optional callback to verify that fingerprint templates have been 547 * successfully removed. May be null of no callback is required. 548 * 549 * @hide 550 */ 551 @RequiresPermission(MANAGE_FINGERPRINT) remove(Fingerprint fp, int userId, RemovalCallback callback)552 public void remove(Fingerprint fp, int userId, RemovalCallback callback) { 553 if (mService != null) try { 554 mRemovalCallback = callback; 555 mRemovalFingerprint = fp; 556 mService.remove(mToken, fp.getBiometricId(), fp.getGroupId(), userId, mServiceReceiver); 557 } catch (RemoteException e) { 558 Slog.w(TAG, "Remote exception in remove: ", e); 559 if (callback != null) { 560 callback.onRemovalError(fp, FINGERPRINT_ERROR_HW_UNAVAILABLE, 561 getErrorString(mContext, FINGERPRINT_ERROR_HW_UNAVAILABLE, 562 0 /* vendorCode */)); 563 } 564 } 565 } 566 567 /** 568 * Enumerate all fingerprint templates stored in hardware and/or protected storage. 569 * @param userId the user who this fingerprint belongs to 570 * @param callback an optional callback to verify that fingerprint templates have been 571 * successfully removed. May be null of no callback is required. 572 * 573 * @hide 574 */ 575 @RequiresPermission(MANAGE_FINGERPRINT) enumerate(int userId, @NonNull EnumerateCallback callback)576 public void enumerate(int userId, @NonNull EnumerateCallback callback) { 577 if (mService != null) try { 578 mEnumerateCallback = callback; 579 mService.enumerate(mToken, userId, mServiceReceiver); 580 } catch (RemoteException e) { 581 Slog.w(TAG, "Remote exception in enumerate: ", e); 582 if (callback != null) { 583 callback.onEnumerateError(FINGERPRINT_ERROR_HW_UNAVAILABLE, 584 getErrorString(mContext, FINGERPRINT_ERROR_HW_UNAVAILABLE, 585 0 /* vendorCode */)); 586 } 587 } 588 } 589 590 /** 591 * Renames the given fingerprint template 592 * @param fpId the fingerprint id 593 * @param userId the user who this fingerprint belongs to 594 * @param newName the new name 595 * 596 * @hide 597 */ 598 @RequiresPermission(MANAGE_FINGERPRINT) rename(int fpId, int userId, String newName)599 public void rename(int fpId, int userId, String newName) { 600 // Renames the given fpId 601 if (mService != null) { 602 try { 603 mService.rename(fpId, userId, newName); 604 } catch (RemoteException e) { 605 throw e.rethrowFromSystemServer(); 606 } 607 } else { 608 Slog.w(TAG, "rename(): Service not connected!"); 609 } 610 } 611 612 /** 613 * Obtain the list of enrolled fingerprints templates. 614 * @return list of current fingerprint items 615 * 616 * @hide 617 */ 618 @RequiresPermission(USE_FINGERPRINT) 619 @UnsupportedAppUsage getEnrolledFingerprints(int userId)620 public List<Fingerprint> getEnrolledFingerprints(int userId) { 621 if (mService != null) try { 622 return mService.getEnrolledFingerprints(userId, mContext.getOpPackageName()); 623 } catch (RemoteException e) { 624 throw e.rethrowFromSystemServer(); 625 } 626 return null; 627 } 628 629 /** 630 * Obtain the list of enrolled fingerprints templates. 631 * @return list of current fingerprint items 632 * 633 * @hide 634 */ 635 @RequiresPermission(USE_FINGERPRINT) 636 @UnsupportedAppUsage getEnrolledFingerprints()637 public List<Fingerprint> getEnrolledFingerprints() { 638 return getEnrolledFingerprints(mContext.getUserId()); 639 } 640 641 /** 642 * @hide 643 */ 644 @Override hasEnrolledTemplates()645 public boolean hasEnrolledTemplates() { 646 return hasEnrolledFingerprints(); 647 } 648 649 /** 650 * @hide 651 */ 652 @Override hasEnrolledTemplates(int userId)653 public boolean hasEnrolledTemplates(int userId) { 654 return hasEnrolledFingerprints(userId); 655 } 656 657 /** 658 * Determine if there is at least one fingerprint enrolled. 659 * 660 * @return true if at least one fingerprint is enrolled, false otherwise 661 * @deprecated See {@link BiometricPrompt} and 662 * {@link FingerprintManager#FINGERPRINT_ERROR_NO_FINGERPRINTS} 663 */ 664 @Deprecated 665 @RequiresPermission(USE_FINGERPRINT) hasEnrolledFingerprints()666 public boolean hasEnrolledFingerprints() { 667 if (mService != null) try { 668 return mService.hasEnrolledFingerprints( 669 mContext.getUserId(), mContext.getOpPackageName()); 670 } catch (RemoteException e) { 671 throw e.rethrowFromSystemServer(); 672 } 673 return false; 674 } 675 676 /** 677 * @hide 678 */ 679 @RequiresPermission(allOf = { 680 USE_FINGERPRINT, 681 INTERACT_ACROSS_USERS}) hasEnrolledFingerprints(int userId)682 public boolean hasEnrolledFingerprints(int userId) { 683 if (mService != null) try { 684 return mService.hasEnrolledFingerprints(userId, mContext.getOpPackageName()); 685 } catch (RemoteException e) { 686 throw e.rethrowFromSystemServer(); 687 } 688 return false; 689 } 690 691 /** 692 * Determine if fingerprint hardware is present and functional. 693 * 694 * @return true if hardware is present and functional, false otherwise. 695 * @deprecated See {@link BiometricPrompt} and 696 * {@link FingerprintManager#FINGERPRINT_ERROR_HW_UNAVAILABLE} 697 */ 698 @Deprecated 699 @RequiresPermission(USE_FINGERPRINT) 700 @Override isHardwareDetected()701 public boolean isHardwareDetected() { 702 if (mService != null) { 703 try { 704 long deviceId = 0; /* TODO: plumb hardware id to FPMS */ 705 return mService.isHardwareDetected(deviceId, mContext.getOpPackageName()); 706 } catch (RemoteException e) { 707 throw e.rethrowFromSystemServer(); 708 } 709 } else { 710 Slog.w(TAG, "isFingerprintHardwareDetected(): Service not connected!"); 711 } 712 return false; 713 } 714 715 /** 716 * Retrieves the authenticator token for binding keys to the lifecycle 717 * of the calling user's fingerprints. Used only by internal clients. 718 * 719 * @hide 720 */ 721 @UnsupportedAppUsage getAuthenticatorId()722 public long getAuthenticatorId() { 723 if (mService != null) { 724 try { 725 return mService.getAuthenticatorId(mContext.getOpPackageName()); 726 } catch (RemoteException e) { 727 throw e.rethrowFromSystemServer(); 728 } 729 } else { 730 Slog.w(TAG, "getAuthenticatorId(): Service not connected!"); 731 } 732 return 0; 733 } 734 735 /** 736 * @hide 737 */ addLockoutResetCallback(final LockoutResetCallback callback)738 public void addLockoutResetCallback(final LockoutResetCallback callback) { 739 if (mService != null) { 740 try { 741 final PowerManager powerManager = mContext.getSystemService(PowerManager.class); 742 mService.addLockoutResetCallback( 743 new IBiometricServiceLockoutResetCallback.Stub() { 744 745 @Override 746 public void onLockoutReset(long deviceId, IRemoteCallback serverCallback) 747 throws RemoteException { 748 try { 749 final PowerManager.WakeLock wakeLock = powerManager.newWakeLock( 750 PowerManager.PARTIAL_WAKE_LOCK, "lockoutResetCallback"); 751 wakeLock.acquire(); 752 mHandler.post(() -> { 753 try { 754 callback.onLockoutReset(); 755 } finally { 756 wakeLock.release(); 757 } 758 }); 759 } finally { 760 serverCallback.sendResult(null /* data */); 761 } 762 } 763 }); 764 } catch (RemoteException e) { 765 throw e.rethrowFromSystemServer(); 766 } 767 } else { 768 Slog.w(TAG, "addLockoutResetCallback(): Service not connected!"); 769 } 770 } 771 772 private class MyHandler extends Handler { MyHandler(Context context)773 private MyHandler(Context context) { 774 super(context.getMainLooper()); 775 } 776 MyHandler(Looper looper)777 private MyHandler(Looper looper) { 778 super(looper); 779 } 780 781 @Override handleMessage(android.os.Message msg)782 public void handleMessage(android.os.Message msg) { 783 switch (msg.what) { 784 case MSG_ENROLL_RESULT: 785 sendEnrollResult((Fingerprint) msg.obj, msg.arg1 /* remaining */); 786 break; 787 case MSG_ACQUIRED: 788 sendAcquiredResult((Long) msg.obj /* deviceId */, msg.arg1 /* acquire info */, 789 msg.arg2 /* vendorCode */); 790 break; 791 case MSG_AUTHENTICATION_SUCCEEDED: 792 sendAuthenticatedSucceeded((Fingerprint) msg.obj, msg.arg1 /* userId */); 793 break; 794 case MSG_AUTHENTICATION_FAILED: 795 sendAuthenticatedFailed(); 796 break; 797 case MSG_ERROR: 798 sendErrorResult((Long) msg.obj /* deviceId */, msg.arg1 /* errMsgId */, 799 msg.arg2 /* vendorCode */); 800 break; 801 case MSG_REMOVED: 802 sendRemovedResult((Fingerprint) msg.obj, msg.arg1 /* remaining */); 803 break; 804 case MSG_ENUMERATED: 805 sendEnumeratedResult((Long) msg.obj /* deviceId */, msg.arg1 /* fingerId */, 806 msg.arg2 /* groupId */); 807 break; 808 } 809 } 810 }; 811 sendRemovedResult(Fingerprint fingerprint, int remaining)812 private void sendRemovedResult(Fingerprint fingerprint, int remaining) { 813 if (mRemovalCallback == null) { 814 return; 815 } 816 if (fingerprint == null) { 817 Slog.e(TAG, "Received MSG_REMOVED, but fingerprint is null"); 818 return; 819 } 820 821 int fingerId = fingerprint.getBiometricId(); 822 int reqFingerId = mRemovalFingerprint.getBiometricId(); 823 if (reqFingerId != 0 && fingerId != 0 && fingerId != reqFingerId) { 824 Slog.w(TAG, "Finger id didn't match: " + fingerId + " != " + reqFingerId); 825 return; 826 } 827 int groupId = fingerprint.getGroupId(); 828 int reqGroupId = mRemovalFingerprint.getGroupId(); 829 if (groupId != reqGroupId) { 830 Slog.w(TAG, "Group id didn't match: " + groupId + " != " + reqGroupId); 831 return; 832 } 833 834 mRemovalCallback.onRemovalSucceeded(fingerprint, remaining); 835 } 836 sendEnumeratedResult(long deviceId, int fingerId, int groupId)837 private void sendEnumeratedResult(long deviceId, int fingerId, int groupId) { 838 if (mEnumerateCallback != null) { 839 mEnumerateCallback.onEnumerate(new Fingerprint(null, groupId, fingerId, deviceId)); 840 } 841 } 842 sendEnrollResult(Fingerprint fp, int remaining)843 private void sendEnrollResult(Fingerprint fp, int remaining) { 844 if (mEnrollmentCallback != null) { 845 mEnrollmentCallback.onEnrollmentProgress(remaining); 846 } 847 } 848 sendAuthenticatedSucceeded(Fingerprint fp, int userId)849 private void sendAuthenticatedSucceeded(Fingerprint fp, int userId) { 850 if (mAuthenticationCallback != null) { 851 final AuthenticationResult result = 852 new AuthenticationResult(mCryptoObject, fp, userId); 853 mAuthenticationCallback.onAuthenticationSucceeded(result); 854 } 855 } 856 sendAuthenticatedFailed()857 private void sendAuthenticatedFailed() { 858 if (mAuthenticationCallback != null) { 859 mAuthenticationCallback.onAuthenticationFailed(); 860 } 861 } 862 sendAcquiredResult(long deviceId, int acquireInfo, int vendorCode)863 private void sendAcquiredResult(long deviceId, int acquireInfo, int vendorCode) { 864 if (mAuthenticationCallback != null) { 865 mAuthenticationCallback.onAuthenticationAcquired(acquireInfo); 866 } 867 final String msg = getAcquiredString(mContext, acquireInfo, vendorCode); 868 if (msg == null) { 869 return; 870 } 871 // emulate HAL 2.1 behavior and send real acquiredInfo 872 final int clientInfo = acquireInfo == FINGERPRINT_ACQUIRED_VENDOR 873 ? (vendorCode + FINGERPRINT_ACQUIRED_VENDOR_BASE) : acquireInfo; 874 if (mEnrollmentCallback != null) { 875 mEnrollmentCallback.onEnrollmentHelp(clientInfo, msg); 876 } else if (mAuthenticationCallback != null) { 877 mAuthenticationCallback.onAuthenticationHelp(clientInfo, msg); 878 } 879 } 880 sendErrorResult(long deviceId, int errMsgId, int vendorCode)881 private void sendErrorResult(long deviceId, int errMsgId, int vendorCode) { 882 // emulate HAL 2.1 behavior and send real errMsgId 883 final int clientErrMsgId = errMsgId == FINGERPRINT_ERROR_VENDOR 884 ? (vendorCode + FINGERPRINT_ERROR_VENDOR_BASE) : errMsgId; 885 if (mEnrollmentCallback != null) { 886 mEnrollmentCallback.onEnrollmentError(clientErrMsgId, 887 getErrorString(mContext, errMsgId, vendorCode)); 888 } else if (mAuthenticationCallback != null) { 889 mAuthenticationCallback.onAuthenticationError(clientErrMsgId, 890 getErrorString(mContext, errMsgId, vendorCode)); 891 } else if (mRemovalCallback != null) { 892 mRemovalCallback.onRemovalError(mRemovalFingerprint, clientErrMsgId, 893 getErrorString(mContext, errMsgId, vendorCode)); 894 } else if (mEnumerateCallback != null) { 895 mEnumerateCallback.onEnumerateError(clientErrMsgId, 896 getErrorString(mContext, errMsgId, vendorCode)); 897 } 898 } 899 900 /** 901 * @hide 902 */ FingerprintManager(Context context, IFingerprintService service)903 public FingerprintManager(Context context, IFingerprintService service) { 904 mContext = context; 905 mService = service; 906 if (mService == null) { 907 Slog.v(TAG, "FingerprintManagerService was null"); 908 } 909 mHandler = new MyHandler(context); 910 } 911 getCurrentUserId()912 private int getCurrentUserId() { 913 try { 914 return ActivityManager.getService().getCurrentUser().id; 915 } catch (RemoteException e) { 916 throw e.rethrowFromSystemServer(); 917 } 918 } 919 cancelEnrollment()920 private void cancelEnrollment() { 921 if (mService != null) try { 922 mService.cancelEnrollment(mToken); 923 } catch (RemoteException e) { 924 throw e.rethrowFromSystemServer(); 925 } 926 } 927 cancelAuthentication(android.hardware.biometrics.CryptoObject cryptoObject)928 private void cancelAuthentication(android.hardware.biometrics.CryptoObject cryptoObject) { 929 if (mService != null) try { 930 mService.cancelAuthentication(mToken, mContext.getOpPackageName()); 931 } catch (RemoteException e) { 932 throw e.rethrowFromSystemServer(); 933 } 934 } 935 936 /** 937 * @hide 938 */ getErrorString(Context context, int errMsg, int vendorCode)939 public static String getErrorString(Context context, int errMsg, int vendorCode) { 940 switch (errMsg) { 941 case FINGERPRINT_ERROR_HW_UNAVAILABLE: 942 return context.getString( 943 com.android.internal.R.string.fingerprint_error_hw_not_available); 944 case FINGERPRINT_ERROR_UNABLE_TO_PROCESS: 945 return context.getString( 946 com.android.internal.R.string.fingerprint_error_unable_to_process); 947 case FINGERPRINT_ERROR_TIMEOUT: 948 return context.getString(com.android.internal.R.string.fingerprint_error_timeout); 949 case FINGERPRINT_ERROR_NO_SPACE: 950 return context.getString( 951 com.android.internal.R.string.fingerprint_error_no_space); 952 case FINGERPRINT_ERROR_CANCELED: 953 return context.getString(com.android.internal.R.string.fingerprint_error_canceled); 954 case FINGERPRINT_ERROR_LOCKOUT: 955 return context.getString(com.android.internal.R.string.fingerprint_error_lockout); 956 case FINGERPRINT_ERROR_LOCKOUT_PERMANENT: 957 return context.getString( 958 com.android.internal.R.string.fingerprint_error_lockout_permanent); 959 case FINGERPRINT_ERROR_USER_CANCELED: 960 return context.getString( 961 com.android.internal.R.string.fingerprint_error_user_canceled); 962 case FINGERPRINT_ERROR_NO_FINGERPRINTS: 963 return context.getString( 964 com.android.internal.R.string.fingerprint_error_no_fingerprints); 965 case FINGERPRINT_ERROR_HW_NOT_PRESENT: 966 return context.getString( 967 com.android.internal.R.string.fingerprint_error_hw_not_present); 968 case FINGERPRINT_ERROR_VENDOR: { 969 String[] msgArray = context.getResources().getStringArray( 970 com.android.internal.R.array.fingerprint_error_vendor); 971 if (vendorCode < msgArray.length) { 972 return msgArray[vendorCode]; 973 } 974 } 975 } 976 Slog.w(TAG, "Invalid error message: " + errMsg + ", " + vendorCode); 977 return null; 978 } 979 980 /** 981 * @hide 982 */ getAcquiredString(Context context, int acquireInfo, int vendorCode)983 public static String getAcquiredString(Context context, int acquireInfo, int vendorCode) { 984 switch (acquireInfo) { 985 case FINGERPRINT_ACQUIRED_GOOD: 986 return null; 987 case FINGERPRINT_ACQUIRED_PARTIAL: 988 return context.getString( 989 com.android.internal.R.string.fingerprint_acquired_partial); 990 case FINGERPRINT_ACQUIRED_INSUFFICIENT: 991 return context.getString( 992 com.android.internal.R.string.fingerprint_acquired_insufficient); 993 case FINGERPRINT_ACQUIRED_IMAGER_DIRTY: 994 return context.getString( 995 com.android.internal.R.string.fingerprint_acquired_imager_dirty); 996 case FINGERPRINT_ACQUIRED_TOO_SLOW: 997 return context.getString( 998 com.android.internal.R.string.fingerprint_acquired_too_slow); 999 case FINGERPRINT_ACQUIRED_TOO_FAST: 1000 return context.getString( 1001 com.android.internal.R.string.fingerprint_acquired_too_fast); 1002 case FINGERPRINT_ACQUIRED_VENDOR: { 1003 String[] msgArray = context.getResources().getStringArray( 1004 com.android.internal.R.array.fingerprint_acquired_vendor); 1005 if (vendorCode < msgArray.length) { 1006 return msgArray[vendorCode]; 1007 } 1008 } 1009 } 1010 Slog.w(TAG, "Invalid acquired message: " + acquireInfo + ", " + vendorCode); 1011 return null; 1012 } 1013 1014 private IFingerprintServiceReceiver mServiceReceiver = new IFingerprintServiceReceiver.Stub() { 1015 1016 @Override // binder call 1017 public void onEnrollResult(long deviceId, int fingerId, int groupId, int remaining) { 1018 mHandler.obtainMessage(MSG_ENROLL_RESULT, remaining, 0, 1019 new Fingerprint(null, groupId, fingerId, deviceId)).sendToTarget(); 1020 } 1021 1022 @Override // binder call 1023 public void onAcquired(long deviceId, int acquireInfo, int vendorCode) { 1024 mHandler.obtainMessage(MSG_ACQUIRED, acquireInfo, vendorCode, 1025 deviceId).sendToTarget(); 1026 } 1027 1028 @Override // binder call 1029 public void onAuthenticationSucceeded(long deviceId, Fingerprint fp, int userId) { 1030 mHandler.obtainMessage(MSG_AUTHENTICATION_SUCCEEDED, userId, 0, fp).sendToTarget(); 1031 } 1032 1033 @Override // binder call 1034 public void onAuthenticationFailed(long deviceId) { 1035 mHandler.obtainMessage(MSG_AUTHENTICATION_FAILED).sendToTarget(); 1036 } 1037 1038 @Override // binder call 1039 public void onError(long deviceId, int error, int vendorCode) { 1040 mHandler.obtainMessage(MSG_ERROR, error, vendorCode, deviceId).sendToTarget(); 1041 } 1042 1043 @Override // binder call 1044 public void onRemoved(long deviceId, int fingerId, int groupId, int remaining) { 1045 mHandler.obtainMessage(MSG_REMOVED, remaining, 0, 1046 new Fingerprint(null, groupId, fingerId, deviceId)).sendToTarget(); 1047 } 1048 1049 @Override // binder call 1050 public void onEnumerated(long deviceId, int fingerId, int groupId, int remaining) { 1051 // TODO: propagate remaining 1052 mHandler.obtainMessage(MSG_ENUMERATED, fingerId, groupId, deviceId).sendToTarget(); 1053 } 1054 }; 1055 1056 } 1057