Merge "First pass at FingerprintService integration with HAL. Move FingerprintService to framework services directory Fix merge conflicts."
diff --git a/api/current.txt b/api/current.txt
index 704a60a..8a61cc0 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -26020,29 +26020,61 @@
package android.service.fingerprint {
public class FingerprintManager {
- ctor public FingerprintManager(android.content.Context);
+ ctor public FingerprintManager(android.content.Context, android.service.fingerprint.IFingerprintService);
method public void enroll(long);
+ method public void enrollCancel();
method public boolean enrolledAndEnabled();
method public void remove(int);
method public void startListening(android.service.fingerprint.FingerprintManagerReceiver);
method public void stopListening();
+ field public static final int FINGERPRINT_ACQUIRED = 1; // 0x1
+ field public static final int FINGERPRINT_ACQUIRED_GOOD = 0; // 0x0
+ field public static final int FINGERPRINT_ACQUIRED_IMAGER_DIRTY = 4; // 0x4
+ field public static final int FINGERPRINT_ACQUIRED_INSUFFICIENT = 2; // 0x2
+ field public static final int FINGERPRINT_ACQUIRED_PARTIAL = 1; // 0x1
+ field public static final int FINGERPRINT_ACQUIRED_TOO_FAST = 16; // 0x10
+ field public static final int FINGERPRINT_ACQUIRED_TOO_SLOW = 8; // 0x8
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_ERROR_UNABLE_TO_PROCESS = 2; // 0x2
+ field public static final int FINGERPRINT_PROCESSED = 2; // 0x2
+ field public static final int FINGERPRINT_TEMPLATE_ENROLLING = 3; // 0x3
field public static final int FINGERPRINT_TEMPLATE_REMOVED = 4; // 0x4
}
public class FingerprintManagerReceiver {
ctor public FingerprintManagerReceiver();
+ method public void onAcquired(int);
method public void onEnrollResult(int, int);
method public void onError(int);
+ method public void onProcessed(int);
method public void onRemoved(int);
- method public void onScanned(int, int);
+ }
+
+ public class FingerprintUtils {
+ ctor public FingerprintUtils();
+ method public static void addFingerprintIdForUser(int, android.content.ContentResolver, int);
+ method public static int[] getFingerprintIdsForUser(android.content.ContentResolver, int);
+ method public static boolean removeFingerprintIdForUser(int, android.content.ContentResolver, int);
+ }
+
+ public abstract interface IFingerprintService implements android.os.IInterface {
+ method public abstract void enroll(android.os.IBinder, long, int) throws android.os.RemoteException;
+ method public abstract void enrollCancel(android.os.IBinder, int) throws android.os.RemoteException;
+ method public abstract void remove(android.os.IBinder, int, int) throws android.os.RemoteException;
+ method public abstract void startListening(android.os.IBinder, android.service.fingerprint.IFingerprintServiceReceiver, int) throws android.os.RemoteException;
+ method public abstract void stopListening(android.os.IBinder, int) throws android.os.RemoteException;
+ }
+
+ public abstract interface IFingerprintServiceReceiver implements android.os.IInterface {
+ method public abstract void onAcquired(int) throws android.os.RemoteException;
+ method public abstract void onEnrollResult(int, int) throws android.os.RemoteException;
+ method public abstract void onError(int) throws android.os.RemoteException;
+ method public abstract void onProcessed(int) throws android.os.RemoteException;
+ method public abstract void onRemoved(int) throws android.os.RemoteException;
}
}
diff --git a/core/java/android/app/ContextImpl.java b/core/java/android/app/ContextImpl.java
index ab3bb49..a42bd3b 100644
--- a/core/java/android/app/ContextImpl.java
+++ b/core/java/android/app/ContextImpl.java
@@ -115,9 +115,8 @@
import android.os.storage.StorageManager;
import android.print.IPrintManager;
import android.print.PrintManager;
+import android.service.fingerprint.IFingerprintService;
import android.service.fingerprint.FingerprintManager;
-import android.service.fingerprint.FingerprintManagerReceiver;
-import android.service.fingerprint.FingerprintService;
import android.telecomm.TelecommManager;
import android.telephony.TelephonyManager;
import android.content.ClipboardManager;
@@ -466,11 +465,6 @@
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());
@@ -690,6 +684,7 @@
return new MediaSessionManager(ctx);
}
});
+
registerService(TRUST_SERVICE, new ServiceFetcher() {
public Object createService(ContextImpl ctx) {
IBinder b = ServiceManager.getService(TRUST_SERVICE);
@@ -697,6 +692,14 @@
}
});
+ registerService(FINGERPRINT_SERVICE, new ServiceFetcher() {
+ public Object createService(ContextImpl ctx) {
+ IBinder b = ServiceManager.getService(FINGERPRINT_SERVICE);
+ IFingerprintService service = IFingerprintService.Stub.asInterface(b);
+ return new FingerprintManager(ctx.getOuterContext(), service);
+ }
+ });
+
registerService(TV_INPUT_SERVICE, new ServiceFetcher() {
public Object createService(ContextImpl ctx) {
IBinder iBinder = ServiceManager.getService(TV_INPUT_SERVICE);
diff --git a/core/java/android/service/fingerprint/FingerprintManager.java b/core/java/android/service/fingerprint/FingerprintManager.java
index 2fcec52..b6137d1 100644
--- a/core/java/android/service/fingerprint/FingerprintManager.java
+++ b/core/java/android/service/fingerprint/FingerprintManager.java
@@ -22,12 +22,14 @@
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.
@@ -36,31 +38,40 @@
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;
+ 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;
- 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;
+ // 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 fingerprint HAL definitions.
+ // Error messages. Must agree with HAL (fingerprint.h)
public static final int FINGERPRINT_ERROR_HW_UNAVAILABLE = 1;
- public static final int FINGERPRINT_ERROR_BAD_CAPTURE = 2;
+ 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) {
@@ -69,8 +80,11 @@
case MSG_ENROLL_RESULT:
mClientReceiver.onEnrollResult(msg.arg1, msg.arg2);
break;
- case MSG_SCANNED:
- mClientReceiver.onScanned(msg.arg1, msg.arg2);
+ case MSG_ACQUIRED:
+ mClientReceiver.onAcquired(msg.arg1);
+ break;
+ case MSG_PROCESSED:
+ mClientReceiver.onProcessed(msg.arg1);
break;
case MSG_ERROR:
mClientReceiver.onError(msg.arg1);
@@ -82,45 +96,26 @@
}
};
- public FingerprintManager(Context context) {
+ public FingerprintManager(Context context, IFingerprintService service) {
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);
+ mService = service;
+ if (mService == null) {
+ Slog.v(TAG, "FingerprintManagerService was null");
}
}
- 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 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) {
@@ -151,12 +146,14 @@
*/
public void enroll(long timeout) {
if (mServiceReceiver == null) {
- throw new IllegalStateException("enroll: Call registerCallback() first");
+ sendError(FINGERPRINT_ERROR_NO_RECEIVER, 0, 0);
+ return;
}
if (mService != null) try {
- mService.enroll(timeout, getCurrentUserId());
+ mService.enroll(mToken, timeout, getCurrentUserId());
} catch (RemoteException e) {
Log.v(TAG, "Remote exception while enrolling: ", e);
+ sendError(FINGERPRINT_ERROR_HW_UNAVAILABLE, 0, 0);
}
}
@@ -166,10 +163,19 @@
* @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);
+ 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);
}
}
@@ -181,10 +187,13 @@
mClientReceiver = receiver;
if (mService != null) {
try {
- mService.startListening(mServiceReceiver, getCurrentUserId());
+ 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);
}
}
@@ -201,15 +210,38 @@
* Stops the client from listening to fingerprint events.
*/
public void stopListening() {
- mClientReceiver = null;
if (mService != null) {
try {
- mService.stopListening(getCurrentUserId());
+ 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);
+ }
}
\ No newline at end of file
diff --git a/core/java/android/service/fingerprint/FingerprintManagerReceiver.java b/core/java/android/service/fingerprint/FingerprintManagerReceiver.java
index 34f1655..e5193f5 100644
--- a/core/java/android/service/fingerprint/FingerprintManagerReceiver.java
+++ b/core/java/android/service/fingerprint/FingerprintManagerReceiver.java
@@ -30,18 +30,32 @@
public void onEnrollResult(int fingerprintId, int remaining) { }
/**
- * Fingerprint scan detected. Most clients will use this function to detect a fingerprint
+ * Fingerprint touch detected, but not processed yet. Clients will use this message to
+ * determine a good or bad scan before the fingerprint is processed. This is meant for the
+ * client to provide feedback about the scan or alert the user that recognition is to follow.
*
- * @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.
+ * @param acquiredInfo one of:
+ * {@link FingerprintManager#FINGERPRINT_ACQUIRED_GOOD},
+ * {@link FingerprintManager#FINGERPRINT_ACQUIRED_PARTIAL},
+ * {@link FingerprintManager#FINGERPRINT_ACQUIRED_INSUFFICIENT},
+ * {@link FingerprintManager#FINGERPRINT_ACQUIRED_IMAGER_DIRTY},
+ * {@link FingerprintManager#FINGERPRINT_ACQUIRED_TOO_SLOW},
+ * {@link FingerprintManager#FINGERPRINT_ACQUIRED_TOO_FAST}
*/
- public void onScanned(int fingerprintId, int confidence) { }
+ public void onAcquired(int acquiredInfo) { }
+
+ /**
+ * Fingerprint has been detected and processed. A non-zero return indicates a valid
+ * fingerprint was detected.
+ *
+ * @param fingerprintId the finger id, or 0 if not recognized.
+ */
+ public void onProcessed(int fingerprintId) { }
/**
* 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_UNABLE_TO_PROCESS} or
* {@link FingerprintManager#FINGERPRINT_ERROR_TIMEOUT}
* {@link FingerprintManager#FINGERPRINT_ERROR_NO_SPACE}
*
diff --git a/core/java/android/service/fingerprint/FingerprintService.java b/core/java/android/service/fingerprint/FingerprintService.java
deleted file mode 100644
index c7fa7cd..0000000
--- a/core/java/android/service/fingerprint/FingerprintService.java
+++ /dev/null
@@ -1,219 +0,0 @@
-/**
- * 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);
- }
- }
-}
diff --git a/core/java/android/service/fingerprint/FingerprintUtils.java b/core/java/android/service/fingerprint/FingerprintUtils.java
index 81a2aac..f4b5526 100644
--- a/core/java/android/service/fingerprint/FingerprintUtils.java
+++ b/core/java/android/service/fingerprint/FingerprintUtils.java
@@ -18,10 +18,12 @@
import android.content.ContentResolver;
import android.provider.Settings;
+import android.text.TextUtils;
import android.util.Log;
import java.util.Arrays;
+public
class FingerprintUtils {
private static final boolean DEBUG = true;
private static final String TAG = "FingerprintUtils";
@@ -30,13 +32,16 @@
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]);
+ int result[] = {};
+ if (!TextUtils.isEmpty(fingerIdsRaw)) {
+ String[] fingerStringIds = fingerIdsRaw.replace("[","").replace("]","").split(", ");
+ 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;
diff --git a/core/java/android/service/fingerprint/IFingerprintService.aidl b/core/java/android/service/fingerprint/IFingerprintService.aidl
index e92c20c..43d5e9a 100644
--- a/core/java/android/service/fingerprint/IFingerprintService.aidl
+++ b/core/java/android/service/fingerprint/IFingerprintService.aidl
@@ -22,17 +22,20 @@
* Communication channel from client to the fingerprint service.
* @hide
*/
-interface IFingerprintService {
- // Returns 0 if successfully started, -1 otherwise
- int enroll(long timeout, int userId);
+oneway interface IFingerprintService {
+ // Any errors resulting from this call will be returned to the listener
+ void enroll(IBinder token, long timeout, int userId);
+
+ // Any errors resulting from this call will be returned to the listener
+ void enrollCancel(IBinder token, int userId);
- // Returns 0 if fingerprintId's template can be removed, -1 otherwise
- int remove(int fingerprintId, int userId);
+ // Any errors resulting from this call will be returned to the listener
+ void remove(IBinder token, 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);
+ void startListening(IBinder token, IFingerprintServiceReceiver receiver, int userId);
// Stops listening for fingerprints
- oneway void stopListening(int userId);
+ void stopListening(IBinder token, int userId);
}
diff --git a/core/java/android/service/fingerprint/IFingerprintServiceReceiver.aidl b/core/java/android/service/fingerprint/IFingerprintServiceReceiver.aidl
index 4826b59..af4128f 100644
--- a/core/java/android/service/fingerprint/IFingerprintServiceReceiver.aidl
+++ b/core/java/android/service/fingerprint/IFingerprintServiceReceiver.aidl
@@ -24,7 +24,8 @@
*/
oneway interface IFingerprintServiceReceiver {
void onEnrollResult(int fingerprintId, int remaining);
- void onScanned(int fingerprintId, int confidence);
+ void onAcquired(int acquiredInfo);
+ void onProcessed(int fingerprintId);
void onError(int error);
void onRemoved(int fingerprintId);
}
diff --git a/core/jni/AndroidRuntime.cpp b/core/jni/AndroidRuntime.cpp
index f2b9bac..a7a1faad 100644
--- a/core/jni/AndroidRuntime.cpp
+++ b/core/jni/AndroidRuntime.cpp
@@ -159,6 +159,7 @@
extern int register_android_text_AndroidCharacter(JNIEnv *env);
extern int register_android_text_AndroidBidi(JNIEnv *env);
extern int register_android_opengl_classes(JNIEnv *env);
+extern int register_android_server_fingerprint_FingerprintService(JNIEnv* env);
extern int register_android_server_NetworkManagementSocketTagger(JNIEnv* env);
extern int register_android_server_Watchdog(JNIEnv* env);
extern int register_android_ddm_DdmHandleNativeHeap(JNIEnv *env);
@@ -1328,6 +1329,7 @@
REG_JNI(register_android_media_ToneGenerator),
REG_JNI(register_android_opengl_classes),
+ REG_JNI(register_android_server_fingerprint_FingerprintService),
REG_JNI(register_android_server_NetworkManagementSocketTagger),
REG_JNI(register_android_server_Watchdog),
REG_JNI(register_android_ddm_DdmHandleNativeHeap),
diff --git a/core/jni/android_server_FingerprintManager.cpp b/core/jni/android_server_FingerprintManager.cpp
index f8a1fd9..ad36843c 100644
--- a/core/jni/android_server_FingerprintManager.cpp
+++ b/core/jni/android_server_FingerprintManager.cpp
@@ -20,30 +20,10 @@
#include <android_runtime/AndroidRuntime.h>
#include <android_runtime/Log.h>
+#include <hardware/hardware.h>
+#include <hardware/fingerprint.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); \
@@ -61,13 +41,174 @@
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 {
+
+static const uint16_t kVersion = HARDWARE_MODULE_API_VERSION(1, 0);
+
+static const char* FINGERPRINT_SERVICE = "com/android/server/fingerprint/FingerprintService";
+static struct {
+ jclass clazz;
+ jmethodID notify;
+ jobject callbackObject;
+} gFingerprintServiceClassInfo;
+
+static struct {
+ fingerprint_module_t const* module;
+ fingerprint_device_t *device;
+} gContext;
+
+// TODO: remove after driver update to use new HAL
+fingerprint_msg_type_t hackTilFpDriverUpdate(fingerprint_msg_type_t t) {
+ switch(static_cast<int>(t)) {
+ case 1: return FINGERPRINT_PROCESSED;
+ case 2: return FINGERPRINT_TEMPLATE_ENROLLING;
+ default: return t;
+ }
+}
+
+// Called by the HAL to notify us of fingerprint events
+static void hal_notify_callback(fingerprint_msg_t msg) {
+ uint32_t arg1 = 0;
+ uint32_t arg2 = 0;
+ uint32_t arg3 = 0; // TODO
+ msg.type = hackTilFpDriverUpdate(msg.type);
+ switch (msg.type) {
+ case FINGERPRINT_ERROR:
+ arg1 = msg.data.error;
+ break;
+ case FINGERPRINT_ACQUIRED:
+ arg1 = msg.data.acquired.acquired_info;
+ break;
+ case FINGERPRINT_PROCESSED:
+ arg1 = msg.data.processed.id;
+ break;
+ case FINGERPRINT_TEMPLATE_ENROLLING:
+ arg1 = msg.data.enroll.id;
+ arg2 = msg.data.enroll.samples_remaining;
+ arg3 = msg.data.enroll.data_collected_bmp;
+ break;
+ case FINGERPRINT_TEMPLATE_REMOVED:
+ arg1 = msg.data.removed.id;
+ break;
+ default:
+ ALOGE("fingerprint: invalid msg: %d", msg.type);
+ return;
+ }
+ //ALOG(LOG_VERBOSE, LOG_TAG, "hal_notify(msg=%d, arg1=%d, arg2=%d)\n", msg.type, arg1, arg2);
+
+ // TODO: fix gross hack to attach JNI to calling thread
+ JNIEnv* env = AndroidRuntime::getJNIEnv();
+ if (env == NULL) {
+ JavaVMAttachArgs args = {JNI_VERSION_1_4, NULL, NULL};
+ JavaVM* vm = AndroidRuntime::getJavaVM();
+ int result = vm->AttachCurrentThread(&env, (void*) &args);
+ if (result != JNI_OK) {
+ ALOGE("Can't call JNI method: attach failed: %#x", result);
+ return;
+ }
+ }
+ env->CallVoidMethod(gFingerprintServiceClassInfo.callbackObject,
+ gFingerprintServiceClassInfo.notify, msg.type, arg1, arg2);
+}
+
+static void nativeInit(JNIEnv *env, jobject clazz, jobject callbackObj) {
+ ALOG(LOG_VERBOSE, LOG_TAG, "nativeInit()\n");
+ FIND_CLASS(gFingerprintServiceClassInfo.clazz, FINGERPRINT_SERVICE);
+ GET_METHOD_ID(gFingerprintServiceClassInfo.notify, gFingerprintServiceClassInfo.clazz,
+ "notify", "(III)V");
+ gFingerprintServiceClassInfo.callbackObject = env->NewGlobalRef(callbackObj);
+}
+
+static jint nativeEnroll(JNIEnv* env, jobject clazz, jint timeout) {
+ ALOG(LOG_VERBOSE, LOG_TAG, "nativeEnroll()\n");
+ int ret = gContext.device->enroll(gContext.device, timeout);
+ return reinterpret_cast<jint>(ret);
+}
+
+static jint nativeEnrollCancel(JNIEnv* env, jobject clazz) {
+ ALOG(LOG_VERBOSE, LOG_TAG, "nativeEnrollCancel()\n");
+ int ret = gContext.device->enroll_cancel(gContext.device);
+ return reinterpret_cast<jint>(ret);
+}
+
+static jint nativeRemove(JNIEnv* env, jobject clazz, jint fingerprintId) {
+ ALOG(LOG_VERBOSE, LOG_TAG, "nativeRemove(%d)\n", fingerprintId);
+ int ret = gContext.device->remove(gContext.device, fingerprintId);
+ return reinterpret_cast<jint>(ret);
+}
+
+static jint nativeOpenHal(JNIEnv* env, jobject clazz) {
+ ALOG(LOG_VERBOSE, LOG_TAG, "nativeOpenHal()\n");
+ int err;
+ const hw_module_t *hw_module = NULL;
+ if (0 != (err = hw_get_module(FINGERPRINT_HARDWARE_MODULE_ID, &hw_module))) {
+ ALOGE("Can't open fingerprint HW Module, error: %d", err);
+ return 0;
+ }
+ if (NULL == hw_module) {
+ ALOGE("No valid fingerprint module");
+ return 0;
+ }
+
+ gContext.module = reinterpret_cast<const fingerprint_module_t*>(hw_module);
+
+ if (gContext.module->common.methods->open == NULL) {
+ ALOGE("No valid open method");
+ return 0;
+ }
+
+ hw_device_t *device = NULL;
+
+ if (0 != (err = gContext.module->common.methods->open(hw_module, NULL, &device))) {
+ ALOGE("Can't open fingerprint methods, error: %d", err);
+ return 0;
+ }
+
+ if (kVersion != device->version) {
+ ALOGE("Wrong fp version. Expected %d, got %d", kVersion, device->version);
+ // return 0; // FIXME
+ }
+
+ gContext.device = reinterpret_cast<fingerprint_device_t*>(device);
+ err = gContext.device->set_notify(gContext.device, hal_notify_callback);
+ if (err < 0) {
+ ALOGE("Failed in call to set_notify(), err=%d", err);
+ return 0;
+ }
+
+ // Sanity check - remove
+ if (gContext.device->notify != hal_notify_callback) {
+ ALOGE("NOTIFY not set properly: %p != %p", gContext.device->notify, hal_notify_callback);
+ }
+
+ ALOG(LOG_VERBOSE, LOG_TAG, "fingerprint HAL successfully initialized");
+ return reinterpret_cast<jlong>(gContext.device);
+}
+
+static jint nativeCloseHal(JNIEnv* env, jobject clazz) {
+ return -ENOSYS; // TODO
+}
+
+// ----------------------------------------------------------------------------
+
+// TODO: clean up void methods
+static const JNINativeMethod g_methods[] = {
+ { "nativeEnroll", "(I)I", (void*)nativeEnroll },
+ { "nativeEnrollCancel", "()I", (void*)nativeEnroll },
+ { "nativeRemove", "(I)I", (void*)nativeRemove },
+ { "nativeOpenHal", "()I", (void*)nativeOpenHal },
+ { "nativeCloseHal", "()I", (void*)nativeCloseHal },
+ { "nativeInit", "(Lcom/android/server/fingerprint/FingerprintService;)V", (void*)nativeInit }
+};
+
+int register_android_server_fingerprint_FingerprintService(JNIEnv* env) {
+ FIND_CLASS(gFingerprintServiceClassInfo.clazz, FINGERPRINT_SERVICE);
+ GET_METHOD_ID(gFingerprintServiceClassInfo.notify, gFingerprintServiceClassInfo.clazz, "notify",
+ "(III)V");
+ int result = AndroidRuntime::registerNativeMethods(
+ env, FINGERPRINT_SERVICE, g_methods, NELEM(g_methods));
+ ALOG(LOG_VERBOSE, LOG_TAG, "FingerprintManager JNI ready.\n");
+ return result;
}
} // namespace android
diff --git a/services/core/java/com/android/server/fingerprint/FingerprintService.java b/services/core/java/com/android/server/fingerprint/FingerprintService.java
new file mode 100644
index 0000000..2941574
--- /dev/null
+++ b/services/core/java/com/android/server/fingerprint/FingerprintService.java
@@ -0,0 +1,328 @@
+/**
+ * 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 com.android.server.fingerprint;
+
+import android.app.Service;
+import android.content.ContentResolver;
+import android.content.Context;
+import android.content.Intent;
+import android.os.Handler;
+import android.os.IBinder;
+import android.os.PowerManager;
+import android.os.RemoteException;
+import android.provider.Settings;
+import android.service.fingerprint.FingerprintManager;
+import android.util.ArrayMap;
+import android.util.Slog;
+
+import com.android.server.SystemService;
+
+import android.service.fingerprint.FingerprintUtils;
+import android.service.fingerprint.IFingerprintService;
+import android.service.fingerprint.IFingerprintServiceReceiver;
+
+import java.io.PrintWriter;
+import java.lang.ref.WeakReference;
+import java.util.HashMap;
+import java.util.Map.Entry;
+import java.util.Set;
+
+/**
+ * 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 SystemService {
+ private final String TAG = "FingerprintService";
+ private static final boolean DEBUG = true;
+ private ArrayMap<IBinder, ClientData> mClients = new ArrayMap<IBinder, 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 Context mContext;
+
+ 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_REMOVING = 3;
+ private static final long MS_PER_SEC = 1000;
+ public static final String USE_FINGERPRINT = "android.permission.USE_FINGERPRINT";
+ public static final String ENROLL_FINGERPRINT = "android.permission.ENROLL_FINGERPRINT";
+
+ private static final class ClientData {
+ public IFingerprintServiceReceiver receiver;
+ int state;
+ int userId;
+ public TokenWatcher tokenWatcher;
+ IBinder getToken() { return tokenWatcher.getToken(); }
+ }
+
+ private class TokenWatcher implements IBinder.DeathRecipient {
+ WeakReference<IBinder> token;
+
+ TokenWatcher(IBinder token) {
+ this.token = new WeakReference<IBinder>(token);
+ }
+
+ IBinder getToken() { return token.get(); }
+ public void binderDied() {
+ mClients.remove(token);
+ this.token = null;
+ }
+
+ protected void finalize() throws Throwable {
+ try {
+ if (token != null) {
+ if (DEBUG) Slog.w(TAG, "removing leaked reference: " + token);
+ mClients.remove(token);
+ }
+ } finally {
+ super.finalize();
+ }
+ }
+ }
+
+ public FingerprintService(Context context) {
+ super(context);
+ mContext = context;
+ nativeInit(this);
+ }
+
+ // TODO: Move these into separate process
+ // JNI methods to communicate from FingerprintManagerService to HAL
+ native int nativeEnroll(int timeout);
+ native int nativeEnrollCancel();
+ native int nativeRemove(int fingerprintId);
+ native int nativeOpenHal();
+ native int nativeCloseHal();
+ native void nativeInit(FingerprintService service);
+
+ // 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) {
+ Slog.v(TAG, "handleNotify(msg=" + msg + ", arg1=" + arg1 + ", arg2=" + arg2 + ")");
+ for (int i = 0; i < mClients.size(); i++) {
+ ClientData clientData = mClients.valueAt(i);
+ if (clientData == null || clientData.receiver == null) {
+ if (DEBUG) Slog.v(TAG, "clientData at " + i + " is invalid!!");
+ continue;
+ }
+ switch (msg) {
+ case FingerprintManager.FINGERPRINT_ERROR: {
+ final int error = arg1;
+ try {
+ clientData.receiver.onError(error);
+ } catch (RemoteException e) {
+ Slog.e(TAG, "can't send message to client. Did it die?", e);
+ mClients.remove(mClients.keyAt(i));
+ }
+ }
+ break;
+ case FingerprintManager.FINGERPRINT_ACQUIRED: {
+ final int acquireInfo = arg1;
+ try {
+ clientData.receiver.onAcquired(acquireInfo);
+ } catch (RemoteException e) {
+ Slog.e(TAG, "can't send message to client. Did it die?", e);
+ mClients.remove(mClients.keyAt(i));
+ }
+ break;
+ }
+ case FingerprintManager.FINGERPRINT_PROCESSED: {
+ final int fingerId = arg1;
+ try {
+ clientData.receiver.onProcessed(fingerId);
+ } catch (RemoteException e) {
+ Slog.e(TAG, "can't send message to client. Did it die?", e);
+ mClients.remove(mClients.keyAt(i));
+ }
+ break;
+ }
+ case FingerprintManager.FINGERPRINT_TEMPLATE_ENROLLING: {
+ final int fingerId = arg1;
+ final int remaining = arg2;
+ if (clientData.state == STATE_ENROLLING) {
+ // Only send enroll updates to clients that are actually enrolling
+ try {
+ clientData.receiver.onEnrollResult(fingerId, remaining);
+ } catch (RemoteException e) {
+ Slog.e(TAG, "can't send message to client. Did it die?", e);
+ mClients.remove(mClients.keyAt(i));
+ }
+ // Update the database with new finger id.
+ // TODO: move to client code (Settings)
+ if (remaining == 0) {
+ FingerprintUtils.addFingerprintIdForUser(fingerId,
+ mContext.getContentResolver(), clientData.userId);
+ clientData.state = STATE_IDLE; // Nothing left to do
+ }
+ } else {
+ if (DEBUG) Slog.w(TAG, "Client not enrolling");
+ break;
+ }
+ break;
+ }
+ case FingerprintManager.FINGERPRINT_TEMPLATE_REMOVED: {
+ int fingerId = arg1;
+ if (fingerId == 0) throw new IllegalStateException("Got illegal id from HAL");
+ FingerprintUtils.removeFingerprintIdForUser(fingerId,
+ mContext.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);
+ mClients.remove(mClients.keyAt(i));
+ }
+ }
+ clientData.state = STATE_LISTENING;
+ }
+ break;
+ }
+ }
+ }
+
+ void startEnroll(IBinder token, long timeout, int userId) {
+ ClientData clientData = mClients.get(token);
+ if (clientData != null) {
+ if (clientData.userId != userId) throw new IllegalStateException("Bad user");
+ clientData.state = STATE_ENROLLING;
+ nativeEnroll((int) (timeout / MS_PER_SEC));
+ } else {
+ Slog.w(TAG, "enroll(): No listener registered");
+ }
+ }
+
+ void startEnrollCancel(IBinder token, int userId) {
+ ClientData clientData = mClients.get(token);
+ if (clientData != null) {
+ if (clientData.userId != userId) throw new IllegalStateException("Bad user");
+ clientData.state = STATE_LISTENING;
+ nativeEnrollCancel();
+ } else {
+ Slog.w(TAG, "enrollCancel(): No listener registered");
+ }
+ }
+
+ // Remove all fingerprints for the given user.
+ void startRemove(IBinder token, int fingerId, int userId) {
+ ClientData clientData = mClients.get(token);
+ if (clientData != null) {
+ if (clientData.userId != userId) throw new IllegalStateException("Bad user");
+ clientData.state = STATE_REMOVING;
+ // The fingerprint id will be removed when we get confirmation from the HAL
+ int result = nativeRemove(fingerId);
+ if (result != 0) {
+ Slog.w(TAG, "Error removing fingerprint with id = " + fingerId);
+ }
+ } else {
+ Slog.w(TAG, "remove(" + token + "): No listener registered");
+ }
+ }
+
+ void addListener(IBinder token, IFingerprintServiceReceiver receiver, int userId) {
+ if (DEBUG) Slog.v(TAG, "startListening(" + receiver + ")");
+ if (mClients.get(token) == null) {
+ ClientData clientData = new ClientData();
+ clientData.state = STATE_LISTENING;
+ clientData.receiver = receiver;
+ clientData.userId = userId;
+ clientData.tokenWatcher = new TokenWatcher(token);
+ try {
+ token.linkToDeath(clientData.tokenWatcher, 0);
+ mClients.put(token, clientData);
+ } catch (RemoteException e) {
+ Slog.w(TAG, "caught remote exception in linkToDeath: ", e);
+ }
+ } else {
+ if (DEBUG) Slog.v(TAG, "listener already registered for " + token);
+ }
+ }
+
+ void removeListener(IBinder token, int userId) {
+ if (DEBUG) Slog.v(TAG, "stopListening(" + token + ")");
+ ClientData clientData = mClients.get(token);
+ if (clientData != null) {
+ token.unlinkToDeath(clientData.tokenWatcher, 0);
+ mClients.remove(token);
+ } else {
+ if (DEBUG) Slog.v(TAG, "listener not registered: " + token);
+ }
+ mClients.remove(token);
+ }
+
+ void checkPermission(String permisison) {
+ // TODO
+ }
+
+ private final class FingerprintServiceWrapper extends IFingerprintService.Stub {
+ @Override // Binder call
+ public void enroll(IBinder token, long timeout, int userId) {
+ checkPermission(ENROLL_FINGERPRINT);
+ startEnroll(token, timeout, userId);
+ }
+
+ @Override // Binder call
+ public void enrollCancel(IBinder token,int userId) {
+ checkPermission(ENROLL_FINGERPRINT);
+ startEnrollCancel(token, userId);
+ }
+
+ @Override // Binder call
+ public void remove(IBinder token, int fingerprintId, int userId) {
+ checkPermission(ENROLL_FINGERPRINT); // TODO: Maybe have another permission
+ startRemove(token, fingerprintId, userId);
+ }
+
+ @Override // Binder call
+ public void startListening(IBinder token, IFingerprintServiceReceiver receiver, int userId)
+ {
+ checkPermission(USE_FINGERPRINT);
+ addListener(token, receiver, userId);
+ }
+
+ @Override // Binder call
+ public void stopListening(IBinder token, int userId) {
+ checkPermission(USE_FINGERPRINT);
+ removeListener(token, userId);
+ }
+ }
+
+ @Override
+ public void onStart() {
+ publishBinderService(Context.FINGERPRINT_SERVICE, new FingerprintServiceWrapper());
+ nativeOpenHal();
+ }
+
+}
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index 3102cce..5cccdd6 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -44,6 +44,7 @@
import android.os.SystemProperties;
import android.os.UserHandle;
import android.service.dreams.DreamService;
+import android.service.fingerprint.FingerprintManager;
import android.util.DisplayMetrics;
import android.util.EventLog;
import android.util.Log;
@@ -63,6 +64,7 @@
import com.android.server.devicepolicy.DevicePolicyManagerService;
import com.android.server.display.DisplayManagerService;
import com.android.server.dreams.DreamManagerService;
+import com.android.server.fingerprint.FingerprintService;
import com.android.server.hdmi.HdmiControlService;
import com.android.server.input.InputManagerService;
import com.android.server.job.JobSchedulerService;
@@ -989,11 +991,19 @@
}
try {
+ Slog.i(TAG, "Fingerprint Manager");
+ mSystemServiceManager.startService(FingerprintService.class);
+ } catch (Throwable e) {
+ Slog.e(TAG, "Failure starting FingerprintService", e);
+ }
+
+ try {
Slog.i(TAG, "BackgroundDexOptService");
new BackgroundDexOptService(context);
} catch (Throwable e) {
reportWtf("starting BackgroundDexOptService", e);
}
+
}
try {