blob: 2fcec52d2e655d5ecfb9469bac9eb35cb0d0687c [file] [log] [blame]
/**
* 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.Handler;
import android.os.IBinder;
import android.os.RemoteException;
import android.os.UserHandle;
import android.provider.Settings;
import android.util.Log;
/**
* A class that coordinates access to the fingerprint hardware.
*/
public class FingerprintManager {
private static final String TAG = "FingerprintManager";
private static final boolean DEBUG = true;
private static final String FINGERPRINT_SERVICE_PACKAGE = "com.android.service.fingerprint";
private static final String FINGERPRINT_SERVICE_CLASS =
"com.android.service.fingerprint.FingerprintService";
private static final int MSG_ENROLL_RESULT = 100;
private static final int MSG_SCANNED = 101;
private static final int MSG_ERROR = 102;
private static final int MSG_REMOVED = 103;
public static final int FINGERPRINT_ERROR_NO_RECEIVER = -10;
public static final int FINGERPRINT_ERROR = -1; // One of the error messages below.
// Progress messages.
public static final int FINGERPRINT_SCANNED = 1;
public static final int FINGERPRINT_TEMPLATE_ENROLLING = 2;
public static final int FINGERPRINT_TEMPLATE_REMOVED = 4;
// Error messages. Must agree with fingerprint HAL definitions.
public static final int FINGERPRINT_ERROR_HW_UNAVAILABLE = 1;
public static final int FINGERPRINT_ERROR_BAD_CAPTURE = 2;
public static final int FINGERPRINT_ERROR_TIMEOUT = 3;
public static final int FINGERPRINT_ERROR_NO_SPACE = 4;
private IFingerprintService mService;
private FingerprintManagerReceiver mClientReceiver;
private Context mContext;
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_SCANNED:
mClientReceiver.onScanned(msg.arg1, msg.arg2);
break;
case MSG_ERROR:
mClientReceiver.onError(msg.arg1);
break;
case MSG_REMOVED:
mClientReceiver.onRemoved(msg.arg1);
}
}
}
};
public FingerprintManager(Context context) {
mContext = context;
// Connect to service...
Intent intent = new Intent();
intent.setClassName(FINGERPRINT_SERVICE_PACKAGE, FINGERPRINT_SERVICE_CLASS);
if (!context.bindServiceAsUser(intent, mFingerprintConnection,
Context.BIND_AUTO_CREATE, UserHandle.CURRENT_OR_SELF)) {
if (DEBUG) Log.v(TAG, "Can't bind to " + FINGERPRINT_SERVICE_CLASS);
}
}
private final ServiceConnection mFingerprintConnection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
if (DEBUG) Log.v(TAG, "Connected to FingerprintService");
mService = IFingerprintService.Stub.asInterface(service);
try {
mService.startListening(mServiceReceiver, getCurrentUserId());
} catch (RemoteException e) {
if (DEBUG) Log.v(TAG, "Failed to set callback", e);
}
}
@Override
public void onServiceDisconnected(ComponentName name) {
if (DEBUG) Log.v(TAG, "Disconnected from FingerprintService");
mService = null;
}
};
private IFingerprintServiceReceiver mServiceReceiver = new IFingerprintServiceReceiver.Stub() {
public void onEnrollResult(int fingerprintId, int remaining) {
mHandler.obtainMessage(MSG_ENROLL_RESULT, fingerprintId, remaining).sendToTarget();
}
public void onScanned(int fingerprintId, int confidence) {
mHandler.obtainMessage(MSG_SCANNED, fingerprintId, confidence)
.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) {
throw new IllegalStateException("enroll: Call registerCallback() first");
}
if (mService != null) try {
mService.enroll(timeout, getCurrentUserId());
} catch (RemoteException e) {
Log.v(TAG, "Remote exception while enrolling: ", e);
}
}
/**
* 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 (mService != null) try {
mService.remove(fingerprintId, getCurrentUserId());
} catch (RemoteException e) {
Log.v(TAG, "Remote exception during remove of fingerprintId: " + fingerprintId, e);
}
}
/**
* 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(mServiceReceiver, getCurrentUserId());
} catch (RemoteException e) {
Log.v(TAG, "Remote exception in startListening(): ", e);
}
}
}
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() {
mClientReceiver = null;
if (mService != null) {
try {
mService.stopListening(getCurrentUserId());
} catch (RemoteException e) {
Log.v(TAG, "Remote exception in stopListening(): ", e);
}
} else {
Log.w(TAG, "stopListening(): Service not connected!");
}
}
}