FingerprintManager.java revision f501b58de8f467a80fef49c704555781bc61ea6f
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    @RequiresPermission(USE_FINGERPRINT)
401    public void authenticate(@Nullable CryptoObject crypto, @Nullable CancellationSignal cancel,
402            int flags, @NonNull AuthenticationCallback callback, @Nullable Handler handler) {
403        authenticate(crypto, cancel, flags, callback, handler, UserHandle.myUserId());
404    }
405
406    /**
407     * Use the provided handler thread for events.
408     * @param handler
409     */
410    private void useHandler(Handler handler) {
411        if (handler != null) {
412            mHandler = new MyHandler(handler.getLooper());
413        } else if (mHandler.getLooper() != mContext.getMainLooper()){
414            mHandler = new MyHandler(mContext.getMainLooper());
415        }
416    }
417
418    /**
419     * Per-user version
420     * @hide
421     */
422    @RequiresPermission(USE_FINGERPRINT)
423    public void authenticate(@Nullable CryptoObject crypto, @Nullable CancellationSignal cancel,
424            int flags, @NonNull AuthenticationCallback callback, Handler handler, int userId) {
425        if (callback == null) {
426            throw new IllegalArgumentException("Must supply an authentication callback");
427        }
428
429        if (cancel != null) {
430            if (cancel.isCanceled()) {
431                Log.w(TAG, "authentication already canceled");
432                return;
433            } else {
434                cancel.setOnCancelListener(new OnAuthenticationCancelListener(crypto));
435            }
436        }
437
438        if (mService != null) try {
439            useHandler(handler);
440            mAuthenticationCallback = callback;
441            mCryptoObject = crypto;
442            long sessionId = crypto != null ? crypto.getOpId() : 0;
443            mService.authenticate(mToken, sessionId, userId, mServiceReceiver, flags,
444                    mContext.getOpPackageName());
445        } catch (RemoteException e) {
446            Log.w(TAG, "Remote exception while authenticating: ", e);
447            if (callback != null) {
448                // Though this may not be a hardware issue, it will cause apps to give up or try
449                // again later.
450                callback.onAuthenticationError(FINGERPRINT_ERROR_HW_UNAVAILABLE,
451                        getErrorString(FINGERPRINT_ERROR_HW_UNAVAILABLE));
452            }
453        }
454    }
455
456    /**
457     * Request fingerprint enrollment. This call warms up the fingerprint hardware
458     * and starts scanning for fingerprints. Progress will be indicated by callbacks to the
459     * {@link EnrollmentCallback} object. It terminates when
460     * {@link EnrollmentCallback#onEnrollmentError(int, CharSequence)} or
461     * {@link EnrollmentCallback#onEnrollmentProgress(int) is called with remaining == 0, at
462     * which point the object is no longer valid. The operation can be canceled by using the
463     * provided cancel object.
464     * @param token a unique token provided by a recent creation or verification of device
465     * credentials (e.g. pin, pattern or password).
466     * @param cancel an object that can be used to cancel enrollment
467     * @param flags optional flags
468     * @param callback an object to receive enrollment events
469     * @hide
470     */
471    @RequiresPermission(MANAGE_FINGERPRINT)
472    public void enroll(byte [] token, CancellationSignal cancel, int flags,
473            EnrollmentCallback callback) {
474        if (callback == null) {
475            throw new IllegalArgumentException("Must supply an enrollment callback");
476        }
477
478        if (cancel != null) {
479            if (cancel.isCanceled()) {
480                Log.w(TAG, "enrollment already canceled");
481                return;
482            } else {
483                cancel.setOnCancelListener(new OnEnrollCancelListener());
484            }
485        }
486
487        if (mService != null) try {
488            mEnrollmentCallback = callback;
489            mService.enroll(mToken, token, getCurrentUserId(), mServiceReceiver, flags);
490        } catch (RemoteException e) {
491            Log.w(TAG, "Remote exception in enroll: ", e);
492            if (callback != null) {
493                // Though this may not be a hardware issue, it will cause apps to give up or try
494                // again later.
495                callback.onEnrollmentError(FINGERPRINT_ERROR_HW_UNAVAILABLE,
496                        getErrorString(FINGERPRINT_ERROR_HW_UNAVAILABLE));
497            }
498        }
499    }
500
501    /**
502     * Requests a pre-enrollment auth token to tie enrollment to the confirmation of
503     * existing device credentials (e.g. pin/pattern/password).
504     * @hide
505     */
506    @RequiresPermission(MANAGE_FINGERPRINT)
507    public long preEnroll() {
508        long result = 0;
509        if (mService != null) try {
510            result = mService.preEnroll(mToken);
511        } catch (RemoteException e) {
512            Log.w(TAG, "Remote exception in enroll: ", e);
513        }
514        return result;
515    }
516
517    /**
518     * Remove given fingerprint template from fingerprint hardware and/or protected storage.
519     * @param fp the fingerprint item to remove
520     * @param callback an optional callback to verify that fingerprint templates have been
521     * successfully removed. May be null of no callback is required.
522     *
523     * @hide
524     */
525    @RequiresPermission(MANAGE_FINGERPRINT)
526    public void remove(Fingerprint fp, RemovalCallback callback) {
527        if (mService != null) try {
528            mRemovalCallback = callback;
529            mRemovalFingerprint = fp;
530            mService.remove(mToken, fp.getFingerId(), getCurrentUserId(), mServiceReceiver);
531        } catch (RemoteException e) {
532            Log.w(TAG, "Remote exception in remove: ", e);
533            if (callback != null) {
534                callback.onRemovalError(fp, FINGERPRINT_ERROR_HW_UNAVAILABLE,
535                        getErrorString(FINGERPRINT_ERROR_HW_UNAVAILABLE));
536            }
537        }
538    }
539
540    /**
541     * Renames the given fingerprint template
542     * @param fpId the fingerprint id
543     * @param newName the new name
544     *
545     * @hide
546     */
547    @RequiresPermission(MANAGE_FINGERPRINT)
548    public void rename(int fpId, String newName) {
549        // Renames the given fpId
550        if (mService != null) {
551            try {
552                mService.rename(fpId, getCurrentUserId(), newName);
553            } catch (RemoteException e) {
554                Log.v(TAG, "Remote exception in rename(): ", e);
555            }
556        } else {
557            Log.w(TAG, "rename(): Service not connected!");
558        }
559    }
560
561    /**
562     * Obtain the list of enrolled fingerprints templates.
563     * @return list of current fingerprint items
564     *
565     * @hide
566     */
567    @RequiresPermission(USE_FINGERPRINT)
568    public List<Fingerprint> getEnrolledFingerprints(int userId) {
569        if (mService != null) try {
570            return mService.getEnrolledFingerprints(userId, mContext.getOpPackageName());
571        } catch (RemoteException e) {
572            Log.v(TAG, "Remote exception in getEnrolledFingerprints: ", e);
573        }
574        return null;
575    }
576
577    /**
578     * Obtain the list of enrolled fingerprints templates.
579     * @return list of current fingerprint items
580     *
581     * @hide
582     */
583    @RequiresPermission(USE_FINGERPRINT)
584    public List<Fingerprint> getEnrolledFingerprints() {
585        return getEnrolledFingerprints(UserHandle.myUserId());
586    }
587
588    /**
589     * Determine if there is at least one fingerprint enrolled.
590     *
591     * @return true if at least one fingerprint is enrolled, false otherwise
592     */
593    @RequiresPermission(USE_FINGERPRINT)
594    public boolean hasEnrolledFingerprints() {
595        if (mService != null) try {
596            return mService.hasEnrolledFingerprints(UserHandle.myUserId(),
597                    mContext.getOpPackageName());
598        } catch (RemoteException e) {
599            Log.v(TAG, "Remote exception in getEnrolledFingerprints: ", e);
600        }
601        return false;
602    }
603
604    /**
605     * Determine if fingerprint hardware is present and functional.
606     *
607     * @return true if hardware is present and functional, false otherwise.
608     */
609    @RequiresPermission(USE_FINGERPRINT)
610    public boolean isHardwareDetected() {
611        if (mService != null) {
612            try {
613                long deviceId = 0; /* TODO: plumb hardware id to FPMS */
614                return mService.isHardwareDetected(deviceId, mContext.getOpPackageName());
615            } catch (RemoteException e) {
616                Log.v(TAG, "Remote exception in isFingerprintHardwareDetected(): ", e);
617            }
618        } else {
619            Log.w(TAG, "isFingerprintHardwareDetected(): Service not connected!");
620        }
621        return false;
622    }
623
624    /**
625     * Retrieves the authenticator token for binding keys to the lifecycle
626     * of the current set of fingerprints. Used only by internal clients.
627     *
628     * @hide
629     */
630    public long getAuthenticatorId() {
631        if (mService != null) {
632            try {
633                return mService.getAuthenticatorId(mContext.getOpPackageName());
634            } catch (RemoteException e) {
635                Log.v(TAG, "Remote exception in getAuthenticatorId(): ", e);
636            }
637        } else {
638            Log.w(TAG, "getAuthenticatorId(): Service not connected!");
639        }
640        return 0;
641    }
642
643    private class MyHandler extends Handler {
644        private MyHandler(Context context) {
645            super(context.getMainLooper());
646        }
647
648        private MyHandler(Looper looper) {
649            super(looper);
650        }
651
652        public void handleMessage(android.os.Message msg) {
653            switch(msg.what) {
654                case MSG_ENROLL_RESULT:
655                    sendEnrollResult((Fingerprint) msg.obj, msg.arg1 /* remaining */);
656                    break;
657                case MSG_ACQUIRED:
658                    sendAcquiredResult((Long) msg.obj /* deviceId */, msg.arg1 /* acquire info */);
659                    break;
660                case MSG_AUTHENTICATION_SUCCEEDED:
661                    sendAuthenticatedSucceeded((Fingerprint) msg.obj);
662                    break;
663                case MSG_AUTHENTICATION_FAILED:
664                    sendAuthenticatedFailed();
665                    break;
666                case MSG_ERROR:
667                    sendErrorResult((Long) msg.obj /* deviceId */, msg.arg1 /* errMsgId */);
668                    break;
669                case MSG_REMOVED:
670                    sendRemovedResult((Long) msg.obj /* deviceId */, msg.arg1 /* fingerId */,
671                            msg.arg2 /* groupId */);
672            }
673        }
674
675        private void sendRemovedResult(long deviceId, int fingerId, int groupId) {
676            if (mRemovalCallback != null) {
677                int reqFingerId = mRemovalFingerprint.getFingerId();
678                int reqGroupId = mRemovalFingerprint.getGroupId();
679                if (fingerId != reqFingerId) {
680                    Log.w(TAG, "Finger id didn't match: " + fingerId + " != " + reqFingerId);
681                }
682                if (fingerId != reqFingerId) {
683                    Log.w(TAG, "Group id didn't match: " + groupId + " != " + reqGroupId);
684                }
685                mRemovalCallback.onRemovalSucceeded(mRemovalFingerprint);
686            }
687        }
688
689        private void sendErrorResult(long deviceId, int errMsgId) {
690            if (mEnrollmentCallback != null) {
691                mEnrollmentCallback.onEnrollmentError(errMsgId, getErrorString(errMsgId));
692            } else if (mAuthenticationCallback != null) {
693                mAuthenticationCallback.onAuthenticationError(errMsgId, getErrorString(errMsgId));
694            } else if (mRemovalCallback != null) {
695                mRemovalCallback.onRemovalError(mRemovalFingerprint, errMsgId,
696                        getErrorString(errMsgId));
697            }
698        }
699
700        private void sendEnrollResult(Fingerprint fp, int remaining) {
701            if (mEnrollmentCallback != null) {
702                mEnrollmentCallback.onEnrollmentProgress(remaining);
703            }
704        }
705
706        private void sendAuthenticatedSucceeded(Fingerprint fp) {
707            if (mAuthenticationCallback != null) {
708                final AuthenticationResult result = new AuthenticationResult(mCryptoObject, fp);
709                mAuthenticationCallback.onAuthenticationSucceeded(result);
710            }
711        }
712
713        private void sendAuthenticatedFailed() {
714            if (mAuthenticationCallback != null) {
715               mAuthenticationCallback.onAuthenticationFailed();
716            }
717        }
718
719        private void sendAcquiredResult(long deviceId, int acquireInfo) {
720            final String msg = getAcquiredString(acquireInfo);
721            if (msg == null) return;
722
723            if (mEnrollmentCallback != null) {
724                mEnrollmentCallback.onEnrollmentHelp(acquireInfo, msg);
725            } else if (mAuthenticationCallback != null) {
726                mAuthenticationCallback.onAuthenticationHelp(acquireInfo, msg);
727            }
728        }
729    };
730
731    /**
732     * @hide
733     */
734    public FingerprintManager(Context context, IFingerprintService service) {
735        mContext = context;
736        mService = service;
737        if (mService == null) {
738            Slog.v(TAG, "FingerprintManagerService was null");
739        }
740        mHandler = new MyHandler(context);
741    }
742
743    private int getCurrentUserId() {
744        try {
745            return ActivityManagerNative.getDefault().getCurrentUser().id;
746        } catch (RemoteException e) {
747            Log.w(TAG, "Failed to get current user id\n");
748            return UserHandle.USER_NULL;
749        }
750    }
751
752    private void cancelEnrollment() {
753        if (mService != null) try {
754            mService.cancelEnrollment(mToken);
755        } catch (RemoteException e) {
756            if (DEBUG) Log.w(TAG, "Remote exception while canceling enrollment");
757        }
758    }
759
760    private void cancelAuthentication(CryptoObject cryptoObject) {
761        if (mService != null) try {
762            mService.cancelAuthentication(mToken, mContext.getOpPackageName());
763        } catch (RemoteException e) {
764            if (DEBUG) Log.w(TAG, "Remote exception while canceling enrollment");
765        }
766    }
767
768    private String getErrorString(int errMsg) {
769        switch (errMsg) {
770            case FINGERPRINT_ERROR_UNABLE_TO_PROCESS:
771                return mContext.getString(
772                    com.android.internal.R.string.fingerprint_error_unable_to_process);
773            case FINGERPRINT_ERROR_HW_UNAVAILABLE:
774                return mContext.getString(
775                    com.android.internal.R.string.fingerprint_error_hw_not_available);
776            case FINGERPRINT_ERROR_NO_SPACE:
777                return mContext.getString(
778                    com.android.internal.R.string.fingerprint_error_no_space);
779            case FINGERPRINT_ERROR_TIMEOUT:
780                return mContext.getString(com.android.internal.R.string.fingerprint_error_timeout);
781            case FINGERPRINT_ERROR_CANCELED:
782                return mContext.getString(com.android.internal.R.string.fingerprint_error_canceled);
783            case FINGERPRINT_ERROR_LOCKOUT:
784                return mContext.getString(com.android.internal.R.string.fingerprint_error_lockout);
785            default:
786                if (errMsg >= FINGERPRINT_ERROR_VENDOR_BASE) {
787                    int msgNumber = errMsg - FINGERPRINT_ERROR_VENDOR_BASE;
788                    String[] msgArray = mContext.getResources().getStringArray(
789                            com.android.internal.R.array.fingerprint_error_vendor);
790                    if (msgNumber < msgArray.length) {
791                        return msgArray[msgNumber];
792                    }
793                }
794                return null;
795        }
796    }
797
798    private String getAcquiredString(int acquireInfo) {
799        switch (acquireInfo) {
800            case FINGERPRINT_ACQUIRED_GOOD:
801                return null;
802            case FINGERPRINT_ACQUIRED_PARTIAL:
803                return mContext.getString(
804                    com.android.internal.R.string.fingerprint_acquired_partial);
805            case FINGERPRINT_ACQUIRED_INSUFFICIENT:
806                return mContext.getString(
807                    com.android.internal.R.string.fingerprint_acquired_insufficient);
808            case FINGERPRINT_ACQUIRED_IMAGER_DIRTY:
809                return mContext.getString(
810                    com.android.internal.R.string.fingerprint_acquired_imager_dirty);
811            case FINGERPRINT_ACQUIRED_TOO_SLOW:
812                return mContext.getString(
813                    com.android.internal.R.string.fingerprint_acquired_too_slow);
814            case FINGERPRINT_ACQUIRED_TOO_FAST:
815                return mContext.getString(
816                    com.android.internal.R.string.fingerprint_acquired_too_fast);
817            default:
818                if (acquireInfo >= FINGERPRINT_ACQUIRED_VENDOR_BASE) {
819                    int msgNumber = acquireInfo - FINGERPRINT_ACQUIRED_VENDOR_BASE;
820                    String[] msgArray = mContext.getResources().getStringArray(
821                            com.android.internal.R.array.fingerprint_acquired_vendor);
822                    if (msgNumber < msgArray.length) {
823                        return msgArray[msgNumber];
824                    }
825                }
826                return null;
827        }
828    }
829
830    private IFingerprintServiceReceiver mServiceReceiver = new IFingerprintServiceReceiver.Stub() {
831
832        @Override // binder call
833        public void onEnrollResult(long deviceId, int fingerId, int groupId, int remaining) {
834            mHandler.obtainMessage(MSG_ENROLL_RESULT, remaining, 0,
835                    new Fingerprint(null, groupId, fingerId, deviceId)).sendToTarget();
836        }
837
838        @Override // binder call
839        public void onAcquired(long deviceId, int acquireInfo) {
840            mHandler.obtainMessage(MSG_ACQUIRED, acquireInfo, 0, deviceId).sendToTarget();
841        }
842
843        @Override // binder call
844        public void onAuthenticationSucceeded(long deviceId, Fingerprint fp) {
845            mHandler.obtainMessage(MSG_AUTHENTICATION_SUCCEEDED, fp).sendToTarget();
846        }
847
848        @Override // binder call
849        public void onAuthenticationFailed(long deviceId) {
850            mHandler.obtainMessage(MSG_AUTHENTICATION_FAILED).sendToTarget();;
851        }
852
853        @Override // binder call
854        public void onError(long deviceId, int error) {
855            mHandler.obtainMessage(MSG_ERROR, error, 0, deviceId).sendToTarget();
856        }
857
858        @Override // binder call
859        public void onRemoved(long deviceId, int fingerId, int groupId) {
860            mHandler.obtainMessage(MSG_REMOVED, fingerId, groupId, deviceId).sendToTarget();
861        }
862    };
863
864}
865
866