1 /**
2  * Copyright (C) 2014 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package android.hardware.fingerprint;
18 
19 import android.annotation.NonNull;
20 import android.annotation.Nullable;
21 import android.annotation.RequiresPermission;
22 import android.app.ActivityManagerNative;
23 import android.content.Context;
24 import android.os.Binder;
25 import android.os.CancellationSignal;
26 import android.os.CancellationSignal.OnCancelListener;
27 import android.os.Handler;
28 import android.os.IBinder;
29 import android.os.Looper;
30 import android.os.RemoteException;
31 import android.os.UserHandle;
32 import android.security.keystore.AndroidKeyStoreProvider;
33 import android.util.Log;
34 import android.util.Slog;
35 
36 import java.security.Signature;
37 import java.util.List;
38 
39 import javax.crypto.Cipher;
40 import javax.crypto.Mac;
41 
42 import static android.Manifest.permission.USE_FINGERPRINT;
43 import 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 
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 
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
onCancel()181         public void onCancel() {
182             cancelEnrollment();
183         }
184     }
185 
186     private class OnAuthenticationCancelListener implements OnCancelListener {
187         private CryptoObject mCrypto;
188 
OnAuthenticationCancelListener(CryptoObject crypto)189         public OnAuthenticationCancelListener(CryptoObject crypto) {
190             mCrypto = crypto;
191         }
192 
193         @Override
onCancel()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 
CryptoObject(@onNull Signature signature)205         public CryptoObject(@NonNull Signature signature) {
206             mCrypto = signature;
207         }
208 
CryptoObject(@onNull Cipher cipher)209         public CryptoObject(@NonNull Cipher cipher) {
210             mCrypto = cipher;
211         }
212 
CryptoObject(@onNull Mac mac)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          */
getSignature()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          */
getCipher()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          */
getMac()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          */
getOpId()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 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          */
AuthenticationResult(CryptoObject crypto, Fingerprint fingerprint)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          */
getCryptoObject()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          */
getFingerprint()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          */
onAuthenticationError(int errorCode, CharSequence errString)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          */
onAuthenticationHelp(int helpCode, CharSequence helpString)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          */
onAuthenticationSucceeded(AuthenticationResult result)318         public void onAuthenticationSucceeded(AuthenticationResult result) { }
319 
320         /**
321          * Called when a fingerprint is valid but not recognized.
322          */
onAuthenticationFailed()323         public void onAuthenticationFailed() { }
324 
325         /**
326          * Called when a fingerprint image has been acquired, but wasn't processed yet.
327          *
328          * @param acquireInfo one of FINGERPRINT_ACQUIRED_* constants
329          * @hide
330          */
onAuthenticationAcquired(int acquireInfo)331         public void onAuthenticationAcquired(int acquireInfo) {}
332     };
333 
334     /**
335      * Callback structure provided to {@link FingerprintManager#enroll(long, EnrollmentCallback,
336      * CancellationSignal, int). Users of {@link #FingerprintManager()}
337      * must provide an implementation of this to {@link FingerprintManager#enroll(long,
338      * CancellationSignal, int, EnrollmentCallback) for listening to fingerprint events.
339      *
340      * @hide
341      */
342     public static abstract class EnrollmentCallback {
343         /**
344          * Called when an unrecoverable error has been encountered and the operation is complete.
345          * No further callbacks will be made on this object.
346          * @param errMsgId An integer identifying the error message
347          * @param errString A human-readable error string that can be shown in UI
348          */
onEnrollmentError(int errMsgId, CharSequence errString)349         public void onEnrollmentError(int errMsgId, CharSequence errString) { }
350 
351         /**
352          * Called when a recoverable error has been encountered during enrollment. The help
353          * string is provided to give the user guidance for what went wrong, such as
354          * "Sensor dirty, please clean it" or what they need to do next, such as
355          * "Touch sensor again."
356          * @param helpMsgId An integer identifying the error message
357          * @param helpString A human-readable string that can be shown in UI
358          */
onEnrollmentHelp(int helpMsgId, CharSequence helpString)359         public void onEnrollmentHelp(int helpMsgId, CharSequence helpString) { }
360 
361         /**
362          * Called as each enrollment step progresses. Enrollment is considered complete when
363          * remaining reaches 0. This function will not be called if enrollment fails. See
364          * {@link EnrollmentCallback#onEnrollmentError(int, CharSequence)}
365          * @param remaining The number of remaining steps
366          */
onEnrollmentProgress(int remaining)367         public void onEnrollmentProgress(int remaining) { }
368     };
369 
370     /**
371      * Callback structure provided to {@link FingerprintManager#remove(int). Users of
372      * {@link #FingerprintManager()} may optionally provide an implementation of this to
373      * {@link FingerprintManager#remove(int, int, RemovalCallback)} for listening to
374      * fingerprint template removal events.
375      *
376      * @hide
377      */
378     public static abstract class RemovalCallback {
379         /**
380          * Called when the given fingerprint can't be removed.
381          * @param fp The fingerprint that the call attempted to remove
382          * @param errMsgId An associated error message id
383          * @param errString An error message indicating why the fingerprint id can't be removed
384          */
onRemovalError(Fingerprint fp, int errMsgId, CharSequence errString)385         public void onRemovalError(Fingerprint fp, int errMsgId, CharSequence errString) { }
386 
387         /**
388          * Called when a given fingerprint is successfully removed.
389          * @param fingerprint the fingerprint template that was removed.
390          */
onRemovalSucceeded(Fingerprint fingerprint)391         public void onRemovalSucceeded(Fingerprint fingerprint) { }
392     };
393 
394     /**
395      * Request authentication of a crypto object. This call warms up the fingerprint hardware
396      * and starts scanning for a fingerprint. It terminates when
397      * {@link AuthenticationCallback#onAuthenticationError(int, CharSequence)} or
398      * {@link AuthenticationCallback#onAuthenticationSucceeded(AuthenticationResult)} is called, at
399      * which point the object is no longer valid. The operation can be canceled by using the
400      * provided cancel object.
401      *
402      * @param crypto object associated with the call or null if none required.
403      * @param cancel an object that can be used to cancel authentication
404      * @param flags optional flags; should be 0
405      * @param callback an object to receive authentication events
406      * @param handler an optional handler to handle callback events
407      *
408      * @throws IllegalArgumentException if the crypto operation is not supported or is not backed
409      *         by <a href="{@docRoot}training/articles/keystore.html">Android Keystore
410      *         facility</a>.
411      * @throws IllegalStateException if the crypto primitive is not initialized.
412      */
413     @RequiresPermission(USE_FINGERPRINT)
authenticate(@ullable CryptoObject crypto, @Nullable CancellationSignal cancel, int flags, @NonNull AuthenticationCallback callback, @Nullable Handler handler)414     public void authenticate(@Nullable CryptoObject crypto, @Nullable CancellationSignal cancel,
415             int flags, @NonNull AuthenticationCallback callback, @Nullable Handler handler) {
416         authenticate(crypto, cancel, flags, callback, handler, UserHandle.myUserId());
417     }
418 
419     /**
420      * Use the provided handler thread for events.
421      * @param handler
422      */
useHandler(Handler handler)423     private void useHandler(Handler handler) {
424         if (handler != null) {
425             mHandler = new MyHandler(handler.getLooper());
426         } else if (mHandler.getLooper() != mContext.getMainLooper()){
427             mHandler = new MyHandler(mContext.getMainLooper());
428         }
429     }
430 
431     /**
432      * Per-user version
433      * @hide
434      */
435     @RequiresPermission(USE_FINGERPRINT)
authenticate(@ullable CryptoObject crypto, @Nullable CancellationSignal cancel, int flags, @NonNull AuthenticationCallback callback, Handler handler, int userId)436     public void authenticate(@Nullable CryptoObject crypto, @Nullable CancellationSignal cancel,
437             int flags, @NonNull AuthenticationCallback callback, Handler handler, int userId) {
438         if (callback == null) {
439             throw new IllegalArgumentException("Must supply an authentication callback");
440         }
441 
442         if (cancel != null) {
443             if (cancel.isCanceled()) {
444                 Log.w(TAG, "authentication already canceled");
445                 return;
446             } else {
447                 cancel.setOnCancelListener(new OnAuthenticationCancelListener(crypto));
448             }
449         }
450 
451         if (mService != null) try {
452             useHandler(handler);
453             mAuthenticationCallback = callback;
454             mCryptoObject = crypto;
455             long sessionId = crypto != null ? crypto.getOpId() : 0;
456             mService.authenticate(mToken, sessionId, userId, mServiceReceiver, flags,
457                     mContext.getOpPackageName());
458         } catch (RemoteException e) {
459             Log.w(TAG, "Remote exception while authenticating: ", e);
460             if (callback != null) {
461                 // Though this may not be a hardware issue, it will cause apps to give up or try
462                 // again later.
463                 callback.onAuthenticationError(FINGERPRINT_ERROR_HW_UNAVAILABLE,
464                         getErrorString(FINGERPRINT_ERROR_HW_UNAVAILABLE));
465             }
466         }
467     }
468 
469     /**
470      * Request fingerprint enrollment. This call warms up the fingerprint hardware
471      * and starts scanning for fingerprints. Progress will be indicated by callbacks to the
472      * {@link EnrollmentCallback} object. It terminates when
473      * {@link EnrollmentCallback#onEnrollmentError(int, CharSequence)} or
474      * {@link EnrollmentCallback#onEnrollmentProgress(int) is called with remaining == 0, at
475      * which point the object is no longer valid. The operation can be canceled by using the
476      * provided cancel object.
477      * @param token a unique token provided by a recent creation or verification of device
478      * credentials (e.g. pin, pattern or password).
479      * @param cancel an object that can be used to cancel enrollment
480      * @param flags optional flags
481      * @param callback an object to receive enrollment events
482      * @hide
483      */
484     @RequiresPermission(MANAGE_FINGERPRINT)
enroll(byte [] token, CancellationSignal cancel, int flags, EnrollmentCallback callback)485     public void enroll(byte [] token, CancellationSignal cancel, int flags,
486             EnrollmentCallback callback) {
487         if (callback == null) {
488             throw new IllegalArgumentException("Must supply an enrollment callback");
489         }
490 
491         if (cancel != null) {
492             if (cancel.isCanceled()) {
493                 Log.w(TAG, "enrollment already canceled");
494                 return;
495             } else {
496                 cancel.setOnCancelListener(new OnEnrollCancelListener());
497             }
498         }
499 
500         if (mService != null) try {
501             mEnrollmentCallback = callback;
502             mService.enroll(mToken, token, getCurrentUserId(), mServiceReceiver, flags);
503         } catch (RemoteException e) {
504             Log.w(TAG, "Remote exception in enroll: ", e);
505             if (callback != null) {
506                 // Though this may not be a hardware issue, it will cause apps to give up or try
507                 // again later.
508                 callback.onEnrollmentError(FINGERPRINT_ERROR_HW_UNAVAILABLE,
509                         getErrorString(FINGERPRINT_ERROR_HW_UNAVAILABLE));
510             }
511         }
512     }
513 
514     /**
515      * Requests a pre-enrollment auth token to tie enrollment to the confirmation of
516      * existing device credentials (e.g. pin/pattern/password).
517      * @hide
518      */
519     @RequiresPermission(MANAGE_FINGERPRINT)
preEnroll()520     public long preEnroll() {
521         long result = 0;
522         if (mService != null) try {
523             result = mService.preEnroll(mToken);
524         } catch (RemoteException e) {
525             Log.w(TAG, "Remote exception in enroll: ", e);
526         }
527         return result;
528     }
529 
530     /**
531      * Finishes enrollment and cancels the current auth token.
532      * @hide
533      */
534     @RequiresPermission(MANAGE_FINGERPRINT)
postEnroll()535     public int postEnroll() {
536         int result = 0;
537         if (mService != null) try {
538             result = mService.postEnroll(mToken);
539         } catch (RemoteException e) {
540             Log.w(TAG, "Remote exception in post enroll: ", e);
541         }
542         return result;
543     }
544 
545     /**
546      * Remove given fingerprint template from fingerprint hardware and/or protected storage.
547      * @param fp the fingerprint item to remove
548      * @param callback an optional callback to verify that fingerprint templates have been
549      * successfully removed. May be null of no callback is required.
550      *
551      * @hide
552      */
553     @RequiresPermission(MANAGE_FINGERPRINT)
remove(Fingerprint fp, RemovalCallback callback)554     public void remove(Fingerprint fp, RemovalCallback callback) {
555         if (mService != null) try {
556             mRemovalCallback = callback;
557             mRemovalFingerprint = fp;
558             mService.remove(mToken, fp.getFingerId(), getCurrentUserId(), mServiceReceiver);
559         } catch (RemoteException e) {
560             Log.w(TAG, "Remote exception in remove: ", e);
561             if (callback != null) {
562                 callback.onRemovalError(fp, FINGERPRINT_ERROR_HW_UNAVAILABLE,
563                         getErrorString(FINGERPRINT_ERROR_HW_UNAVAILABLE));
564             }
565         }
566     }
567 
568     /**
569      * Renames the given fingerprint template
570      * @param fpId the fingerprint id
571      * @param newName the new name
572      *
573      * @hide
574      */
575     @RequiresPermission(MANAGE_FINGERPRINT)
rename(int fpId, String newName)576     public void rename(int fpId, String newName) {
577         // Renames the given fpId
578         if (mService != null) {
579             try {
580                 mService.rename(fpId, getCurrentUserId(), newName);
581             } catch (RemoteException e) {
582                 Log.v(TAG, "Remote exception in rename(): ", e);
583             }
584         } else {
585             Log.w(TAG, "rename(): Service not connected!");
586         }
587     }
588 
589     /**
590      * Obtain the list of enrolled fingerprints templates.
591      * @return list of current fingerprint items
592      *
593      * @hide
594      */
595     @RequiresPermission(USE_FINGERPRINT)
getEnrolledFingerprints(int userId)596     public List<Fingerprint> getEnrolledFingerprints(int userId) {
597         if (mService != null) try {
598             return mService.getEnrolledFingerprints(userId, mContext.getOpPackageName());
599         } catch (RemoteException e) {
600             Log.v(TAG, "Remote exception in getEnrolledFingerprints: ", e);
601         }
602         return null;
603     }
604 
605     /**
606      * Obtain the list of enrolled fingerprints templates.
607      * @return list of current fingerprint items
608      *
609      * @hide
610      */
611     @RequiresPermission(USE_FINGERPRINT)
getEnrolledFingerprints()612     public List<Fingerprint> getEnrolledFingerprints() {
613         return getEnrolledFingerprints(UserHandle.myUserId());
614     }
615 
616     /**
617      * Determine if there is at least one fingerprint enrolled.
618      *
619      * @return true if at least one fingerprint is enrolled, false otherwise
620      */
621     @RequiresPermission(USE_FINGERPRINT)
hasEnrolledFingerprints()622     public boolean hasEnrolledFingerprints() {
623         if (mService != null) try {
624             return mService.hasEnrolledFingerprints(UserHandle.myUserId(),
625                     mContext.getOpPackageName());
626         } catch (RemoteException e) {
627             Log.v(TAG, "Remote exception in getEnrolledFingerprints: ", e);
628         }
629         return false;
630     }
631 
632     /**
633      * Determine if fingerprint hardware is present and functional.
634      *
635      * @return true if hardware is present and functional, false otherwise.
636      */
637     @RequiresPermission(USE_FINGERPRINT)
isHardwareDetected()638     public boolean isHardwareDetected() {
639         if (mService != null) {
640             try {
641                 long deviceId = 0; /* TODO: plumb hardware id to FPMS */
642                 return mService.isHardwareDetected(deviceId, mContext.getOpPackageName());
643             } catch (RemoteException e) {
644                 Log.v(TAG, "Remote exception in isFingerprintHardwareDetected(): ", e);
645             }
646         } else {
647             Log.w(TAG, "isFingerprintHardwareDetected(): Service not connected!");
648         }
649         return false;
650     }
651 
652     /**
653      * Retrieves the authenticator token for binding keys to the lifecycle
654      * of the current set of fingerprints. Used only by internal clients.
655      *
656      * @hide
657      */
getAuthenticatorId()658     public long getAuthenticatorId() {
659         if (mService != null) {
660             try {
661                 return mService.getAuthenticatorId(mContext.getOpPackageName());
662             } catch (RemoteException e) {
663                 Log.v(TAG, "Remote exception in getAuthenticatorId(): ", e);
664             }
665         } else {
666             Log.w(TAG, "getAuthenticatorId(): Service not connected!");
667         }
668         return 0;
669     }
670 
671     private class MyHandler extends Handler {
MyHandler(Context context)672         private MyHandler(Context context) {
673             super(context.getMainLooper());
674         }
675 
MyHandler(Looper looper)676         private MyHandler(Looper looper) {
677             super(looper);
678         }
679 
handleMessage(android.os.Message msg)680         public void handleMessage(android.os.Message msg) {
681             switch(msg.what) {
682                 case MSG_ENROLL_RESULT:
683                     sendEnrollResult((Fingerprint) msg.obj, msg.arg1 /* remaining */);
684                     break;
685                 case MSG_ACQUIRED:
686                     sendAcquiredResult((Long) msg.obj /* deviceId */, msg.arg1 /* acquire info */);
687                     break;
688                 case MSG_AUTHENTICATION_SUCCEEDED:
689                     sendAuthenticatedSucceeded((Fingerprint) msg.obj);
690                     break;
691                 case MSG_AUTHENTICATION_FAILED:
692                     sendAuthenticatedFailed();
693                     break;
694                 case MSG_ERROR:
695                     sendErrorResult((Long) msg.obj /* deviceId */, msg.arg1 /* errMsgId */);
696                     break;
697                 case MSG_REMOVED:
698                     sendRemovedResult((Long) msg.obj /* deviceId */, msg.arg1 /* fingerId */,
699                             msg.arg2 /* groupId */);
700             }
701         }
702 
sendRemovedResult(long deviceId, int fingerId, int groupId)703         private void sendRemovedResult(long deviceId, int fingerId, int groupId) {
704             if (mRemovalCallback != null) {
705                 int reqFingerId = mRemovalFingerprint.getFingerId();
706                 int reqGroupId = mRemovalFingerprint.getGroupId();
707                 if (fingerId != reqFingerId) {
708                     Log.w(TAG, "Finger id didn't match: " + fingerId + " != " + reqFingerId);
709                 }
710                 if (fingerId != reqFingerId) {
711                     Log.w(TAG, "Group id didn't match: " + groupId + " != " + reqGroupId);
712                 }
713                 mRemovalCallback.onRemovalSucceeded(mRemovalFingerprint);
714             }
715         }
716 
sendErrorResult(long deviceId, int errMsgId)717         private void sendErrorResult(long deviceId, int errMsgId) {
718             if (mEnrollmentCallback != null) {
719                 mEnrollmentCallback.onEnrollmentError(errMsgId, getErrorString(errMsgId));
720             } else if (mAuthenticationCallback != null) {
721                 mAuthenticationCallback.onAuthenticationError(errMsgId, getErrorString(errMsgId));
722             } else if (mRemovalCallback != null) {
723                 mRemovalCallback.onRemovalError(mRemovalFingerprint, errMsgId,
724                         getErrorString(errMsgId));
725             }
726         }
727 
sendEnrollResult(Fingerprint fp, int remaining)728         private void sendEnrollResult(Fingerprint fp, int remaining) {
729             if (mEnrollmentCallback != null) {
730                 mEnrollmentCallback.onEnrollmentProgress(remaining);
731             }
732         }
733 
sendAuthenticatedSucceeded(Fingerprint fp)734         private void sendAuthenticatedSucceeded(Fingerprint fp) {
735             if (mAuthenticationCallback != null) {
736                 final AuthenticationResult result = new AuthenticationResult(mCryptoObject, fp);
737                 mAuthenticationCallback.onAuthenticationSucceeded(result);
738             }
739         }
740 
sendAuthenticatedFailed()741         private void sendAuthenticatedFailed() {
742             if (mAuthenticationCallback != null) {
743                mAuthenticationCallback.onAuthenticationFailed();
744             }
745         }
746 
sendAcquiredResult(long deviceId, int acquireInfo)747         private void sendAcquiredResult(long deviceId, int acquireInfo) {
748             if (mAuthenticationCallback != null) {
749                 mAuthenticationCallback.onAuthenticationAcquired(acquireInfo);
750             }
751             final String msg = getAcquiredString(acquireInfo);
752             if (msg == null) {
753                 return;
754             }
755             if (mEnrollmentCallback != null) {
756                 mEnrollmentCallback.onEnrollmentHelp(acquireInfo, msg);
757             } else if (mAuthenticationCallback != null) {
758                 mAuthenticationCallback.onAuthenticationHelp(acquireInfo, msg);
759             }
760         }
761     };
762 
763     /**
764      * @hide
765      */
FingerprintManager(Context context, IFingerprintService service)766     public FingerprintManager(Context context, IFingerprintService service) {
767         mContext = context;
768         mService = service;
769         if (mService == null) {
770             Slog.v(TAG, "FingerprintManagerService was null");
771         }
772         mHandler = new MyHandler(context);
773     }
774 
getCurrentUserId()775     private int getCurrentUserId() {
776         try {
777             return ActivityManagerNative.getDefault().getCurrentUser().id;
778         } catch (RemoteException e) {
779             Log.w(TAG, "Failed to get current user id\n");
780             return UserHandle.USER_NULL;
781         }
782     }
783 
cancelEnrollment()784     private void cancelEnrollment() {
785         if (mService != null) try {
786             mService.cancelEnrollment(mToken);
787         } catch (RemoteException e) {
788             if (DEBUG) Log.w(TAG, "Remote exception while canceling enrollment");
789         }
790     }
791 
cancelAuthentication(CryptoObject cryptoObject)792     private void cancelAuthentication(CryptoObject cryptoObject) {
793         if (mService != null) try {
794             mService.cancelAuthentication(mToken, mContext.getOpPackageName());
795         } catch (RemoteException e) {
796             if (DEBUG) Log.w(TAG, "Remote exception while canceling enrollment");
797         }
798     }
799 
getErrorString(int errMsg)800     private String getErrorString(int errMsg) {
801         switch (errMsg) {
802             case FINGERPRINT_ERROR_UNABLE_TO_PROCESS:
803                 return mContext.getString(
804                     com.android.internal.R.string.fingerprint_error_unable_to_process);
805             case FINGERPRINT_ERROR_HW_UNAVAILABLE:
806                 return mContext.getString(
807                     com.android.internal.R.string.fingerprint_error_hw_not_available);
808             case FINGERPRINT_ERROR_NO_SPACE:
809                 return mContext.getString(
810                     com.android.internal.R.string.fingerprint_error_no_space);
811             case FINGERPRINT_ERROR_TIMEOUT:
812                 return mContext.getString(com.android.internal.R.string.fingerprint_error_timeout);
813             case FINGERPRINT_ERROR_CANCELED:
814                 return mContext.getString(com.android.internal.R.string.fingerprint_error_canceled);
815             case FINGERPRINT_ERROR_LOCKOUT:
816                 return mContext.getString(com.android.internal.R.string.fingerprint_error_lockout);
817             default:
818                 if (errMsg >= FINGERPRINT_ERROR_VENDOR_BASE) {
819                     int msgNumber = errMsg - FINGERPRINT_ERROR_VENDOR_BASE;
820                     String[] msgArray = mContext.getResources().getStringArray(
821                             com.android.internal.R.array.fingerprint_error_vendor);
822                     if (msgNumber < msgArray.length) {
823                         return msgArray[msgNumber];
824                     }
825                 }
826                 return null;
827         }
828     }
829 
getAcquiredString(int acquireInfo)830     private String getAcquiredString(int acquireInfo) {
831         switch (acquireInfo) {
832             case FINGERPRINT_ACQUIRED_GOOD:
833                 return null;
834             case FINGERPRINT_ACQUIRED_PARTIAL:
835                 return mContext.getString(
836                     com.android.internal.R.string.fingerprint_acquired_partial);
837             case FINGERPRINT_ACQUIRED_INSUFFICIENT:
838                 return mContext.getString(
839                     com.android.internal.R.string.fingerprint_acquired_insufficient);
840             case FINGERPRINT_ACQUIRED_IMAGER_DIRTY:
841                 return mContext.getString(
842                     com.android.internal.R.string.fingerprint_acquired_imager_dirty);
843             case FINGERPRINT_ACQUIRED_TOO_SLOW:
844                 return mContext.getString(
845                     com.android.internal.R.string.fingerprint_acquired_too_slow);
846             case FINGERPRINT_ACQUIRED_TOO_FAST:
847                 return mContext.getString(
848                     com.android.internal.R.string.fingerprint_acquired_too_fast);
849             default:
850                 if (acquireInfo >= FINGERPRINT_ACQUIRED_VENDOR_BASE) {
851                     int msgNumber = acquireInfo - FINGERPRINT_ACQUIRED_VENDOR_BASE;
852                     String[] msgArray = mContext.getResources().getStringArray(
853                             com.android.internal.R.array.fingerprint_acquired_vendor);
854                     if (msgNumber < msgArray.length) {
855                         return msgArray[msgNumber];
856                     }
857                 }
858                 return null;
859         }
860     }
861 
862     private IFingerprintServiceReceiver mServiceReceiver = new IFingerprintServiceReceiver.Stub() {
863 
864         @Override // binder call
865         public void onEnrollResult(long deviceId, int fingerId, int groupId, int remaining) {
866             mHandler.obtainMessage(MSG_ENROLL_RESULT, remaining, 0,
867                     new Fingerprint(null, groupId, fingerId, deviceId)).sendToTarget();
868         }
869 
870         @Override // binder call
871         public void onAcquired(long deviceId, int acquireInfo) {
872             mHandler.obtainMessage(MSG_ACQUIRED, acquireInfo, 0, deviceId).sendToTarget();
873         }
874 
875         @Override // binder call
876         public void onAuthenticationSucceeded(long deviceId, Fingerprint fp) {
877             mHandler.obtainMessage(MSG_AUTHENTICATION_SUCCEEDED, fp).sendToTarget();
878         }
879 
880         @Override // binder call
881         public void onAuthenticationFailed(long deviceId) {
882             mHandler.obtainMessage(MSG_AUTHENTICATION_FAILED).sendToTarget();;
883         }
884 
885         @Override // binder call
886         public void onError(long deviceId, int error) {
887             mHandler.obtainMessage(MSG_ERROR, error, 0, deviceId).sendToTarget();
888         }
889 
890         @Override // binder call
891         public void onRemoved(long deviceId, int fingerId, int groupId) {
892             mHandler.obtainMessage(MSG_REMOVED, fingerId, groupId, deviceId).sendToTarget();
893         }
894     };
895 
896 }
897 
898