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         private int mUserId;
    263 
    264         /**
    265          * Authentication result
    266          *
    267          * @param crypto the crypto object
    268          * @param fingerprint the recognized fingerprint data, if allowed.
    269          * @hide
    270          */
    271         public AuthenticationResult(CryptoObject crypto, Fingerprint fingerprint, int userId) {
    272             mCryptoObject = crypto;
    273             mFingerprint = fingerprint;
    274             mUserId = userId;
    275         }
    276 
    277         /**
    278          * Obtain the crypto object associated with this transaction
    279          * @return crypto object provided to {@link FingerprintManager#authenticate(CryptoObject,
    280          *     CancellationSignal, int, AuthenticationCallback, Handler)}.
    281          */
    282         public CryptoObject getCryptoObject() { return mCryptoObject; }
    283 
    284         /**
    285          * Obtain the Fingerprint associated with this operation. Applications are strongly
    286          * discouraged from associating specific fingers with specific applications or operations.
    287          *
    288          * @hide
    289          */
    290         public Fingerprint getFingerprint() { return mFingerprint; }
    291 
    292         /**
    293          * Obtain the userId for which this fingerprint was authenticated.
    294          * @hide
    295          */
    296         public int getUserId() { return mUserId; }
    297     };
    298 
    299     /**
    300      * Callback structure provided to {@link FingerprintManager#authenticate(CryptoObject,
    301      * CancellationSignal, int, AuthenticationCallback, Handler)}. Users of {@link
    302      * FingerprintManager#authenticate(CryptoObject, CancellationSignal,
    303      * int, AuthenticationCallback, Handler) } must provide an implementation of this for listening to
    304      * fingerprint events.
    305      */
    306     public static abstract class AuthenticationCallback {
    307         /**
    308          * Called when an unrecoverable error has been encountered and the operation is complete.
    309          * No further callbacks will be made on this object.
    310          * @param errorCode An integer identifying the error message
    311          * @param errString A human-readable error string that can be shown in UI
    312          */
    313         public void onAuthenticationError(int errorCode, CharSequence errString) { }
    314 
    315         /**
    316          * Called when a recoverable error has been encountered during authentication. The help
    317          * string is provided to give the user guidance for what went wrong, such as
    318          * "Sensor dirty, please clean it."
    319          * @param helpCode An integer identifying the error message
    320          * @param helpString A human-readable string that can be shown in UI
    321          */
    322         public void onAuthenticationHelp(int helpCode, CharSequence helpString) { }
    323 
    324         /**
    325          * Called when a fingerprint is recognized.
    326          * @param result An object containing authentication-related data
    327          */
    328         public void onAuthenticationSucceeded(AuthenticationResult result) { }
    329 
    330         /**
    331          * Called when a fingerprint is valid but not recognized.
    332          */
    333         public void onAuthenticationFailed() { }
    334 
    335         /**
    336          * Called when a fingerprint image has been acquired, but wasn't processed yet.
    337          *
    338          * @param acquireInfo one of FINGERPRINT_ACQUIRED_* constants
    339          * @hide
    340          */
    341         public void onAuthenticationAcquired(int acquireInfo) {}
    342     };
    343 
    344     /**
    345      * Callback structure provided to {@link FingerprintManager#enroll(long, EnrollmentCallback,
    346      * CancellationSignal, int). Users of {@link #FingerprintManager()}
    347      * must provide an implementation of this to {@link FingerprintManager#enroll(long,
    348      * CancellationSignal, int, EnrollmentCallback) for listening to fingerprint events.
    349      *
    350      * @hide
    351      */
    352     public static abstract class EnrollmentCallback {
    353         /**
    354          * Called when an unrecoverable error has been encountered and the operation is complete.
    355          * No further callbacks will be made on this object.
    356          * @param errMsgId An integer identifying the error message
    357          * @param errString A human-readable error string that can be shown in UI
    358          */
    359         public void onEnrollmentError(int errMsgId, CharSequence errString) { }
    360 
    361         /**
    362          * Called when a recoverable error has been encountered during enrollment. The help
    363          * string is provided to give the user guidance for what went wrong, such as
    364          * "Sensor dirty, please clean it" or what they need to do next, such as
    365          * "Touch sensor again."
    366          * @param helpMsgId An integer identifying the error message
    367          * @param helpString A human-readable string that can be shown in UI
    368          */
    369         public void onEnrollmentHelp(int helpMsgId, CharSequence helpString) { }
    370 
    371         /**
    372          * Called as each enrollment step progresses. Enrollment is considered complete when
    373          * remaining reaches 0. This function will not be called if enrollment fails. See
    374          * {@link EnrollmentCallback#onEnrollmentError(int, CharSequence)}
    375          * @param remaining The number of remaining steps
    376          */
    377         public void onEnrollmentProgress(int remaining) { }
    378     };
    379 
    380     /**
    381      * Callback structure provided to {@link FingerprintManager#remove(int). Users of
    382      * {@link #FingerprintManager()} may optionally provide an implementation of this to
    383      * {@link FingerprintManager#remove(int, int, RemovalCallback)} for listening to
    384      * fingerprint template removal events.
    385      *
    386      * @hide
    387      */
    388     public static abstract class RemovalCallback {
    389         /**
    390          * Called when the given fingerprint can't be removed.
    391          * @param fp The fingerprint that the call attempted to remove
    392          * @param errMsgId An associated error message id
    393          * @param errString An error message indicating why the fingerprint id can't be removed
    394          */
    395         public void onRemovalError(Fingerprint fp, int errMsgId, CharSequence errString) { }
    396 
    397         /**
    398          * Called when a given fingerprint is successfully removed.
    399          * @param fingerprint the fingerprint template that was removed.
    400          */
    401         public void onRemovalSucceeded(Fingerprint fingerprint) { }
    402     };
    403 
    404     /**
    405      * @hide
    406      */
    407     public static abstract class LockoutResetCallback {
    408 
    409         /**
    410          * Called when lockout period expired and clients are allowed to listen for fingerprint
    411          * again.
    412          */
    413         public void onLockoutReset() { }
    414     };
    415 
    416     /**
    417      * Request authentication of a crypto object. This call warms up the fingerprint hardware
    418      * and starts scanning for a fingerprint. It terminates when
    419      * {@link AuthenticationCallback#onAuthenticationError(int, CharSequence)} or
    420      * {@link AuthenticationCallback#onAuthenticationSucceeded(AuthenticationResult)} is called, at
    421      * which point the object is no longer valid. The operation can be canceled by using the
    422      * provided cancel object.
    423      *
    424      * @param crypto object associated with the call or null if none required.
    425      * @param cancel an object that can be used to cancel authentication
    426      * @param flags optional flags; should be 0
    427      * @param callback an object to receive authentication events
    428      * @param handler an optional handler to handle callback events
    429      *
    430      * @throws IllegalArgumentException if the crypto operation is not supported or is not backed
    431      *         by <a href="{@docRoot}training/articles/keystore.html">Android Keystore
    432      *         facility</a>.
    433      * @throws IllegalStateException if the crypto primitive is not initialized.
    434      */
    435     @RequiresPermission(USE_FINGERPRINT)
    436     public void authenticate(@Nullable CryptoObject crypto, @Nullable CancellationSignal cancel,
    437             int flags, @NonNull AuthenticationCallback callback, @Nullable Handler handler) {
    438         authenticate(crypto, cancel, flags, callback, handler, UserHandle.myUserId());
    439     }
    440 
    441     /**
    442      * Use the provided handler thread for events.
    443      * @param handler
    444      */
    445     private void useHandler(Handler handler) {
    446         if (handler != null) {
    447             mHandler = new MyHandler(handler.getLooper());
    448         } else if (mHandler.getLooper() != mContext.getMainLooper()){
    449             mHandler = new MyHandler(mContext.getMainLooper());
    450         }
    451     }
    452 
    453     /**
    454      * Per-user version
    455      * @hide
    456      */
    457     @RequiresPermission(USE_FINGERPRINT)
    458     public void authenticate(@Nullable CryptoObject crypto, @Nullable CancellationSignal cancel,
    459             int flags, @NonNull AuthenticationCallback callback, Handler handler, int userId) {
    460         if (callback == null) {
    461             throw new IllegalArgumentException("Must supply an authentication callback");
    462         }
    463 
    464         if (cancel != null) {
    465             if (cancel.isCanceled()) {
    466                 Log.w(TAG, "authentication already canceled");
    467                 return;
    468             } else {
    469                 cancel.setOnCancelListener(new OnAuthenticationCancelListener(crypto));
    470             }
    471         }
    472 
    473         if (mService != null) try {
    474             useHandler(handler);
    475             mAuthenticationCallback = callback;
    476             mCryptoObject = crypto;
    477             long sessionId = crypto != null ? crypto.getOpId() : 0;
    478             mService.authenticate(mToken, sessionId, userId, mServiceReceiver, flags,
    479                     mContext.getOpPackageName());
    480         } catch (RemoteException e) {
    481             Log.w(TAG, "Remote exception while authenticating: ", e);
    482             if (callback != null) {
    483                 // Though this may not be a hardware issue, it will cause apps to give up or try
    484                 // again later.
    485                 callback.onAuthenticationError(FINGERPRINT_ERROR_HW_UNAVAILABLE,
    486                         getErrorString(FINGERPRINT_ERROR_HW_UNAVAILABLE));
    487             }
    488         }
    489     }
    490 
    491     /**
    492      * Request fingerprint enrollment. This call warms up the fingerprint hardware
    493      * and starts scanning for fingerprints. Progress will be indicated by callbacks to the
    494      * {@link EnrollmentCallback} object. It terminates when
    495      * {@link EnrollmentCallback#onEnrollmentError(int, CharSequence)} or
    496      * {@link EnrollmentCallback#onEnrollmentProgress(int) is called with remaining == 0, at
    497      * which point the object is no longer valid. The operation can be canceled by using the
    498      * provided cancel object.
    499      * @param token a unique token provided by a recent creation or verification of device
    500      * credentials (e.g. pin, pattern or password).
    501      * @param cancel an object that can be used to cancel enrollment
    502      * @param flags optional flags
    503      * @param userId the user to whom this fingerprint will belong to
    504      * @param callback an object to receive enrollment events
    505      * @hide
    506      */
    507     @RequiresPermission(MANAGE_FINGERPRINT)
    508     public void enroll(byte [] token, CancellationSignal cancel, int flags,
    509             int userId, EnrollmentCallback callback) {
    510         if (userId == UserHandle.USER_CURRENT) {
    511             userId = getCurrentUserId();
    512         }
    513         if (callback == null) {
    514             throw new IllegalArgumentException("Must supply an enrollment callback");
    515         }
    516 
    517         if (cancel != null) {
    518             if (cancel.isCanceled()) {
    519                 Log.w(TAG, "enrollment already canceled");
    520                 return;
    521             } else {
    522                 cancel.setOnCancelListener(new OnEnrollCancelListener());
    523             }
    524         }
    525 
    526         if (mService != null) try {
    527             mEnrollmentCallback = callback;
    528             mService.enroll(mToken, token, userId, mServiceReceiver, flags,
    529                     mContext.getOpPackageName());
    530         } catch (RemoteException e) {
    531             Log.w(TAG, "Remote exception in enroll: ", e);
    532             if (callback != null) {
    533                 // Though this may not be a hardware issue, it will cause apps to give up or try
    534                 // again later.
    535                 callback.onEnrollmentError(FINGERPRINT_ERROR_HW_UNAVAILABLE,
    536                         getErrorString(FINGERPRINT_ERROR_HW_UNAVAILABLE));
    537             }
    538         }
    539     }
    540 
    541     /**
    542      * Requests a pre-enrollment auth token to tie enrollment to the confirmation of
    543      * existing device credentials (e.g. pin/pattern/password).
    544      * @hide
    545      */
    546     @RequiresPermission(MANAGE_FINGERPRINT)
    547     public long preEnroll() {
    548         long result = 0;
    549         if (mService != null) try {
    550             result = mService.preEnroll(mToken);
    551         } catch (RemoteException e) {
    552             throw e.rethrowFromSystemServer();
    553         }
    554         return result;
    555     }
    556 
    557     /**
    558      * Finishes enrollment and cancels the current auth token.
    559      * @hide
    560      */
    561     @RequiresPermission(MANAGE_FINGERPRINT)
    562     public int postEnroll() {
    563         int result = 0;
    564         if (mService != null) try {
    565             result = mService.postEnroll(mToken);
    566         } catch (RemoteException e) {
    567             throw e.rethrowFromSystemServer();
    568         }
    569         return result;
    570     }
    571 
    572     /**
    573      * Sets the active user. This is meant to be used to select the current profile for enrollment
    574      * to allow separate enrolled fingers for a work profile
    575      * @param userId
    576      * @hide
    577      */
    578     @RequiresPermission(MANAGE_FINGERPRINT)
    579     public void setActiveUser(int userId) {
    580         if (mService != null) try {
    581             mService.setActiveUser(userId);
    582         } catch (RemoteException e) {
    583             throw e.rethrowFromSystemServer();
    584         }
    585     }
    586 
    587     /**
    588      * Remove given fingerprint template from fingerprint hardware and/or protected storage.
    589      * @param fp the fingerprint item to remove
    590      * @param userId the user who this fingerprint belongs to
    591      * @param callback an optional callback to verify that fingerprint templates have been
    592      * successfully removed. May be null of no callback is required.
    593      *
    594      * @hide
    595      */
    596     @RequiresPermission(MANAGE_FINGERPRINT)
    597     public void remove(Fingerprint fp, int userId, RemovalCallback callback) {
    598         if (mService != null) try {
    599             mRemovalCallback = callback;
    600             mRemovalFingerprint = fp;
    601             mService.remove(mToken, fp.getFingerId(), fp.getGroupId(), userId, mServiceReceiver);
    602         } catch (RemoteException e) {
    603             Log.w(TAG, "Remote exception in remove: ", e);
    604             if (callback != null) {
    605                 callback.onRemovalError(fp, FINGERPRINT_ERROR_HW_UNAVAILABLE,
    606                         getErrorString(FINGERPRINT_ERROR_HW_UNAVAILABLE));
    607             }
    608         }
    609     }
    610 
    611     /**
    612      * Renames the given fingerprint template
    613      * @param fpId the fingerprint id
    614      * @param userId the user who this fingerprint belongs to
    615      * @param newName the new name
    616      *
    617      * @hide
    618      */
    619     @RequiresPermission(MANAGE_FINGERPRINT)
    620     public void rename(int fpId, int userId, String newName) {
    621         // Renames the given fpId
    622         if (mService != null) {
    623             try {
    624                 mService.rename(fpId, userId, newName);
    625             } catch (RemoteException e) {
    626                 throw e.rethrowFromSystemServer();
    627             }
    628         } else {
    629             Log.w(TAG, "rename(): Service not connected!");
    630         }
    631     }
    632 
    633     /**
    634      * Obtain the list of enrolled fingerprints templates.
    635      * @return list of current fingerprint items
    636      *
    637      * @hide
    638      */
    639     @RequiresPermission(USE_FINGERPRINT)
    640     public List<Fingerprint> getEnrolledFingerprints(int userId) {
    641         if (mService != null) try {
    642             return mService.getEnrolledFingerprints(userId, mContext.getOpPackageName());
    643         } catch (RemoteException e) {
    644             throw e.rethrowFromSystemServer();
    645         }
    646         return null;
    647     }
    648 
    649     /**
    650      * Obtain the list of enrolled fingerprints templates.
    651      * @return list of current fingerprint items
    652      *
    653      * @hide
    654      */
    655     @RequiresPermission(USE_FINGERPRINT)
    656     public List<Fingerprint> getEnrolledFingerprints() {
    657         return getEnrolledFingerprints(UserHandle.myUserId());
    658     }
    659 
    660     /**
    661      * Determine if there is at least one fingerprint enrolled.
    662      *
    663      * @return true if at least one fingerprint is enrolled, false otherwise
    664      */
    665     @RequiresPermission(USE_FINGERPRINT)
    666     public boolean hasEnrolledFingerprints() {
    667         if (mService != null) try {
    668             return mService.hasEnrolledFingerprints(
    669                     UserHandle.myUserId(), mContext.getOpPackageName());
    670         } catch (RemoteException e) {
    671             throw e.rethrowFromSystemServer();
    672         }
    673         return false;
    674     }
    675 
    676     /**
    677      * @hide
    678      */
    679     @RequiresPermission(allOf = {
    680             USE_FINGERPRINT,
    681             INTERACT_ACROSS_USERS})
    682     public boolean hasEnrolledFingerprints(int userId) {
    683         if (mService != null) try {
    684             return mService.hasEnrolledFingerprints(userId, mContext.getOpPackageName());
    685         } catch (RemoteException e) {
    686             throw e.rethrowFromSystemServer();
    687         }
    688         return false;
    689     }
    690 
    691     /**
    692      * Determine if fingerprint hardware is present and functional.
    693      *
    694      * @return true if hardware is present and functional, false otherwise.
    695      */
    696     @RequiresPermission(USE_FINGERPRINT)
    697     public boolean isHardwareDetected() {
    698         if (mService != null) {
    699             try {
    700                 long deviceId = 0; /* TODO: plumb hardware id to FPMS */
    701                 return mService.isHardwareDetected(deviceId, mContext.getOpPackageName());
    702             } catch (RemoteException e) {
    703                 throw e.rethrowFromSystemServer();
    704             }
    705         } else {
    706             Log.w(TAG, "isFingerprintHardwareDetected(): Service not connected!");
    707         }
    708         return false;
    709     }
    710 
    711     /**
    712      * Retrieves the authenticator token for binding keys to the lifecycle
    713      * of the current set of fingerprints. Used only by internal clients.
    714      *
    715      * @hide
    716      */
    717     public long getAuthenticatorId() {
    718         if (mService != null) {
    719             try {
    720                 return mService.getAuthenticatorId(mContext.getOpPackageName());
    721             } catch (RemoteException e) {
    722                 throw e.rethrowFromSystemServer();
    723             }
    724         } else {
    725             Log.w(TAG, "getAuthenticatorId(): Service not connected!");
    726         }
    727         return 0;
    728     }
    729 
    730     /**
    731      * Reset the lockout timer when asked to do so by keyguard.
    732      *
    733      * @param token an opaque token returned by password confirmation.
    734      *
    735      * @hide
    736      */
    737     public void resetTimeout(byte[] token) {
    738         if (mService != null) {
    739             try {
    740                 mService.resetTimeout(token);
    741             } catch (RemoteException e) {
    742                 throw e.rethrowFromSystemServer();
    743             }
    744         } else {
    745             Log.w(TAG, "resetTimeout(): Service not connected!");
    746         }
    747     }
    748 
    749     /**
    750      * @hide
    751      */
    752     public void addLockoutResetCallback(final LockoutResetCallback callback) {
    753         if (mService != null) {
    754             try {
    755                 final PowerManager powerManager = mContext.getSystemService(PowerManager.class);
    756                 mService.addLockoutResetCallback(
    757                         new IFingerprintServiceLockoutResetCallback.Stub() {
    758 
    759                     @Override
    760                     public void onLockoutReset(long deviceId) throws RemoteException {
    761                         final PowerManager.WakeLock wakeLock = powerManager.newWakeLock(
    762                                 PowerManager.PARTIAL_WAKE_LOCK, "lockoutResetCallback");
    763                         wakeLock.acquire();
    764                         mHandler.post(new Runnable() {
    765                             @Override
    766                             public void run() {
    767                                 try {
    768                                     callback.onLockoutReset();
    769                                 } finally {
    770                                     wakeLock.release();
    771                                 }
    772                             }
    773                         });
    774                     }
    775                 });
    776             } catch (RemoteException e) {
    777                 throw e.rethrowFromSystemServer();
    778             }
    779         } else {
    780             Log.w(TAG, "addLockoutResetCallback(): Service not connected!");
    781         }
    782     }
    783 
    784     private class MyHandler extends Handler {
    785         private MyHandler(Context context) {
    786             super(context.getMainLooper());
    787         }
    788 
    789         private MyHandler(Looper looper) {
    790             super(looper);
    791         }
    792 
    793         @Override
    794         public void handleMessage(android.os.Message msg) {
    795             switch(msg.what) {
    796                 case MSG_ENROLL_RESULT:
    797                     sendEnrollResult((Fingerprint) msg.obj, msg.arg1 /* remaining */);
    798                     break;
    799                 case MSG_ACQUIRED:
    800                     sendAcquiredResult((Long) msg.obj /* deviceId */, msg.arg1 /* acquire info */);
    801                     break;
    802                 case MSG_AUTHENTICATION_SUCCEEDED:
    803                     sendAuthenticatedSucceeded((Fingerprint) msg.obj, msg.arg1 /* userId */);
    804                     break;
    805                 case MSG_AUTHENTICATION_FAILED:
    806                     sendAuthenticatedFailed();
    807                     break;
    808                 case MSG_ERROR:
    809                     sendErrorResult((Long) msg.obj /* deviceId */, msg.arg1 /* errMsgId */);
    810                     break;
    811                 case MSG_REMOVED:
    812                     sendRemovedResult((Long) msg.obj /* deviceId */, msg.arg1 /* fingerId */,
    813                             msg.arg2 /* groupId */);
    814             }
    815         }
    816 
    817         private void sendRemovedResult(long deviceId, int fingerId, int groupId) {
    818             if (mRemovalCallback != null) {
    819                 int reqFingerId = mRemovalFingerprint.getFingerId();
    820                 int reqGroupId = mRemovalFingerprint.getGroupId();
    821                 if (reqFingerId != 0 && fingerId != 0  &&  fingerId != reqFingerId) {
    822                     Log.w(TAG, "Finger id didn't match: " + fingerId + " != " + reqFingerId);
    823                     return;
    824                 }
    825                 if (groupId != reqGroupId) {
    826                     Log.w(TAG, "Group id didn't match: " + groupId + " != " + reqGroupId);
    827                     return;
    828                 }
    829                 mRemovalCallback.onRemovalSucceeded(new Fingerprint(null, groupId, fingerId,
    830                         deviceId));
    831             }
    832         }
    833 
    834         private void sendErrorResult(long deviceId, int errMsgId) {
    835             if (mEnrollmentCallback != null) {
    836                 mEnrollmentCallback.onEnrollmentError(errMsgId, getErrorString(errMsgId));
    837             } else if (mAuthenticationCallback != null) {
    838                 mAuthenticationCallback.onAuthenticationError(errMsgId, getErrorString(errMsgId));
    839             } else if (mRemovalCallback != null) {
    840                 mRemovalCallback.onRemovalError(mRemovalFingerprint, errMsgId,
    841                         getErrorString(errMsgId));
    842             }
    843         }
    844 
    845         private void sendEnrollResult(Fingerprint fp, int remaining) {
    846             if (mEnrollmentCallback != null) {
    847                 mEnrollmentCallback.onEnrollmentProgress(remaining);
    848             }
    849         }
    850 
    851         private void sendAuthenticatedSucceeded(Fingerprint fp, int userId) {
    852             if (mAuthenticationCallback != null) {
    853                 final AuthenticationResult result =
    854                         new AuthenticationResult(mCryptoObject, fp, userId);
    855                 mAuthenticationCallback.onAuthenticationSucceeded(result);
    856             }
    857         }
    858 
    859         private void sendAuthenticatedFailed() {
    860             if (mAuthenticationCallback != null) {
    861                mAuthenticationCallback.onAuthenticationFailed();
    862             }
    863         }
    864 
    865         private void sendAcquiredResult(long deviceId, int acquireInfo) {
    866             if (mAuthenticationCallback != null) {
    867                 mAuthenticationCallback.onAuthenticationAcquired(acquireInfo);
    868             }
    869             final String msg = getAcquiredString(acquireInfo);
    870             if (msg == null) {
    871                 return;
    872             }
    873             if (mEnrollmentCallback != null) {
    874                 mEnrollmentCallback.onEnrollmentHelp(acquireInfo, msg);
    875             } else if (mAuthenticationCallback != null) {
    876                 mAuthenticationCallback.onAuthenticationHelp(acquireInfo, msg);
    877             }
    878         }
    879     };
    880 
    881     /**
    882      * @hide
    883      */
    884     public FingerprintManager(Context context, IFingerprintService service) {
    885         mContext = context;
    886         mService = service;
    887         if (mService == null) {
    888             Slog.v(TAG, "FingerprintManagerService was null");
    889         }
    890         mHandler = new MyHandler(context);
    891     }
    892 
    893     private int getCurrentUserId() {
    894         try {
    895             return ActivityManagerNative.getDefault().getCurrentUser().id;
    896         } catch (RemoteException e) {
    897             throw e.rethrowFromSystemServer();
    898         }
    899     }
    900 
    901     private void cancelEnrollment() {
    902         if (mService != null) try {
    903             mService.cancelEnrollment(mToken);
    904         } catch (RemoteException e) {
    905             throw e.rethrowFromSystemServer();
    906         }
    907     }
    908 
    909     private void cancelAuthentication(CryptoObject cryptoObject) {
    910         if (mService != null) try {
    911             mService.cancelAuthentication(mToken, mContext.getOpPackageName());
    912         } catch (RemoteException e) {
    913             throw e.rethrowFromSystemServer();
    914         }
    915     }
    916 
    917     private String getErrorString(int errMsg) {
    918         switch (errMsg) {
    919             case FINGERPRINT_ERROR_UNABLE_TO_PROCESS:
    920                 return mContext.getString(
    921                     com.android.internal.R.string.fingerprint_error_unable_to_process);
    922             case FINGERPRINT_ERROR_HW_UNAVAILABLE:
    923                 return mContext.getString(
    924                     com.android.internal.R.string.fingerprint_error_hw_not_available);
    925             case FINGERPRINT_ERROR_NO_SPACE:
    926                 return mContext.getString(
    927                     com.android.internal.R.string.fingerprint_error_no_space);
    928             case FINGERPRINT_ERROR_TIMEOUT:
    929                 return mContext.getString(com.android.internal.R.string.fingerprint_error_timeout);
    930             case FINGERPRINT_ERROR_CANCELED:
    931                 return mContext.getString(com.android.internal.R.string.fingerprint_error_canceled);
    932             case FINGERPRINT_ERROR_LOCKOUT:
    933                 return mContext.getString(com.android.internal.R.string.fingerprint_error_lockout);
    934             default:
    935                 if (errMsg >= FINGERPRINT_ERROR_VENDOR_BASE) {
    936                     int msgNumber = errMsg - FINGERPRINT_ERROR_VENDOR_BASE;
    937                     String[] msgArray = mContext.getResources().getStringArray(
    938                             com.android.internal.R.array.fingerprint_error_vendor);
    939                     if (msgNumber < msgArray.length) {
    940                         return msgArray[msgNumber];
    941                     }
    942                 }
    943                 return null;
    944         }
    945     }
    946 
    947     private String getAcquiredString(int acquireInfo) {
    948         switch (acquireInfo) {
    949             case FINGERPRINT_ACQUIRED_GOOD:
    950                 return null;
    951             case FINGERPRINT_ACQUIRED_PARTIAL:
    952                 return mContext.getString(
    953                     com.android.internal.R.string.fingerprint_acquired_partial);
    954             case FINGERPRINT_ACQUIRED_INSUFFICIENT:
    955                 return mContext.getString(
    956                     com.android.internal.R.string.fingerprint_acquired_insufficient);
    957             case FINGERPRINT_ACQUIRED_IMAGER_DIRTY:
    958                 return mContext.getString(
    959                     com.android.internal.R.string.fingerprint_acquired_imager_dirty);
    960             case FINGERPRINT_ACQUIRED_TOO_SLOW:
    961                 return mContext.getString(
    962                     com.android.internal.R.string.fingerprint_acquired_too_slow);
    963             case FINGERPRINT_ACQUIRED_TOO_FAST:
    964                 return mContext.getString(
    965                     com.android.internal.R.string.fingerprint_acquired_too_fast);
    966             default:
    967                 if (acquireInfo >= FINGERPRINT_ACQUIRED_VENDOR_BASE) {
    968                     int msgNumber = acquireInfo - FINGERPRINT_ACQUIRED_VENDOR_BASE;
    969                     String[] msgArray = mContext.getResources().getStringArray(
    970                             com.android.internal.R.array.fingerprint_acquired_vendor);
    971                     if (msgNumber < msgArray.length) {
    972                         return msgArray[msgNumber];
    973                     }
    974                 }
    975                 return null;
    976         }
    977     }
    978 
    979     private IFingerprintServiceReceiver mServiceReceiver = new IFingerprintServiceReceiver.Stub() {
    980 
    981         @Override // binder call
    982         public void onEnrollResult(long deviceId, int fingerId, int groupId, int remaining) {
    983             mHandler.obtainMessage(MSG_ENROLL_RESULT, remaining, 0,
    984                     new Fingerprint(null, groupId, fingerId, deviceId)).sendToTarget();
    985         }
    986 
    987         @Override // binder call
    988         public void onAcquired(long deviceId, int acquireInfo) {
    989             mHandler.obtainMessage(MSG_ACQUIRED, acquireInfo, 0, deviceId).sendToTarget();
    990         }
    991 
    992         @Override // binder call
    993         public void onAuthenticationSucceeded(long deviceId, Fingerprint fp, int userId) {
    994             mHandler.obtainMessage(MSG_AUTHENTICATION_SUCCEEDED, userId, 0, fp).sendToTarget();
    995         }
    996 
    997         @Override // binder call
    998         public void onAuthenticationFailed(long deviceId) {
    999             mHandler.obtainMessage(MSG_AUTHENTICATION_FAILED).sendToTarget();;
   1000         }
   1001 
   1002         @Override // binder call
   1003         public void onError(long deviceId, int error) {
   1004             mHandler.obtainMessage(MSG_ERROR, error, 0, deviceId).sendToTarget();
   1005         }
   1006 
   1007         @Override // binder call
   1008         public void onRemoved(long deviceId, int fingerId, int groupId) {
   1009             mHandler.obtainMessage(MSG_REMOVED, fingerId, groupId, deviceId).sendToTarget();
   1010         }
   1011     };
   1012 
   1013 }
   1014