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