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