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 263 /** 264 * Authentication result 265 * 266 * @param crypto the crypto object 267 * @param fingerprint the recognized fingerprint data, if allowed. 268 * @hide 269 */ 270 public AuthenticationResult(CryptoObject crypto, Fingerprint fingerprint) { 271 mCryptoObject = crypto; 272 mFingerprint = fingerprint; 273 } 274 275 /** 276 * Obtain the crypto object associated with this transaction 277 * @return crypto object provided to {@link FingerprintManager#authenticate(CryptoObject, 278 * CancellationSignal, int, AuthenticationCallback, Handler)}. 279 */ 280 public CryptoObject getCryptoObject() { return mCryptoObject; } 281 282 /** 283 * Obtain the Fingerprint associated with this operation. Applications are strongly 284 * discouraged from associating specific fingers with specific applications or operations. 285 * 286 * @hide 287 */ 288 public Fingerprint getFingerprint() { return mFingerprint; } 289 }; 290 291 /** 292 * Callback structure provided to {@link FingerprintManager#authenticate(CryptoObject, 293 * CancellationSignal, int, AuthenticationCallback, Handler)}. Users of {@link 294 * FingerprintManager#authenticate(CryptoObject, CancellationSignal, 295 * int, AuthenticationCallback, Handler) } must provide an implementation of this for listening to 296 * fingerprint events. 297 */ 298 public static abstract class AuthenticationCallback { 299 /** 300 * Called when an unrecoverable error has been encountered and the operation is complete. 301 * No further callbacks will be made on this object. 302 * @param errorCode An integer identifying the error message 303 * @param errString A human-readable error string that can be shown in UI 304 */ 305 public void onAuthenticationError(int errorCode, CharSequence errString) { } 306 307 /** 308 * Called when a recoverable error has been encountered during authentication. The help 309 * string is provided to give the user guidance for what went wrong, such as 310 * "Sensor dirty, please clean it." 311 * @param helpCode An integer identifying the error message 312 * @param helpString A human-readable string that can be shown in UI 313 */ 314 public void onAuthenticationHelp(int helpCode, CharSequence helpString) { } 315 316 /** 317 * Called when a fingerprint is recognized. 318 * @param result An object containing authentication-related data 319 */ 320 public void onAuthenticationSucceeded(AuthenticationResult result) { } 321 322 /** 323 * Called when a fingerprint is valid but not recognized. 324 */ 325 public void onAuthenticationFailed() { } 326 327 /** 328 * Called when a fingerprint image has been acquired, but wasn't processed yet. 329 * 330 * @param acquireInfo one of FINGERPRINT_ACQUIRED_* constants 331 * @hide 332 */ 333 public void onAuthenticationAcquired(int acquireInfo) {} 334 }; 335 336 /** 337 * Callback structure provided to {@link FingerprintManager#enroll(long, EnrollmentCallback, 338 * CancellationSignal, int). Users of {@link #FingerprintManager()} 339 * must provide an implementation of this to {@link FingerprintManager#enroll(long, 340 * CancellationSignal, int, EnrollmentCallback) for listening to fingerprint events. 341 * 342 * @hide 343 */ 344 public static abstract class EnrollmentCallback { 345 /** 346 * Called when an unrecoverable error has been encountered and the operation is complete. 347 * No further callbacks will be made on this object. 348 * @param errMsgId An integer identifying the error message 349 * @param errString A human-readable error string that can be shown in UI 350 */ 351 public void onEnrollmentError(int errMsgId, CharSequence errString) { } 352 353 /** 354 * Called when a recoverable error has been encountered during enrollment. The help 355 * string is provided to give the user guidance for what went wrong, such as 356 * "Sensor dirty, please clean it" or what they need to do next, such as 357 * "Touch sensor again." 358 * @param helpMsgId An integer identifying the error message 359 * @param helpString A human-readable string that can be shown in UI 360 */ 361 public void onEnrollmentHelp(int helpMsgId, CharSequence helpString) { } 362 363 /** 364 * Called as each enrollment step progresses. Enrollment is considered complete when 365 * remaining reaches 0. This function will not be called if enrollment fails. See 366 * {@link EnrollmentCallback#onEnrollmentError(int, CharSequence)} 367 * @param remaining The number of remaining steps 368 */ 369 public void onEnrollmentProgress(int remaining) { } 370 }; 371 372 /** 373 * Callback structure provided to {@link FingerprintManager#remove(int). Users of 374 * {@link #FingerprintManager()} may optionally provide an implementation of this to 375 * {@link FingerprintManager#remove(int, int, RemovalCallback)} for listening to 376 * fingerprint template removal events. 377 * 378 * @hide 379 */ 380 public static abstract class RemovalCallback { 381 /** 382 * Called when the given fingerprint can't be removed. 383 * @param fp The fingerprint that the call attempted to remove 384 * @param errMsgId An associated error message id 385 * @param errString An error message indicating why the fingerprint id can't be removed 386 */ 387 public void onRemovalError(Fingerprint fp, int errMsgId, CharSequence errString) { } 388 389 /** 390 * Called when a given fingerprint is successfully removed. 391 * @param fingerprint the fingerprint template that was removed. 392 */ 393 public void onRemovalSucceeded(Fingerprint fingerprint) { } 394 }; 395 396 /** 397 * @hide 398 */ 399 public static abstract class LockoutResetCallback { 400 401 /** 402 * Called when lockout period expired and clients are allowed to listen for fingerprint 403 * again. 404 */ 405 public void onLockoutReset() { } 406 }; 407 408 /** 409 * Request authentication of a crypto object. This call warms up the fingerprint hardware 410 * and starts scanning for a fingerprint. It terminates when 411 * {@link AuthenticationCallback#onAuthenticationError(int, CharSequence)} or 412 * {@link AuthenticationCallback#onAuthenticationSucceeded(AuthenticationResult)} is called, at 413 * which point the object is no longer valid. The operation can be canceled by using the 414 * provided cancel object. 415 * 416 * @param crypto object associated with the call or null if none required. 417 * @param cancel an object that can be used to cancel authentication 418 * @param flags optional flags; should be 0 419 * @param callback an object to receive authentication events 420 * @param handler an optional handler to handle callback events 421 * 422 * @throws IllegalArgumentException if the crypto operation is not supported or is not backed 423 * by <a href="{@docRoot}training/articles/keystore.html">Android Keystore 424 * facility</a>. 425 * @throws IllegalStateException if the crypto primitive is not initialized. 426 */ 427 @RequiresPermission(USE_FINGERPRINT) 428 public void authenticate(@Nullable CryptoObject crypto, @Nullable CancellationSignal cancel, 429 int flags, @NonNull AuthenticationCallback callback, @Nullable Handler handler) { 430 authenticate(crypto, cancel, flags, callback, handler, UserHandle.myUserId()); 431 } 432 433 /** 434 * Use the provided handler thread for events. 435 * @param handler 436 */ 437 private void useHandler(Handler handler) { 438 if (handler != null) { 439 mHandler = new MyHandler(handler.getLooper()); 440 } else if (mHandler.getLooper() != mContext.getMainLooper()){ 441 mHandler = new MyHandler(mContext.getMainLooper()); 442 } 443 } 444 445 /** 446 * Per-user version 447 * @hide 448 */ 449 @RequiresPermission(USE_FINGERPRINT) 450 public void authenticate(@Nullable CryptoObject crypto, @Nullable CancellationSignal cancel, 451 int flags, @NonNull AuthenticationCallback callback, Handler handler, int userId) { 452 if (callback == null) { 453 throw new IllegalArgumentException("Must supply an authentication callback"); 454 } 455 456 if (cancel != null) { 457 if (cancel.isCanceled()) { 458 Log.w(TAG, "authentication already canceled"); 459 return; 460 } else { 461 cancel.setOnCancelListener(new OnAuthenticationCancelListener(crypto)); 462 } 463 } 464 465 if (mService != null) try { 466 useHandler(handler); 467 mAuthenticationCallback = callback; 468 mCryptoObject = crypto; 469 long sessionId = crypto != null ? crypto.getOpId() : 0; 470 mService.authenticate(mToken, sessionId, userId, mServiceReceiver, flags, 471 mContext.getOpPackageName()); 472 } catch (RemoteException e) { 473 Log.w(TAG, "Remote exception while authenticating: ", e); 474 if (callback != null) { 475 // Though this may not be a hardware issue, it will cause apps to give up or try 476 // again later. 477 callback.onAuthenticationError(FINGERPRINT_ERROR_HW_UNAVAILABLE, 478 getErrorString(FINGERPRINT_ERROR_HW_UNAVAILABLE)); 479 } 480 } 481 } 482 483 /** 484 * Request fingerprint enrollment. This call warms up the fingerprint hardware 485 * and starts scanning for fingerprints. Progress will be indicated by callbacks to the 486 * {@link EnrollmentCallback} object. It terminates when 487 * {@link EnrollmentCallback#onEnrollmentError(int, CharSequence)} or 488 * {@link EnrollmentCallback#onEnrollmentProgress(int) is called with remaining == 0, at 489 * which point the object is no longer valid. The operation can be canceled by using the 490 * provided cancel object. 491 * @param token a unique token provided by a recent creation or verification of device 492 * credentials (e.g. pin, pattern or password). 493 * @param cancel an object that can be used to cancel enrollment 494 * @param flags optional flags 495 * @param userId the user to whom this fingerprint will belong to 496 * @param callback an object to receive enrollment events 497 * @hide 498 */ 499 @RequiresPermission(MANAGE_FINGERPRINT) 500 public void enroll(byte [] token, CancellationSignal cancel, int flags, 501 int userId, EnrollmentCallback callback) { 502 if (userId == UserHandle.USER_CURRENT) { 503 userId = getCurrentUserId(); 504 } 505 if (callback == null) { 506 throw new IllegalArgumentException("Must supply an enrollment callback"); 507 } 508 509 if (cancel != null) { 510 if (cancel.isCanceled()) { 511 Log.w(TAG, "enrollment already canceled"); 512 return; 513 } else { 514 cancel.setOnCancelListener(new OnEnrollCancelListener()); 515 } 516 } 517 518 if (mService != null) try { 519 mEnrollmentCallback = callback; 520 mService.enroll(mToken, token, userId, mServiceReceiver, flags, 521 mContext.getOpPackageName()); 522 } catch (RemoteException e) { 523 Log.w(TAG, "Remote exception in enroll: ", e); 524 if (callback != null) { 525 // Though this may not be a hardware issue, it will cause apps to give up or try 526 // again later. 527 callback.onEnrollmentError(FINGERPRINT_ERROR_HW_UNAVAILABLE, 528 getErrorString(FINGERPRINT_ERROR_HW_UNAVAILABLE)); 529 } 530 } 531 } 532 533 /** 534 * Requests a pre-enrollment auth token to tie enrollment to the confirmation of 535 * existing device credentials (e.g. pin/pattern/password). 536 * @hide 537 */ 538 @RequiresPermission(MANAGE_FINGERPRINT) 539 public long preEnroll() { 540 long result = 0; 541 if (mService != null) try { 542 result = mService.preEnroll(mToken); 543 } catch (RemoteException e) { 544 throw e.rethrowFromSystemServer(); 545 } 546 return result; 547 } 548 549 /** 550 * Finishes enrollment and cancels the current auth token. 551 * @hide 552 */ 553 @RequiresPermission(MANAGE_FINGERPRINT) 554 public int postEnroll() { 555 int result = 0; 556 if (mService != null) try { 557 result = mService.postEnroll(mToken); 558 } catch (RemoteException e) { 559 throw e.rethrowFromSystemServer(); 560 } 561 return result; 562 } 563 564 /** 565 * Sets the active user. This is meant to be used to select the current profile for enrollment 566 * to allow separate enrolled fingers for a work profile 567 * @param userId 568 * @hide 569 */ 570 @RequiresPermission(MANAGE_FINGERPRINT) 571 public void setActiveUser(int userId) { 572 if (mService != null) try { 573 mService.setActiveUser(userId); 574 } catch (RemoteException e) { 575 throw e.rethrowFromSystemServer(); 576 } 577 } 578 579 /** 580 * Remove given fingerprint template from fingerprint hardware and/or protected storage. 581 * @param fp the fingerprint item to remove 582 * @param userId the user who this fingerprint belongs to 583 * @param callback an optional callback to verify that fingerprint templates have been 584 * successfully removed. May be null of no callback is required. 585 * 586 * @hide 587 */ 588 @RequiresPermission(MANAGE_FINGERPRINT) 589 public void remove(Fingerprint fp, int userId, RemovalCallback callback) { 590 if (mService != null) try { 591 mRemovalCallback = callback; 592 mRemovalFingerprint = fp; 593 mService.remove(mToken, fp.getFingerId(), fp.getGroupId(), userId, mServiceReceiver); 594 } catch (RemoteException e) { 595 Log.w(TAG, "Remote exception in remove: ", e); 596 if (callback != null) { 597 callback.onRemovalError(fp, FINGERPRINT_ERROR_HW_UNAVAILABLE, 598 getErrorString(FINGERPRINT_ERROR_HW_UNAVAILABLE)); 599 } 600 } 601 } 602 603 /** 604 * Renames the given fingerprint template 605 * @param fpId the fingerprint id 606 * @param userId the user who this fingerprint belongs to 607 * @param newName the new name 608 * 609 * @hide 610 */ 611 @RequiresPermission(MANAGE_FINGERPRINT) 612 public void rename(int fpId, int userId, String newName) { 613 // Renames the given fpId 614 if (mService != null) { 615 try { 616 mService.rename(fpId, userId, newName); 617 } catch (RemoteException e) { 618 throw e.rethrowFromSystemServer(); 619 } 620 } else { 621 Log.w(TAG, "rename(): Service not connected!"); 622 } 623 } 624 625 /** 626 * Obtain the list of enrolled fingerprints templates. 627 * @return list of current fingerprint items 628 * 629 * @hide 630 */ 631 @RequiresPermission(USE_FINGERPRINT) 632 public List<Fingerprint> getEnrolledFingerprints(int userId) { 633 if (mService != null) try { 634 return mService.getEnrolledFingerprints(userId, mContext.getOpPackageName()); 635 } catch (RemoteException e) { 636 throw e.rethrowFromSystemServer(); 637 } 638 return null; 639 } 640 641 /** 642 * Obtain the list of enrolled fingerprints templates. 643 * @return list of current fingerprint items 644 * 645 * @hide 646 */ 647 @RequiresPermission(USE_FINGERPRINT) 648 public List<Fingerprint> getEnrolledFingerprints() { 649 return getEnrolledFingerprints(UserHandle.myUserId()); 650 } 651 652 /** 653 * Determine if there is at least one fingerprint enrolled. 654 * 655 * @return true if at least one fingerprint is enrolled, false otherwise 656 */ 657 @RequiresPermission(USE_FINGERPRINT) 658 public boolean hasEnrolledFingerprints() { 659 if (mService != null) try { 660 return mService.hasEnrolledFingerprints( 661 UserHandle.myUserId(), mContext.getOpPackageName()); 662 } catch (RemoteException e) { 663 throw e.rethrowFromSystemServer(); 664 } 665 return false; 666 } 667 668 /** 669 * @hide 670 */ 671 @RequiresPermission(allOf = { 672 USE_FINGERPRINT, 673 INTERACT_ACROSS_USERS}) 674 public boolean hasEnrolledFingerprints(int userId) { 675 if (mService != null) try { 676 return mService.hasEnrolledFingerprints(userId, mContext.getOpPackageName()); 677 } catch (RemoteException e) { 678 throw e.rethrowFromSystemServer(); 679 } 680 return false; 681 } 682 683 /** 684 * Determine if fingerprint hardware is present and functional. 685 * 686 * @return true if hardware is present and functional, false otherwise. 687 */ 688 @RequiresPermission(USE_FINGERPRINT) 689 public boolean isHardwareDetected() { 690 if (mService != null) { 691 try { 692 long deviceId = 0; /* TODO: plumb hardware id to FPMS */ 693 return mService.isHardwareDetected(deviceId, mContext.getOpPackageName()); 694 } catch (RemoteException e) { 695 throw e.rethrowFromSystemServer(); 696 } 697 } else { 698 Log.w(TAG, "isFingerprintHardwareDetected(): Service not connected!"); 699 } 700 return false; 701 } 702 703 /** 704 * Retrieves the authenticator token for binding keys to the lifecycle 705 * of the current set of fingerprints. Used only by internal clients. 706 * 707 * @hide 708 */ 709 public long getAuthenticatorId() { 710 if (mService != null) { 711 try { 712 return mService.getAuthenticatorId(mContext.getOpPackageName()); 713 } catch (RemoteException e) { 714 throw e.rethrowFromSystemServer(); 715 } 716 } else { 717 Log.w(TAG, "getAuthenticatorId(): Service not connected!"); 718 } 719 return 0; 720 } 721 722 /** 723 * Reset the lockout timer when asked to do so by keyguard. 724 * 725 * @param token an opaque token returned by password confirmation. 726 * 727 * @hide 728 */ 729 public void resetTimeout(byte[] token) { 730 if (mService != null) { 731 try { 732 mService.resetTimeout(token); 733 } catch (RemoteException e) { 734 throw e.rethrowFromSystemServer(); 735 } 736 } else { 737 Log.w(TAG, "resetTimeout(): Service not connected!"); 738 } 739 } 740 741 /** 742 * @hide 743 */ 744 public void addLockoutResetCallback(final LockoutResetCallback callback) { 745 if (mService != null) { 746 try { 747 final PowerManager powerManager = mContext.getSystemService(PowerManager.class); 748 mService.addLockoutResetCallback( 749 new IFingerprintServiceLockoutResetCallback.Stub() { 750 751 @Override 752 public void onLockoutReset(long deviceId) throws RemoteException { 753 final PowerManager.WakeLock wakeLock = powerManager.newWakeLock( 754 PowerManager.PARTIAL_WAKE_LOCK, "lockoutResetCallback"); 755 wakeLock.acquire(); 756 mHandler.post(new Runnable() { 757 @Override 758 public void run() { 759 try { 760 callback.onLockoutReset(); 761 } finally { 762 wakeLock.release(); 763 } 764 } 765 }); 766 } 767 }); 768 } catch (RemoteException e) { 769 throw e.rethrowFromSystemServer(); 770 } 771 } else { 772 Log.w(TAG, "addLockoutResetCallback(): Service not connected!"); 773 } 774 } 775 776 private class MyHandler extends Handler { 777 private MyHandler(Context context) { 778 super(context.getMainLooper()); 779 } 780 781 private MyHandler(Looper looper) { 782 super(looper); 783 } 784 785 @Override 786 public void handleMessage(android.os.Message msg) { 787 switch(msg.what) { 788 case MSG_ENROLL_RESULT: 789 sendEnrollResult((Fingerprint) msg.obj, msg.arg1 /* remaining */); 790 break; 791 case MSG_ACQUIRED: 792 sendAcquiredResult((Long) msg.obj /* deviceId */, msg.arg1 /* acquire info */); 793 break; 794 case MSG_AUTHENTICATION_SUCCEEDED: 795 sendAuthenticatedSucceeded((Fingerprint) msg.obj); 796 break; 797 case MSG_AUTHENTICATION_FAILED: 798 sendAuthenticatedFailed(); 799 break; 800 case MSG_ERROR: 801 sendErrorResult((Long) msg.obj /* deviceId */, msg.arg1 /* errMsgId */); 802 break; 803 case MSG_REMOVED: 804 sendRemovedResult((Long) msg.obj /* deviceId */, msg.arg1 /* fingerId */, 805 msg.arg2 /* groupId */); 806 } 807 } 808 809 private void sendRemovedResult(long deviceId, int fingerId, int groupId) { 810 if (mRemovalCallback != null) { 811 int reqFingerId = mRemovalFingerprint.getFingerId(); 812 int reqGroupId = mRemovalFingerprint.getGroupId(); 813 if (reqFingerId != 0 && fingerId != 0 && fingerId != reqFingerId) { 814 Log.w(TAG, "Finger id didn't match: " + fingerId + " != " + reqFingerId); 815 return; 816 } 817 if (groupId != reqGroupId) { 818 Log.w(TAG, "Group id didn't match: " + groupId + " != " + reqGroupId); 819 return; 820 } 821 mRemovalCallback.onRemovalSucceeded(new Fingerprint(null, groupId, fingerId, 822 deviceId)); 823 } 824 } 825 826 private void sendErrorResult(long deviceId, int errMsgId) { 827 if (mEnrollmentCallback != null) { 828 mEnrollmentCallback.onEnrollmentError(errMsgId, getErrorString(errMsgId)); 829 } else if (mAuthenticationCallback != null) { 830 mAuthenticationCallback.onAuthenticationError(errMsgId, getErrorString(errMsgId)); 831 } else if (mRemovalCallback != null) { 832 mRemovalCallback.onRemovalError(mRemovalFingerprint, errMsgId, 833 getErrorString(errMsgId)); 834 } 835 } 836 837 private void sendEnrollResult(Fingerprint fp, int remaining) { 838 if (mEnrollmentCallback != null) { 839 mEnrollmentCallback.onEnrollmentProgress(remaining); 840 } 841 } 842 843 private void sendAuthenticatedSucceeded(Fingerprint fp) { 844 if (mAuthenticationCallback != null) { 845 final AuthenticationResult result = new AuthenticationResult(mCryptoObject, fp); 846 mAuthenticationCallback.onAuthenticationSucceeded(result); 847 } 848 } 849 850 private void sendAuthenticatedFailed() { 851 if (mAuthenticationCallback != null) { 852 mAuthenticationCallback.onAuthenticationFailed(); 853 } 854 } 855 856 private void sendAcquiredResult(long deviceId, int acquireInfo) { 857 if (mAuthenticationCallback != null) { 858 mAuthenticationCallback.onAuthenticationAcquired(acquireInfo); 859 } 860 final String msg = getAcquiredString(acquireInfo); 861 if (msg == null) { 862 return; 863 } 864 if (mEnrollmentCallback != null) { 865 mEnrollmentCallback.onEnrollmentHelp(acquireInfo, msg); 866 } else if (mAuthenticationCallback != null) { 867 mAuthenticationCallback.onAuthenticationHelp(acquireInfo, msg); 868 } 869 } 870 }; 871 872 /** 873 * @hide 874 */ 875 public FingerprintManager(Context context, IFingerprintService service) { 876 mContext = context; 877 mService = service; 878 if (mService == null) { 879 Slog.v(TAG, "FingerprintManagerService was null"); 880 } 881 mHandler = new MyHandler(context); 882 } 883 884 private int getCurrentUserId() { 885 try { 886 return ActivityManagerNative.getDefault().getCurrentUser().id; 887 } catch (RemoteException e) { 888 throw e.rethrowFromSystemServer(); 889 } 890 } 891 892 private void cancelEnrollment() { 893 if (mService != null) try { 894 mService.cancelEnrollment(mToken); 895 } catch (RemoteException e) { 896 throw e.rethrowFromSystemServer(); 897 } 898 } 899 900 private void cancelAuthentication(CryptoObject cryptoObject) { 901 if (mService != null) try { 902 mService.cancelAuthentication(mToken, mContext.getOpPackageName()); 903 } catch (RemoteException e) { 904 throw e.rethrowFromSystemServer(); 905 } 906 } 907 908 private String getErrorString(int errMsg) { 909 switch (errMsg) { 910 case FINGERPRINT_ERROR_UNABLE_TO_PROCESS: 911 return mContext.getString( 912 com.android.internal.R.string.fingerprint_error_unable_to_process); 913 case FINGERPRINT_ERROR_HW_UNAVAILABLE: 914 return mContext.getString( 915 com.android.internal.R.string.fingerprint_error_hw_not_available); 916 case FINGERPRINT_ERROR_NO_SPACE: 917 return mContext.getString( 918 com.android.internal.R.string.fingerprint_error_no_space); 919 case FINGERPRINT_ERROR_TIMEOUT: 920 return mContext.getString(com.android.internal.R.string.fingerprint_error_timeout); 921 case FINGERPRINT_ERROR_CANCELED: 922 return mContext.getString(com.android.internal.R.string.fingerprint_error_canceled); 923 case FINGERPRINT_ERROR_LOCKOUT: 924 return mContext.getString(com.android.internal.R.string.fingerprint_error_lockout); 925 default: 926 if (errMsg >= FINGERPRINT_ERROR_VENDOR_BASE) { 927 int msgNumber = errMsg - FINGERPRINT_ERROR_VENDOR_BASE; 928 String[] msgArray = mContext.getResources().getStringArray( 929 com.android.internal.R.array.fingerprint_error_vendor); 930 if (msgNumber < msgArray.length) { 931 return msgArray[msgNumber]; 932 } 933 } 934 return null; 935 } 936 } 937 938 private String getAcquiredString(int acquireInfo) { 939 switch (acquireInfo) { 940 case FINGERPRINT_ACQUIRED_GOOD: 941 return null; 942 case FINGERPRINT_ACQUIRED_PARTIAL: 943 return mContext.getString( 944 com.android.internal.R.string.fingerprint_acquired_partial); 945 case FINGERPRINT_ACQUIRED_INSUFFICIENT: 946 return mContext.getString( 947 com.android.internal.R.string.fingerprint_acquired_insufficient); 948 case FINGERPRINT_ACQUIRED_IMAGER_DIRTY: 949 return mContext.getString( 950 com.android.internal.R.string.fingerprint_acquired_imager_dirty); 951 case FINGERPRINT_ACQUIRED_TOO_SLOW: 952 return mContext.getString( 953 com.android.internal.R.string.fingerprint_acquired_too_slow); 954 case FINGERPRINT_ACQUIRED_TOO_FAST: 955 return mContext.getString( 956 com.android.internal.R.string.fingerprint_acquired_too_fast); 957 default: 958 if (acquireInfo >= FINGERPRINT_ACQUIRED_VENDOR_BASE) { 959 int msgNumber = acquireInfo - FINGERPRINT_ACQUIRED_VENDOR_BASE; 960 String[] msgArray = mContext.getResources().getStringArray( 961 com.android.internal.R.array.fingerprint_acquired_vendor); 962 if (msgNumber < msgArray.length) { 963 return msgArray[msgNumber]; 964 } 965 } 966 return null; 967 } 968 } 969 970 private IFingerprintServiceReceiver mServiceReceiver = new IFingerprintServiceReceiver.Stub() { 971 972 @Override // binder call 973 public void onEnrollResult(long deviceId, int fingerId, int groupId, int remaining) { 974 mHandler.obtainMessage(MSG_ENROLL_RESULT, remaining, 0, 975 new Fingerprint(null, groupId, fingerId, deviceId)).sendToTarget(); 976 } 977 978 @Override // binder call 979 public void onAcquired(long deviceId, int acquireInfo) { 980 mHandler.obtainMessage(MSG_ACQUIRED, acquireInfo, 0, deviceId).sendToTarget(); 981 } 982 983 @Override // binder call 984 public void onAuthenticationSucceeded(long deviceId, Fingerprint fp) { 985 mHandler.obtainMessage(MSG_AUTHENTICATION_SUCCEEDED, fp).sendToTarget(); 986 } 987 988 @Override // binder call 989 public void onAuthenticationFailed(long deviceId) { 990 mHandler.obtainMessage(MSG_AUTHENTICATION_FAILED).sendToTarget();; 991 } 992 993 @Override // binder call 994 public void onError(long deviceId, int error) { 995 mHandler.obtainMessage(MSG_ERROR, error, 0, deviceId).sendToTarget(); 996 } 997 998 @Override // binder call 999 public void onRemoved(long deviceId, int fingerId, int groupId) { 1000 mHandler.obtainMessage(MSG_REMOVED, fingerId, groupId, deviceId).sendToTarget(); 1001 } 1002 }; 1003 1004 } 1005