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