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