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