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