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