Merge "Add callback for when enrollment state changes" into sc-qpr1-dev

This commit is contained in:
Kevin Chyn
2021-09-07 22:36:04 +00:00
committed by Android (Google) Code Review
22 changed files with 456 additions and 136 deletions

View File

@@ -849,26 +849,6 @@ public class FingerprintManager implements BiometricAuthenticator, BiometricFing
return hasEnrolledFingerprints(userId); return hasEnrolledFingerprints(userId);
} }
/**
* Checks if the specified user has enrollments in any of the specified sensors.
* @hide
*/
@RequiresPermission(USE_BIOMETRIC_INTERNAL)
public boolean hasEnrolledTemplatesForAnySensor(int userId,
@NonNull List<FingerprintSensorPropertiesInternal> sensors) {
if (mService == null) {
Slog.w(TAG, "hasEnrolledTemplatesForAnySensor: no fingerprint service");
return false;
}
try {
return mService.hasEnrolledTemplatesForAnySensor(userId, sensors,
mContext.getOpPackageName());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
}
/** /**
* @hide * @hide
*/ */

View File

@@ -49,5 +49,10 @@ public abstract class FingerprintStateListener extends IFingerprintStateListener
* Defines behavior in response to state update * Defines behavior in response to state update
* @param newState new state of fingerprint sensor * @param newState new state of fingerprint sensor
*/ */
public abstract void onStateChanged(@FingerprintStateListener.State int newState); public void onStateChanged(@FingerprintStateListener.State int newState) {};
/**
* Invoked when enrollment state changes for the specified user
*/
public void onEnrollmentsChanged(int userId, int sensorId, boolean hasEnrollments) {};
} }

View File

@@ -120,9 +120,6 @@ interface IFingerprintService {
// Determine if a user has at least one enrolled fingerprint. // Determine if a user has at least one enrolled fingerprint.
boolean hasEnrolledFingerprints(int sensorId, int userId, String opPackageName); boolean hasEnrolledFingerprints(int sensorId, int userId, String opPackageName);
// Determine if a user has at least one enrolled fingerprint in any of the specified sensors
boolean hasEnrolledTemplatesForAnySensor(int userId, in List<FingerprintSensorPropertiesInternal> sensors, String opPackageName);
// Return the LockoutTracker status for the specified user // Return the LockoutTracker status for the specified user
int getLockoutModeForUser(int sensorId, int userId); int getLockoutModeForUser(int sensorId, int userId);

View File

@@ -24,4 +24,5 @@ import android.hardware.fingerprint.Fingerprint;
*/ */
oneway interface IFingerprintStateListener { oneway interface IFingerprintStateListener {
void onStateChanged(int newState); void onStateChanged(int newState);
void onEnrollmentsChanged(int userId, int sensorId, boolean hasEnrollments);
} }

View File

@@ -42,6 +42,7 @@ import android.hardware.face.FaceManager;
import android.hardware.face.FaceSensorPropertiesInternal; import android.hardware.face.FaceSensorPropertiesInternal;
import android.hardware.fingerprint.FingerprintManager; import android.hardware.fingerprint.FingerprintManager;
import android.hardware.fingerprint.FingerprintSensorPropertiesInternal; import android.hardware.fingerprint.FingerprintSensorPropertiesInternal;
import android.hardware.fingerprint.FingerprintStateListener;
import android.hardware.fingerprint.IFingerprintAuthenticatorsRegisteredCallback; import android.hardware.fingerprint.IFingerprintAuthenticatorsRegisteredCallback;
import android.hardware.fingerprint.IUdfpsHbmListener; import android.hardware.fingerprint.IUdfpsHbmListener;
import android.os.Bundle; import android.os.Bundle;
@@ -49,6 +50,7 @@ import android.os.Handler;
import android.os.Looper; import android.os.Looper;
import android.os.RemoteException; import android.os.RemoteException;
import android.util.Log; import android.util.Log;
import android.util.SparseBooleanArray;
import android.view.MotionEvent; import android.view.MotionEvent;
import android.view.WindowManager; import android.view.WindowManager;
@@ -76,6 +78,9 @@ import kotlin.Unit;
/** /**
* Receives messages sent from {@link com.android.server.biometrics.BiometricService} and shows the * Receives messages sent from {@link com.android.server.biometrics.BiometricService} and shows the
* appropriate biometric UI (e.g. BiometricDialogView). * appropriate biometric UI (e.g. BiometricDialogView).
*
* Also coordinates biometric-related things, such as UDFPS, with
* {@link com.android.keyguard.KeyguardUpdateMonitor}
*/ */
@SysUISingleton @SysUISingleton
public class AuthController extends SystemUI implements CommandQueue.Callbacks, public class AuthController extends SystemUI implements CommandQueue.Callbacks,
@@ -115,6 +120,8 @@ public class AuthController extends SystemUI implements CommandQueue.Callbacks,
@Nullable private List<FingerprintSensorPropertiesInternal> mUdfpsProps; @Nullable private List<FingerprintSensorPropertiesInternal> mUdfpsProps;
@Nullable private List<FingerprintSensorPropertiesInternal> mSidefpsProps; @Nullable private List<FingerprintSensorPropertiesInternal> mSidefpsProps;
@NonNull private final SparseBooleanArray mUdfpsEnrolledForUser;
private class BiometricTaskStackListener extends TaskStackListener { private class BiometricTaskStackListener extends TaskStackListener {
@Override @Override
public void onTaskStackChanged() { public void onTaskStackChanged() {
@@ -122,6 +129,21 @@ public class AuthController extends SystemUI implements CommandQueue.Callbacks,
} }
} }
private final FingerprintStateListener mFingerprintStateListener =
new FingerprintStateListener() {
@Override
public void onEnrollmentsChanged(int userId, int sensorId, boolean hasEnrollments) {
Log.d(TAG, "onEnrollmentsChanged, userId: " + userId
+ ", sensorId: " + sensorId
+ ", hasEnrollments: " + hasEnrollments);
for (FingerprintSensorPropertiesInternal prop : mUdfpsProps) {
if (prop.sensorId == sensorId) {
mUdfpsEnrolledForUser.put(userId, hasEnrollments);
}
}
}
};
@NonNull @NonNull
private final IFingerprintAuthenticatorsRegisteredCallback private final IFingerprintAuthenticatorsRegisteredCallback
mFingerprintAuthenticatorsRegisteredCallback = mFingerprintAuthenticatorsRegisteredCallback =
@@ -436,6 +458,7 @@ public class AuthController extends SystemUI implements CommandQueue.Callbacks,
mUdfpsControllerFactory = udfpsControllerFactory; mUdfpsControllerFactory = udfpsControllerFactory;
mSidefpsControllerFactory = sidefpsControllerFactory; mSidefpsControllerFactory = sidefpsControllerFactory;
mWindowManager = windowManager; mWindowManager = windowManager;
mUdfpsEnrolledForUser = new SparseBooleanArray();
mOrientationListener = new BiometricOrientationEventListener(context, mOrientationListener = new BiometricOrientationEventListener(context,
() -> { () -> {
onOrientationChanged(); onOrientationChanged();
@@ -474,6 +497,7 @@ public class AuthController extends SystemUI implements CommandQueue.Callbacks,
if (mFingerprintManager != null) { if (mFingerprintManager != null) {
mFingerprintManager.addAuthenticatorsRegisteredCallback( mFingerprintManager.addAuthenticatorsRegisteredCallback(
mFingerprintAuthenticatorsRegisteredCallback); mFingerprintAuthenticatorsRegisteredCallback);
mFingerprintManager.registerFingerprintStateListener(mFingerprintStateListener);
} }
mTaskStackListener = new BiometricTaskStackListener(); mTaskStackListener = new BiometricTaskStackListener();
@@ -673,7 +697,7 @@ public class AuthController extends SystemUI implements CommandQueue.Callbacks,
return false; return false;
} }
return mFingerprintManager.hasEnrolledTemplatesForAnySensor(userId, mUdfpsProps); return mUdfpsEnrolledForUser.get(userId);
} }
private void showDialog(SomeArgs args, boolean skipAnimation, Bundle savedState) { private void showDialog(SomeArgs args, boolean skipAnimation, Bundle savedState) {

View File

@@ -26,6 +26,8 @@ import android.util.Slog;
import com.android.internal.annotations.VisibleForTesting; import com.android.internal.annotations.VisibleForTesting;
import java.util.ArrayList;
import java.util.List;
import java.util.NoSuchElementException; import java.util.NoSuchElementException;
/** /**
@@ -70,26 +72,32 @@ public abstract class BaseClientMonitor extends LoggableMonitor
} }
/** Holder for wrapping multiple handlers into a single Callback. */ /** Holder for wrapping multiple handlers into a single Callback. */
protected static class CompositeCallback implements Callback { public static class CompositeCallback implements Callback {
@NonNull @NonNull
private final Callback[] mCallbacks; private final List<Callback> mCallbacks;
public CompositeCallback(@NonNull Callback... callbacks) { public CompositeCallback(@NonNull Callback... callbacks) {
mCallbacks = callbacks; mCallbacks = new ArrayList<>();
for (Callback callback : callbacks) {
if (callback != null) {
mCallbacks.add(callback);
}
}
} }
@Override @Override
public final void onClientStarted(@NonNull BaseClientMonitor clientMonitor) { public final void onClientStarted(@NonNull BaseClientMonitor clientMonitor) {
for (int i = 0; i < mCallbacks.length; i++) { for (int i = 0; i < mCallbacks.size(); i++) {
mCallbacks[i].onClientStarted(clientMonitor); mCallbacks.get(i).onClientStarted(clientMonitor);
} }
} }
@Override @Override
public final void onClientFinished(@NonNull BaseClientMonitor clientMonitor, public final void onClientFinished(@NonNull BaseClientMonitor clientMonitor,
boolean success) { boolean success) {
for (int i = mCallbacks.length - 1; i >= 0; i--) { for (int i = mCallbacks.size() - 1; i >= 0; i--) {
mCallbacks[i].onClientFinished(clientMonitor, success); mCallbacks.get(i).onClientFinished(clientMonitor, success);
} }
} }
} }
@@ -256,7 +264,7 @@ public abstract class BaseClientMonitor extends LoggableMonitor
return mToken; return mToken;
} }
public final int getSensorId() { public int getSensorId() {
return mSensorId; return mSensorId;
} }

View File

@@ -31,7 +31,7 @@ import java.util.Arrays;
/** /**
* A class to keep track of the enrollment state for a given client. * A class to keep track of the enrollment state for a given client.
*/ */
public abstract class EnrollClient<T> extends AcquisitionClient<T> { public abstract class EnrollClient<T> extends AcquisitionClient<T> implements EnrollmentModifier {
private static final String TAG = "Biometrics/EnrollClient"; private static final String TAG = "Biometrics/EnrollClient";
@@ -40,6 +40,7 @@ public abstract class EnrollClient<T> extends AcquisitionClient<T> {
protected final BiometricUtils mBiometricUtils; protected final BiometricUtils mBiometricUtils;
private long mEnrollmentStartTimeMs; private long mEnrollmentStartTimeMs;
private final boolean mHasEnrollmentsBeforeStarting;
/** /**
* @return true if the user has already enrolled the maximum number of templates. * @return true if the user has already enrolled the maximum number of templates.
@@ -56,6 +57,18 @@ public abstract class EnrollClient<T> extends AcquisitionClient<T> {
mBiometricUtils = utils; mBiometricUtils = utils;
mHardwareAuthToken = Arrays.copyOf(hardwareAuthToken, hardwareAuthToken.length); mHardwareAuthToken = Arrays.copyOf(hardwareAuthToken, hardwareAuthToken.length);
mTimeoutSec = timeoutSec; mTimeoutSec = timeoutSec;
mHasEnrollmentsBeforeStarting = hasEnrollments();
}
@Override
public boolean hasEnrollmentStateChanged() {
final boolean hasEnrollmentsNow = hasEnrollments();
return hasEnrollmentsNow != mHasEnrollmentsBeforeStarting;
}
@Override
public boolean hasEnrollments() {
return !mBiometricUtils.getBiometricsForUser(getContext(), getTargetUserId()).isEmpty();
} }
public void onEnrollResult(BiometricAuthenticator.Identifier identifier, int remaining) { public void onEnrollResult(BiometricAuthenticator.Identifier identifier, int remaining) {

View File

@@ -0,0 +1,39 @@
/*
* Copyright (C) 2021 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.biometrics.sensors;
/**
* Interface for {@link BaseClientMonitor} subclasses that affect the state of enrollment.
*/
public interface EnrollmentModifier {
/**
* Callers should typically check this after
* {@link BaseClientMonitor.Callback#onClientFinished(BaseClientMonitor, boolean)}
*
* @return true if the user has gone from:
* 1) none-enrolled --> enrolled
* 2) enrolled --> none-enrolled
* but NOT any-enrolled --> more-enrolled
*/
boolean hasEnrollmentStateChanged();
/**
* @return true if the user has any enrollments
*/
boolean hasEnrollments();
}

View File

@@ -40,7 +40,8 @@ import java.util.Map;
* {@link #onRemoved(BiometricAuthenticator.Identifier, int)} returns true/ * {@link #onRemoved(BiometricAuthenticator.Identifier, int)} returns true/
*/ */
public abstract class InternalCleanupClient<S extends BiometricAuthenticator.Identifier, T> public abstract class InternalCleanupClient<S extends BiometricAuthenticator.Identifier, T>
extends HalClientMonitor<T> implements EnumerateConsumer, RemovalConsumer { extends HalClientMonitor<T> implements EnumerateConsumer, RemovalConsumer,
EnrollmentModifier {
private static final String TAG = "Biometrics/InternalCleanupClient"; private static final String TAG = "Biometrics/InternalCleanupClient";
@@ -61,6 +62,7 @@ public abstract class InternalCleanupClient<S extends BiometricAuthenticator.Ide
private final BiometricUtils<S> mBiometricUtils; private final BiometricUtils<S> mBiometricUtils;
private final Map<Integer, Long> mAuthenticatorIds; private final Map<Integer, Long> mAuthenticatorIds;
private final List<S> mEnrolledList; private final List<S> mEnrolledList;
private final boolean mHasEnrollmentsBeforeStarting;
private BaseClientMonitor mCurrentTask; private BaseClientMonitor mCurrentTask;
private final Callback mEnumerateCallback = new Callback() { private final Callback mEnumerateCallback = new Callback() {
@@ -115,6 +117,7 @@ public abstract class InternalCleanupClient<S extends BiometricAuthenticator.Ide
mBiometricUtils = utils; mBiometricUtils = utils;
mAuthenticatorIds = authenticatorIds; mAuthenticatorIds = authenticatorIds;
mEnrolledList = enrolledList; mEnrolledList = enrolledList;
mHasEnrollmentsBeforeStarting = !utils.getBiometricsForUser(context, userId).isEmpty();
} }
private void startCleanupUnknownHalTemplates() { private void startCleanupUnknownHalTemplates() {
@@ -165,6 +168,18 @@ public abstract class InternalCleanupClient<S extends BiometricAuthenticator.Ide
((RemovalClient<S, T>) mCurrentTask).onRemoved(identifier, remaining); ((RemovalClient<S, T>) mCurrentTask).onRemoved(identifier, remaining);
} }
@Override
public boolean hasEnrollmentStateChanged() {
final boolean hasEnrollmentsNow = !mBiometricUtils
.getBiometricsForUser(getContext(), getTargetUserId()).isEmpty();
return hasEnrollmentsNow != mHasEnrollmentsBeforeStarting;
}
@Override
public boolean hasEnrollments() {
return !mBiometricUtils.getBiometricsForUser(getContext(), getTargetUserId()).isEmpty();
}
@Override @Override
public void onEnumerationResult(BiometricAuthenticator.Identifier identifier, public void onEnumerationResult(BiometricAuthenticator.Identifier identifier,
int remaining) { int remaining) {

View File

@@ -33,12 +33,13 @@ import java.util.Map;
* A class to keep track of the remove state for a given client. * A class to keep track of the remove state for a given client.
*/ */
public abstract class RemovalClient<S extends BiometricAuthenticator.Identifier, T> public abstract class RemovalClient<S extends BiometricAuthenticator.Identifier, T>
extends HalClientMonitor<T> implements RemovalConsumer { extends HalClientMonitor<T> implements RemovalConsumer, EnrollmentModifier {
private static final String TAG = "Biometrics/RemovalClient"; private static final String TAG = "Biometrics/RemovalClient";
private final BiometricUtils<S> mBiometricUtils; private final BiometricUtils<S> mBiometricUtils;
private final Map<Integer, Long> mAuthenticatorIds; private final Map<Integer, Long> mAuthenticatorIds;
private final boolean mHasEnrollmentsBeforeStarting;
public RemovalClient(@NonNull Context context, @NonNull LazyDaemon<T> lazyDaemon, public RemovalClient(@NonNull Context context, @NonNull LazyDaemon<T> lazyDaemon,
@NonNull IBinder token, @NonNull ClientMonitorCallbackConverter listener, @NonNull IBinder token, @NonNull ClientMonitorCallbackConverter listener,
@@ -49,6 +50,7 @@ public abstract class RemovalClient<S extends BiometricAuthenticator.Identifier,
BiometricsProtoEnums.CLIENT_UNKNOWN); BiometricsProtoEnums.CLIENT_UNKNOWN);
mBiometricUtils = utils; mBiometricUtils = utils;
mAuthenticatorIds = authenticatorIds; mAuthenticatorIds = authenticatorIds;
mHasEnrollmentsBeforeStarting = !utils.getBiometricsForUser(context, userId).isEmpty();
} }
@Override @Override
@@ -90,6 +92,18 @@ public abstract class RemovalClient<S extends BiometricAuthenticator.Identifier,
} }
} }
@Override
public boolean hasEnrollmentStateChanged() {
final boolean hasEnrollmentsNow = !mBiometricUtils
.getBiometricsForUser(getContext(), getTargetUserId()).isEmpty();
return hasEnrollmentsNow != mHasEnrollmentsBeforeStarting;
}
@Override
public boolean hasEnrollments() {
return !mBiometricUtils.getBiometricsForUser(getContext(), getTargetUserId()).isEmpty();
}
@Override @Override
public int getProtoEnum() { public int getProtoEnum() {
return BiometricsProto.CM_REMOVE; return BiometricsProto.CM_REMOVE;

View File

@@ -35,6 +35,7 @@ import android.annotation.Nullable;
import android.app.AppOpsManager; import android.app.AppOpsManager;
import android.content.Context; import android.content.Context;
import android.content.pm.PackageManager; import android.content.pm.PackageManager;
import android.content.pm.UserInfo;
import android.hardware.biometrics.BiometricManager; import android.hardware.biometrics.BiometricManager;
import android.hardware.biometrics.BiometricPrompt; import android.hardware.biometrics.BiometricPrompt;
import android.hardware.biometrics.BiometricsProtoEnums; import android.hardware.biometrics.BiometricsProtoEnums;
@@ -62,11 +63,13 @@ import android.os.Build;
import android.os.CancellationSignal; import android.os.CancellationSignal;
import android.os.Handler; import android.os.Handler;
import android.os.IBinder; import android.os.IBinder;
import android.os.Looper;
import android.os.Process; import android.os.Process;
import android.os.RemoteCallbackList; import android.os.RemoteCallbackList;
import android.os.RemoteException; import android.os.RemoteException;
import android.os.ServiceManager; import android.os.ServiceManager;
import android.os.UserHandle; import android.os.UserHandle;
import android.os.UserManager;
import android.provider.Settings; import android.provider.Settings;
import android.util.EventLog; import android.util.EventLog;
import android.util.Pair; import android.util.Pair;
@@ -111,6 +114,7 @@ public class FingerprintService extends SystemService {
private final FingerprintServiceWrapper mServiceWrapper; private final FingerprintServiceWrapper mServiceWrapper;
@NonNull private final List<ServiceProvider> mServiceProviders; @NonNull private final List<ServiceProvider> mServiceProviders;
@NonNull private final FingerprintStateCallback mFingerprintStateCallback; @NonNull private final FingerprintStateCallback mFingerprintStateCallback;
@NonNull private final Handler mHandler;
@GuardedBy("mLock") @GuardedBy("mLock")
@NonNull private final RemoteCallbackList<IFingerprintAuthenticatorsRegisteredCallback> @NonNull private final RemoteCallbackList<IFingerprintAuthenticatorsRegisteredCallback>
@@ -125,6 +129,37 @@ public class FingerprintService extends SystemService {
*/ */
public void registerFingerprintStateListener(@NonNull IFingerprintStateListener listener) { public void registerFingerprintStateListener(@NonNull IFingerprintStateListener listener) {
mFingerprintStateCallback.registerFingerprintStateListener(listener); mFingerprintStateCallback.registerFingerprintStateListener(listener);
broadcastCurrentEnrollmentState(listener);
}
/**
* @param listener if non-null, notifies only this listener. if null, notifies all listeners
* in {@link FingerprintStateCallback}. This is slightly ugly, but reduces
* redundant code.
*/
private void broadcastCurrentEnrollmentState(@Nullable IFingerprintStateListener listener) {
final UserManager um = UserManager.get(getContext());
synchronized (mLock) {
// Update the new listener with current state of all sensors
for (FingerprintSensorPropertiesInternal prop : mSensorProps) {
final ServiceProvider provider = getProviderForSensor(prop.sensorId);
for (UserInfo userInfo : um.getAliveUsers()) {
final boolean enrolled = !provider
.getEnrolledFingerprints(prop.sensorId, userInfo.id).isEmpty();
// Defer this work and allow the loop to release the lock sooner
mHandler.post(() -> {
if (listener != null) {
mFingerprintStateCallback.notifyFingerprintEnrollmentStateChanged(
listener, userInfo.id, prop.sensorId, enrolled);
} else {
mFingerprintStateCallback.notifyAllFingerprintEnrollmentStateChanged(
userInfo.id, prop.sensorId, enrolled);
}
});
}
}
}
} }
/** /**
@@ -143,8 +178,7 @@ public class FingerprintService extends SystemService {
return null; return null;
} }
return provider.createTestSession(sensorId, callback, mFingerprintStateCallback, return provider.createTestSession(sensorId, callback, opPackageName);
opPackageName);
} }
@Override @Override
@@ -227,7 +261,7 @@ public class FingerprintService extends SystemService {
} }
provider.second.scheduleEnroll(provider.first, token, hardwareAuthToken, userId, provider.second.scheduleEnroll(provider.first, token, hardwareAuthToken, userId,
receiver, opPackageName, enrollReason, mFingerprintStateCallback); receiver, opPackageName, enrollReason);
} }
@Override // Binder call @Override // Binder call
@@ -306,7 +340,7 @@ public class FingerprintService extends SystemService {
} }
return provider.second.scheduleAuthenticate(provider.first, token, operationId, userId, return provider.second.scheduleAuthenticate(provider.first, token, operationId, userId,
0 /* cookie */, new ClientMonitorCallbackConverter(receiver), opPackageName, 0 /* cookie */, new ClientMonitorCallbackConverter(receiver), opPackageName,
restricted, statsClient, isKeyguard, mFingerprintStateCallback); restricted, statsClient, isKeyguard);
} }
private long authenticateWithPrompt( private long authenticateWithPrompt(
@@ -414,7 +448,7 @@ public class FingerprintService extends SystemService {
return provider.second.scheduleFingerDetect(provider.first, token, userId, return provider.second.scheduleFingerDetect(provider.first, token, userId,
new ClientMonitorCallbackConverter(receiver), opPackageName, new ClientMonitorCallbackConverter(receiver), opPackageName,
BiometricsProtoEnums.CLIENT_KEYGUARD, mFingerprintStateCallback); BiometricsProtoEnums.CLIENT_KEYGUARD);
} }
@Override // Binder call @Override // Binder call
@@ -433,7 +467,7 @@ public class FingerprintService extends SystemService {
provider.scheduleAuthenticate(sensorId, token, operationId, userId, cookie, provider.scheduleAuthenticate(sensorId, token, operationId, userId, cookie,
new ClientMonitorCallbackConverter(sensorReceiver), opPackageName, requestId, new ClientMonitorCallbackConverter(sensorReceiver), opPackageName, requestId,
restricted, BiometricsProtoEnums.CLIENT_BIOMETRIC_PROMPT, restricted, BiometricsProtoEnums.CLIENT_BIOMETRIC_PROMPT,
allowBackgroundAuthentication, mFingerprintStateCallback); allowBackgroundAuthentication);
} }
@Override // Binder call @Override // Binder call
@@ -687,27 +721,6 @@ public class FingerprintService extends SystemService {
.isEmpty(); .isEmpty();
} }
@Override // Binder call
public boolean hasEnrolledTemplatesForAnySensor(int userId,
@NonNull List<FingerprintSensorPropertiesInternal> sensors,
@NonNull String opPackageName) {
Utils.checkPermission(getContext(), USE_BIOMETRIC_INTERNAL);
for (FingerprintSensorPropertiesInternal prop : sensors) {
final ServiceProvider provider = getProviderForSensor(prop.sensorId);
if (provider == null) {
Slog.w(TAG, "Null provider for sensorId: " + prop.sensorId
+ ", caller: " + opPackageName);
continue;
}
if (!provider.getEnrolledFingerprints(prop.sensorId, userId).isEmpty()) {
return true;
}
}
return false;
}
public boolean hasEnrolledFingerprints(int sensorId, int userId, String opPackageName) { public boolean hasEnrolledFingerprints(int sensorId, int userId, String opPackageName) {
Utils.checkPermission(getContext(), USE_BIOMETRIC_INTERNAL); Utils.checkPermission(getContext(), USE_BIOMETRIC_INTERNAL);
@@ -797,10 +810,12 @@ public class FingerprintService extends SystemService {
&& Settings.Secure.getIntForUser(getContext().getContentResolver(), && Settings.Secure.getIntForUser(getContext().getContentResolver(),
Fingerprint21UdfpsMock.CONFIG_ENABLE_TEST_UDFPS, 0 /* default */, Fingerprint21UdfpsMock.CONFIG_ENABLE_TEST_UDFPS, 0 /* default */,
UserHandle.USER_CURRENT) != 0) { UserHandle.USER_CURRENT) != 0) {
fingerprint21 = Fingerprint21UdfpsMock.newInstance(getContext(), hidlSensor, fingerprint21 = Fingerprint21UdfpsMock.newInstance(getContext(),
mFingerprintStateCallback, hidlSensor,
mLockoutResetDispatcher, mGestureAvailabilityDispatcher); mLockoutResetDispatcher, mGestureAvailabilityDispatcher);
} else { } else {
fingerprint21 = Fingerprint21.newInstance(getContext(), hidlSensor, fingerprint21 = Fingerprint21.newInstance(getContext(),
mFingerprintStateCallback, hidlSensor,
mLockoutResetDispatcher, mGestureAvailabilityDispatcher); mLockoutResetDispatcher, mGestureAvailabilityDispatcher);
} }
mServiceProviders.add(fingerprint21); mServiceProviders.add(fingerprint21);
@@ -823,8 +838,9 @@ public class FingerprintService extends SystemService {
try { try {
final SensorProps[] props = fp.getSensorProps(); final SensorProps[] props = fp.getSensorProps();
final FingerprintProvider provider = final FingerprintProvider provider =
new FingerprintProvider(getContext(), props, instance, new FingerprintProvider(getContext(), mFingerprintStateCallback, props,
mLockoutResetDispatcher, mGestureAvailabilityDispatcher); instance, mLockoutResetDispatcher,
mGestureAvailabilityDispatcher);
mServiceProviders.add(provider); mServiceProviders.add(provider);
} catch (RemoteException e) { } catch (RemoteException e) {
Slog.e(TAG, "Remote exception in getSensorProps: " + fqName); Slog.e(TAG, "Remote exception in getSensorProps: " + fqName);
@@ -878,6 +894,7 @@ public class FingerprintService extends SystemService {
} }
} }
broadcastCurrentEnrollmentState(null); // broadcasts to all listeners
broadcastAllAuthenticatorsRegistered(); broadcastAllAuthenticatorsRegistered();
}); });
} }
@@ -975,6 +992,7 @@ public class FingerprintService extends SystemService {
mFingerprintStateCallback = new FingerprintStateCallback(); mFingerprintStateCallback = new FingerprintStateCallback();
mAuthenticatorsRegisteredCallbacks = new RemoteCallbackList<>(); mAuthenticatorsRegisteredCallbacks = new RemoteCallbackList<>();
mSensorProps = new ArrayList<>(); mSensorProps = new ArrayList<>();
mHandler = new Handler(Looper.getMainLooper());
} }
// Notifies the callbacks that all of the authenticators have been registered and removes the // Notifies the callbacks that all of the authenticators have been registered and removes the

View File

@@ -23,6 +23,7 @@ import static android.hardware.fingerprint.FingerprintStateListener.STATE_IDLE;
import static android.hardware.fingerprint.FingerprintStateListener.STATE_KEYGUARD_AUTH; import static android.hardware.fingerprint.FingerprintStateListener.STATE_KEYGUARD_AUTH;
import android.annotation.NonNull; import android.annotation.NonNull;
import android.content.Context;
import android.hardware.fingerprint.FingerprintStateListener; import android.hardware.fingerprint.FingerprintStateListener;
import android.hardware.fingerprint.IFingerprintStateListener; import android.hardware.fingerprint.IFingerprintStateListener;
import android.os.RemoteException; import android.os.RemoteException;
@@ -31,6 +32,9 @@ import android.util.Slog;
import com.android.server.biometrics.Utils; import com.android.server.biometrics.Utils;
import com.android.server.biometrics.sensors.AuthenticationClient; import com.android.server.biometrics.sensors.AuthenticationClient;
import com.android.server.biometrics.sensors.BaseClientMonitor; import com.android.server.biometrics.sensors.BaseClientMonitor;
import com.android.server.biometrics.sensors.EnrollClient;
import com.android.server.biometrics.sensors.EnrollmentModifier;
import com.android.server.biometrics.sensors.RemovalConsumer;
import com.android.server.biometrics.sensors.fingerprint.hidl.FingerprintEnrollClient; import com.android.server.biometrics.sensors.fingerprint.hidl.FingerprintEnrollClient;
import java.util.concurrent.CopyOnWriteArrayList; import java.util.concurrent.CopyOnWriteArrayList;
@@ -39,10 +43,12 @@ import java.util.concurrent.CopyOnWriteArrayList;
* A callback for receiving notifications about changes in fingerprint state. * A callback for receiving notifications about changes in fingerprint state.
*/ */
public class FingerprintStateCallback implements BaseClientMonitor.Callback { public class FingerprintStateCallback implements BaseClientMonitor.Callback {
private @FingerprintStateListener.State int mFingerprintState;
@NonNull private final CopyOnWriteArrayList<IFingerprintStateListener> @NonNull private final CopyOnWriteArrayList<IFingerprintStateListener>
mFingerprintStateListeners = new CopyOnWriteArrayList<>(); mFingerprintStateListeners = new CopyOnWriteArrayList<>();
private @FingerprintStateListener.State int mFingerprintState;
public FingerprintStateCallback() { public FingerprintStateCallback() {
mFingerprintState = STATE_IDLE; mFingerprintState = STATE_IDLE;
} }
@@ -54,8 +60,9 @@ public class FingerprintStateCallback implements BaseClientMonitor.Callback {
@Override @Override
public void onClientStarted(@NonNull BaseClientMonitor client) { public void onClientStarted(@NonNull BaseClientMonitor client) {
final int previousFingerprintState = mFingerprintState; final int previousFingerprintState = mFingerprintState;
if (client instanceof AuthenticationClient) { if (client instanceof AuthenticationClient) {
AuthenticationClient authClient = (AuthenticationClient) client; final AuthenticationClient<?> authClient = (AuthenticationClient<?>) client;
if (authClient.isKeyguard()) { if (authClient.isKeyguard()) {
mFingerprintState = STATE_KEYGUARD_AUTH; mFingerprintState = STATE_KEYGUARD_AUTH;
} else if (authClient.isBiometricPrompt()) { } else if (authClient.isBiometricPrompt()) {
@@ -70,6 +77,7 @@ public class FingerprintStateCallback implements BaseClientMonitor.Callback {
"Other authentication client: " + Utils.getClientName(client)); "Other authentication client: " + Utils.getClientName(client));
mFingerprintState = STATE_IDLE; mFingerprintState = STATE_IDLE;
} }
Slog.d(FingerprintService.TAG, "Fps state updated from " + previousFingerprintState Slog.d(FingerprintService.TAG, "Fps state updated from " + previousFingerprintState
+ " to " + mFingerprintState + ", client " + client); + " to " + mFingerprintState + ", client " + client);
notifyFingerprintStateListeners(mFingerprintState); notifyFingerprintStateListeners(mFingerprintState);
@@ -81,6 +89,18 @@ public class FingerprintStateCallback implements BaseClientMonitor.Callback {
Slog.d(FingerprintService.TAG, Slog.d(FingerprintService.TAG,
"Client finished, fps state updated to " + mFingerprintState + ", client " "Client finished, fps state updated to " + mFingerprintState + ", client "
+ client); + client);
if (client instanceof EnrollmentModifier) {
EnrollmentModifier enrollmentModifier = (EnrollmentModifier) client;
final boolean enrollmentStateChanged = enrollmentModifier.hasEnrollmentStateChanged();
Slog.d(FingerprintService.TAG, "Enrollment state changed: " + enrollmentStateChanged);
if (enrollmentStateChanged) {
notifyAllFingerprintEnrollmentStateChanged(client.getTargetUserId(),
client.getSensorId(),
enrollmentModifier.hasEnrollments());
}
}
notifyFingerprintStateListeners(mFingerprintState); notifyFingerprintStateListeners(mFingerprintState);
} }
@@ -94,6 +114,32 @@ public class FingerprintStateCallback implements BaseClientMonitor.Callback {
} }
} }
/**
* This should be invoked when:
* 1) Enrolled --> None-enrolled
* 2) None-enrolled --> enrolled
* 3) HAL becomes ready
* 4) Listener is registered
*/
void notifyAllFingerprintEnrollmentStateChanged(int userId, int sensorId,
boolean hasEnrollments) {
for (IFingerprintStateListener listener : mFingerprintStateListeners) {
notifyFingerprintEnrollmentStateChanged(listener, userId, sensorId, hasEnrollments);
}
}
/**
* Notifies the listener of enrollment state changes.
*/
void notifyFingerprintEnrollmentStateChanged(@NonNull IFingerprintStateListener listener,
int userId, int sensorId, boolean hasEnrollments) {
try {
listener.onEnrollmentsChanged(userId, sensorId, hasEnrollments);
} catch (RemoteException e) {
Slog.e(FingerprintService.TAG, "Remote exception", e);
}
}
/** /**
* Enables clients to register a FingerprintStateListener. Used by FingerprintService to forward * Enables clients to register a FingerprintStateListener. Used by FingerprintService to forward
* updates in fingerprint sensor state to the SideFpNsEventHandler * updates in fingerprint sensor state to the SideFpNsEventHandler

View File

@@ -90,27 +90,23 @@ public interface ServiceProvider {
*/ */
void scheduleEnroll(int sensorId, @NonNull IBinder token, @NonNull byte[] hardwareAuthToken, void scheduleEnroll(int sensorId, @NonNull IBinder token, @NonNull byte[] hardwareAuthToken,
int userId, @NonNull IFingerprintServiceReceiver receiver, int userId, @NonNull IFingerprintServiceReceiver receiver,
@NonNull String opPackageName, @FingerprintManager.EnrollReason int enrollReason, @NonNull String opPackageName, @FingerprintManager.EnrollReason int enrollReason);
@NonNull FingerprintStateCallback fingerprintStateCallback);
void cancelEnrollment(int sensorId, @NonNull IBinder token); void cancelEnrollment(int sensorId, @NonNull IBinder token);
long scheduleFingerDetect(int sensorId, @NonNull IBinder token, int userId, long scheduleFingerDetect(int sensorId, @NonNull IBinder token, int userId,
@NonNull ClientMonitorCallbackConverter callback, @NonNull String opPackageName, @NonNull ClientMonitorCallbackConverter callback, @NonNull String opPackageName,
int statsClient, int statsClient);
@NonNull FingerprintStateCallback fingerprintStateCallback);
void scheduleAuthenticate(int sensorId, @NonNull IBinder token, long operationId, int userId, void scheduleAuthenticate(int sensorId, @NonNull IBinder token, long operationId, int userId,
int cookie, @NonNull ClientMonitorCallbackConverter callback, int cookie, @NonNull ClientMonitorCallbackConverter callback,
@NonNull String opPackageName, long requestId, boolean restricted, int statsClient, @NonNull String opPackageName, long requestId, boolean restricted, int statsClient,
boolean allowBackgroundAuthentication, boolean allowBackgroundAuthentication);
@NonNull FingerprintStateCallback fingerprintStateCallback);
long scheduleAuthenticate(int sensorId, @NonNull IBinder token, long operationId, int userId, long scheduleAuthenticate(int sensorId, @NonNull IBinder token, long operationId, int userId,
int cookie, @NonNull ClientMonitorCallbackConverter callback, int cookie, @NonNull ClientMonitorCallbackConverter callback,
@NonNull String opPackageName, boolean restricted, int statsClient, @NonNull String opPackageName, boolean restricted, int statsClient,
boolean allowBackgroundAuthentication, boolean allowBackgroundAuthentication);
@NonNull FingerprintStateCallback fingerprintStateCallback);
void startPreparedClient(int sensorId, int cookie); void startPreparedClient(int sensorId, int cookie);
@@ -169,6 +165,5 @@ public interface ServiceProvider {
@NonNull @NonNull
ITestSession createTestSession(int sensorId, @NonNull ITestSessionCallback callback, ITestSession createTestSession(int sensorId, @NonNull ITestSessionCallback callback,
@NonNull FingerprintStateCallback fingerprintStateCallback,
@NonNull String opPackageName); @NonNull String opPackageName);
} }

View File

@@ -143,8 +143,7 @@ class BiometricTestSessionImpl extends ITestSession.Stub {
Utils.checkPermission(mContext, TEST_BIOMETRIC); Utils.checkPermission(mContext, TEST_BIOMETRIC);
mProvider.scheduleEnroll(mSensorId, new Binder(), new byte[69], userId, mReceiver, mProvider.scheduleEnroll(mSensorId, new Binder(), new byte[69], userId, mReceiver,
mContext.getOpPackageName(), FingerprintManager.ENROLL_ENROLL, mContext.getOpPackageName(), FingerprintManager.ENROLL_ENROLL);
mFingerprintStateCallback);
} }
@Override @Override

View File

@@ -82,6 +82,7 @@ public class FingerprintProvider implements IBinder.DeathRecipient, ServiceProvi
private boolean mTestHalEnabled; private boolean mTestHalEnabled;
@NonNull private final Context mContext; @NonNull private final Context mContext;
@NonNull private final FingerprintStateCallback mFingerprintStateCallback;
@NonNull private final String mHalInstanceName; @NonNull private final String mHalInstanceName;
@NonNull @VisibleForTesting @NonNull @VisibleForTesting
final SparseArray<Sensor> mSensors; // Map of sensors that this HAL supports final SparseArray<Sensor> mSensors; // Map of sensors that this HAL supports
@@ -130,10 +131,13 @@ public class FingerprintProvider implements IBinder.DeathRecipient, ServiceProvi
} }
} }
public FingerprintProvider(@NonNull Context context, @NonNull SensorProps[] props, public FingerprintProvider(@NonNull Context context,
@NonNull String halInstanceName, @NonNull LockoutResetDispatcher lockoutResetDispatcher, @NonNull FingerprintStateCallback fingerprintStateCallback,
@NonNull SensorProps[] props, @NonNull String halInstanceName,
@NonNull LockoutResetDispatcher lockoutResetDispatcher,
@NonNull GestureAvailabilityDispatcher gestureAvailabilityDispatcher) { @NonNull GestureAvailabilityDispatcher gestureAvailabilityDispatcher) {
mContext = context; mContext = context;
mFingerprintStateCallback = fingerprintStateCallback;
mHalInstanceName = halInstanceName; mHalInstanceName = halInstanceName;
mSensors = new SparseArray<>(); mSensors = new SparseArray<>();
mHandler = new Handler(Looper.getMainLooper()); mHandler = new Handler(Looper.getMainLooper());
@@ -335,8 +339,7 @@ public class FingerprintProvider implements IBinder.DeathRecipient, ServiceProvi
public void scheduleEnroll(int sensorId, @NonNull IBinder token, public void scheduleEnroll(int sensorId, @NonNull IBinder token,
@NonNull byte[] hardwareAuthToken, int userId, @NonNull byte[] hardwareAuthToken, int userId,
@NonNull IFingerprintServiceReceiver receiver, @NonNull String opPackageName, @NonNull IFingerprintServiceReceiver receiver, @NonNull String opPackageName,
@FingerprintManager.EnrollReason int enrollReason, @FingerprintManager.EnrollReason int enrollReason) {
@NonNull FingerprintStateCallback fingerprintStateCallback) {
mHandler.post(() -> { mHandler.post(() -> {
final int maxTemplatesPerUser = mSensors.get(sensorId).getSensorProperties() final int maxTemplatesPerUser = mSensors.get(sensorId).getSensorProperties()
.maxEnrollmentsPerUser; .maxEnrollmentsPerUser;
@@ -350,13 +353,13 @@ public class FingerprintProvider implements IBinder.DeathRecipient, ServiceProvi
@Override @Override
public void onClientStarted(@NonNull BaseClientMonitor clientMonitor) { public void onClientStarted(@NonNull BaseClientMonitor clientMonitor) {
fingerprintStateCallback.onClientStarted(clientMonitor); mFingerprintStateCallback.onClientStarted(clientMonitor);
} }
@Override @Override
public void onClientFinished(@NonNull BaseClientMonitor clientMonitor, public void onClientFinished(@NonNull BaseClientMonitor clientMonitor,
boolean success) { boolean success) {
fingerprintStateCallback.onClientFinished(clientMonitor, success); mFingerprintStateCallback.onClientFinished(clientMonitor, success);
if (success) { if (success) {
scheduleLoadAuthenticatorIdsForUser(sensorId, userId); scheduleLoadAuthenticatorIdsForUser(sensorId, userId);
scheduleInvalidationRequest(sensorId, userId); scheduleInvalidationRequest(sensorId, userId);
@@ -374,17 +377,15 @@ public class FingerprintProvider implements IBinder.DeathRecipient, ServiceProvi
@Override @Override
public long scheduleFingerDetect(int sensorId, @NonNull IBinder token, int userId, public long scheduleFingerDetect(int sensorId, @NonNull IBinder token, int userId,
@NonNull ClientMonitorCallbackConverter callback, @NonNull String opPackageName, @NonNull ClientMonitorCallbackConverter callback, @NonNull String opPackageName,
int statsClient, int statsClient) {
@NonNull FingerprintStateCallback fingerprintStateCallback) {
final long id = mRequestCounter.incrementAndGet(); final long id = mRequestCounter.incrementAndGet();
mHandler.post(() -> { mHandler.post(() -> {
final boolean isStrongBiometric = Utils.isStrongBiometric(sensorId); final boolean isStrongBiometric = Utils.isStrongBiometric(sensorId);
final FingerprintDetectClient client = new FingerprintDetectClient(mContext, final FingerprintDetectClient client = new FingerprintDetectClient(mContext,
mSensors.get(sensorId).getLazySession(), token, id, callback, userId, mSensors.get(sensorId).getLazySession(), token, id, callback, userId,
opPackageName, sensorId, mUdfpsOverlayController, isStrongBiometric, opPackageName, sensorId, mUdfpsOverlayController, isStrongBiometric,
statsClient); statsClient);
scheduleForSensor(sensorId, client, fingerprintStateCallback); scheduleForSensor(sensorId, client, mFingerprintStateCallback);
}); });
return id; return id;
@@ -394,8 +395,7 @@ public class FingerprintProvider implements IBinder.DeathRecipient, ServiceProvi
public void scheduleAuthenticate(int sensorId, @NonNull IBinder token, long operationId, public void scheduleAuthenticate(int sensorId, @NonNull IBinder token, long operationId,
int userId, int cookie, @NonNull ClientMonitorCallbackConverter callback, int userId, int cookie, @NonNull ClientMonitorCallbackConverter callback,
@NonNull String opPackageName, long requestId, boolean restricted, int statsClient, @NonNull String opPackageName, long requestId, boolean restricted, int statsClient,
boolean allowBackgroundAuthentication, boolean allowBackgroundAuthentication) {
@NonNull FingerprintStateCallback fingerprintStateCallback) {
mHandler.post(() -> { mHandler.post(() -> {
final boolean isStrongBiometric = Utils.isStrongBiometric(sensorId); final boolean isStrongBiometric = Utils.isStrongBiometric(sensorId);
final FingerprintAuthenticationClient client = new FingerprintAuthenticationClient( final FingerprintAuthenticationClient client = new FingerprintAuthenticationClient(
@@ -405,7 +405,7 @@ public class FingerprintProvider implements IBinder.DeathRecipient, ServiceProvi
mTaskStackListener, mSensors.get(sensorId).getLockoutCache(), mTaskStackListener, mSensors.get(sensorId).getLockoutCache(),
mUdfpsOverlayController, allowBackgroundAuthentication, mUdfpsOverlayController, allowBackgroundAuthentication,
mSensors.get(sensorId).getSensorProperties()); mSensors.get(sensorId).getSensorProperties());
scheduleForSensor(sensorId, client, fingerprintStateCallback); scheduleForSensor(sensorId, client, mFingerprintStateCallback);
}); });
} }
@@ -413,13 +413,11 @@ public class FingerprintProvider implements IBinder.DeathRecipient, ServiceProvi
public long scheduleAuthenticate(int sensorId, @NonNull IBinder token, long operationId, public long scheduleAuthenticate(int sensorId, @NonNull IBinder token, long operationId,
int userId, int cookie, @NonNull ClientMonitorCallbackConverter callback, int userId, int cookie, @NonNull ClientMonitorCallbackConverter callback,
@NonNull String opPackageName, boolean restricted, int statsClient, @NonNull String opPackageName, boolean restricted, int statsClient,
boolean allowBackgroundAuthentication, boolean allowBackgroundAuthentication) {
@NonNull FingerprintStateCallback fingerprintStateCallback) {
final long id = mRequestCounter.incrementAndGet(); final long id = mRequestCounter.incrementAndGet();
scheduleAuthenticate(sensorId, token, operationId, userId, cookie, callback, scheduleAuthenticate(sensorId, token, operationId, userId, cookie, callback,
opPackageName, id, restricted, statsClient, allowBackgroundAuthentication, opPackageName, id, restricted, statsClient, allowBackgroundAuthentication);
fingerprintStateCallback);
return id; return id;
} }
@@ -466,7 +464,7 @@ public class FingerprintProvider implements IBinder.DeathRecipient, ServiceProvi
new ClientMonitorCallbackConverter(receiver), fingerprintIds, userId, new ClientMonitorCallbackConverter(receiver), fingerprintIds, userId,
opPackageName, FingerprintUtils.getInstance(sensorId), sensorId, opPackageName, FingerprintUtils.getInstance(sensorId), sensorId,
mSensors.get(sensorId).getAuthenticatorIds()); mSensors.get(sensorId).getAuthenticatorIds());
scheduleForSensor(sensorId, client); scheduleForSensor(sensorId, client, mFingerprintStateCallback);
}); });
} }
@@ -481,7 +479,8 @@ public class FingerprintProvider implements IBinder.DeathRecipient, ServiceProvi
mContext.getOpPackageName(), sensorId, enrolledList, mContext.getOpPackageName(), sensorId, enrolledList,
FingerprintUtils.getInstance(sensorId), FingerprintUtils.getInstance(sensorId),
mSensors.get(sensorId).getAuthenticatorIds()); mSensors.get(sensorId).getAuthenticatorIds());
scheduleForSensor(sensorId, client, callback); scheduleForSensor(sensorId, client, new BaseClientMonitor.CompositeCallback(callback,
mFingerprintStateCallback));
}); });
} }
@@ -626,9 +625,8 @@ public class FingerprintProvider implements IBinder.DeathRecipient, ServiceProvi
@NonNull @NonNull
@Override @Override
public ITestSession createTestSession(int sensorId, @NonNull ITestSessionCallback callback, public ITestSession createTestSession(int sensorId, @NonNull ITestSessionCallback callback,
@NonNull FingerprintStateCallback fingerprintStateCallback,
@NonNull String opPackageName) { @NonNull String opPackageName) {
return mSensors.get(sensorId).createTestSession(callback, fingerprintStateCallback); return mSensors.get(sensorId).createTestSession(callback, mFingerprintStateCallback);
} }
@Override @Override

View File

@@ -143,8 +143,7 @@ public class BiometricTestSessionImpl extends ITestSession.Stub {
Utils.checkPermission(mContext, TEST_BIOMETRIC); Utils.checkPermission(mContext, TEST_BIOMETRIC);
mFingerprint21.scheduleEnroll(mSensorId, new Binder(), new byte[69], userId, mReceiver, mFingerprint21.scheduleEnroll(mSensorId, new Binder(), new byte[69], userId, mReceiver,
mContext.getOpPackageName(), FingerprintManager.ENROLL_ENROLL, mContext.getOpPackageName(), FingerprintManager.ENROLL_ENROLL);
mFingerprintStateCallback);
} }
@Override @Override

View File

@@ -102,6 +102,7 @@ public class Fingerprint21 implements IHwBinder.DeathRecipient, ServiceProvider
private boolean mTestHalEnabled; private boolean mTestHalEnabled;
final Context mContext; final Context mContext;
@NonNull private final FingerprintStateCallback mFingerprintStateCallback;
private final ActivityTaskManager mActivityTaskManager; private final ActivityTaskManager mActivityTaskManager;
@NonNull private final FingerprintSensorPropertiesInternal mSensorProperties; @NonNull private final FingerprintSensorPropertiesInternal mSensorProperties;
private final BiometricScheduler mScheduler; private final BiometricScheduler mScheduler;
@@ -317,11 +318,13 @@ public class Fingerprint21 implements IHwBinder.DeathRecipient, ServiceProvider
} }
Fingerprint21(@NonNull Context context, Fingerprint21(@NonNull Context context,
@NonNull FingerprintStateCallback fingerprintStateCallback,
@NonNull FingerprintSensorPropertiesInternal sensorProps, @NonNull FingerprintSensorPropertiesInternal sensorProps,
@NonNull BiometricScheduler scheduler, @NonNull Handler handler, @NonNull BiometricScheduler scheduler, @NonNull Handler handler,
@NonNull LockoutResetDispatcher lockoutResetDispatcher, @NonNull LockoutResetDispatcher lockoutResetDispatcher,
@NonNull HalResultController controller) { @NonNull HalResultController controller) {
mContext = context; mContext = context;
mFingerprintStateCallback = fingerprintStateCallback;
mSensorProperties = sensorProps; mSensorProperties = sensorProps;
mSensorId = sensorProps.sensorId; mSensorId = sensorProps.sensorId;
@@ -351,6 +354,7 @@ public class Fingerprint21 implements IHwBinder.DeathRecipient, ServiceProvider
} }
public static Fingerprint21 newInstance(@NonNull Context context, public static Fingerprint21 newInstance(@NonNull Context context,
@NonNull FingerprintStateCallback fingerprintStateCallback,
@NonNull FingerprintSensorPropertiesInternal sensorProps, @NonNull FingerprintSensorPropertiesInternal sensorProps,
@NonNull LockoutResetDispatcher lockoutResetDispatcher, @NonNull LockoutResetDispatcher lockoutResetDispatcher,
@NonNull GestureAvailabilityDispatcher gestureAvailabilityDispatcher) { @NonNull GestureAvailabilityDispatcher gestureAvailabilityDispatcher) {
@@ -362,8 +366,8 @@ public class Fingerprint21 implements IHwBinder.DeathRecipient, ServiceProvider
final HalResultController controller = new HalResultController(sensorProps.sensorId, final HalResultController controller = new HalResultController(sensorProps.sensorId,
context, handler, context, handler,
scheduler); scheduler);
return new Fingerprint21(context, sensorProps, scheduler, handler, lockoutResetDispatcher, return new Fingerprint21(context, fingerprintStateCallback, sensorProps, scheduler, handler,
controller); lockoutResetDispatcher, controller);
} }
@Override @Override
@@ -557,8 +561,7 @@ public class Fingerprint21 implements IHwBinder.DeathRecipient, ServiceProvider
public void scheduleEnroll(int sensorId, @NonNull IBinder token, public void scheduleEnroll(int sensorId, @NonNull IBinder token,
@NonNull byte[] hardwareAuthToken, int userId, @NonNull byte[] hardwareAuthToken, int userId,
@NonNull IFingerprintServiceReceiver receiver, @NonNull String opPackageName, @NonNull IFingerprintServiceReceiver receiver, @NonNull String opPackageName,
@FingerprintManager.EnrollReason int enrollReason, @FingerprintManager.EnrollReason int enrollReason) {
@NonNull FingerprintStateCallback fingerprintStateCallback) {
mHandler.post(() -> { mHandler.post(() -> {
scheduleUpdateActiveUserWithoutHandler(userId); scheduleUpdateActiveUserWithoutHandler(userId);
@@ -570,13 +573,13 @@ public class Fingerprint21 implements IHwBinder.DeathRecipient, ServiceProvider
mScheduler.scheduleClientMonitor(client, new BaseClientMonitor.Callback() { mScheduler.scheduleClientMonitor(client, new BaseClientMonitor.Callback() {
@Override @Override
public void onClientStarted(@NonNull BaseClientMonitor clientMonitor) { public void onClientStarted(@NonNull BaseClientMonitor clientMonitor) {
fingerprintStateCallback.onClientStarted(clientMonitor); mFingerprintStateCallback.onClientStarted(clientMonitor);
} }
@Override @Override
public void onClientFinished(@NonNull BaseClientMonitor clientMonitor, public void onClientFinished(@NonNull BaseClientMonitor clientMonitor,
boolean success) { boolean success) {
fingerprintStateCallback.onClientFinished(clientMonitor, success); mFingerprintStateCallback.onClientFinished(clientMonitor, success);
if (success) { if (success) {
// Update authenticatorIds // Update authenticatorIds
scheduleUpdateActiveUserWithoutHandler(clientMonitor.getTargetUserId(), scheduleUpdateActiveUserWithoutHandler(clientMonitor.getTargetUserId(),
@@ -597,10 +600,8 @@ public class Fingerprint21 implements IHwBinder.DeathRecipient, ServiceProvider
@Override @Override
public long scheduleFingerDetect(int sensorId, @NonNull IBinder token, int userId, public long scheduleFingerDetect(int sensorId, @NonNull IBinder token, int userId,
@NonNull ClientMonitorCallbackConverter listener, @NonNull String opPackageName, @NonNull ClientMonitorCallbackConverter listener, @NonNull String opPackageName,
int statsClient, int statsClient) {
@NonNull FingerprintStateCallback fingerprintStateCallback) {
final long id = mRequestCounter.incrementAndGet(); final long id = mRequestCounter.incrementAndGet();
mHandler.post(() -> { mHandler.post(() -> {
scheduleUpdateActiveUserWithoutHandler(userId); scheduleUpdateActiveUserWithoutHandler(userId);
@@ -609,7 +610,7 @@ public class Fingerprint21 implements IHwBinder.DeathRecipient, ServiceProvider
mLazyDaemon, token, id, listener, userId, opPackageName, mLazyDaemon, token, id, listener, userId, opPackageName,
mSensorProperties.sensorId, mUdfpsOverlayController, isStrongBiometric, mSensorProperties.sensorId, mUdfpsOverlayController, isStrongBiometric,
statsClient); statsClient);
mScheduler.scheduleClientMonitor(client, fingerprintStateCallback); mScheduler.scheduleClientMonitor(client, mFingerprintStateCallback);
}); });
return id; return id;
@@ -619,8 +620,7 @@ public class Fingerprint21 implements IHwBinder.DeathRecipient, ServiceProvider
public void scheduleAuthenticate(int sensorId, @NonNull IBinder token, long operationId, public void scheduleAuthenticate(int sensorId, @NonNull IBinder token, long operationId,
int userId, int cookie, @NonNull ClientMonitorCallbackConverter listener, int userId, int cookie, @NonNull ClientMonitorCallbackConverter listener,
@NonNull String opPackageName, long requestId, boolean restricted, int statsClient, @NonNull String opPackageName, long requestId, boolean restricted, int statsClient,
boolean allowBackgroundAuthentication, boolean allowBackgroundAuthentication) {
@NonNull FingerprintStateCallback fingerprintStateCallback) {
mHandler.post(() -> { mHandler.post(() -> {
scheduleUpdateActiveUserWithoutHandler(userId); scheduleUpdateActiveUserWithoutHandler(userId);
@@ -631,7 +631,7 @@ public class Fingerprint21 implements IHwBinder.DeathRecipient, ServiceProvider
mSensorProperties.sensorId, isStrongBiometric, statsClient, mSensorProperties.sensorId, isStrongBiometric, statsClient,
mTaskStackListener, mLockoutTracker, mUdfpsOverlayController, mTaskStackListener, mLockoutTracker, mUdfpsOverlayController,
allowBackgroundAuthentication, mSensorProperties); allowBackgroundAuthentication, mSensorProperties);
mScheduler.scheduleClientMonitor(client, fingerprintStateCallback); mScheduler.scheduleClientMonitor(client, mFingerprintStateCallback);
}); });
} }
@@ -639,13 +639,11 @@ public class Fingerprint21 implements IHwBinder.DeathRecipient, ServiceProvider
public long scheduleAuthenticate(int sensorId, @NonNull IBinder token, long operationId, public long scheduleAuthenticate(int sensorId, @NonNull IBinder token, long operationId,
int userId, int cookie, @NonNull ClientMonitorCallbackConverter listener, int userId, int cookie, @NonNull ClientMonitorCallbackConverter listener,
@NonNull String opPackageName, boolean restricted, int statsClient, @NonNull String opPackageName, boolean restricted, int statsClient,
boolean allowBackgroundAuthentication, boolean allowBackgroundAuthentication) {
@NonNull FingerprintStateCallback fingerprintStateCallback) {
final long id = mRequestCounter.incrementAndGet(); final long id = mRequestCounter.incrementAndGet();
scheduleAuthenticate(sensorId, token, operationId, userId, cookie, listener, scheduleAuthenticate(sensorId, token, operationId, userId, cookie, listener,
opPackageName, id, restricted, statsClient, allowBackgroundAuthentication, opPackageName, id, restricted, statsClient, allowBackgroundAuthentication);
fingerprintStateCallback);
return id; return id;
} }
@@ -672,7 +670,7 @@ public class Fingerprint21 implements IHwBinder.DeathRecipient, ServiceProvider
mLazyDaemon, token, new ClientMonitorCallbackConverter(receiver), fingerId, mLazyDaemon, token, new ClientMonitorCallbackConverter(receiver), fingerId,
userId, opPackageName, FingerprintUtils.getLegacyInstance(mSensorId), userId, opPackageName, FingerprintUtils.getLegacyInstance(mSensorId),
mSensorProperties.sensorId, mAuthenticatorIds); mSensorProperties.sensorId, mAuthenticatorIds);
mScheduler.scheduleClientMonitor(client); mScheduler.scheduleClientMonitor(client, mFingerprintStateCallback);
}); });
} }
@@ -689,7 +687,7 @@ public class Fingerprint21 implements IHwBinder.DeathRecipient, ServiceProvider
0 /* fingerprintId */, userId, opPackageName, 0 /* fingerprintId */, userId, opPackageName,
FingerprintUtils.getLegacyInstance(mSensorId), FingerprintUtils.getLegacyInstance(mSensorId),
mSensorProperties.sensorId, mAuthenticatorIds); mSensorProperties.sensorId, mAuthenticatorIds);
mScheduler.scheduleClientMonitor(client); mScheduler.scheduleClientMonitor(client, mFingerprintStateCallback);
}); });
} }
@@ -711,7 +709,8 @@ public class Fingerprint21 implements IHwBinder.DeathRecipient, ServiceProvider
@Override @Override
public void scheduleInternalCleanup(int sensorId, int userId, public void scheduleInternalCleanup(int sensorId, int userId,
@Nullable BaseClientMonitor.Callback callback) { @Nullable BaseClientMonitor.Callback callback) {
scheduleInternalCleanup(userId, callback); scheduleInternalCleanup(userId, new BaseClientMonitor.CompositeCallback(callback,
mFingerprintStateCallback));
} }
@Override @Override
@@ -919,9 +918,8 @@ public class Fingerprint21 implements IHwBinder.DeathRecipient, ServiceProvider
@NonNull @NonNull
@Override @Override
public ITestSession createTestSession(int sensorId, @NonNull ITestSessionCallback callback, public ITestSession createTestSession(int sensorId, @NonNull ITestSessionCallback callback,
@NonNull FingerprintStateCallback fingerprintStateCallback,
@NonNull String opPackageName) { @NonNull String opPackageName) {
return new BiometricTestSessionImpl(mContext, mSensorProperties.sensorId, callback, return new BiometricTestSessionImpl(mContext, mSensorProperties.sensorId, callback,
fingerprintStateCallback, this, mHalResultController); mFingerprintStateCallback, this, mHalResultController);
} }
} }

View File

@@ -26,6 +26,7 @@ import android.hardware.fingerprint.FingerprintManager.AuthenticationCallback;
import android.hardware.fingerprint.FingerprintManager.AuthenticationResult; import android.hardware.fingerprint.FingerprintManager.AuthenticationResult;
import android.hardware.fingerprint.FingerprintSensorProperties; import android.hardware.fingerprint.FingerprintSensorProperties;
import android.hardware.fingerprint.FingerprintSensorPropertiesInternal; import android.hardware.fingerprint.FingerprintSensorPropertiesInternal;
import android.hardware.fingerprint.FingerprintStateListener;
import android.hardware.fingerprint.IUdfpsOverlayController; import android.hardware.fingerprint.IUdfpsOverlayController;
import android.os.Handler; import android.os.Handler;
import android.os.IBinder; import android.os.IBinder;
@@ -42,6 +43,7 @@ import com.android.server.biometrics.sensors.BaseClientMonitor;
import com.android.server.biometrics.sensors.BiometricScheduler; import com.android.server.biometrics.sensors.BiometricScheduler;
import com.android.server.biometrics.sensors.ClientMonitorCallbackConverter; import com.android.server.biometrics.sensors.ClientMonitorCallbackConverter;
import com.android.server.biometrics.sensors.LockoutResetDispatcher; import com.android.server.biometrics.sensors.LockoutResetDispatcher;
import com.android.server.biometrics.sensors.fingerprint.FingerprintStateCallback;
import com.android.server.biometrics.sensors.fingerprint.GestureAvailabilityDispatcher; import com.android.server.biometrics.sensors.fingerprint.GestureAvailabilityDispatcher;
import java.util.ArrayList; import java.util.ArrayList;
@@ -270,6 +272,7 @@ public class Fingerprint21UdfpsMock extends Fingerprint21 implements TrustManage
} }
public static Fingerprint21UdfpsMock newInstance(@NonNull Context context, public static Fingerprint21UdfpsMock newInstance(@NonNull Context context,
@NonNull FingerprintStateCallback fingerprintStateCallback,
@NonNull FingerprintSensorPropertiesInternal sensorProps, @NonNull FingerprintSensorPropertiesInternal sensorProps,
@NonNull LockoutResetDispatcher lockoutResetDispatcher, @NonNull LockoutResetDispatcher lockoutResetDispatcher,
@NonNull GestureAvailabilityDispatcher gestureAvailabilityDispatcher) { @NonNull GestureAvailabilityDispatcher gestureAvailabilityDispatcher) {
@@ -280,8 +283,8 @@ public class Fingerprint21UdfpsMock extends Fingerprint21 implements TrustManage
new TestableBiometricScheduler(TAG, gestureAvailabilityDispatcher); new TestableBiometricScheduler(TAG, gestureAvailabilityDispatcher);
final MockHalResultController controller = final MockHalResultController controller =
new MockHalResultController(sensorProps.sensorId, context, handler, scheduler); new MockHalResultController(sensorProps.sensorId, context, handler, scheduler);
return new Fingerprint21UdfpsMock(context, sensorProps, scheduler, handler, return new Fingerprint21UdfpsMock(context, fingerprintStateCallback, sensorProps, scheduler,
lockoutResetDispatcher, controller); handler, lockoutResetDispatcher, controller);
} }
private static abstract class FakeFingerRunnable implements Runnable { private static abstract class FakeFingerRunnable implements Runnable {
@@ -400,17 +403,19 @@ public class Fingerprint21UdfpsMock extends Fingerprint21 implements TrustManage
// internal preemption logic is not run. // internal preemption logic is not run.
mFingerprint21.scheduleAuthenticate(mFingerprint21.mSensorProperties.sensorId, token, mFingerprint21.scheduleAuthenticate(mFingerprint21.mSensorProperties.sensorId, token,
operationId, user, cookie, listener, opPackageName, restricted, statsClient, operationId, user, cookie, listener, opPackageName, restricted, statsClient,
isKeyguard, null /* fingerprintStateCallback */); isKeyguard);
} }
} }
private Fingerprint21UdfpsMock(@NonNull Context context, private Fingerprint21UdfpsMock(@NonNull Context context,
@NonNull FingerprintStateCallback fingerprintStateCallback,
@NonNull FingerprintSensorPropertiesInternal sensorProps, @NonNull FingerprintSensorPropertiesInternal sensorProps,
@NonNull TestableBiometricScheduler scheduler, @NonNull TestableBiometricScheduler scheduler,
@NonNull Handler handler, @NonNull Handler handler,
@NonNull LockoutResetDispatcher lockoutResetDispatcher, @NonNull LockoutResetDispatcher lockoutResetDispatcher,
@NonNull MockHalResultController controller) { @NonNull MockHalResultController controller) {
super(context, sensorProps, scheduler, handler, lockoutResetDispatcher, controller); super(context, fingerprintStateCallback, sensorProps, scheduler, handler,
lockoutResetDispatcher, controller);
mScheduler = scheduler; mScheduler = scheduler;
mScheduler.init(this); mScheduler.init(this);
mHandler = handler; mHandler = handler;

View File

@@ -0,0 +1,52 @@
/*
* Copyright (C) 2021 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.biometrics.sensors;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
import android.platform.test.annotations.Presubmit;
import androidx.test.filters.SmallTest;
import org.junit.Test;
@Presubmit
@SmallTest
public class CompositeCallbackTest {
@Test
public void testNullCallback() {
BaseClientMonitor.Callback callback1 = mock(BaseClientMonitor.Callback.class);
BaseClientMonitor.Callback callback2 = mock(BaseClientMonitor.Callback.class);
BaseClientMonitor.Callback callback3 = null;
BaseClientMonitor.CompositeCallback callback = new BaseClientMonitor.CompositeCallback(
callback1, callback2, callback3);
BaseClientMonitor clientMonitor = mock(BaseClientMonitor.class);
callback.onClientStarted(clientMonitor);
verify(callback1).onClientStarted(eq(clientMonitor));
verify(callback2).onClientStarted(eq(clientMonitor));
callback.onClientFinished(clientMonitor, true /* success */);
verify(callback1).onClientFinished(eq(clientMonitor), eq(true));
verify(callback2).onClientFinished(eq(clientMonitor), eq(true));
}
}

View File

@@ -0,0 +1,104 @@
/*
* Copyright (C) 2021 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.biometrics.sensors.fingerprint;
import static org.mockito.ArgumentMatchers.anyBoolean;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import android.hardware.fingerprint.FingerprintStateListener;
import android.platform.test.annotations.Presubmit;
import androidx.test.filters.SmallTest;
import com.android.server.biometrics.sensors.AuthenticationClient;
import com.android.server.biometrics.sensors.EnrollClient;
import org.junit.Before;
import org.junit.Test;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
@Presubmit
@SmallTest
public class FingerprintStateCallbackTest {
private FingerprintStateCallback mCallback;
@Mock
FingerprintStateListener mFingerprintStateListener;
@Before
public void setup() {
MockitoAnnotations.initMocks(this);
mCallback = new FingerprintStateCallback();
mCallback.registerFingerprintStateListener(mFingerprintStateListener);
}
@Test
public void testNoEnrollmentsToEnrollments_callbackNotified() {
testEnrollmentCallback(true /* changed */, true /* isNowEnrolled */,
true /* expectCallback */, true /* expectedCallbackValue */);
}
@Test
public void testEnrollmentsToNoEnrollments_callbackNotified() {
testEnrollmentCallback(true /* changed */, false /* isNowEnrolled */,
true /* expectCallback */, false /* expectedCallbackValue */);
}
@Test
public void testEnrollmentsToEnrollments_callbackNotNotified() {
testEnrollmentCallback(false /* changed */, true /* isNowEnrolled */,
false /* expectCallback */, false /* expectedCallbackValue */);
}
private void testEnrollmentCallback(boolean changed, boolean isNowEnrolled,
boolean expectCallback, boolean expectedCallbackValue) {
EnrollClient<?> client = mock(EnrollClient.class);
final int userId = 10;
final int sensorId = 100;
when(client.hasEnrollmentStateChanged()).thenReturn(changed);
when(client.hasEnrollments()).thenReturn(isNowEnrolled);
when(client.getTargetUserId()).thenReturn(userId);
when(client.getSensorId()).thenReturn(sensorId);
mCallback.onClientFinished(client, true /* success */);
if (expectCallback) {
verify(mFingerprintStateListener).onEnrollmentsChanged(eq(userId), eq(sensorId),
eq(expectedCallbackValue));
} else {
verify(mFingerprintStateListener, never()).onEnrollmentsChanged(anyInt(), anyInt(),
anyBoolean());
}
}
@Test
public void testAuthentication_enrollmentCallbackNeverNotified() {
AuthenticationClient<?> client = mock(AuthenticationClient.class);
mCallback.onClientFinished(client, true /* success */);
verify(mFingerprintStateListener, never()).onEnrollmentsChanged(anyInt(), anyInt(),
anyBoolean());
}
}

View File

@@ -37,6 +37,7 @@ import androidx.test.filters.SmallTest;
import com.android.server.biometrics.sensors.BiometricScheduler; import com.android.server.biometrics.sensors.BiometricScheduler;
import com.android.server.biometrics.sensors.HalClientMonitor; import com.android.server.biometrics.sensors.HalClientMonitor;
import com.android.server.biometrics.sensors.LockoutResetDispatcher; import com.android.server.biometrics.sensors.LockoutResetDispatcher;
import com.android.server.biometrics.sensors.fingerprint.FingerprintStateCallback;
import com.android.server.biometrics.sensors.fingerprint.GestureAvailabilityDispatcher; import com.android.server.biometrics.sensors.fingerprint.GestureAvailabilityDispatcher;
import org.junit.Before; import org.junit.Before;
@@ -58,6 +59,8 @@ public class FingerprintProviderTest {
private UserManager mUserManager; private UserManager mUserManager;
@Mock @Mock
private GestureAvailabilityDispatcher mGestureAvailabilityDispatcher; private GestureAvailabilityDispatcher mGestureAvailabilityDispatcher;
@Mock
private FingerprintStateCallback mFingerprintStateCallback;
private SensorProps[] mSensorProps; private SensorProps[] mSensorProps;
private LockoutResetDispatcher mLockoutResetDispatcher; private LockoutResetDispatcher mLockoutResetDispatcher;
@@ -87,8 +90,8 @@ public class FingerprintProviderTest {
mLockoutResetDispatcher = new LockoutResetDispatcher(mContext); mLockoutResetDispatcher = new LockoutResetDispatcher(mContext);
mFingerprintProvider = new TestableFingerprintProvider(mContext, mSensorProps, TAG, mFingerprintProvider = new TestableFingerprintProvider(mContext, mFingerprintStateCallback,
mLockoutResetDispatcher, mGestureAvailabilityDispatcher); mSensorProps, TAG, mLockoutResetDispatcher, mGestureAvailabilityDispatcher);
} }
@SuppressWarnings("rawtypes") @SuppressWarnings("rawtypes")
@@ -133,11 +136,12 @@ public class FingerprintProviderTest {
private static class TestableFingerprintProvider extends FingerprintProvider { private static class TestableFingerprintProvider extends FingerprintProvider {
public TestableFingerprintProvider(@NonNull Context context, public TestableFingerprintProvider(@NonNull Context context,
@NonNull FingerprintStateCallback fingerprintStateCallback,
@NonNull SensorProps[] props, @NonNull SensorProps[] props,
@NonNull String halInstanceName, @NonNull String halInstanceName,
@NonNull LockoutResetDispatcher lockoutResetDispatcher, @NonNull LockoutResetDispatcher lockoutResetDispatcher,
@NonNull GestureAvailabilityDispatcher gestureAvailabilityDispatcher) { @NonNull GestureAvailabilityDispatcher gestureAvailabilityDispatcher) {
super(context, props, halInstanceName, lockoutResetDispatcher, super(context, fingerprintStateCallback, props, halInstanceName, lockoutResetDispatcher,
gestureAvailabilityDispatcher); gestureAvailabilityDispatcher);
} }

View File

@@ -41,6 +41,7 @@ import androidx.test.filters.SmallTest;
import com.android.internal.R; import com.android.internal.R;
import com.android.server.biometrics.sensors.BiometricScheduler; import com.android.server.biometrics.sensors.BiometricScheduler;
import com.android.server.biometrics.sensors.LockoutResetDispatcher; import com.android.server.biometrics.sensors.LockoutResetDispatcher;
import com.android.server.biometrics.sensors.fingerprint.FingerprintStateCallback;
import org.junit.Before; import org.junit.Before;
import org.junit.Test; import org.junit.Test;
@@ -67,6 +68,8 @@ public class Fingerprint21Test {
Fingerprint21.HalResultController mHalResultController; Fingerprint21.HalResultController mHalResultController;
@Mock @Mock
private BiometricScheduler mScheduler; private BiometricScheduler mScheduler;
@Mock
private FingerprintStateCallback mFingerprintStateCallback;
private LockoutResetDispatcher mLockoutResetDispatcher; private LockoutResetDispatcher mLockoutResetDispatcher;
private Fingerprint21 mFingerprint21; private Fingerprint21 mFingerprint21;
@@ -96,8 +99,9 @@ public class Fingerprint21Test {
componentInfo, FingerprintSensorProperties.TYPE_UNKNOWN, componentInfo, FingerprintSensorProperties.TYPE_UNKNOWN,
resetLockoutRequiresHardwareAuthToken); resetLockoutRequiresHardwareAuthToken);
mFingerprint21 = new TestableFingerprint21(mContext, sensorProps, mScheduler, mFingerprint21 = new TestableFingerprint21(mContext, mFingerprintStateCallback, sensorProps,
new Handler(Looper.getMainLooper()), mLockoutResetDispatcher, mHalResultController); mScheduler, new Handler(Looper.getMainLooper()), mLockoutResetDispatcher,
mHalResultController);
} }
@Test @Test
@@ -118,11 +122,13 @@ public class Fingerprint21Test {
private static class TestableFingerprint21 extends Fingerprint21 { private static class TestableFingerprint21 extends Fingerprint21 {
TestableFingerprint21(@NonNull Context context, TestableFingerprint21(@NonNull Context context,
@NonNull FingerprintStateCallback fingerprintStateCallback,
@NonNull FingerprintSensorPropertiesInternal sensorProps, @NonNull FingerprintSensorPropertiesInternal sensorProps,
@NonNull BiometricScheduler scheduler, @NonNull Handler handler, @NonNull BiometricScheduler scheduler, @NonNull Handler handler,
@NonNull LockoutResetDispatcher lockoutResetDispatcher, @NonNull LockoutResetDispatcher lockoutResetDispatcher,
@NonNull HalResultController controller) { @NonNull HalResultController controller) {
super(context, sensorProps, scheduler, handler, lockoutResetDispatcher, controller); super(context, fingerprintStateCallback, sensorProps, scheduler, handler,
lockoutResetDispatcher, controller);
} }
@Override @Override