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