| /** |
| * Copyright (C) 2014 The Android Open Source Project |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| package android.service.fingerprint; |
| |
| import android.app.ActivityManagerNative; |
| import android.content.ComponentName; |
| import android.content.ContentResolver; |
| import android.content.Context; |
| import android.content.Intent; |
| import android.content.ServiceConnection; |
| import android.os.Binder; |
| import android.os.Handler; |
| import android.os.IBinder; |
| import android.os.RemoteException; |
| import android.os.UserHandle; |
| import android.provider.Settings; |
| import android.util.Log; |
| import android.util.Slog; |
| |
| /** |
| * A class that coordinates access to the fingerprint hardware. |
| * @hide |
| */ |
| |
| public class FingerprintManager { |
| private static final String TAG = "FingerprintManager"; |
| private static final boolean DEBUG = true; |
| private static final int MSG_ENROLL_RESULT = 100; |
| private static final int MSG_ACQUIRED = 101; |
| private static final int MSG_PROCESSED = 102; |
| private static final int MSG_ERROR = 103; |
| private static final int MSG_REMOVED = 104; |
| |
| // Errors generated by layers above HAL |
| public static final int FINGERPRINT_ERROR_NO_RECEIVER = -10; |
| |
| // Message types. Must agree with HAL (fingerprint.h) |
| public static final int FINGERPRINT_ERROR = -1; |
| public static final int FINGERPRINT_ACQUIRED = 1; |
| public static final int FINGERPRINT_PROCESSED = 2; |
| public static final int FINGERPRINT_TEMPLATE_ENROLLING = 3; |
| public static final int FINGERPRINT_TEMPLATE_REMOVED = 4; |
| |
| // Error messages. Must agree with HAL (fingerprint.h) |
| public static final int FINGERPRINT_ERROR_HW_UNAVAILABLE = 1; |
| public static final int FINGERPRINT_ERROR_UNABLE_TO_PROCESS = 2; |
| public static final int FINGERPRINT_ERROR_TIMEOUT = 3; |
| public static final int FINGERPRINT_ERROR_NO_SPACE = 4; |
| |
| // FINGERPRINT_ACQUIRED messages. Must agree with HAL (fingerprint.h) |
| public static final int FINGERPRINT_ACQUIRED_GOOD = 0; |
| public static final int FINGERPRINT_ACQUIRED_PARTIAL = 1; |
| public static final int FINGERPRINT_ACQUIRED_INSUFFICIENT = 2; |
| public static final int FINGERPRINT_ACQUIRED_IMAGER_DIRTY = 4; |
| public static final int FINGERPRINT_ACQUIRED_TOO_SLOW = 8; |
| public static final int FINGERPRINT_ACQUIRED_TOO_FAST = 16; |
| |
| private IFingerprintService mService; |
| private FingerprintManagerReceiver mClientReceiver; |
| private Context mContext; |
| private IBinder mToken = new Binder(); |
| |
| private Handler mHandler = new Handler() { |
| public void handleMessage(android.os.Message msg) { |
| if (mClientReceiver != null) { |
| switch(msg.what) { |
| case MSG_ENROLL_RESULT: |
| mClientReceiver.onEnrollResult(msg.arg1, msg.arg2); |
| break; |
| case MSG_ACQUIRED: |
| mClientReceiver.onAcquired(msg.arg1); |
| break; |
| case MSG_PROCESSED: |
| mClientReceiver.onProcessed(msg.arg1); |
| break; |
| case MSG_ERROR: |
| mClientReceiver.onError(msg.arg1); |
| break; |
| case MSG_REMOVED: |
| mClientReceiver.onRemoved(msg.arg1); |
| } |
| } |
| } |
| }; |
| |
| /** |
| * @hide |
| */ |
| public FingerprintManager(Context context, IFingerprintService service) { |
| mContext = context; |
| mService = service; |
| if (mService == null) { |
| Slog.v(TAG, "FingerprintManagerService was null"); |
| } |
| } |
| |
| private IFingerprintServiceReceiver mServiceReceiver = new IFingerprintServiceReceiver.Stub() { |
| |
| public void onEnrollResult(int fingerprintId, int remaining) { |
| mHandler.obtainMessage(MSG_ENROLL_RESULT, fingerprintId, remaining).sendToTarget(); |
| } |
| |
| public void onAcquired(int acquireInfo) { |
| mHandler.obtainMessage(MSG_ACQUIRED, acquireInfo, 0).sendToTarget(); |
| } |
| |
| public void onProcessed(int fingerprintId) { |
| mHandler.obtainMessage(MSG_PROCESSED, fingerprintId, 0).sendToTarget(); |
| } |
| |
| public void onError(int error) { |
| mHandler.obtainMessage(MSG_ERROR, error, 0).sendToTarget(); |
| } |
| |
| public void onRemoved(int fingerprintId) { |
| mHandler.obtainMessage(MSG_REMOVED, fingerprintId, 0).sendToTarget(); |
| } |
| }; |
| |
| /** |
| * Determine whether the user has at least one fingerprint enrolled and enabled. |
| * |
| * @return true if at least one is enrolled and enabled |
| */ |
| public boolean enrolledAndEnabled() { |
| ContentResolver res = mContext.getContentResolver(); |
| return Settings.Secure.getInt(res, "fingerprint_enabled", 0) != 0 |
| && FingerprintUtils.getFingerprintIdsForUser(res, getCurrentUserId()).length > 0; |
| } |
| |
| /** |
| * Start the enrollment process. Timeout dictates how long to wait for the user to |
| * enroll a fingerprint. |
| * |
| * @param timeout |
| */ |
| public void enroll(long timeout) { |
| if (mServiceReceiver == null) { |
| sendError(FINGERPRINT_ERROR_NO_RECEIVER, 0, 0); |
| return; |
| } |
| if (mService != null) try { |
| mService.enroll(mToken, timeout, getCurrentUserId()); |
| } catch (RemoteException e) { |
| Log.v(TAG, "Remote exception while enrolling: ", e); |
| sendError(FINGERPRINT_ERROR_HW_UNAVAILABLE, 0, 0); |
| } |
| } |
| |
| /** |
| * Remove the given fingerprintId from the system. FingerprintId of 0 has special meaning |
| * which is to delete all fingerprint data for the current user. Use with caution. |
| * @param fingerprintId |
| */ |
| public void remove(int fingerprintId) { |
| if (mServiceReceiver == null) { |
| sendError(FINGERPRINT_ERROR_NO_RECEIVER, 0, 0); |
| return; |
| } |
| if (mService != null) { |
| try { |
| mService.remove(mToken, fingerprintId, getCurrentUserId()); |
| } catch (RemoteException e) { |
| Log.v(TAG, "Remote exception during remove of fingerprintId: " + fingerprintId, e); |
| } |
| } else { |
| Log.w(TAG, "remove(): Service not connected!"); |
| sendError(FINGERPRINT_ERROR_HW_UNAVAILABLE, 0, 0); |
| } |
| } |
| |
| /** |
| * Starts listening for fingerprint events. When a finger is scanned or recognized, the |
| * client will be notified via the callback. |
| */ |
| public void startListening(FingerprintManagerReceiver receiver) { |
| mClientReceiver = receiver; |
| if (mService != null) { |
| try { |
| mService.startListening(mToken, mServiceReceiver, getCurrentUserId()); |
| } catch (RemoteException e) { |
| Log.v(TAG, "Remote exception in startListening(): ", e); |
| } |
| } else { |
| Log.w(TAG, "startListening(): Service not connected!"); |
| sendError(FINGERPRINT_ERROR_HW_UNAVAILABLE, 0, 0); |
| } |
| } |
| |
| private int getCurrentUserId() { |
| try { |
| return ActivityManagerNative.getDefault().getCurrentUser().id; |
| } catch (RemoteException e) { |
| Log.w(TAG, "Failed to get current user id\n"); |
| return UserHandle.USER_NULL; |
| } |
| } |
| |
| /** |
| * Stops the client from listening to fingerprint events. |
| */ |
| public void stopListening() { |
| if (mService != null) { |
| try { |
| mService.stopListening(mToken, getCurrentUserId()); |
| mClientReceiver = null; |
| } catch (RemoteException e) { |
| Log.v(TAG, "Remote exception in stopListening(): ", e); |
| } |
| } else { |
| Log.w(TAG, "stopListening(): Service not connected!"); |
| sendError(FINGERPRINT_ERROR_HW_UNAVAILABLE, 0, 0); |
| } |
| } |
| |
| public void enrollCancel() { |
| if (mServiceReceiver == null) { |
| sendError(FINGERPRINT_ERROR_NO_RECEIVER, 0, 0); |
| return; |
| } |
| if (mService != null) { |
| try { |
| mService.enrollCancel(mToken, getCurrentUserId()); |
| mClientReceiver = null; |
| } catch (RemoteException e) { |
| Log.v(TAG, "Remote exception in enrollCancel(): ", e); |
| sendError(FINGERPRINT_ERROR_HW_UNAVAILABLE, 0, 0); |
| } |
| } else { |
| Log.w(TAG, "enrollCancel(): Service not connected!"); |
| } |
| } |
| |
| private void sendError(int msg, int arg1, int arg2) { |
| mHandler.obtainMessage(msg, arg1, arg2); |
| } |
| } |