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