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