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