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