• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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         private int mUserId;
263 
264         /**
265          * Authentication result
266          *
267          * @param crypto the crypto object
268          * @param fingerprint the recognized fingerprint data, if allowed.
269          * @hide
270          */
AuthenticationResult(CryptoObject crypto, Fingerprint fingerprint, int userId)271         public AuthenticationResult(CryptoObject crypto, Fingerprint fingerprint, int userId) {
272             mCryptoObject = crypto;
273             mFingerprint = fingerprint;
274             mUserId = userId;
275         }
276 
277         /**
278          * Obtain the crypto object associated with this transaction
279          * @return crypto object provided to {@link FingerprintManager#authenticate(CryptoObject,
280          *     CancellationSignal, int, AuthenticationCallback, Handler)}.
281          */
getCryptoObject()282         public CryptoObject getCryptoObject() { return mCryptoObject; }
283 
284         /**
285          * Obtain the Fingerprint associated with this operation. Applications are strongly
286          * discouraged from associating specific fingers with specific applications or operations.
287          *
288          * @hide
289          */
getFingerprint()290         public Fingerprint getFingerprint() { return mFingerprint; }
291 
292         /**
293          * Obtain the userId for which this fingerprint was authenticated.
294          * @hide
295          */
getUserId()296         public int getUserId() { return mUserId; }
297     };
298 
299     /**
300      * Callback structure provided to {@link FingerprintManager#authenticate(CryptoObject,
301      * CancellationSignal, int, AuthenticationCallback, Handler)}. Users of {@link
302      * FingerprintManager#authenticate(CryptoObject, CancellationSignal,
303      * int, AuthenticationCallback, Handler) } must provide an implementation of this for listening to
304      * fingerprint events.
305      */
306     public static abstract class AuthenticationCallback {
307         /**
308          * Called when an unrecoverable error has been encountered and the operation is complete.
309          * No further callbacks will be made on this object.
310          * @param errorCode An integer identifying the error message
311          * @param errString A human-readable error string that can be shown in UI
312          */
onAuthenticationError(int errorCode, CharSequence errString)313         public void onAuthenticationError(int errorCode, CharSequence errString) { }
314 
315         /**
316          * Called when a recoverable error has been encountered during authentication. The help
317          * string is provided to give the user guidance for what went wrong, such as
318          * "Sensor dirty, please clean it."
319          * @param helpCode An integer identifying the error message
320          * @param helpString A human-readable string that can be shown in UI
321          */
onAuthenticationHelp(int helpCode, CharSequence helpString)322         public void onAuthenticationHelp(int helpCode, CharSequence helpString) { }
323 
324         /**
325          * Called when a fingerprint is recognized.
326          * @param result An object containing authentication-related data
327          */
onAuthenticationSucceeded(AuthenticationResult result)328         public void onAuthenticationSucceeded(AuthenticationResult result) { }
329 
330         /**
331          * Called when a fingerprint is valid but not recognized.
332          */
onAuthenticationFailed()333         public void onAuthenticationFailed() { }
334 
335         /**
336          * Called when a fingerprint image has been acquired, but wasn't processed yet.
337          *
338          * @param acquireInfo one of FINGERPRINT_ACQUIRED_* constants
339          * @hide
340          */
onAuthenticationAcquired(int acquireInfo)341         public void onAuthenticationAcquired(int acquireInfo) {}
342     };
343 
344     /**
345      * Callback structure provided to {@link FingerprintManager#enroll(long, EnrollmentCallback,
346      * CancellationSignal, int). Users of {@link #FingerprintManager()}
347      * must provide an implementation of this to {@link FingerprintManager#enroll(long,
348      * CancellationSignal, int, EnrollmentCallback) for listening to fingerprint events.
349      *
350      * @hide
351      */
352     public static abstract class EnrollmentCallback {
353         /**
354          * Called when an unrecoverable error has been encountered and the operation is complete.
355          * No further callbacks will be made on this object.
356          * @param errMsgId An integer identifying the error message
357          * @param errString A human-readable error string that can be shown in UI
358          */
onEnrollmentError(int errMsgId, CharSequence errString)359         public void onEnrollmentError(int errMsgId, CharSequence errString) { }
360 
361         /**
362          * Called when a recoverable error has been encountered during enrollment. The help
363          * string is provided to give the user guidance for what went wrong, such as
364          * "Sensor dirty, please clean it" or what they need to do next, such as
365          * "Touch sensor again."
366          * @param helpMsgId An integer identifying the error message
367          * @param helpString A human-readable string that can be shown in UI
368          */
onEnrollmentHelp(int helpMsgId, CharSequence helpString)369         public void onEnrollmentHelp(int helpMsgId, CharSequence helpString) { }
370 
371         /**
372          * Called as each enrollment step progresses. Enrollment is considered complete when
373          * remaining reaches 0. This function will not be called if enrollment fails. See
374          * {@link EnrollmentCallback#onEnrollmentError(int, CharSequence)}
375          * @param remaining The number of remaining steps
376          */
onEnrollmentProgress(int remaining)377         public void onEnrollmentProgress(int remaining) { }
378     };
379 
380     /**
381      * Callback structure provided to {@link FingerprintManager#remove(int). Users of
382      * {@link #FingerprintManager()} may optionally provide an implementation of this to
383      * {@link FingerprintManager#remove(int, int, RemovalCallback)} for listening to
384      * fingerprint template removal events.
385      *
386      * @hide
387      */
388     public static abstract class RemovalCallback {
389         /**
390          * Called when the given fingerprint can't be removed.
391          * @param fp The fingerprint that the call attempted to remove
392          * @param errMsgId An associated error message id
393          * @param errString An error message indicating why the fingerprint id can't be removed
394          */
onRemovalError(Fingerprint fp, int errMsgId, CharSequence errString)395         public void onRemovalError(Fingerprint fp, int errMsgId, CharSequence errString) { }
396 
397         /**
398          * Called when a given fingerprint is successfully removed.
399          * @param fingerprint the fingerprint template that was removed.
400          */
onRemovalSucceeded(Fingerprint fingerprint)401         public void onRemovalSucceeded(Fingerprint fingerprint) { }
402     };
403 
404     /**
405      * @hide
406      */
407     public static abstract class LockoutResetCallback {
408 
409         /**
410          * Called when lockout period expired and clients are allowed to listen for fingerprint
411          * again.
412          */
onLockoutReset()413         public void onLockoutReset() { }
414     };
415 
416     /**
417      * Request authentication of a crypto object. This call warms up the fingerprint hardware
418      * and starts scanning for a fingerprint. It terminates when
419      * {@link AuthenticationCallback#onAuthenticationError(int, CharSequence)} or
420      * {@link AuthenticationCallback#onAuthenticationSucceeded(AuthenticationResult)} is called, at
421      * which point the object is no longer valid. The operation can be canceled by using the
422      * provided cancel object.
423      *
424      * @param crypto object associated with the call or null if none required.
425      * @param cancel an object that can be used to cancel authentication
426      * @param flags optional flags; should be 0
427      * @param callback an object to receive authentication events
428      * @param handler an optional handler to handle callback events
429      *
430      * @throws IllegalArgumentException if the crypto operation is not supported or is not backed
431      *         by <a href="{@docRoot}training/articles/keystore.html">Android Keystore
432      *         facility</a>.
433      * @throws IllegalStateException if the crypto primitive is not initialized.
434      */
435     @RequiresPermission(USE_FINGERPRINT)
authenticate(@ullable CryptoObject crypto, @Nullable CancellationSignal cancel, int flags, @NonNull AuthenticationCallback callback, @Nullable Handler handler)436     public void authenticate(@Nullable CryptoObject crypto, @Nullable CancellationSignal cancel,
437             int flags, @NonNull AuthenticationCallback callback, @Nullable Handler handler) {
438         authenticate(crypto, cancel, flags, callback, handler, UserHandle.myUserId());
439     }
440 
441     /**
442      * Use the provided handler thread for events.
443      * @param handler
444      */
useHandler(Handler handler)445     private void useHandler(Handler handler) {
446         if (handler != null) {
447             mHandler = new MyHandler(handler.getLooper());
448         } else if (mHandler.getLooper() != mContext.getMainLooper()){
449             mHandler = new MyHandler(mContext.getMainLooper());
450         }
451     }
452 
453     /**
454      * Per-user version
455      * @hide
456      */
457     @RequiresPermission(USE_FINGERPRINT)
authenticate(@ullable CryptoObject crypto, @Nullable CancellationSignal cancel, int flags, @NonNull AuthenticationCallback callback, Handler handler, int userId)458     public void authenticate(@Nullable CryptoObject crypto, @Nullable CancellationSignal cancel,
459             int flags, @NonNull AuthenticationCallback callback, Handler handler, int userId) {
460         if (callback == null) {
461             throw new IllegalArgumentException("Must supply an authentication callback");
462         }
463 
464         if (cancel != null) {
465             if (cancel.isCanceled()) {
466                 Log.w(TAG, "authentication already canceled");
467                 return;
468             } else {
469                 cancel.setOnCancelListener(new OnAuthenticationCancelListener(crypto));
470             }
471         }
472 
473         if (mService != null) try {
474             useHandler(handler);
475             mAuthenticationCallback = callback;
476             mCryptoObject = crypto;
477             long sessionId = crypto != null ? crypto.getOpId() : 0;
478             mService.authenticate(mToken, sessionId, userId, mServiceReceiver, flags,
479                     mContext.getOpPackageName());
480         } catch (RemoteException e) {
481             Log.w(TAG, "Remote exception while authenticating: ", e);
482             if (callback != null) {
483                 // Though this may not be a hardware issue, it will cause apps to give up or try
484                 // again later.
485                 callback.onAuthenticationError(FINGERPRINT_ERROR_HW_UNAVAILABLE,
486                         getErrorString(FINGERPRINT_ERROR_HW_UNAVAILABLE));
487             }
488         }
489     }
490 
491     /**
492      * Request fingerprint enrollment. This call warms up the fingerprint hardware
493      * and starts scanning for fingerprints. Progress will be indicated by callbacks to the
494      * {@link EnrollmentCallback} object. It terminates when
495      * {@link EnrollmentCallback#onEnrollmentError(int, CharSequence)} or
496      * {@link EnrollmentCallback#onEnrollmentProgress(int) is called with remaining == 0, at
497      * which point the object is no longer valid. The operation can be canceled by using the
498      * provided cancel object.
499      * @param token a unique token provided by a recent creation or verification of device
500      * credentials (e.g. pin, pattern or password).
501      * @param cancel an object that can be used to cancel enrollment
502      * @param flags optional flags
503      * @param userId the user to whom this fingerprint will belong to
504      * @param callback an object to receive enrollment events
505      * @hide
506      */
507     @RequiresPermission(MANAGE_FINGERPRINT)
enroll(byte [] token, CancellationSignal cancel, int flags, int userId, EnrollmentCallback callback)508     public void enroll(byte [] token, CancellationSignal cancel, int flags,
509             int userId, EnrollmentCallback callback) {
510         if (userId == UserHandle.USER_CURRENT) {
511             userId = getCurrentUserId();
512         }
513         if (callback == null) {
514             throw new IllegalArgumentException("Must supply an enrollment callback");
515         }
516 
517         if (cancel != null) {
518             if (cancel.isCanceled()) {
519                 Log.w(TAG, "enrollment already canceled");
520                 return;
521             } else {
522                 cancel.setOnCancelListener(new OnEnrollCancelListener());
523             }
524         }
525 
526         if (mService != null) try {
527             mEnrollmentCallback = callback;
528             mService.enroll(mToken, token, userId, mServiceReceiver, flags,
529                     mContext.getOpPackageName());
530         } catch (RemoteException e) {
531             Log.w(TAG, "Remote exception in enroll: ", e);
532             if (callback != null) {
533                 // Though this may not be a hardware issue, it will cause apps to give up or try
534                 // again later.
535                 callback.onEnrollmentError(FINGERPRINT_ERROR_HW_UNAVAILABLE,
536                         getErrorString(FINGERPRINT_ERROR_HW_UNAVAILABLE));
537             }
538         }
539     }
540 
541     /**
542      * Requests a pre-enrollment auth token to tie enrollment to the confirmation of
543      * existing device credentials (e.g. pin/pattern/password).
544      * @hide
545      */
546     @RequiresPermission(MANAGE_FINGERPRINT)
preEnroll()547     public long preEnroll() {
548         long result = 0;
549         if (mService != null) try {
550             result = mService.preEnroll(mToken);
551         } catch (RemoteException e) {
552             throw e.rethrowFromSystemServer();
553         }
554         return result;
555     }
556 
557     /**
558      * Finishes enrollment and cancels the current auth token.
559      * @hide
560      */
561     @RequiresPermission(MANAGE_FINGERPRINT)
postEnroll()562     public int postEnroll() {
563         int result = 0;
564         if (mService != null) try {
565             result = mService.postEnroll(mToken);
566         } catch (RemoteException e) {
567             throw e.rethrowFromSystemServer();
568         }
569         return result;
570     }
571 
572     /**
573      * Sets the active user. This is meant to be used to select the current profile for enrollment
574      * to allow separate enrolled fingers for a work profile
575      * @param userId
576      * @hide
577      */
578     @RequiresPermission(MANAGE_FINGERPRINT)
setActiveUser(int userId)579     public void setActiveUser(int userId) {
580         if (mService != null) try {
581             mService.setActiveUser(userId);
582         } catch (RemoteException e) {
583             throw e.rethrowFromSystemServer();
584         }
585     }
586 
587     /**
588      * Remove given fingerprint template from fingerprint hardware and/or protected storage.
589      * @param fp the fingerprint item to remove
590      * @param userId the user who this fingerprint belongs to
591      * @param callback an optional callback to verify that fingerprint templates have been
592      * successfully removed. May be null of no callback is required.
593      *
594      * @hide
595      */
596     @RequiresPermission(MANAGE_FINGERPRINT)
remove(Fingerprint fp, int userId, RemovalCallback callback)597     public void remove(Fingerprint fp, int userId, RemovalCallback callback) {
598         if (mService != null) try {
599             mRemovalCallback = callback;
600             mRemovalFingerprint = fp;
601             mService.remove(mToken, fp.getFingerId(), fp.getGroupId(), userId, mServiceReceiver);
602         } catch (RemoteException e) {
603             Log.w(TAG, "Remote exception in remove: ", e);
604             if (callback != null) {
605                 callback.onRemovalError(fp, FINGERPRINT_ERROR_HW_UNAVAILABLE,
606                         getErrorString(FINGERPRINT_ERROR_HW_UNAVAILABLE));
607             }
608         }
609     }
610 
611     /**
612      * Renames the given fingerprint template
613      * @param fpId the fingerprint id
614      * @param userId the user who this fingerprint belongs to
615      * @param newName the new name
616      *
617      * @hide
618      */
619     @RequiresPermission(MANAGE_FINGERPRINT)
rename(int fpId, int userId, String newName)620     public void rename(int fpId, int userId, String newName) {
621         // Renames the given fpId
622         if (mService != null) {
623             try {
624                 mService.rename(fpId, userId, newName);
625             } catch (RemoteException e) {
626                 throw e.rethrowFromSystemServer();
627             }
628         } else {
629             Log.w(TAG, "rename(): Service not connected!");
630         }
631     }
632 
633     /**
634      * Obtain the list of enrolled fingerprints templates.
635      * @return list of current fingerprint items
636      *
637      * @hide
638      */
639     @RequiresPermission(USE_FINGERPRINT)
getEnrolledFingerprints(int userId)640     public List<Fingerprint> getEnrolledFingerprints(int userId) {
641         if (mService != null) try {
642             return mService.getEnrolledFingerprints(userId, mContext.getOpPackageName());
643         } catch (RemoteException e) {
644             throw e.rethrowFromSystemServer();
645         }
646         return null;
647     }
648 
649     /**
650      * Obtain the list of enrolled fingerprints templates.
651      * @return list of current fingerprint items
652      *
653      * @hide
654      */
655     @RequiresPermission(USE_FINGERPRINT)
getEnrolledFingerprints()656     public List<Fingerprint> getEnrolledFingerprints() {
657         return getEnrolledFingerprints(UserHandle.myUserId());
658     }
659 
660     /**
661      * Determine if there is at least one fingerprint enrolled.
662      *
663      * @return true if at least one fingerprint is enrolled, false otherwise
664      */
665     @RequiresPermission(USE_FINGERPRINT)
hasEnrolledFingerprints()666     public boolean hasEnrolledFingerprints() {
667         if (mService != null) try {
668             return mService.hasEnrolledFingerprints(
669                     UserHandle.myUserId(), mContext.getOpPackageName());
670         } catch (RemoteException e) {
671             throw e.rethrowFromSystemServer();
672         }
673         return false;
674     }
675 
676     /**
677      * @hide
678      */
679     @RequiresPermission(allOf = {
680             USE_FINGERPRINT,
681             INTERACT_ACROSS_USERS})
hasEnrolledFingerprints(int userId)682     public boolean hasEnrolledFingerprints(int userId) {
683         if (mService != null) try {
684             return mService.hasEnrolledFingerprints(userId, mContext.getOpPackageName());
685         } catch (RemoteException e) {
686             throw e.rethrowFromSystemServer();
687         }
688         return false;
689     }
690 
691     /**
692      * Determine if fingerprint hardware is present and functional.
693      *
694      * @return true if hardware is present and functional, false otherwise.
695      */
696     @RequiresPermission(USE_FINGERPRINT)
isHardwareDetected()697     public boolean isHardwareDetected() {
698         if (mService != null) {
699             try {
700                 long deviceId = 0; /* TODO: plumb hardware id to FPMS */
701                 return mService.isHardwareDetected(deviceId, mContext.getOpPackageName());
702             } catch (RemoteException e) {
703                 throw e.rethrowFromSystemServer();
704             }
705         } else {
706             Log.w(TAG, "isFingerprintHardwareDetected(): Service not connected!");
707         }
708         return false;
709     }
710 
711     /**
712      * Retrieves the authenticator token for binding keys to the lifecycle
713      * of the current set of fingerprints. Used only by internal clients.
714      *
715      * @hide
716      */
getAuthenticatorId()717     public long getAuthenticatorId() {
718         if (mService != null) {
719             try {
720                 return mService.getAuthenticatorId(mContext.getOpPackageName());
721             } catch (RemoteException e) {
722                 throw e.rethrowFromSystemServer();
723             }
724         } else {
725             Log.w(TAG, "getAuthenticatorId(): Service not connected!");
726         }
727         return 0;
728     }
729 
730     /**
731      * Reset the lockout timer when asked to do so by keyguard.
732      *
733      * @param token an opaque token returned by password confirmation.
734      *
735      * @hide
736      */
resetTimeout(byte[] token)737     public void resetTimeout(byte[] token) {
738         if (mService != null) {
739             try {
740                 mService.resetTimeout(token);
741             } catch (RemoteException e) {
742                 throw e.rethrowFromSystemServer();
743             }
744         } else {
745             Log.w(TAG, "resetTimeout(): Service not connected!");
746         }
747     }
748 
749     /**
750      * @hide
751      */
addLockoutResetCallback(final LockoutResetCallback callback)752     public void addLockoutResetCallback(final LockoutResetCallback callback) {
753         if (mService != null) {
754             try {
755                 final PowerManager powerManager = mContext.getSystemService(PowerManager.class);
756                 mService.addLockoutResetCallback(
757                         new IFingerprintServiceLockoutResetCallback.Stub() {
758 
759                     @Override
760                     public void onLockoutReset(long deviceId) throws RemoteException {
761                         final PowerManager.WakeLock wakeLock = powerManager.newWakeLock(
762                                 PowerManager.PARTIAL_WAKE_LOCK, "lockoutResetCallback");
763                         wakeLock.acquire();
764                         mHandler.post(new Runnable() {
765                             @Override
766                             public void run() {
767                                 try {
768                                     callback.onLockoutReset();
769                                 } finally {
770                                     wakeLock.release();
771                                 }
772                             }
773                         });
774                     }
775                 });
776             } catch (RemoteException e) {
777                 throw e.rethrowFromSystemServer();
778             }
779         } else {
780             Log.w(TAG, "addLockoutResetCallback(): Service not connected!");
781         }
782     }
783 
784     private class MyHandler extends Handler {
MyHandler(Context context)785         private MyHandler(Context context) {
786             super(context.getMainLooper());
787         }
788 
MyHandler(Looper looper)789         private MyHandler(Looper looper) {
790             super(looper);
791         }
792 
793         @Override
handleMessage(android.os.Message msg)794         public void handleMessage(android.os.Message msg) {
795             switch(msg.what) {
796                 case MSG_ENROLL_RESULT:
797                     sendEnrollResult((Fingerprint) msg.obj, msg.arg1 /* remaining */);
798                     break;
799                 case MSG_ACQUIRED:
800                     sendAcquiredResult((Long) msg.obj /* deviceId */, msg.arg1 /* acquire info */);
801                     break;
802                 case MSG_AUTHENTICATION_SUCCEEDED:
803                     sendAuthenticatedSucceeded((Fingerprint) msg.obj, msg.arg1 /* userId */);
804                     break;
805                 case MSG_AUTHENTICATION_FAILED:
806                     sendAuthenticatedFailed();
807                     break;
808                 case MSG_ERROR:
809                     sendErrorResult((Long) msg.obj /* deviceId */, msg.arg1 /* errMsgId */);
810                     break;
811                 case MSG_REMOVED:
812                     sendRemovedResult((Long) msg.obj /* deviceId */, msg.arg1 /* fingerId */,
813                             msg.arg2 /* groupId */);
814             }
815         }
816 
sendRemovedResult(long deviceId, int fingerId, int groupId)817         private void sendRemovedResult(long deviceId, int fingerId, int groupId) {
818             if (mRemovalCallback != null) {
819                 int reqFingerId = mRemovalFingerprint.getFingerId();
820                 int reqGroupId = mRemovalFingerprint.getGroupId();
821                 if (reqFingerId != 0 && fingerId != 0  &&  fingerId != reqFingerId) {
822                     Log.w(TAG, "Finger id didn't match: " + fingerId + " != " + reqFingerId);
823                     return;
824                 }
825                 if (groupId != reqGroupId) {
826                     Log.w(TAG, "Group id didn't match: " + groupId + " != " + reqGroupId);
827                     return;
828                 }
829                 mRemovalCallback.onRemovalSucceeded(new Fingerprint(null, groupId, fingerId,
830                         deviceId));
831             }
832         }
833 
sendErrorResult(long deviceId, int errMsgId)834         private void sendErrorResult(long deviceId, int errMsgId) {
835             if (mEnrollmentCallback != null) {
836                 mEnrollmentCallback.onEnrollmentError(errMsgId, getErrorString(errMsgId));
837             } else if (mAuthenticationCallback != null) {
838                 mAuthenticationCallback.onAuthenticationError(errMsgId, getErrorString(errMsgId));
839             } else if (mRemovalCallback != null) {
840                 mRemovalCallback.onRemovalError(mRemovalFingerprint, errMsgId,
841                         getErrorString(errMsgId));
842             }
843         }
844 
sendEnrollResult(Fingerprint fp, int remaining)845         private void sendEnrollResult(Fingerprint fp, int remaining) {
846             if (mEnrollmentCallback != null) {
847                 mEnrollmentCallback.onEnrollmentProgress(remaining);
848             }
849         }
850 
sendAuthenticatedSucceeded(Fingerprint fp, int userId)851         private void sendAuthenticatedSucceeded(Fingerprint fp, int userId) {
852             if (mAuthenticationCallback != null) {
853                 final AuthenticationResult result =
854                         new AuthenticationResult(mCryptoObject, fp, userId);
855                 mAuthenticationCallback.onAuthenticationSucceeded(result);
856             }
857         }
858 
sendAuthenticatedFailed()859         private void sendAuthenticatedFailed() {
860             if (mAuthenticationCallback != null) {
861                mAuthenticationCallback.onAuthenticationFailed();
862             }
863         }
864 
sendAcquiredResult(long deviceId, int acquireInfo)865         private void sendAcquiredResult(long deviceId, int acquireInfo) {
866             if (mAuthenticationCallback != null) {
867                 mAuthenticationCallback.onAuthenticationAcquired(acquireInfo);
868             }
869             final String msg = getAcquiredString(acquireInfo);
870             if (msg == null) {
871                 return;
872             }
873             if (mEnrollmentCallback != null) {
874                 mEnrollmentCallback.onEnrollmentHelp(acquireInfo, msg);
875             } else if (mAuthenticationCallback != null) {
876                 mAuthenticationCallback.onAuthenticationHelp(acquireInfo, msg);
877             }
878         }
879     };
880 
881     /**
882      * @hide
883      */
FingerprintManager(Context context, IFingerprintService service)884     public FingerprintManager(Context context, IFingerprintService service) {
885         mContext = context;
886         mService = service;
887         if (mService == null) {
888             Slog.v(TAG, "FingerprintManagerService was null");
889         }
890         mHandler = new MyHandler(context);
891     }
892 
getCurrentUserId()893     private int getCurrentUserId() {
894         try {
895             return ActivityManagerNative.getDefault().getCurrentUser().id;
896         } catch (RemoteException e) {
897             throw e.rethrowFromSystemServer();
898         }
899     }
900 
cancelEnrollment()901     private void cancelEnrollment() {
902         if (mService != null) try {
903             mService.cancelEnrollment(mToken);
904         } catch (RemoteException e) {
905             throw e.rethrowFromSystemServer();
906         }
907     }
908 
cancelAuthentication(CryptoObject cryptoObject)909     private void cancelAuthentication(CryptoObject cryptoObject) {
910         if (mService != null) try {
911             mService.cancelAuthentication(mToken, mContext.getOpPackageName());
912         } catch (RemoteException e) {
913             throw e.rethrowFromSystemServer();
914         }
915     }
916 
getErrorString(int errMsg)917     private String getErrorString(int errMsg) {
918         switch (errMsg) {
919             case FINGERPRINT_ERROR_UNABLE_TO_PROCESS:
920                 return mContext.getString(
921                     com.android.internal.R.string.fingerprint_error_unable_to_process);
922             case FINGERPRINT_ERROR_HW_UNAVAILABLE:
923                 return mContext.getString(
924                     com.android.internal.R.string.fingerprint_error_hw_not_available);
925             case FINGERPRINT_ERROR_NO_SPACE:
926                 return mContext.getString(
927                     com.android.internal.R.string.fingerprint_error_no_space);
928             case FINGERPRINT_ERROR_TIMEOUT:
929                 return mContext.getString(com.android.internal.R.string.fingerprint_error_timeout);
930             case FINGERPRINT_ERROR_CANCELED:
931                 return mContext.getString(com.android.internal.R.string.fingerprint_error_canceled);
932             case FINGERPRINT_ERROR_LOCKOUT:
933                 return mContext.getString(com.android.internal.R.string.fingerprint_error_lockout);
934             default:
935                 if (errMsg >= FINGERPRINT_ERROR_VENDOR_BASE) {
936                     int msgNumber = errMsg - FINGERPRINT_ERROR_VENDOR_BASE;
937                     String[] msgArray = mContext.getResources().getStringArray(
938                             com.android.internal.R.array.fingerprint_error_vendor);
939                     if (msgNumber < msgArray.length) {
940                         return msgArray[msgNumber];
941                     }
942                 }
943                 return null;
944         }
945     }
946 
getAcquiredString(int acquireInfo)947     private String getAcquiredString(int acquireInfo) {
948         switch (acquireInfo) {
949             case FINGERPRINT_ACQUIRED_GOOD:
950                 return null;
951             case FINGERPRINT_ACQUIRED_PARTIAL:
952                 return mContext.getString(
953                     com.android.internal.R.string.fingerprint_acquired_partial);
954             case FINGERPRINT_ACQUIRED_INSUFFICIENT:
955                 return mContext.getString(
956                     com.android.internal.R.string.fingerprint_acquired_insufficient);
957             case FINGERPRINT_ACQUIRED_IMAGER_DIRTY:
958                 return mContext.getString(
959                     com.android.internal.R.string.fingerprint_acquired_imager_dirty);
960             case FINGERPRINT_ACQUIRED_TOO_SLOW:
961                 return mContext.getString(
962                     com.android.internal.R.string.fingerprint_acquired_too_slow);
963             case FINGERPRINT_ACQUIRED_TOO_FAST:
964                 return mContext.getString(
965                     com.android.internal.R.string.fingerprint_acquired_too_fast);
966             default:
967                 if (acquireInfo >= FINGERPRINT_ACQUIRED_VENDOR_BASE) {
968                     int msgNumber = acquireInfo - FINGERPRINT_ACQUIRED_VENDOR_BASE;
969                     String[] msgArray = mContext.getResources().getStringArray(
970                             com.android.internal.R.array.fingerprint_acquired_vendor);
971                     if (msgNumber < msgArray.length) {
972                         return msgArray[msgNumber];
973                     }
974                 }
975                 return null;
976         }
977     }
978 
979     private IFingerprintServiceReceiver mServiceReceiver = new IFingerprintServiceReceiver.Stub() {
980 
981         @Override // binder call
982         public void onEnrollResult(long deviceId, int fingerId, int groupId, int remaining) {
983             mHandler.obtainMessage(MSG_ENROLL_RESULT, remaining, 0,
984                     new Fingerprint(null, groupId, fingerId, deviceId)).sendToTarget();
985         }
986 
987         @Override // binder call
988         public void onAcquired(long deviceId, int acquireInfo) {
989             mHandler.obtainMessage(MSG_ACQUIRED, acquireInfo, 0, deviceId).sendToTarget();
990         }
991 
992         @Override // binder call
993         public void onAuthenticationSucceeded(long deviceId, Fingerprint fp, int userId) {
994             mHandler.obtainMessage(MSG_AUTHENTICATION_SUCCEEDED, userId, 0, fp).sendToTarget();
995         }
996 
997         @Override // binder call
998         public void onAuthenticationFailed(long deviceId) {
999             mHandler.obtainMessage(MSG_AUTHENTICATION_FAILED).sendToTarget();;
1000         }
1001 
1002         @Override // binder call
1003         public void onError(long deviceId, int error) {
1004             mHandler.obtainMessage(MSG_ERROR, error, 0, deviceId).sendToTarget();
1005         }
1006 
1007         @Override // binder call
1008         public void onRemoved(long deviceId, int fingerId, int groupId) {
1009             mHandler.obtainMessage(MSG_REMOVED, fingerId, groupId, deviceId).sendToTarget();
1010         }
1011     };
1012 
1013 }
1014