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