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
263        /**
264         * Authentication result
265         *
266         * @param crypto the crypto object
267         * @param fingerprint the recognized fingerprint data, if allowed.
268         * @hide
269         */
270        public AuthenticationResult(CryptoObject crypto, Fingerprint fingerprint) {
271            mCryptoObject = crypto;
272            mFingerprint = fingerprint;
273        }
274
275        /**
276         * Obtain the crypto object associated with this transaction
277         * @return crypto object provided to {@link FingerprintManager#authenticate(CryptoObject,
278         *     CancellationSignal, int, AuthenticationCallback, Handler)}.
279         */
280        public CryptoObject getCryptoObject() { return mCryptoObject; }
281
282        /**
283         * Obtain the Fingerprint associated with this operation. Applications are strongly
284         * discouraged from associating specific fingers with specific applications or operations.
285         *
286         * @hide
287         */
288        public Fingerprint getFingerprint() { return mFingerprint; }
289    };
290
291    /**
292     * Callback structure provided to {@link FingerprintManager#authenticate(CryptoObject,
293     * CancellationSignal, int, AuthenticationCallback, Handler)}. Users of {@link
294     * FingerprintManager#authenticate(CryptoObject, CancellationSignal,
295     * int, AuthenticationCallback, Handler) } must provide an implementation of this for listening to
296     * fingerprint events.
297     */
298    public static abstract class AuthenticationCallback {
299        /**
300         * Called when an unrecoverable error has been encountered and the operation is complete.
301         * No further callbacks will be made on this object.
302         * @param errorCode An integer identifying the error message
303         * @param errString A human-readable error string that can be shown in UI
304         */
305        public void onAuthenticationError(int errorCode, CharSequence errString) { }
306
307        /**
308         * Called when a recoverable error has been encountered during authentication. The help
309         * string is provided to give the user guidance for what went wrong, such as
310         * "Sensor dirty, please clean it."
311         * @param helpCode An integer identifying the error message
312         * @param helpString A human-readable string that can be shown in UI
313         */
314        public void onAuthenticationHelp(int helpCode, CharSequence helpString) { }
315
316        /**
317         * Called when a fingerprint is recognized.
318         * @param result An object containing authentication-related data
319         */
320        public void onAuthenticationSucceeded(AuthenticationResult result) { }
321
322        /**
323         * Called when a fingerprint is valid but not recognized.
324         */
325        public void onAuthenticationFailed() { }
326
327        /**
328         * Called when a fingerprint image has been acquired, but wasn't processed yet.
329         *
330         * @param acquireInfo one of FINGERPRINT_ACQUIRED_* constants
331         * @hide
332         */
333        public void onAuthenticationAcquired(int acquireInfo) {}
334    };
335
336    /**
337     * Callback structure provided to {@link FingerprintManager#enroll(long, EnrollmentCallback,
338     * CancellationSignal, int). Users of {@link #FingerprintManager()}
339     * must provide an implementation of this to {@link FingerprintManager#enroll(long,
340     * CancellationSignal, int, EnrollmentCallback) for listening to fingerprint events.
341     *
342     * @hide
343     */
344    public static abstract class EnrollmentCallback {
345        /**
346         * Called when an unrecoverable error has been encountered and the operation is complete.
347         * No further callbacks will be made on this object.
348         * @param errMsgId An integer identifying the error message
349         * @param errString A human-readable error string that can be shown in UI
350         */
351        public void onEnrollmentError(int errMsgId, CharSequence errString) { }
352
353        /**
354         * Called when a recoverable error has been encountered during enrollment. The help
355         * string is provided to give the user guidance for what went wrong, such as
356         * "Sensor dirty, please clean it" or what they need to do next, such as
357         * "Touch sensor again."
358         * @param helpMsgId An integer identifying the error message
359         * @param helpString A human-readable string that can be shown in UI
360         */
361        public void onEnrollmentHelp(int helpMsgId, CharSequence helpString) { }
362
363        /**
364         * Called as each enrollment step progresses. Enrollment is considered complete when
365         * remaining reaches 0. This function will not be called if enrollment fails. See
366         * {@link EnrollmentCallback#onEnrollmentError(int, CharSequence)}
367         * @param remaining The number of remaining steps
368         */
369        public void onEnrollmentProgress(int remaining) { }
370    };
371
372    /**
373     * Callback structure provided to {@link FingerprintManager#remove(int). Users of
374     * {@link #FingerprintManager()} may optionally provide an implementation of this to
375     * {@link FingerprintManager#remove(int, int, RemovalCallback)} for listening to
376     * fingerprint template removal events.
377     *
378     * @hide
379     */
380    public static abstract class RemovalCallback {
381        /**
382         * Called when the given fingerprint can't be removed.
383         * @param fp The fingerprint that the call attempted to remove
384         * @param errMsgId An associated error message id
385         * @param errString An error message indicating why the fingerprint id can't be removed
386         */
387        public void onRemovalError(Fingerprint fp, int errMsgId, CharSequence errString) { }
388
389        /**
390         * Called when a given fingerprint is successfully removed.
391         * @param fingerprint the fingerprint template that was removed.
392         */
393        public void onRemovalSucceeded(Fingerprint fingerprint) { }
394    };
395
396    /**
397     * @hide
398     */
399    public static abstract class LockoutResetCallback {
400
401        /**
402         * Called when lockout period expired and clients are allowed to listen for fingerprint
403         * again.
404         */
405        public void onLockoutReset() { }
406    };
407
408    /**
409     * Request authentication of a crypto object. This call warms up the fingerprint hardware
410     * and starts scanning for a fingerprint. It terminates when
411     * {@link AuthenticationCallback#onAuthenticationError(int, CharSequence)} or
412     * {@link AuthenticationCallback#onAuthenticationSucceeded(AuthenticationResult)} is called, at
413     * which point the object is no longer valid. The operation can be canceled by using the
414     * provided cancel object.
415     *
416     * @param crypto object associated with the call or null if none required.
417     * @param cancel an object that can be used to cancel authentication
418     * @param flags optional flags; should be 0
419     * @param callback an object to receive authentication events
420     * @param handler an optional handler to handle callback events
421     *
422     * @throws IllegalArgumentException if the crypto operation is not supported or is not backed
423     *         by <a href="{@docRoot}training/articles/keystore.html">Android Keystore
424     *         facility</a>.
425     * @throws IllegalStateException if the crypto primitive is not initialized.
426     */
427    @RequiresPermission(USE_FINGERPRINT)
428    public void authenticate(@Nullable CryptoObject crypto, @Nullable CancellationSignal cancel,
429            int flags, @NonNull AuthenticationCallback callback, @Nullable Handler handler) {
430        authenticate(crypto, cancel, flags, callback, handler, UserHandle.myUserId());
431    }
432
433    /**
434     * Use the provided handler thread for events.
435     * @param handler
436     */
437    private void useHandler(Handler handler) {
438        if (handler != null) {
439            mHandler = new MyHandler(handler.getLooper());
440        } else if (mHandler.getLooper() != mContext.getMainLooper()){
441            mHandler = new MyHandler(mContext.getMainLooper());
442        }
443    }
444
445    /**
446     * Per-user version
447     * @hide
448     */
449    @RequiresPermission(USE_FINGERPRINT)
450    public void authenticate(@Nullable CryptoObject crypto, @Nullable CancellationSignal cancel,
451            int flags, @NonNull AuthenticationCallback callback, Handler handler, int userId) {
452        if (callback == null) {
453            throw new IllegalArgumentException("Must supply an authentication callback");
454        }
455
456        if (cancel != null) {
457            if (cancel.isCanceled()) {
458                Log.w(TAG, "authentication already canceled");
459                return;
460            } else {
461                cancel.setOnCancelListener(new OnAuthenticationCancelListener(crypto));
462            }
463        }
464
465        if (mService != null) try {
466            useHandler(handler);
467            mAuthenticationCallback = callback;
468            mCryptoObject = crypto;
469            long sessionId = crypto != null ? crypto.getOpId() : 0;
470            mService.authenticate(mToken, sessionId, userId, mServiceReceiver, flags,
471                    mContext.getOpPackageName());
472        } catch (RemoteException e) {
473            Log.w(TAG, "Remote exception while authenticating: ", e);
474            if (callback != null) {
475                // Though this may not be a hardware issue, it will cause apps to give up or try
476                // again later.
477                callback.onAuthenticationError(FINGERPRINT_ERROR_HW_UNAVAILABLE,
478                        getErrorString(FINGERPRINT_ERROR_HW_UNAVAILABLE));
479            }
480        }
481    }
482
483    /**
484     * Request fingerprint enrollment. This call warms up the fingerprint hardware
485     * and starts scanning for fingerprints. Progress will be indicated by callbacks to the
486     * {@link EnrollmentCallback} object. It terminates when
487     * {@link EnrollmentCallback#onEnrollmentError(int, CharSequence)} or
488     * {@link EnrollmentCallback#onEnrollmentProgress(int) is called with remaining == 0, at
489     * which point the object is no longer valid. The operation can be canceled by using the
490     * provided cancel object.
491     * @param token a unique token provided by a recent creation or verification of device
492     * credentials (e.g. pin, pattern or password).
493     * @param cancel an object that can be used to cancel enrollment
494     * @param flags optional flags
495     * @param userId the user to whom this fingerprint will belong to
496     * @param callback an object to receive enrollment events
497     * @hide
498     */
499    @RequiresPermission(MANAGE_FINGERPRINT)
500    public void enroll(byte [] token, CancellationSignal cancel, int flags,
501            int userId, EnrollmentCallback callback) {
502        if (userId == UserHandle.USER_CURRENT) {
503            userId = getCurrentUserId();
504        }
505        if (callback == null) {
506            throw new IllegalArgumentException("Must supply an enrollment callback");
507        }
508
509        if (cancel != null) {
510            if (cancel.isCanceled()) {
511                Log.w(TAG, "enrollment already canceled");
512                return;
513            } else {
514                cancel.setOnCancelListener(new OnEnrollCancelListener());
515            }
516        }
517
518        if (mService != null) try {
519            mEnrollmentCallback = callback;
520            mService.enroll(mToken, token, userId, mServiceReceiver, flags,
521                    mContext.getOpPackageName());
522        } catch (RemoteException e) {
523            Log.w(TAG, "Remote exception in enroll: ", e);
524            if (callback != null) {
525                // Though this may not be a hardware issue, it will cause apps to give up or try
526                // again later.
527                callback.onEnrollmentError(FINGERPRINT_ERROR_HW_UNAVAILABLE,
528                        getErrorString(FINGERPRINT_ERROR_HW_UNAVAILABLE));
529            }
530        }
531    }
532
533    /**
534     * Requests a pre-enrollment auth token to tie enrollment to the confirmation of
535     * existing device credentials (e.g. pin/pattern/password).
536     * @hide
537     */
538    @RequiresPermission(MANAGE_FINGERPRINT)
539    public long preEnroll() {
540        long result = 0;
541        if (mService != null) try {
542            result = mService.preEnroll(mToken);
543        } catch (RemoteException e) {
544            throw e.rethrowFromSystemServer();
545        }
546        return result;
547    }
548
549    /**
550     * Finishes enrollment and cancels the current auth token.
551     * @hide
552     */
553    @RequiresPermission(MANAGE_FINGERPRINT)
554    public int postEnroll() {
555        int result = 0;
556        if (mService != null) try {
557            result = mService.postEnroll(mToken);
558        } catch (RemoteException e) {
559            throw e.rethrowFromSystemServer();
560        }
561        return result;
562    }
563
564    /**
565     * Sets the active user. This is meant to be used to select the current profile for enrollment
566     * to allow separate enrolled fingers for a work profile
567     * @param userId
568     * @hide
569     */
570    @RequiresPermission(MANAGE_FINGERPRINT)
571    public void setActiveUser(int userId) {
572        if (mService != null) try {
573            mService.setActiveUser(userId);
574        } catch (RemoteException e) {
575            throw e.rethrowFromSystemServer();
576        }
577    }
578
579    /**
580     * Remove given fingerprint template from fingerprint hardware and/or protected storage.
581     * @param fp the fingerprint item to remove
582     * @param userId the user who this fingerprint belongs to
583     * @param callback an optional callback to verify that fingerprint templates have been
584     * successfully removed. May be null of no callback is required.
585     *
586     * @hide
587     */
588    @RequiresPermission(MANAGE_FINGERPRINT)
589    public void remove(Fingerprint fp, int userId, RemovalCallback callback) {
590        if (mService != null) try {
591            mRemovalCallback = callback;
592            mRemovalFingerprint = fp;
593            mService.remove(mToken, fp.getFingerId(), fp.getGroupId(), userId, mServiceReceiver);
594        } catch (RemoteException e) {
595            Log.w(TAG, "Remote exception in remove: ", e);
596            if (callback != null) {
597                callback.onRemovalError(fp, FINGERPRINT_ERROR_HW_UNAVAILABLE,
598                        getErrorString(FINGERPRINT_ERROR_HW_UNAVAILABLE));
599            }
600        }
601    }
602
603    /**
604     * Renames the given fingerprint template
605     * @param fpId the fingerprint id
606     * @param userId the user who this fingerprint belongs to
607     * @param newName the new name
608     *
609     * @hide
610     */
611    @RequiresPermission(MANAGE_FINGERPRINT)
612    public void rename(int fpId, int userId, String newName) {
613        // Renames the given fpId
614        if (mService != null) {
615            try {
616                mService.rename(fpId, userId, newName);
617            } catch (RemoteException e) {
618                throw e.rethrowFromSystemServer();
619            }
620        } else {
621            Log.w(TAG, "rename(): Service not connected!");
622        }
623    }
624
625    /**
626     * Obtain the list of enrolled fingerprints templates.
627     * @return list of current fingerprint items
628     *
629     * @hide
630     */
631    @RequiresPermission(USE_FINGERPRINT)
632    public List<Fingerprint> getEnrolledFingerprints(int userId) {
633        if (mService != null) try {
634            return mService.getEnrolledFingerprints(userId, mContext.getOpPackageName());
635        } catch (RemoteException e) {
636            throw e.rethrowFromSystemServer();
637        }
638        return null;
639    }
640
641    /**
642     * Obtain the list of enrolled fingerprints templates.
643     * @return list of current fingerprint items
644     *
645     * @hide
646     */
647    @RequiresPermission(USE_FINGERPRINT)
648    public List<Fingerprint> getEnrolledFingerprints() {
649        return getEnrolledFingerprints(UserHandle.myUserId());
650    }
651
652    /**
653     * Determine if there is at least one fingerprint enrolled.
654     *
655     * @return true if at least one fingerprint is enrolled, false otherwise
656     */
657    @RequiresPermission(USE_FINGERPRINT)
658    public boolean hasEnrolledFingerprints() {
659        if (mService != null) try {
660            return mService.hasEnrolledFingerprints(
661                    UserHandle.myUserId(), mContext.getOpPackageName());
662        } catch (RemoteException e) {
663            throw e.rethrowFromSystemServer();
664        }
665        return false;
666    }
667
668    /**
669     * @hide
670     */
671    @RequiresPermission(allOf = {
672            USE_FINGERPRINT,
673            INTERACT_ACROSS_USERS})
674    public boolean hasEnrolledFingerprints(int userId) {
675        if (mService != null) try {
676            return mService.hasEnrolledFingerprints(userId, mContext.getOpPackageName());
677        } catch (RemoteException e) {
678            throw e.rethrowFromSystemServer();
679        }
680        return false;
681    }
682
683    /**
684     * Determine if fingerprint hardware is present and functional.
685     *
686     * @return true if hardware is present and functional, false otherwise.
687     */
688    @RequiresPermission(USE_FINGERPRINT)
689    public boolean isHardwareDetected() {
690        if (mService != null) {
691            try {
692                long deviceId = 0; /* TODO: plumb hardware id to FPMS */
693                return mService.isHardwareDetected(deviceId, mContext.getOpPackageName());
694            } catch (RemoteException e) {
695                throw e.rethrowFromSystemServer();
696            }
697        } else {
698            Log.w(TAG, "isFingerprintHardwareDetected(): Service not connected!");
699        }
700        return false;
701    }
702
703    /**
704     * Retrieves the authenticator token for binding keys to the lifecycle
705     * of the current set of fingerprints. Used only by internal clients.
706     *
707     * @hide
708     */
709    public long getAuthenticatorId() {
710        if (mService != null) {
711            try {
712                return mService.getAuthenticatorId(mContext.getOpPackageName());
713            } catch (RemoteException e) {
714                throw e.rethrowFromSystemServer();
715            }
716        } else {
717            Log.w(TAG, "getAuthenticatorId(): Service not connected!");
718        }
719        return 0;
720    }
721
722    /**
723     * Reset the lockout timer when asked to do so by keyguard.
724     *
725     * @param token an opaque token returned by password confirmation.
726     *
727     * @hide
728     */
729    public void resetTimeout(byte[] token) {
730        if (mService != null) {
731            try {
732                mService.resetTimeout(token);
733            } catch (RemoteException e) {
734                throw e.rethrowFromSystemServer();
735            }
736        } else {
737            Log.w(TAG, "resetTimeout(): Service not connected!");
738        }
739    }
740
741    /**
742     * @hide
743     */
744    public void addLockoutResetCallback(final LockoutResetCallback callback) {
745        if (mService != null) {
746            try {
747                final PowerManager powerManager = mContext.getSystemService(PowerManager.class);
748                mService.addLockoutResetCallback(
749                        new IFingerprintServiceLockoutResetCallback.Stub() {
750
751                    @Override
752                    public void onLockoutReset(long deviceId) throws RemoteException {
753                        final PowerManager.WakeLock wakeLock = powerManager.newWakeLock(
754                                PowerManager.PARTIAL_WAKE_LOCK, "lockoutResetCallback");
755                        wakeLock.acquire();
756                        mHandler.post(new Runnable() {
757                            @Override
758                            public void run() {
759                                try {
760                                    callback.onLockoutReset();
761                                } finally {
762                                    wakeLock.release();
763                                }
764                            }
765                        });
766                    }
767                });
768            } catch (RemoteException e) {
769                throw e.rethrowFromSystemServer();
770            }
771        } else {
772            Log.w(TAG, "addLockoutResetCallback(): Service not connected!");
773        }
774    }
775
776    private class MyHandler extends Handler {
777        private MyHandler(Context context) {
778            super(context.getMainLooper());
779        }
780
781        private MyHandler(Looper looper) {
782            super(looper);
783        }
784
785        @Override
786        public void handleMessage(android.os.Message msg) {
787            switch(msg.what) {
788                case MSG_ENROLL_RESULT:
789                    sendEnrollResult((Fingerprint) msg.obj, msg.arg1 /* remaining */);
790                    break;
791                case MSG_ACQUIRED:
792                    sendAcquiredResult((Long) msg.obj /* deviceId */, msg.arg1 /* acquire info */);
793                    break;
794                case MSG_AUTHENTICATION_SUCCEEDED:
795                    sendAuthenticatedSucceeded((Fingerprint) msg.obj);
796                    break;
797                case MSG_AUTHENTICATION_FAILED:
798                    sendAuthenticatedFailed();
799                    break;
800                case MSG_ERROR:
801                    sendErrorResult((Long) msg.obj /* deviceId */, msg.arg1 /* errMsgId */);
802                    break;
803                case MSG_REMOVED:
804                    sendRemovedResult((Long) msg.obj /* deviceId */, msg.arg1 /* fingerId */,
805                            msg.arg2 /* groupId */);
806            }
807        }
808
809        private void sendRemovedResult(long deviceId, int fingerId, int groupId) {
810            if (mRemovalCallback != null) {
811                int reqFingerId = mRemovalFingerprint.getFingerId();
812                int reqGroupId = mRemovalFingerprint.getGroupId();
813                if (reqFingerId != 0 && fingerId != 0  &&  fingerId != reqFingerId) {
814                    Log.w(TAG, "Finger id didn't match: " + fingerId + " != " + reqFingerId);
815                    return;
816                }
817                if (groupId != reqGroupId) {
818                    Log.w(TAG, "Group id didn't match: " + groupId + " != " + reqGroupId);
819                    return;
820                }
821                mRemovalCallback.onRemovalSucceeded(new Fingerprint(null, groupId, fingerId,
822                        deviceId));
823            }
824        }
825
826        private void sendErrorResult(long deviceId, int errMsgId) {
827            if (mEnrollmentCallback != null) {
828                mEnrollmentCallback.onEnrollmentError(errMsgId, getErrorString(errMsgId));
829            } else if (mAuthenticationCallback != null) {
830                mAuthenticationCallback.onAuthenticationError(errMsgId, getErrorString(errMsgId));
831            } else if (mRemovalCallback != null) {
832                mRemovalCallback.onRemovalError(mRemovalFingerprint, errMsgId,
833                        getErrorString(errMsgId));
834            }
835        }
836
837        private void sendEnrollResult(Fingerprint fp, int remaining) {
838            if (mEnrollmentCallback != null) {
839                mEnrollmentCallback.onEnrollmentProgress(remaining);
840            }
841        }
842
843        private void sendAuthenticatedSucceeded(Fingerprint fp) {
844            if (mAuthenticationCallback != null) {
845                final AuthenticationResult result = new AuthenticationResult(mCryptoObject, fp);
846                mAuthenticationCallback.onAuthenticationSucceeded(result);
847            }
848        }
849
850        private void sendAuthenticatedFailed() {
851            if (mAuthenticationCallback != null) {
852               mAuthenticationCallback.onAuthenticationFailed();
853            }
854        }
855
856        private void sendAcquiredResult(long deviceId, int acquireInfo) {
857            if (mAuthenticationCallback != null) {
858                mAuthenticationCallback.onAuthenticationAcquired(acquireInfo);
859            }
860            final String msg = getAcquiredString(acquireInfo);
861            if (msg == null) {
862                return;
863            }
864            if (mEnrollmentCallback != null) {
865                mEnrollmentCallback.onEnrollmentHelp(acquireInfo, msg);
866            } else if (mAuthenticationCallback != null) {
867                mAuthenticationCallback.onAuthenticationHelp(acquireInfo, msg);
868            }
869        }
870    };
871
872    /**
873     * @hide
874     */
875    public FingerprintManager(Context context, IFingerprintService service) {
876        mContext = context;
877        mService = service;
878        if (mService == null) {
879            Slog.v(TAG, "FingerprintManagerService was null");
880        }
881        mHandler = new MyHandler(context);
882    }
883
884    private int getCurrentUserId() {
885        try {
886            return ActivityManagerNative.getDefault().getCurrentUser().id;
887        } catch (RemoteException e) {
888            throw e.rethrowFromSystemServer();
889        }
890    }
891
892    private void cancelEnrollment() {
893        if (mService != null) try {
894            mService.cancelEnrollment(mToken);
895        } catch (RemoteException e) {
896            throw e.rethrowFromSystemServer();
897        }
898    }
899
900    private void cancelAuthentication(CryptoObject cryptoObject) {
901        if (mService != null) try {
902            mService.cancelAuthentication(mToken, mContext.getOpPackageName());
903        } catch (RemoteException e) {
904            throw e.rethrowFromSystemServer();
905        }
906    }
907
908    private String getErrorString(int errMsg) {
909        switch (errMsg) {
910            case FINGERPRINT_ERROR_UNABLE_TO_PROCESS:
911                return mContext.getString(
912                    com.android.internal.R.string.fingerprint_error_unable_to_process);
913            case FINGERPRINT_ERROR_HW_UNAVAILABLE:
914                return mContext.getString(
915                    com.android.internal.R.string.fingerprint_error_hw_not_available);
916            case FINGERPRINT_ERROR_NO_SPACE:
917                return mContext.getString(
918                    com.android.internal.R.string.fingerprint_error_no_space);
919            case FINGERPRINT_ERROR_TIMEOUT:
920                return mContext.getString(com.android.internal.R.string.fingerprint_error_timeout);
921            case FINGERPRINT_ERROR_CANCELED:
922                return mContext.getString(com.android.internal.R.string.fingerprint_error_canceled);
923            case FINGERPRINT_ERROR_LOCKOUT:
924                return mContext.getString(com.android.internal.R.string.fingerprint_error_lockout);
925            default:
926                if (errMsg >= FINGERPRINT_ERROR_VENDOR_BASE) {
927                    int msgNumber = errMsg - FINGERPRINT_ERROR_VENDOR_BASE;
928                    String[] msgArray = mContext.getResources().getStringArray(
929                            com.android.internal.R.array.fingerprint_error_vendor);
930                    if (msgNumber < msgArray.length) {
931                        return msgArray[msgNumber];
932                    }
933                }
934                return null;
935        }
936    }
937
938    private String getAcquiredString(int acquireInfo) {
939        switch (acquireInfo) {
940            case FINGERPRINT_ACQUIRED_GOOD:
941                return null;
942            case FINGERPRINT_ACQUIRED_PARTIAL:
943                return mContext.getString(
944                    com.android.internal.R.string.fingerprint_acquired_partial);
945            case FINGERPRINT_ACQUIRED_INSUFFICIENT:
946                return mContext.getString(
947                    com.android.internal.R.string.fingerprint_acquired_insufficient);
948            case FINGERPRINT_ACQUIRED_IMAGER_DIRTY:
949                return mContext.getString(
950                    com.android.internal.R.string.fingerprint_acquired_imager_dirty);
951            case FINGERPRINT_ACQUIRED_TOO_SLOW:
952                return mContext.getString(
953                    com.android.internal.R.string.fingerprint_acquired_too_slow);
954            case FINGERPRINT_ACQUIRED_TOO_FAST:
955                return mContext.getString(
956                    com.android.internal.R.string.fingerprint_acquired_too_fast);
957            default:
958                if (acquireInfo >= FINGERPRINT_ACQUIRED_VENDOR_BASE) {
959                    int msgNumber = acquireInfo - FINGERPRINT_ACQUIRED_VENDOR_BASE;
960                    String[] msgArray = mContext.getResources().getStringArray(
961                            com.android.internal.R.array.fingerprint_acquired_vendor);
962                    if (msgNumber < msgArray.length) {
963                        return msgArray[msgNumber];
964                    }
965                }
966                return null;
967        }
968    }
969
970    private IFingerprintServiceReceiver mServiceReceiver = new IFingerprintServiceReceiver.Stub() {
971
972        @Override // binder call
973        public void onEnrollResult(long deviceId, int fingerId, int groupId, int remaining) {
974            mHandler.obtainMessage(MSG_ENROLL_RESULT, remaining, 0,
975                    new Fingerprint(null, groupId, fingerId, deviceId)).sendToTarget();
976        }
977
978        @Override // binder call
979        public void onAcquired(long deviceId, int acquireInfo) {
980            mHandler.obtainMessage(MSG_ACQUIRED, acquireInfo, 0, deviceId).sendToTarget();
981        }
982
983        @Override // binder call
984        public void onAuthenticationSucceeded(long deviceId, Fingerprint fp) {
985            mHandler.obtainMessage(MSG_AUTHENTICATION_SUCCEEDED, fp).sendToTarget();
986        }
987
988        @Override // binder call
989        public void onAuthenticationFailed(long deviceId) {
990            mHandler.obtainMessage(MSG_AUTHENTICATION_FAILED).sendToTarget();;
991        }
992
993        @Override // binder call
994        public void onError(long deviceId, int error) {
995            mHandler.obtainMessage(MSG_ERROR, error, 0, deviceId).sendToTarget();
996        }
997
998        @Override // binder call
999        public void onRemoved(long deviceId, int fingerId, int groupId) {
1000            mHandler.obtainMessage(MSG_REMOVED, fingerId, groupId, deviceId).sendToTarget();
1001        }
1002    };
1003
1004}
1005