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