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