First pass at adding FingerprintManagerService
This adds a new service for monitoring and enrolling fingerprints to the platform. Fixed documentation links. Change-Id: I66013be5e09be9c5f9746c46aacf32d3e26c3b73
This commit is contained in:
@@ -199,6 +199,8 @@ LOCAL_SRC_FILES += \
|
||||
core/java/android/service/dreams/IDozeHardware.aidl \
|
||||
core/java/android/service/dreams/IDreamManager.aidl \
|
||||
core/java/android/service/dreams/IDreamService.aidl \
|
||||
core/java/android/service/fingerprint/IFingerprintService.aidl \
|
||||
core/java/android/service/fingerprint/IFingerprintServiceReceiver.aidl \
|
||||
core/java/android/service/trust/ITrustAgentService.aidl \
|
||||
core/java/android/service/trust/ITrustAgentServiceCallback.aidl \
|
||||
core/java/android/service/voice/IVoiceInteractionService.aidl \
|
||||
|
||||
@@ -6614,6 +6614,7 @@ package android.content {
|
||||
field public static final java.lang.String DISPLAY_SERVICE = "display";
|
||||
field public static final java.lang.String DOWNLOAD_SERVICE = "download";
|
||||
field public static final java.lang.String DROPBOX_SERVICE = "dropbox";
|
||||
field public static final java.lang.String FINGERPRINT_SERVICE = "fingerprint";
|
||||
field public static final java.lang.String HDMI_CEC_SERVICE = "hdmi_cec";
|
||||
field public static final java.lang.String INPUT_METHOD_SERVICE = "input_method";
|
||||
field public static final java.lang.String INPUT_SERVICE = "input";
|
||||
@@ -25059,6 +25060,36 @@ package android.service.dreams {
|
||||
|
||||
}
|
||||
|
||||
package android.service.fingerprint {
|
||||
|
||||
public class FingerprintManager {
|
||||
ctor public FingerprintManager(android.content.Context);
|
||||
method public void enroll(long);
|
||||
method public void remove(int);
|
||||
method public void startListening(android.service.fingerprint.FingerprintManagerReceiver);
|
||||
method public void stopListening();
|
||||
field protected static final boolean DEBUG = true;
|
||||
field public static final int FINGERPRINT_ERROR = -1; // 0xffffffff
|
||||
field public static final int FINGERPRINT_ERROR_BAD_CAPTURE = 2; // 0x2
|
||||
field public static final int FINGERPRINT_ERROR_HW_UNAVAILABLE = 1; // 0x1
|
||||
field public static final int FINGERPRINT_ERROR_NO_RECEIVER = -10; // 0xfffffff6
|
||||
field public static final int FINGERPRINT_ERROR_NO_SPACE = 4; // 0x4
|
||||
field public static final int FINGERPRINT_ERROR_TIMEOUT = 3; // 0x3
|
||||
field public static final int FINGERPRINT_SCANNED = 1; // 0x1
|
||||
field public static final int FINGERPRINT_TEMPLATE_ENROLLING = 2; // 0x2
|
||||
field public static final int FINGERPRINT_TEMPLATE_REMOVED = 4; // 0x4
|
||||
}
|
||||
|
||||
public class FingerprintManagerReceiver {
|
||||
ctor public FingerprintManagerReceiver();
|
||||
method public void onEnrollResult(int, int);
|
||||
method public void onError(int);
|
||||
method public void onRemoved(int);
|
||||
method public void onScanned(int, int);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
package android.service.notification {
|
||||
|
||||
public abstract class NotificationListenerService extends android.app.Service {
|
||||
|
||||
@@ -106,6 +106,9 @@ import android.os.storage.IMountService;
|
||||
import android.os.storage.StorageManager;
|
||||
import android.print.IPrintManager;
|
||||
import android.print.PrintManager;
|
||||
import android.service.fingerprint.FingerprintManager;
|
||||
import android.service.fingerprint.FingerprintManagerReceiver;
|
||||
import android.service.fingerprint.FingerprintService;
|
||||
import android.telephony.TelephonyManager;
|
||||
import android.tv.ITvInputManager;
|
||||
import android.tv.TvInputManager;
|
||||
@@ -451,6 +454,11 @@ class ContextImpl extends Context {
|
||||
return new KeyguardManager();
|
||||
}});
|
||||
|
||||
registerService(FINGERPRINT_SERVICE, new ServiceFetcher() {
|
||||
public Object createService(ContextImpl ctx) {
|
||||
return new FingerprintManager(ctx);
|
||||
}});
|
||||
|
||||
registerService(LAYOUT_INFLATER_SERVICE, new ServiceFetcher() {
|
||||
public Object createService(ContextImpl ctx) {
|
||||
return PolicyManager.makeNewLayoutInflater(ctx.getOuterContext());
|
||||
|
||||
@@ -2375,6 +2375,16 @@ public abstract class Context {
|
||||
*/
|
||||
public static final String AUDIO_SERVICE = "audio";
|
||||
|
||||
/**
|
||||
* Use with {@link #getSystemService} to retrieve a
|
||||
* {@link android.service.fingerprint.FingerprintManager} for handling management
|
||||
* of fingerprints.
|
||||
*
|
||||
* @see #getSystemService
|
||||
* @see android.app.FingerprintManager
|
||||
*/
|
||||
public static final String FINGERPRINT_SERVICE = "fingerprint";
|
||||
|
||||
/**
|
||||
* Use with {@link #getSystemService} to retrieve a
|
||||
* {@link android.media.MediaRouter} for controlling and managing
|
||||
|
||||
@@ -3479,6 +3479,12 @@ public final class Settings {
|
||||
public static final String LOCK_SCREEN_APPWIDGET_IDS =
|
||||
"lock_screen_appwidget_ids";
|
||||
|
||||
/**
|
||||
* List of enrolled fingerprint identifiers (comma-delimited).
|
||||
* @hide
|
||||
*/
|
||||
public static final String USER_FINGERPRINT_IDS = "user_fingerprint_ids";
|
||||
|
||||
/**
|
||||
* Id of the appwidget shown on the lock screen when appwidgets are disabled.
|
||||
* @hide
|
||||
|
||||
200
core/java/android/service/fingerprint/FingerprintManager.java
Normal file
200
core/java/android/service/fingerprint/FingerprintManager.java
Normal file
@@ -0,0 +1,200 @@
|
||||
/**
|
||||
* 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.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.util.Log;
|
||||
|
||||
/**
|
||||
* A class that coordinates access to the fingerprint hardware.
|
||||
*/
|
||||
|
||||
public class FingerprintManager {
|
||||
private static final String TAG = "FingerprintManager";
|
||||
protected 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 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) {
|
||||
// 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();
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* 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!");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,59 @@
|
||||
package android.service.fingerprint;
|
||||
/**
|
||||
* 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.
|
||||
*/
|
||||
|
||||
public class FingerprintManagerReceiver {
|
||||
/**
|
||||
* Fingerprint enrollment progress update. Enrollment is considered complete if
|
||||
* remaining hits 0 without {@link #onError(int)} being called.
|
||||
*
|
||||
* @param fingerprintId the fingerprint we're currently enrolling
|
||||
* @param remaining the number of samples required to complete enrollment. It's up to
|
||||
* the hardware to define what each step in enrollment means. Some hardware
|
||||
* requires multiple samples of the same part of the finger. Others require sampling of
|
||||
* different parts of the finger. The enrollment flow can use remaining to
|
||||
* mean "step x" of the process or "just need another sample."
|
||||
*/
|
||||
public void onEnrollResult(int fingerprintId, int remaining) { }
|
||||
|
||||
/**
|
||||
* Fingerprint scan detected. Most clients will use this function to detect a fingerprint
|
||||
*
|
||||
* @param fingerprintId is the finger the hardware has detected.
|
||||
* @param confidence from 0 (no confidence) to 65535 (high confidence). Fingerprint 0 has
|
||||
* special meaning - the finger wasn't recognized.
|
||||
*/
|
||||
public void onScanned(int fingerprintId, int confidence) { }
|
||||
|
||||
/**
|
||||
* An error was detected during scan or enrollment. One of
|
||||
* {@link FingerprintManager#FINGERPRINT_ERROR_HW_UNAVAILABLE},
|
||||
* {@link FingerprintManager#FINGERPRINT_ERROR_BAD_CAPTURE} or
|
||||
* {@link FingerprintManager#FINGERPRINT_ERROR_TIMEOUT}
|
||||
* {@link FingerprintManager#FINGERPRINT_ERROR_NO_SPACE}
|
||||
*
|
||||
* @param error one of the above error codes
|
||||
*/
|
||||
public void onError(int error) { }
|
||||
|
||||
/**
|
||||
* The given fingerprint template was successfully removed by the driver.
|
||||
* See {@link FingerprintManager#remove(int)}
|
||||
*
|
||||
* @param fingerprintId id of template to remove.
|
||||
*/
|
||||
public void onRemoved(int fingerprintId) { }
|
||||
}
|
||||
219
core/java/android/service/fingerprint/FingerprintService.java
Normal file
219
core/java/android/service/fingerprint/FingerprintService.java
Normal file
@@ -0,0 +1,219 @@
|
||||
/**
|
||||
* 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.Service;
|
||||
import android.content.ContentResolver;
|
||||
import android.content.Intent;
|
||||
import android.os.Handler;
|
||||
import android.os.IBinder;
|
||||
import android.os.RemoteException;
|
||||
import android.provider.Settings;
|
||||
import android.util.Slog;
|
||||
|
||||
import java.io.PrintWriter;
|
||||
import java.util.HashMap;
|
||||
|
||||
/**
|
||||
* A service to manage multiple clients that want to access the fingerprint HAL API.
|
||||
* The service is responsible for maintaining a list of clients and dispatching all
|
||||
* fingerprint -related events.
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
public class FingerprintService extends Service {
|
||||
private final String TAG = FingerprintService.class.getSimpleName() +
|
||||
"[" + getClass().getSimpleName() + "]";
|
||||
private static final boolean DEBUG = true;
|
||||
HashMap<IFingerprintServiceReceiver, ClientData> mClients =
|
||||
new HashMap<IFingerprintServiceReceiver, ClientData>();
|
||||
|
||||
private static final int MSG_NOTIFY = 10;
|
||||
|
||||
Handler mHandler = new Handler() {
|
||||
public void handleMessage(android.os.Message msg) {
|
||||
switch (msg.what) {
|
||||
case MSG_NOTIFY:
|
||||
handleNotify(msg.arg1, msg.arg2, (Integer) msg.obj);
|
||||
break;
|
||||
|
||||
default:
|
||||
Slog.w(TAG, "Unknown message:" + msg.what);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
private static final int STATE_IDLE = 0;
|
||||
private static final int STATE_LISTENING = 1;
|
||||
private static final int STATE_ENROLLING = 2;
|
||||
private static final int STATE_DELETING = 3;
|
||||
private static final long MS_PER_SEC = 1000;
|
||||
|
||||
private static final class ClientData {
|
||||
public IFingerprintServiceReceiver receiver;
|
||||
int state;
|
||||
int userId;
|
||||
}
|
||||
|
||||
@Override
|
||||
public final IBinder onBind(Intent intent) {
|
||||
if (DEBUG) Slog.v(TAG, "onBind() intent = " + intent);
|
||||
return new FingerprintServiceWrapper();
|
||||
}
|
||||
|
||||
// JNI methods to communicate from FingerprintManagerService to HAL
|
||||
native int nativeEnroll(int timeout);
|
||||
native int nativeRemove(int fingerprintId);
|
||||
|
||||
// JNI methods for communicating from HAL to clients
|
||||
void notify(int msg, int arg1, int arg2) {
|
||||
mHandler.obtainMessage(MSG_NOTIFY, msg, arg1, arg2).sendToTarget();
|
||||
}
|
||||
|
||||
void handleNotify(int msg, int arg1, int arg2) {
|
||||
for (int i = 0; i < mClients.size(); i++) {
|
||||
ClientData clientData = mClients.get(i);
|
||||
switch (msg) {
|
||||
case FingerprintManager.FINGERPRINT_ERROR: {
|
||||
if (clientData.state != STATE_IDLE) {
|
||||
// FINGERPRINT_ERROR_HW_UNAVAILABLE
|
||||
// FINGERPRINT_ERROR_BAD_CAPTURE
|
||||
// FINGERPRINT_ERROR_TIMEOUT
|
||||
// FINGERPRINT_ERROR_NO_SPACE
|
||||
final int error = arg1;
|
||||
clientData.state = STATE_IDLE;
|
||||
if (clientData.receiver != null) {
|
||||
try {
|
||||
clientData.receiver.onError(error);
|
||||
} catch (RemoteException e) {
|
||||
Slog.e(TAG, "can't send message to client. Did it die?", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
case FingerprintManager.FINGERPRINT_SCANNED: {
|
||||
final int fingerId = arg1;
|
||||
final int confidence = arg2;
|
||||
if (clientData.state == STATE_LISTENING && clientData.receiver != null) {
|
||||
try {
|
||||
clientData.receiver.onScanned(fingerId, confidence);
|
||||
} catch (RemoteException e) {
|
||||
Slog.e(TAG, "can't send message to client. Did it die?", e);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case FingerprintManager.FINGERPRINT_TEMPLATE_ENROLLING: {
|
||||
if (clientData.state == STATE_ENROLLING) {
|
||||
final int fingerId = arg1;
|
||||
final int remaining = arg2;
|
||||
if (remaining == 0) {
|
||||
FingerprintUtils.addFingerprintIdForUser(fingerId,
|
||||
getContentResolver(), clientData.userId);
|
||||
clientData.state = STATE_IDLE; // Nothing left to do
|
||||
}
|
||||
if (clientData.receiver != null) {
|
||||
try {
|
||||
clientData.receiver.onEnrollResult(fingerId, remaining);
|
||||
} catch (RemoteException e) {
|
||||
Slog.e(TAG, "can't send message to client. Did it die?", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case FingerprintManager.FINGERPRINT_TEMPLATE_REMOVED: {
|
||||
int fingerId = arg1;
|
||||
if (fingerId == 0) throw new IllegalStateException("Got illegal id from HAL");
|
||||
if (clientData.state == STATE_DELETING) {
|
||||
FingerprintUtils.removeFingerprintIdForUser(fingerId, getContentResolver(),
|
||||
clientData.userId);
|
||||
if (clientData.receiver != null) {
|
||||
try {
|
||||
clientData.receiver.onRemoved(fingerId);
|
||||
} catch (RemoteException e) {
|
||||
Slog.e(TAG, "can't send message to client. Did it die?", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int enroll(IFingerprintServiceReceiver receiver, long timeout, int userId) {
|
||||
ClientData clientData = mClients.get(receiver);
|
||||
if (clientData != null) {
|
||||
if (clientData.userId != userId) throw new IllegalStateException("Bad user");
|
||||
clientData.state = STATE_ENROLLING;
|
||||
return nativeEnroll((int) (timeout / MS_PER_SEC));
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
int remove(IFingerprintServiceReceiver receiver, int fingerId, int userId) {
|
||||
ClientData clientData = mClients.get(receiver);
|
||||
if (clientData != null) {
|
||||
if (clientData.userId != userId) throw new IllegalStateException("Bad user");
|
||||
clientData.state = STATE_DELETING;
|
||||
// The fingerprint id will be removed when we get confirmation from the HAL
|
||||
return nativeRemove(fingerId);
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
void startListening(IFingerprintServiceReceiver receiver, int userId) {
|
||||
ClientData clientData = new ClientData();
|
||||
clientData.state = STATE_LISTENING;
|
||||
clientData.receiver = receiver;
|
||||
clientData.userId = userId;
|
||||
mClients.put(receiver, clientData);
|
||||
}
|
||||
|
||||
void stopListening(IFingerprintServiceReceiver receiver, int userId) {
|
||||
ClientData clientData = mClients.get(receiver);
|
||||
if (clientData != null) {
|
||||
clientData.state = STATE_IDLE;
|
||||
clientData.userId = -1;
|
||||
clientData.receiver = null;
|
||||
}
|
||||
mClients.remove(receiver);
|
||||
}
|
||||
|
||||
private final class FingerprintServiceWrapper extends IFingerprintService.Stub {
|
||||
IFingerprintServiceReceiver mReceiver;
|
||||
public int enroll(long timeout, int userId) {
|
||||
return mReceiver != null ? FingerprintService.this.enroll(mReceiver, timeout, userId)
|
||||
: FingerprintManager.FINGERPRINT_ERROR_NO_RECEIVER;
|
||||
}
|
||||
|
||||
public int remove(int fingerprintId, int userId) {
|
||||
return FingerprintService.this.remove(mReceiver, fingerprintId, userId);
|
||||
}
|
||||
|
||||
public void startListening(IFingerprintServiceReceiver receiver, int userId) {
|
||||
mReceiver = receiver;
|
||||
FingerprintService.this.startListening(receiver, userId);
|
||||
}
|
||||
|
||||
public void stopListening(int userId) {
|
||||
FingerprintService.this.stopListening(mReceiver, userId);
|
||||
}
|
||||
}
|
||||
}
|
||||
85
core/java/android/service/fingerprint/FingerprintUtils.java
Normal file
85
core/java/android/service/fingerprint/FingerprintUtils.java
Normal file
@@ -0,0 +1,85 @@
|
||||
/**
|
||||
* 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.content.ContentResolver;
|
||||
import android.provider.Settings;
|
||||
import android.util.Log;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
class FingerprintUtils {
|
||||
private static final boolean DEBUG = true;
|
||||
private static final String TAG = "FingerprintUtils";
|
||||
|
||||
public static int[] getFingerprintIdsForUser(ContentResolver res, int userId) {
|
||||
String fingerIdsRaw = Settings.Secure.getStringForUser(res,
|
||||
Settings.Secure.USER_FINGERPRINT_IDS, userId);
|
||||
|
||||
String[] fingerStringIds = fingerIdsRaw.replace("[","").replace("]","").split(", ");
|
||||
int result[] = new int[fingerStringIds.length];
|
||||
for (int i = 0; i < result.length; i++) {
|
||||
try {
|
||||
result[i] = Integer.decode(fingerStringIds[i]);
|
||||
} catch (NumberFormatException e) {
|
||||
if (DEBUG) Log.d(TAG, "Error when parsing finger id " + fingerStringIds[i]);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
public static void addFingerprintIdForUser(int fingerId, ContentResolver res, int userId) {
|
||||
int[] fingerIds = getFingerprintIdsForUser(res, userId);
|
||||
|
||||
// FingerId 0 has special meaning.
|
||||
if (fingerId == 0) return;
|
||||
|
||||
// Don't allow dups
|
||||
for (int i = 0; i < fingerIds.length; i++) {
|
||||
if (fingerIds[i] == fingerId) return;
|
||||
}
|
||||
int[] newList = Arrays.copyOf(fingerIds, fingerIds.length + 1);
|
||||
newList[fingerIds.length] = fingerId;
|
||||
Settings.Secure.putStringForUser(res, Settings.Secure.USER_FINGERPRINT_IDS,
|
||||
Arrays.toString(newList), userId);
|
||||
}
|
||||
|
||||
public static boolean removeFingerprintIdForUser(int fingerId, ContentResolver res, int userId)
|
||||
{
|
||||
// FingerId 0 has special meaning. The HAL layer is supposed to remove each finger one
|
||||
// at a time and invoke notify() for each fingerId. If we get called with 0 here, it means
|
||||
// something bad has happened.
|
||||
if (fingerId == 0) throw new IllegalStateException("Bad fingerId");
|
||||
|
||||
int[] fingerIds = getFingerprintIdsForUser(res, userId);
|
||||
int[] resultIds = Arrays.copyOf(fingerIds, fingerIds.length);
|
||||
int resultCount = 0;
|
||||
for (int i = 0; i < fingerIds.length; i++) {
|
||||
if (fingerId != fingerIds[i]) {
|
||||
resultIds[resultCount++] = fingerIds[i];
|
||||
}
|
||||
}
|
||||
if (resultCount > 0) {
|
||||
Settings.Secure.putStringForUser(res, Settings.Secure.USER_FINGERPRINT_IDS,
|
||||
Arrays.toString(Arrays.copyOf(resultIds, resultCount)), userId);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
@@ -0,0 +1,38 @@
|
||||
/*
|
||||
* 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.os.Bundle;
|
||||
import android.service.fingerprint.IFingerprintServiceReceiver;
|
||||
|
||||
/**
|
||||
* Communication channel from client to the fingerprint service.
|
||||
* @hide
|
||||
*/
|
||||
interface IFingerprintService {
|
||||
// Returns 0 if successfully started, -1 otherwise
|
||||
int enroll(long timeout, int userId);
|
||||
|
||||
// Returns 0 if fingerprintId's template can be removed, -1 otherwise
|
||||
int remove(int fingerprintId, int userId);
|
||||
|
||||
// Start listening for fingerprint events. This has the side effect of starting
|
||||
// the hardware if not already started.
|
||||
oneway void startListening(IFingerprintServiceReceiver receiver, int userId);
|
||||
|
||||
// Stops listening for fingerprints
|
||||
oneway void stopListening(int userId);
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
/*
|
||||
* 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.os.Bundle;
|
||||
import android.os.UserHandle;
|
||||
|
||||
/**
|
||||
* Communication channel from the FingerprintService back to FingerprintManager.
|
||||
* @hide
|
||||
*/
|
||||
oneway interface IFingerprintServiceReceiver {
|
||||
void onEnrollResult(int fingerprintId, int remaining);
|
||||
void onScanned(int fingerprintId, int confidence);
|
||||
void onError(int error);
|
||||
void onRemoved(int fingerprintId);
|
||||
}
|
||||
@@ -141,6 +141,7 @@ LOCAL_SRC_FILES:= \
|
||||
android_util_FileObserver.cpp \
|
||||
android/opengl/poly_clip.cpp.arm \
|
||||
android/opengl/util.cpp.arm \
|
||||
android_server_FingerprintManager.cpp \
|
||||
android_server_NetworkManagementSocketTagger.cpp \
|
||||
android_server_Watchdog.cpp \
|
||||
android_ddm_DdmHandleNativeHeap.cpp \
|
||||
|
||||
73
core/jni/android_server_FingerprintManager.cpp
Normal file
73
core/jni/android_server_FingerprintManager.cpp
Normal file
@@ -0,0 +1,73 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#define LOG_TAG "Fingerprint-JNI"
|
||||
|
||||
#include "JNIHelp.h"
|
||||
|
||||
#include <android_runtime/AndroidRuntime.h>
|
||||
#include <android_runtime/Log.h>
|
||||
#include <utils/Log.h>
|
||||
|
||||
namespace android {
|
||||
|
||||
static struct {
|
||||
jclass clazz;
|
||||
jmethodID notify;
|
||||
} gFingerprintManagerClassInfo;
|
||||
|
||||
static jint nativeEnroll(JNIEnv* env, jobject clazz, jint timeout) {
|
||||
return -1; // TODO
|
||||
}
|
||||
|
||||
static jint nativeRemove(JNIEnv* env, jobject clazz, jint fingerprintId) {
|
||||
return -1; // TODO
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
static const JNINativeMethod g_methods[] = {
|
||||
{ "nativeEnroll", "(I)I", (void*)nativeEnroll },
|
||||
{ "nativeRemove", "(I)I", (void*)nativeRemove },
|
||||
};
|
||||
|
||||
#define FIND_CLASS(var, className) \
|
||||
var = env->FindClass(className); \
|
||||
LOG_FATAL_IF(! var, "Unable to find class " className); \
|
||||
var = jclass(env->NewGlobalRef(var));
|
||||
|
||||
#define GET_STATIC_METHOD_ID(var, clazz, methodName, fieldDescriptor) \
|
||||
var = env->GetStaticMethodID(clazz, methodName, fieldDescriptor); \
|
||||
LOG_FATAL_IF(! var, "Unable to find static method" methodName);
|
||||
|
||||
#define GET_METHOD_ID(var, clazz, methodName, fieldDescriptor) \
|
||||
var = env->GetMethodID(clazz, methodName, fieldDescriptor); \
|
||||
LOG_FATAL_IF(! var, "Unable to find method" methodName);
|
||||
|
||||
#define GET_FIELD_ID(var, clazz, fieldName, fieldDescriptor) \
|
||||
var = env->GetFieldID(clazz, fieldName, fieldDescriptor); \
|
||||
LOG_FATAL_IF(! var, "Unable to find field " fieldName);
|
||||
|
||||
int register_android_server_FingerprintManager(JNIEnv* env) {
|
||||
FIND_CLASS(gFingerprintManagerClassInfo.clazz,
|
||||
"android/service/fingerprint/FingerprintManager");
|
||||
GET_METHOD_ID(gFingerprintManagerClassInfo.notify, gFingerprintManagerClassInfo.clazz,
|
||||
"notify", "(III)V");
|
||||
return AndroidRuntime::registerNativeMethods(
|
||||
env, "com/android/service/fingerprint/FingerprintManager", g_methods, NELEM(g_methods));
|
||||
}
|
||||
|
||||
} // namespace android
|
||||
Reference in New Issue
Block a user