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