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