Home | History | Annotate | Download | only in fingerprint
      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 
     17 package android.hardware.fingerprint;
     18 
     19 import android.annotation.NonNull;
     20 import android.annotation.Nullable;
     21 import android.annotation.RequiresPermission;
     22 import android.app.ActivityManagerNative;
     23 import android.content.Context;
     24 import android.os.Binder;
     25 import android.os.CancellationSignal;
     26 import android.os.CancellationSignal.OnCancelListener;
     27 import android.os.Handler;
     28 import android.os.IBinder;
     29 import android.os.Looper;
     30 import android.os.RemoteException;
     31 import android.os.UserHandle;
     32 import android.security.keystore.AndroidKeyStoreProvider;
     33 import android.util.Log;
     34 import android.util.Slog;
     35 
     36 import java.security.Signature;
     37 import java.util.List;
     38 
     39 import javax.crypto.Cipher;
     40 import javax.crypto.Mac;
     41 
     42 import static android.Manifest.permission.USE_FINGERPRINT;
     43 import 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 
     53 public 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 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          * Called when a fingerprint image has been acquired, but wasn't processed yet.
    327          *
    328          * @param acquireInfo one of FINGERPRINT_ACQUIRED_* constants
    329          * @hide
    330          */
    331         public void onAuthenticationAcquired(int acquireInfo) {}
    332     };
    333 
    334     /**
    335      * Callback structure provided to {@link FingerprintManager#enroll(long, EnrollmentCallback,
    336      * CancellationSignal, int). Users of {@link #FingerprintManager()}
    337      * must provide an implementation of this to {@link FingerprintManager#enroll(long,
    338      * CancellationSignal, int, EnrollmentCallback) for listening to fingerprint events.
    339      *
    340      * @hide
    341      */
    342     public static abstract class EnrollmentCallback {
    343         /**
    344          * Called when an unrecoverable error has been encountered and the operation is complete.
    345          * No further callbacks will be made on this object.
    346          * @param errMsgId An integer identifying the error message
    347          * @param errString A human-readable error string that can be shown in UI
    348          */
    349         public void onEnrollmentError(int errMsgId, CharSequence errString) { }
    350 
    351         /**
    352          * Called when a recoverable error has been encountered during enrollment. The help
    353          * string is provided to give the user guidance for what went wrong, such as
    354          * "Sensor dirty, please clean it" or what they need to do next, such as
    355          * "Touch sensor again."
    356          * @param helpMsgId An integer identifying the error message
    357          * @param helpString A human-readable string that can be shown in UI
    358          */
    359         public void onEnrollmentHelp(int helpMsgId, CharSequence helpString) { }
    360 
    361         /**
    362          * Called as each enrollment step progresses. Enrollment is considered complete when
    363          * remaining reaches 0. This function will not be called if enrollment fails. See
    364          * {@link EnrollmentCallback#onEnrollmentError(int, CharSequence)}
    365          * @param remaining The number of remaining steps
    366          */
    367         public void onEnrollmentProgress(int remaining) { }
    368     };
    369 
    370     /**
    371      * Callback structure provided to {@link FingerprintManager#remove(int). Users of
    372      * {@link #FingerprintManager()} may optionally provide an implementation of this to
    373      * {@link FingerprintManager#remove(int, int, RemovalCallback)} for listening to
    374      * fingerprint template removal events.
    375      *
    376      * @hide
    377      */
    378     public static abstract class RemovalCallback {
    379         /**
    380          * Called when the given fingerprint can't be removed.
    381          * @param fp The fingerprint that the call attempted to remove
    382          * @param errMsgId An associated error message id
    383          * @param errString An error message indicating why the fingerprint id can't be removed
    384          */
    385         public void onRemovalError(Fingerprint fp, int errMsgId, CharSequence errString) { }
    386 
    387         /**
    388          * Called when a given fingerprint is successfully removed.
    389          * @param fingerprint the fingerprint template that was removed.
    390          */
    391         public void onRemovalSucceeded(Fingerprint fingerprint) { }
    392     };
    393 
    394     /**
    395      * Request authentication of a crypto object. This call warms up the fingerprint hardware
    396      * and starts scanning for a fingerprint. It terminates when
    397      * {@link AuthenticationCallback#onAuthenticationError(int, CharSequence)} or
    398      * {@link AuthenticationCallback#onAuthenticationSucceeded(AuthenticationResult)} is called, at
    399      * which point the object is no longer valid. The operation can be canceled by using the
    400      * provided cancel object.
    401      *
    402      * @param crypto object associated with the call or null if none required.
    403      * @param cancel an object that can be used to cancel authentication
    404      * @param flags optional flags; should be 0
    405      * @param callback an object to receive authentication events
    406      * @param handler an optional handler to handle callback events
    407      *
    408      * @throws IllegalArgumentException if the crypto operation is not supported or is not backed
    409      *         by <a href="{@docRoot}training/articles/keystore.html">Android Keystore
    410      *         facility</a>.
    411      * @throws IllegalStateException if the crypto primitive is not initialized.
    412      */
    413     @RequiresPermission(USE_FINGERPRINT)
    414     public void authenticate(@Nullable CryptoObject crypto, @Nullable CancellationSignal cancel,
    415             int flags, @NonNull AuthenticationCallback callback, @Nullable Handler handler) {
    416         authenticate(crypto, cancel, flags, callback, handler, UserHandle.myUserId());
    417     }
    418 
    419     /**
    420      * Use the provided handler thread for events.
    421      * @param handler
    422      */
    423     private void useHandler(Handler handler) {
    424         if (handler != null) {
    425             mHandler = new MyHandler(handler.getLooper());
    426         } else if (mHandler.getLooper() != mContext.getMainLooper()){
    427             mHandler = new MyHandler(mContext.getMainLooper());
    428         }
    429     }
    430 
    431     /**
    432      * Per-user version
    433      * @hide
    434      */
    435     @RequiresPermission(USE_FINGERPRINT)
    436     public void authenticate(@Nullable CryptoObject crypto, @Nullable CancellationSignal cancel,
    437             int flags, @NonNull AuthenticationCallback callback, Handler handler, int userId) {
    438         if (callback == null) {
    439             throw new IllegalArgumentException("Must supply an authentication callback");
    440         }
    441 
    442         if (cancel != null) {
    443             if (cancel.isCanceled()) {
    444                 Log.w(TAG, "authentication already canceled");
    445                 return;
    446             } else {
    447                 cancel.setOnCancelListener(new OnAuthenticationCancelListener(crypto));
    448             }
    449         }
    450 
    451         if (mService != null) try {
    452             useHandler(handler);
    453             mAuthenticationCallback = callback;
    454             mCryptoObject = crypto;
    455             long sessionId = crypto != null ? crypto.getOpId() : 0;
    456             mService.authenticate(mToken, sessionId, userId, mServiceReceiver, flags,
    457                     mContext.getOpPackageName());
    458         } catch (RemoteException e) {
    459             Log.w(TAG, "Remote exception while authenticating: ", e);
    460             if (callback != null) {
    461                 // Though this may not be a hardware issue, it will cause apps to give up or try
    462                 // again later.
    463                 callback.onAuthenticationError(FINGERPRINT_ERROR_HW_UNAVAILABLE,
    464                         getErrorString(FINGERPRINT_ERROR_HW_UNAVAILABLE));
    465             }
    466         }
    467     }
    468 
    469     /**
    470      * Request fingerprint enrollment. This call warms up the fingerprint hardware
    471      * and starts scanning for fingerprints. Progress will be indicated by callbacks to the
    472      * {@link EnrollmentCallback} object. It terminates when
    473      * {@link EnrollmentCallback#onEnrollmentError(int, CharSequence)} or
    474      * {@link EnrollmentCallback#onEnrollmentProgress(int) is called with remaining == 0, at
    475      * which point the object is no longer valid. The operation can be canceled by using the
    476      * provided cancel object.
    477      * @param token a unique token provided by a recent creation or verification of device
    478      * credentials (e.g. pin, pattern or password).
    479      * @param cancel an object that can be used to cancel enrollment
    480      * @param flags optional flags
    481      * @param callback an object to receive enrollment events
    482      * @hide
    483      */
    484     @RequiresPermission(MANAGE_FINGERPRINT)
    485     public void enroll(byte [] token, CancellationSignal cancel, int flags,
    486             EnrollmentCallback callback) {
    487         if (callback == null) {
    488             throw new IllegalArgumentException("Must supply an enrollment callback");
    489         }
    490 
    491         if (cancel != null) {
    492             if (cancel.isCanceled()) {
    493                 Log.w(TAG, "enrollment already canceled");
    494                 return;
    495             } else {
    496                 cancel.setOnCancelListener(new OnEnrollCancelListener());
    497             }
    498         }
    499 
    500         if (mService != null) try {
    501             mEnrollmentCallback = callback;
    502             mService.enroll(mToken, token, getCurrentUserId(), mServiceReceiver, flags);
    503         } catch (RemoteException e) {
    504             Log.w(TAG, "Remote exception in enroll: ", e);
    505             if (callback != null) {
    506                 // Though this may not be a hardware issue, it will cause apps to give up or try
    507                 // again later.
    508                 callback.onEnrollmentError(FINGERPRINT_ERROR_HW_UNAVAILABLE,
    509                         getErrorString(FINGERPRINT_ERROR_HW_UNAVAILABLE));
    510             }
    511         }
    512     }
    513 
    514     /**
    515      * Requests a pre-enrollment auth token to tie enrollment to the confirmation of
    516      * existing device credentials (e.g. pin/pattern/password).
    517      * @hide
    518      */
    519     @RequiresPermission(MANAGE_FINGERPRINT)
    520     public long preEnroll() {
    521         long result = 0;
    522         if (mService != null) try {
    523             result = mService.preEnroll(mToken);
    524         } catch (RemoteException e) {
    525             Log.w(TAG, "Remote exception in enroll: ", e);
    526         }
    527         return result;
    528     }
    529 
    530     /**
    531      * Finishes enrollment and cancels the current auth token.
    532      * @hide
    533      */
    534     @RequiresPermission(MANAGE_FINGERPRINT)
    535     public int postEnroll() {
    536         int result = 0;
    537         if (mService != null) try {
    538             result = mService.postEnroll(mToken);
    539         } catch (RemoteException e) {
    540             Log.w(TAG, "Remote exception in post enroll: ", e);
    541         }
    542         return result;
    543     }
    544 
    545     /**
    546      * Remove given fingerprint template from fingerprint hardware and/or protected storage.
    547      * @param fp the fingerprint item to remove
    548      * @param callback an optional callback to verify that fingerprint templates have been
    549      * successfully removed. May be null of no callback is required.
    550      *
    551      * @hide
    552      */
    553     @RequiresPermission(MANAGE_FINGERPRINT)
    554     public void remove(Fingerprint fp, RemovalCallback callback) {
    555         if (mService != null) try {
    556             mRemovalCallback = callback;
    557             mRemovalFingerprint = fp;
    558             mService.remove(mToken, fp.getFingerId(), getCurrentUserId(), mServiceReceiver);
    559         } catch (RemoteException e) {
    560             Log.w(TAG, "Remote exception in remove: ", e);
    561             if (callback != null) {
    562                 callback.onRemovalError(fp, FINGERPRINT_ERROR_HW_UNAVAILABLE,
    563                         getErrorString(FINGERPRINT_ERROR_HW_UNAVAILABLE));
    564             }
    565         }
    566     }
    567 
    568     /**
    569      * Renames the given fingerprint template
    570      * @param fpId the fingerprint id
    571      * @param newName the new name
    572      *
    573      * @hide
    574      */
    575     @RequiresPermission(MANAGE_FINGERPRINT)
    576     public void rename(int fpId, String newName) {
    577         // Renames the given fpId
    578         if (mService != null) {
    579             try {
    580                 mService.rename(fpId, getCurrentUserId(), newName);
    581             } catch (RemoteException e) {
    582                 Log.v(TAG, "Remote exception in rename(): ", e);
    583             }
    584         } else {
    585             Log.w(TAG, "rename(): Service not connected!");
    586         }
    587     }
    588 
    589     /**
    590      * Obtain the list of enrolled fingerprints templates.
    591      * @return list of current fingerprint items
    592      *
    593      * @hide
    594      */
    595     @RequiresPermission(USE_FINGERPRINT)
    596     public List<Fingerprint> getEnrolledFingerprints(int userId) {
    597         if (mService != null) try {
    598             return mService.getEnrolledFingerprints(userId, mContext.getOpPackageName());
    599         } catch (RemoteException e) {
    600             Log.v(TAG, "Remote exception in getEnrolledFingerprints: ", e);
    601         }
    602         return null;
    603     }
    604 
    605     /**
    606      * Obtain the list of enrolled fingerprints templates.
    607      * @return list of current fingerprint items
    608      *
    609      * @hide
    610      */
    611     @RequiresPermission(USE_FINGERPRINT)
    612     public List<Fingerprint> getEnrolledFingerprints() {
    613         return getEnrolledFingerprints(UserHandle.myUserId());
    614     }
    615 
    616     /**
    617      * Determine if there is at least one fingerprint enrolled.
    618      *
    619      * @return true if at least one fingerprint is enrolled, false otherwise
    620      */
    621     @RequiresPermission(USE_FINGERPRINT)
    622     public boolean hasEnrolledFingerprints() {
    623         if (mService != null) try {
    624             return mService.hasEnrolledFingerprints(UserHandle.myUserId(),
    625                     mContext.getOpPackageName());
    626         } catch (RemoteException e) {
    627             Log.v(TAG, "Remote exception in getEnrolledFingerprints: ", e);
    628         }
    629         return false;
    630     }
    631 
    632     /**
    633      * Determine if fingerprint hardware is present and functional.
    634      *
    635      * @return true if hardware is present and functional, false otherwise.
    636      */
    637     @RequiresPermission(USE_FINGERPRINT)
    638     public boolean isHardwareDetected() {
    639         if (mService != null) {
    640             try {
    641                 long deviceId = 0; /* TODO: plumb hardware id to FPMS */
    642                 return mService.isHardwareDetected(deviceId, mContext.getOpPackageName());
    643             } catch (RemoteException e) {
    644                 Log.v(TAG, "Remote exception in isFingerprintHardwareDetected(): ", e);
    645             }
    646         } else {
    647             Log.w(TAG, "isFingerprintHardwareDetected(): Service not connected!");
    648         }
    649         return false;
    650     }
    651 
    652     /**
    653      * Retrieves the authenticator token for binding keys to the lifecycle
    654      * of the current set of fingerprints. Used only by internal clients.
    655      *
    656      * @hide
    657      */
    658     public long getAuthenticatorId() {
    659         if (mService != null) {
    660             try {
    661                 return mService.getAuthenticatorId(mContext.getOpPackageName());
    662             } catch (RemoteException e) {
    663                 Log.v(TAG, "Remote exception in getAuthenticatorId(): ", e);
    664             }
    665         } else {
    666             Log.w(TAG, "getAuthenticatorId(): Service not connected!");
    667         }
    668         return 0;
    669     }
    670 
    671     private class MyHandler extends Handler {
    672         private MyHandler(Context context) {
    673             super(context.getMainLooper());
    674         }
    675 
    676         private MyHandler(Looper looper) {
    677             super(looper);
    678         }
    679 
    680         public void handleMessage(android.os.Message msg) {
    681             switch(msg.what) {
    682                 case MSG_ENROLL_RESULT:
    683                     sendEnrollResult((Fingerprint) msg.obj, msg.arg1 /* remaining */);
    684                     break;
    685                 case MSG_ACQUIRED:
    686                     sendAcquiredResult((Long) msg.obj /* deviceId */, msg.arg1 /* acquire info */);
    687                     break;
    688                 case MSG_AUTHENTICATION_SUCCEEDED:
    689                     sendAuthenticatedSucceeded((Fingerprint) msg.obj);
    690                     break;
    691                 case MSG_AUTHENTICATION_FAILED:
    692                     sendAuthenticatedFailed();
    693                     break;
    694                 case MSG_ERROR:
    695                     sendErrorResult((Long) msg.obj /* deviceId */, msg.arg1 /* errMsgId */);
    696                     break;
    697                 case MSG_REMOVED:
    698                     sendRemovedResult((Long) msg.obj /* deviceId */, msg.arg1 /* fingerId */,
    699                             msg.arg2 /* groupId */);
    700             }
    701         }
    702 
    703         private void sendRemovedResult(long deviceId, int fingerId, int groupId) {
    704             if (mRemovalCallback != null) {
    705                 int reqFingerId = mRemovalFingerprint.getFingerId();
    706                 int reqGroupId = mRemovalFingerprint.getGroupId();
    707                 if (fingerId != reqFingerId) {
    708                     Log.w(TAG, "Finger id didn't match: " + fingerId + " != " + reqFingerId);
    709                 }
    710                 if (fingerId != reqFingerId) {
    711                     Log.w(TAG, "Group id didn't match: " + groupId + " != " + reqGroupId);
    712                 }
    713                 mRemovalCallback.onRemovalSucceeded(mRemovalFingerprint);
    714             }
    715         }
    716 
    717         private void sendErrorResult(long deviceId, int errMsgId) {
    718             if (mEnrollmentCallback != null) {
    719                 mEnrollmentCallback.onEnrollmentError(errMsgId, getErrorString(errMsgId));
    720             } else if (mAuthenticationCallback != null) {
    721                 mAuthenticationCallback.onAuthenticationError(errMsgId, getErrorString(errMsgId));
    722             } else if (mRemovalCallback != null) {
    723                 mRemovalCallback.onRemovalError(mRemovalFingerprint, errMsgId,
    724                         getErrorString(errMsgId));
    725             }
    726         }
    727 
    728         private void sendEnrollResult(Fingerprint fp, int remaining) {
    729             if (mEnrollmentCallback != null) {
    730                 mEnrollmentCallback.onEnrollmentProgress(remaining);
    731             }
    732         }
    733 
    734         private void sendAuthenticatedSucceeded(Fingerprint fp) {
    735             if (mAuthenticationCallback != null) {
    736                 final AuthenticationResult result = new AuthenticationResult(mCryptoObject, fp);
    737                 mAuthenticationCallback.onAuthenticationSucceeded(result);
    738             }
    739         }
    740 
    741         private void sendAuthenticatedFailed() {
    742             if (mAuthenticationCallback != null) {
    743                mAuthenticationCallback.onAuthenticationFailed();
    744             }
    745         }
    746 
    747         private void sendAcquiredResult(long deviceId, int acquireInfo) {
    748             if (mAuthenticationCallback != null) {
    749                 mAuthenticationCallback.onAuthenticationAcquired(acquireInfo);
    750             }
    751             final String msg = getAcquiredString(acquireInfo);
    752             if (msg == null) {
    753                 return;
    754             }
    755             if (mEnrollmentCallback != null) {
    756                 mEnrollmentCallback.onEnrollmentHelp(acquireInfo, msg);
    757             } else if (mAuthenticationCallback != null) {
    758                 mAuthenticationCallback.onAuthenticationHelp(acquireInfo, msg);
    759             }
    760         }
    761     };
    762 
    763     /**
    764      * @hide
    765      */
    766     public FingerprintManager(Context context, IFingerprintService service) {
    767         mContext = context;
    768         mService = service;
    769         if (mService == null) {
    770             Slog.v(TAG, "FingerprintManagerService was null");
    771         }
    772         mHandler = new MyHandler(context);
    773     }
    774 
    775     private int getCurrentUserId() {
    776         try {
    777             return ActivityManagerNative.getDefault().getCurrentUser().id;
    778         } catch (RemoteException e) {
    779             Log.w(TAG, "Failed to get current user id\n");
    780             return UserHandle.USER_NULL;
    781         }
    782     }
    783 
    784     private void cancelEnrollment() {
    785         if (mService != null) try {
    786             mService.cancelEnrollment(mToken);
    787         } catch (RemoteException e) {
    788             if (DEBUG) Log.w(TAG, "Remote exception while canceling enrollment");
    789         }
    790     }
    791 
    792     private void cancelAuthentication(CryptoObject cryptoObject) {
    793         if (mService != null) try {
    794             mService.cancelAuthentication(mToken, mContext.getOpPackageName());
    795         } catch (RemoteException e) {
    796             if (DEBUG) Log.w(TAG, "Remote exception while canceling enrollment");
    797         }
    798     }
    799 
    800     private String getErrorString(int errMsg) {
    801         switch (errMsg) {
    802             case FINGERPRINT_ERROR_UNABLE_TO_PROCESS:
    803                 return mContext.getString(
    804                     com.android.internal.R.string.fingerprint_error_unable_to_process);
    805             case FINGERPRINT_ERROR_HW_UNAVAILABLE:
    806                 return mContext.getString(
    807                     com.android.internal.R.string.fingerprint_error_hw_not_available);
    808             case FINGERPRINT_ERROR_NO_SPACE:
    809                 return mContext.getString(
    810                     com.android.internal.R.string.fingerprint_error_no_space);
    811             case FINGERPRINT_ERROR_TIMEOUT:
    812                 return mContext.getString(com.android.internal.R.string.fingerprint_error_timeout);
    813             case FINGERPRINT_ERROR_CANCELED:
    814                 return mContext.getString(com.android.internal.R.string.fingerprint_error_canceled);
    815             case FINGERPRINT_ERROR_LOCKOUT:
    816                 return mContext.getString(com.android.internal.R.string.fingerprint_error_lockout);
    817             default:
    818                 if (errMsg >= FINGERPRINT_ERROR_VENDOR_BASE) {
    819                     int msgNumber = errMsg - FINGERPRINT_ERROR_VENDOR_BASE;
    820                     String[] msgArray = mContext.getResources().getStringArray(
    821                             com.android.internal.R.array.fingerprint_error_vendor);
    822                     if (msgNumber < msgArray.length) {
    823                         return msgArray[msgNumber];
    824                     }
    825                 }
    826                 return null;
    827         }
    828     }
    829 
    830     private String getAcquiredString(int acquireInfo) {
    831         switch (acquireInfo) {
    832             case FINGERPRINT_ACQUIRED_GOOD:
    833                 return null;
    834             case FINGERPRINT_ACQUIRED_PARTIAL:
    835                 return mContext.getString(
    836                     com.android.internal.R.string.fingerprint_acquired_partial);
    837             case FINGERPRINT_ACQUIRED_INSUFFICIENT:
    838                 return mContext.getString(
    839                     com.android.internal.R.string.fingerprint_acquired_insufficient);
    840             case FINGERPRINT_ACQUIRED_IMAGER_DIRTY:
    841                 return mContext.getString(
    842                     com.android.internal.R.string.fingerprint_acquired_imager_dirty);
    843             case FINGERPRINT_ACQUIRED_TOO_SLOW:
    844                 return mContext.getString(
    845                     com.android.internal.R.string.fingerprint_acquired_too_slow);
    846             case FINGERPRINT_ACQUIRED_TOO_FAST:
    847                 return mContext.getString(
    848                     com.android.internal.R.string.fingerprint_acquired_too_fast);
    849             default:
    850                 if (acquireInfo >= FINGERPRINT_ACQUIRED_VENDOR_BASE) {
    851                     int msgNumber = acquireInfo - FINGERPRINT_ACQUIRED_VENDOR_BASE;
    852                     String[] msgArray = mContext.getResources().getStringArray(
    853                             com.android.internal.R.array.fingerprint_acquired_vendor);
    854                     if (msgNumber < msgArray.length) {
    855                         return msgArray[msgNumber];
    856                     }
    857                 }
    858                 return null;
    859         }
    860     }
    861 
    862     private IFingerprintServiceReceiver mServiceReceiver = new IFingerprintServiceReceiver.Stub() {
    863 
    864         @Override // binder call
    865         public void onEnrollResult(long deviceId, int fingerId, int groupId, int remaining) {
    866             mHandler.obtainMessage(MSG_ENROLL_RESULT, remaining, 0,
    867                     new Fingerprint(null, groupId, fingerId, deviceId)).sendToTarget();
    868         }
    869 
    870         @Override // binder call
    871         public void onAcquired(long deviceId, int acquireInfo) {
    872             mHandler.obtainMessage(MSG_ACQUIRED, acquireInfo, 0, deviceId).sendToTarget();
    873         }
    874 
    875         @Override // binder call
    876         public void onAuthenticationSucceeded(long deviceId, Fingerprint fp) {
    877             mHandler.obtainMessage(MSG_AUTHENTICATION_SUCCEEDED, fp).sendToTarget();
    878         }
    879 
    880         @Override // binder call
    881         public void onAuthenticationFailed(long deviceId) {
    882             mHandler.obtainMessage(MSG_AUTHENTICATION_FAILED).sendToTarget();;
    883         }
    884 
    885         @Override // binder call
    886         public void onError(long deviceId, int error) {
    887             mHandler.obtainMessage(MSG_ERROR, error, 0, deviceId).sendToTarget();
    888         }
    889 
    890         @Override // binder call
    891         public void onRemoved(long deviceId, int fingerId, int groupId) {
    892             mHandler.obtainMessage(MSG_REMOVED, fingerId, groupId, deviceId).sendToTarget();
    893         }
    894     };
    895 
    896 }
    897 
    898