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

Original change: https://googleplex-android-review.googlesource.com/c/platform/frameworks/base/+/15730868

Change-Id: I20576b5e8311c1ed641dcc2851f78f8286154dbc
This commit is contained in:
Kevin Chyn
2021-09-07 22:47:44 +00:00
committed by Automerger Merge Worker
22 changed files with 456 additions and 136 deletions

View File

@@ -849,26 +849,6 @@ public class FingerprintManager implements BiometricAuthenticator, BiometricFing
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
*/

View File

@@ -49,5 +49,10 @@ public abstract class FingerprintStateListener extends IFingerprintStateListener
* Defines behavior in response to state update
* @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.
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
int getLockoutModeForUser(int sensorId, int userId);

View File

@@ -24,4 +24,5 @@ import android.hardware.fingerprint.Fingerprint;
*/
oneway interface IFingerprintStateListener {
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.fingerprint.FingerprintManager;
import android.hardware.fingerprint.FingerprintSensorPropertiesInternal;
import android.hardware.fingerprint.FingerprintStateListener;
import android.hardware.fingerprint.IFingerprintAuthenticatorsRegisteredCallback;
import android.hardware.fingerprint.IUdfpsHbmListener;
import android.os.Bundle;
@@ -49,6 +50,7 @@ import android.os.Handler;
import android.os.Looper;
import android.os.RemoteException;
import android.util.Log;
import android.util.SparseBooleanArray;
import android.view.MotionEvent;
import android.view.WindowManager;
@@ -76,6 +78,9 @@ import kotlin.Unit;
/**
* Receives messages sent from {@link com.android.server.biometrics.BiometricService} and shows the
* appropriate biometric UI (e.g. BiometricDialogView).
*
* Also coordinates biometric-related things, such as UDFPS, with
* {@link com.android.keyguard.KeyguardUpdateMonitor}
*/
@SysUISingleton
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> mSidefpsProps;
@NonNull private final SparseBooleanArray mUdfpsEnrolledForUser;
private class BiometricTaskStackListener extends TaskStackListener {
@Override
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
private final IFingerprintAuthenticatorsRegisteredCallback
mFingerprintAuthenticatorsRegisteredCallback =
@@ -436,6 +458,7 @@ public class AuthController extends SystemUI implements CommandQueue.Callbacks,
mUdfpsControllerFactory = udfpsControllerFactory;
mSidefpsControllerFactory = sidefpsControllerFactory;
mWindowManager = windowManager;
mUdfpsEnrolledForUser = new SparseBooleanArray();
mOrientationListener = new BiometricOrientationEventListener(context,
() -> {
onOrientationChanged();
@@ -474,6 +497,7 @@ public class AuthController extends SystemUI implements CommandQueue.Callbacks,
if (mFingerprintManager != null) {
mFingerprintManager.addAuthenticatorsRegisteredCallback(
mFingerprintAuthenticatorsRegisteredCallback);
mFingerprintManager.registerFingerprintStateListener(mFingerprintStateListener);
}
mTaskStackListener = new BiometricTaskStackListener();
@@ -673,7 +697,7 @@ public class AuthController extends SystemUI implements CommandQueue.Callbacks,
return false;
}
return mFingerprintManager.hasEnrolledTemplatesForAnySensor(userId, mUdfpsProps);
return mUdfpsEnrolledForUser.get(userId);
}
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 java.util.ArrayList;
import java.util.List;
import java.util.NoSuchElementException;
/**
@@ -70,26 +72,32 @@ public abstract class BaseClientMonitor extends LoggableMonitor
}
/** Holder for wrapping multiple handlers into a single Callback. */
protected static class CompositeCallback implements Callback {
public static class CompositeCallback implements Callback {
@NonNull
private final Callback[] mCallbacks;
private final List<Callback> mCallbacks;
public CompositeCallback(@NonNull Callback... callbacks) {
mCallbacks = callbacks;
mCallbacks = new ArrayList<>();
for (Callback callback : callbacks) {
if (callback != null) {
mCallbacks.add(callback);
}
}
}
@Override
public final void onClientStarted(@NonNull BaseClientMonitor clientMonitor) {
for (int i = 0; i < mCallbacks.length; i++) {
mCallbacks[i].onClientStarted(clientMonitor);
for (int i = 0; i < mCallbacks.size(); i++) {
mCallbacks.get(i).onClientStarted(clientMonitor);
}
}
@Override
public final void onClientFinished(@NonNull BaseClientMonitor clientMonitor,
boolean success) {
for (int i = mCallbacks.length - 1; i >= 0; i--) {
mCallbacks[i].onClientFinished(clientMonitor, success);
for (int i = mCallbacks.size() - 1; i >= 0; i--) {
mCallbacks.get(i).onClientFinished(clientMonitor, success);
}
}
}
@@ -256,7 +264,7 @@ public abstract class BaseClientMonitor extends LoggableMonitor
return mToken;
}
public final int getSensorId() {
public int getSensorId() {
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.
*/
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";
@@ -40,6 +40,7 @@ public abstract class EnrollClient<T> extends AcquisitionClient<T> {
protected final BiometricUtils mBiometricUtils;
private long mEnrollmentStartTimeMs;
private final boolean mHasEnrollmentsBeforeStarting;
/**
* @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;
mHardwareAuthToken = Arrays.copyOf(hardwareAuthToken, hardwareAuthToken.length);
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) {

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/
*/
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";
@@ -61,6 +62,7 @@ public abstract class InternalCleanupClient<S extends BiometricAuthenticator.Ide
private final BiometricUtils<S> mBiometricUtils;
private final Map<Integer, Long> mAuthenticatorIds;
private final List<S> mEnrolledList;
private final boolean mHasEnrollmentsBeforeStarting;
private BaseClientMonitor mCurrentTask;
private final Callback mEnumerateCallback = new Callback() {
@@ -115,6 +117,7 @@ public abstract class InternalCleanupClient<S extends BiometricAuthenticator.Ide
mBiometricUtils = utils;
mAuthenticatorIds = authenticatorIds;
mEnrolledList = enrolledList;
mHasEnrollmentsBeforeStarting = !utils.getBiometricsForUser(context, userId).isEmpty();
}
private void startCleanupUnknownHalTemplates() {
@@ -165,6 +168,18 @@ public abstract class InternalCleanupClient<S extends BiometricAuthenticator.Ide
((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
public void onEnumerationResult(BiometricAuthenticator.Identifier identifier,
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.
*/
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 final BiometricUtils<S> mBiometricUtils;
private final Map<Integer, Long> mAuthenticatorIds;
private final boolean mHasEnrollmentsBeforeStarting;
public RemovalClient(@NonNull Context context, @NonNull LazyDaemon<T> lazyDaemon,
@NonNull IBinder token, @NonNull ClientMonitorCallbackConverter listener,
@@ -49,6 +50,7 @@ public abstract class RemovalClient<S extends BiometricAuthenticator.Identifier,
BiometricsProtoEnums.CLIENT_UNKNOWN);
mBiometricUtils = utils;
mAuthenticatorIds = authenticatorIds;
mHasEnrollmentsBeforeStarting = !utils.getBiometricsForUser(context, userId).isEmpty();
}
@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
public int getProtoEnum() {
return BiometricsProto.CM_REMOVE;

View File

@@ -35,6 +35,7 @@ import android.annotation.Nullable;
import android.app.AppOpsManager;
import android.content.Context;
import android.content.pm.PackageManager;
import android.content.pm.UserInfo;
import android.hardware.biometrics.BiometricManager;
import android.hardware.biometrics.BiometricPrompt;
import android.hardware.biometrics.BiometricsProtoEnums;
@@ -62,11 +63,13 @@ import android.os.Build;
import android.os.CancellationSignal;
import android.os.Handler;
import android.os.IBinder;
import android.os.Looper;
import android.os.Process;
import android.os.RemoteCallbackList;
import android.os.RemoteException;
import android.os.ServiceManager;
import android.os.UserHandle;
import android.os.UserManager;
import android.provider.Settings;
import android.util.EventLog;
import android.util.Pair;
@@ -111,6 +114,7 @@ public class FingerprintService extends SystemService {
private final FingerprintServiceWrapper mServiceWrapper;
@NonNull private final List<ServiceProvider> mServiceProviders;
@NonNull private final FingerprintStateCallback mFingerprintStateCallback;
@NonNull private final Handler mHandler;
@GuardedBy("mLock")
@NonNull private final RemoteCallbackList<IFingerprintAuthenticatorsRegisteredCallback>
@@ -125,6 +129,37 @@ public class FingerprintService extends SystemService {
*/
public void registerFingerprintStateListener(@NonNull IFingerprintStateListener 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 provider.createTestSession(sensorId, callback, mFingerprintStateCallback,
opPackageName);
return provider.createTestSession(sensorId, callback, opPackageName);
}
@Override
@@ -227,7 +261,7 @@ public class FingerprintService extends SystemService {
}
provider.second.scheduleEnroll(provider.first, token, hardwareAuthToken, userId,
receiver, opPackageName, enrollReason, mFingerprintStateCallback);
receiver, opPackageName, enrollReason);
}
@Override // Binder call
@@ -306,7 +340,7 @@ public class FingerprintService extends SystemService {
}
return provider.second.scheduleAuthenticate(provider.first, token, operationId, userId,
0 /* cookie */, new ClientMonitorCallbackConverter(receiver), opPackageName,
restricted, statsClient, isKeyguard, mFingerprintStateCallback);
restricted, statsClient, isKeyguard);
}
private long authenticateWithPrompt(
@@ -414,7 +448,7 @@ public class FingerprintService extends SystemService {
return provider.second.scheduleFingerDetect(provider.first, token, userId,
new ClientMonitorCallbackConverter(receiver), opPackageName,
BiometricsProtoEnums.CLIENT_KEYGUARD, mFingerprintStateCallback);
BiometricsProtoEnums.CLIENT_KEYGUARD);
}
@Override // Binder call
@@ -433,7 +467,7 @@ public class FingerprintService extends SystemService {
provider.scheduleAuthenticate(sensorId, token, operationId, userId, cookie,
new ClientMonitorCallbackConverter(sensorReceiver), opPackageName, requestId,
restricted, BiometricsProtoEnums.CLIENT_BIOMETRIC_PROMPT,
allowBackgroundAuthentication, mFingerprintStateCallback);
allowBackgroundAuthentication);
}
@Override // Binder call
@@ -687,27 +721,6 @@ public class FingerprintService extends SystemService {
.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) {
Utils.checkPermission(getContext(), USE_BIOMETRIC_INTERNAL);
@@ -797,10 +810,12 @@ public class FingerprintService extends SystemService {
&& Settings.Secure.getIntForUser(getContext().getContentResolver(),
Fingerprint21UdfpsMock.CONFIG_ENABLE_TEST_UDFPS, 0 /* default */,
UserHandle.USER_CURRENT) != 0) {
fingerprint21 = Fingerprint21UdfpsMock.newInstance(getContext(), hidlSensor,
fingerprint21 = Fingerprint21UdfpsMock.newInstance(getContext(),
mFingerprintStateCallback, hidlSensor,
mLockoutResetDispatcher, mGestureAvailabilityDispatcher);
} else {
fingerprint21 = Fingerprint21.newInstance(getContext(), hidlSensor,
fingerprint21 = Fingerprint21.newInstance(getContext(),
mFingerprintStateCallback, hidlSensor,
mLockoutResetDispatcher, mGestureAvailabilityDispatcher);
}
mServiceProviders.add(fingerprint21);
@@ -823,8 +838,9 @@ public class FingerprintService extends SystemService {
try {
final SensorProps[] props = fp.getSensorProps();
final FingerprintProvider provider =
new FingerprintProvider(getContext(), props, instance,
mLockoutResetDispatcher, mGestureAvailabilityDispatcher);
new FingerprintProvider(getContext(), mFingerprintStateCallback, props,
instance, mLockoutResetDispatcher,
mGestureAvailabilityDispatcher);
mServiceProviders.add(provider);
} catch (RemoteException e) {
Slog.e(TAG, "Remote exception in getSensorProps: " + fqName);
@@ -878,6 +894,7 @@ public class FingerprintService extends SystemService {
}
}
broadcastCurrentEnrollmentState(null); // broadcasts to all listeners
broadcastAllAuthenticatorsRegistered();
});
}
@@ -975,6 +992,7 @@ public class FingerprintService extends SystemService {
mFingerprintStateCallback = new FingerprintStateCallback();
mAuthenticatorsRegisteredCallbacks = new RemoteCallbackList<>();
mSensorProps = new ArrayList<>();
mHandler = new Handler(Looper.getMainLooper());
}
// 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 android.annotation.NonNull;
import android.content.Context;
import android.hardware.fingerprint.FingerprintStateListener;
import android.hardware.fingerprint.IFingerprintStateListener;
import android.os.RemoteException;
@@ -31,6 +32,9 @@ import android.util.Slog;
import com.android.server.biometrics.Utils;
import com.android.server.biometrics.sensors.AuthenticationClient;
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 java.util.concurrent.CopyOnWriteArrayList;
@@ -39,9 +43,11 @@ import java.util.concurrent.CopyOnWriteArrayList;
* A callback for receiving notifications about changes in fingerprint state.
*/
public class FingerprintStateCallback implements BaseClientMonitor.Callback {
private @FingerprintStateListener.State int mFingerprintState;
@NonNull private final CopyOnWriteArrayList<IFingerprintStateListener>
mFingerprintStateListeners = new CopyOnWriteArrayList<>();
mFingerprintStateListeners = new CopyOnWriteArrayList<>();
private @FingerprintStateListener.State int mFingerprintState;
public FingerprintStateCallback() {
mFingerprintState = STATE_IDLE;
@@ -54,8 +60,9 @@ public class FingerprintStateCallback implements BaseClientMonitor.Callback {
@Override
public void onClientStarted(@NonNull BaseClientMonitor client) {
final int previousFingerprintState = mFingerprintState;
if (client instanceof AuthenticationClient) {
AuthenticationClient authClient = (AuthenticationClient) client;
final AuthenticationClient<?> authClient = (AuthenticationClient<?>) client;
if (authClient.isKeyguard()) {
mFingerprintState = STATE_KEYGUARD_AUTH;
} else if (authClient.isBiometricPrompt()) {
@@ -70,6 +77,7 @@ public class FingerprintStateCallback implements BaseClientMonitor.Callback {
"Other authentication client: " + Utils.getClientName(client));
mFingerprintState = STATE_IDLE;
}
Slog.d(FingerprintService.TAG, "Fps state updated from " + previousFingerprintState
+ " to " + mFingerprintState + ", client " + client);
notifyFingerprintStateListeners(mFingerprintState);
@@ -81,6 +89,18 @@ public class FingerprintStateCallback implements BaseClientMonitor.Callback {
Slog.d(FingerprintService.TAG,
"Client finished, fps state updated to " + mFingerprintState + ", 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);
}
@@ -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
* 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,
int userId, @NonNull IFingerprintServiceReceiver receiver,
@NonNull String opPackageName, @FingerprintManager.EnrollReason int enrollReason,
@NonNull FingerprintStateCallback fingerprintStateCallback);
@NonNull String opPackageName, @FingerprintManager.EnrollReason int enrollReason);
void cancelEnrollment(int sensorId, @NonNull IBinder token);
long scheduleFingerDetect(int sensorId, @NonNull IBinder token, int userId,
@NonNull ClientMonitorCallbackConverter callback, @NonNull String opPackageName,
int statsClient,
@NonNull FingerprintStateCallback fingerprintStateCallback);
int statsClient);
void scheduleAuthenticate(int sensorId, @NonNull IBinder token, long operationId, int userId,
int cookie, @NonNull ClientMonitorCallbackConverter callback,
@NonNull String opPackageName, long requestId, boolean restricted, int statsClient,
boolean allowBackgroundAuthentication,
@NonNull FingerprintStateCallback fingerprintStateCallback);
boolean allowBackgroundAuthentication);
long scheduleAuthenticate(int sensorId, @NonNull IBinder token, long operationId, int userId,
int cookie, @NonNull ClientMonitorCallbackConverter callback,
@NonNull String opPackageName, boolean restricted, int statsClient,
boolean allowBackgroundAuthentication,
@NonNull FingerprintStateCallback fingerprintStateCallback);
boolean allowBackgroundAuthentication);
void startPreparedClient(int sensorId, int cookie);
@@ -169,6 +165,5 @@ public interface ServiceProvider {
@NonNull
ITestSession createTestSession(int sensorId, @NonNull ITestSessionCallback callback,
@NonNull FingerprintStateCallback fingerprintStateCallback,
@NonNull String opPackageName);
}

View File

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

View File

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

View File

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

View File

@@ -102,6 +102,7 @@ public class Fingerprint21 implements IHwBinder.DeathRecipient, ServiceProvider
private boolean mTestHalEnabled;
final Context mContext;
@NonNull private final FingerprintStateCallback mFingerprintStateCallback;
private final ActivityTaskManager mActivityTaskManager;
@NonNull private final FingerprintSensorPropertiesInternal mSensorProperties;
private final BiometricScheduler mScheduler;
@@ -317,11 +318,13 @@ public class Fingerprint21 implements IHwBinder.DeathRecipient, ServiceProvider
}
Fingerprint21(@NonNull Context context,
@NonNull FingerprintStateCallback fingerprintStateCallback,
@NonNull FingerprintSensorPropertiesInternal sensorProps,
@NonNull BiometricScheduler scheduler, @NonNull Handler handler,
@NonNull LockoutResetDispatcher lockoutResetDispatcher,
@NonNull HalResultController controller) {
mContext = context;
mFingerprintStateCallback = fingerprintStateCallback;
mSensorProperties = sensorProps;
mSensorId = sensorProps.sensorId;
@@ -351,6 +354,7 @@ public class Fingerprint21 implements IHwBinder.DeathRecipient, ServiceProvider
}
public static Fingerprint21 newInstance(@NonNull Context context,
@NonNull FingerprintStateCallback fingerprintStateCallback,
@NonNull FingerprintSensorPropertiesInternal sensorProps,
@NonNull LockoutResetDispatcher lockoutResetDispatcher,
@NonNull GestureAvailabilityDispatcher gestureAvailabilityDispatcher) {
@@ -362,8 +366,8 @@ public class Fingerprint21 implements IHwBinder.DeathRecipient, ServiceProvider
final HalResultController controller = new HalResultController(sensorProps.sensorId,
context, handler,
scheduler);
return new Fingerprint21(context, sensorProps, scheduler, handler, lockoutResetDispatcher,
controller);
return new Fingerprint21(context, fingerprintStateCallback, sensorProps, scheduler, handler,
lockoutResetDispatcher, controller);
}
@Override
@@ -557,8 +561,7 @@ public class Fingerprint21 implements IHwBinder.DeathRecipient, ServiceProvider
public void scheduleEnroll(int sensorId, @NonNull IBinder token,
@NonNull byte[] hardwareAuthToken, int userId,
@NonNull IFingerprintServiceReceiver receiver, @NonNull String opPackageName,
@FingerprintManager.EnrollReason int enrollReason,
@NonNull FingerprintStateCallback fingerprintStateCallback) {
@FingerprintManager.EnrollReason int enrollReason) {
mHandler.post(() -> {
scheduleUpdateActiveUserWithoutHandler(userId);
@@ -570,13 +573,13 @@ public class Fingerprint21 implements IHwBinder.DeathRecipient, ServiceProvider
mScheduler.scheduleClientMonitor(client, new BaseClientMonitor.Callback() {
@Override
public void onClientStarted(@NonNull BaseClientMonitor clientMonitor) {
fingerprintStateCallback.onClientStarted(clientMonitor);
mFingerprintStateCallback.onClientStarted(clientMonitor);
}
@Override
public void onClientFinished(@NonNull BaseClientMonitor clientMonitor,
boolean success) {
fingerprintStateCallback.onClientFinished(clientMonitor, success);
mFingerprintStateCallback.onClientFinished(clientMonitor, success);
if (success) {
// Update authenticatorIds
scheduleUpdateActiveUserWithoutHandler(clientMonitor.getTargetUserId(),
@@ -597,10 +600,8 @@ public class Fingerprint21 implements IHwBinder.DeathRecipient, ServiceProvider
@Override
public long scheduleFingerDetect(int sensorId, @NonNull IBinder token, int userId,
@NonNull ClientMonitorCallbackConverter listener, @NonNull String opPackageName,
int statsClient,
@NonNull FingerprintStateCallback fingerprintStateCallback) {
int statsClient) {
final long id = mRequestCounter.incrementAndGet();
mHandler.post(() -> {
scheduleUpdateActiveUserWithoutHandler(userId);
@@ -609,7 +610,7 @@ public class Fingerprint21 implements IHwBinder.DeathRecipient, ServiceProvider
mLazyDaemon, token, id, listener, userId, opPackageName,
mSensorProperties.sensorId, mUdfpsOverlayController, isStrongBiometric,
statsClient);
mScheduler.scheduleClientMonitor(client, fingerprintStateCallback);
mScheduler.scheduleClientMonitor(client, mFingerprintStateCallback);
});
return id;
@@ -619,8 +620,7 @@ public class Fingerprint21 implements IHwBinder.DeathRecipient, ServiceProvider
public void scheduleAuthenticate(int sensorId, @NonNull IBinder token, long operationId,
int userId, int cookie, @NonNull ClientMonitorCallbackConverter listener,
@NonNull String opPackageName, long requestId, boolean restricted, int statsClient,
boolean allowBackgroundAuthentication,
@NonNull FingerprintStateCallback fingerprintStateCallback) {
boolean allowBackgroundAuthentication) {
mHandler.post(() -> {
scheduleUpdateActiveUserWithoutHandler(userId);
@@ -631,7 +631,7 @@ public class Fingerprint21 implements IHwBinder.DeathRecipient, ServiceProvider
mSensorProperties.sensorId, isStrongBiometric, statsClient,
mTaskStackListener, mLockoutTracker, mUdfpsOverlayController,
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,
int userId, int cookie, @NonNull ClientMonitorCallbackConverter listener,
@NonNull String opPackageName, boolean restricted, int statsClient,
boolean allowBackgroundAuthentication,
@NonNull FingerprintStateCallback fingerprintStateCallback) {
boolean allowBackgroundAuthentication) {
final long id = mRequestCounter.incrementAndGet();
scheduleAuthenticate(sensorId, token, operationId, userId, cookie, listener,
opPackageName, id, restricted, statsClient, allowBackgroundAuthentication,
fingerprintStateCallback);
opPackageName, id, restricted, statsClient, allowBackgroundAuthentication);
return id;
}
@@ -672,7 +670,7 @@ public class Fingerprint21 implements IHwBinder.DeathRecipient, ServiceProvider
mLazyDaemon, token, new ClientMonitorCallbackConverter(receiver), fingerId,
userId, opPackageName, FingerprintUtils.getLegacyInstance(mSensorId),
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,
FingerprintUtils.getLegacyInstance(mSensorId),
mSensorProperties.sensorId, mAuthenticatorIds);
mScheduler.scheduleClientMonitor(client);
mScheduler.scheduleClientMonitor(client, mFingerprintStateCallback);
});
}
@@ -711,7 +709,8 @@ public class Fingerprint21 implements IHwBinder.DeathRecipient, ServiceProvider
@Override
public void scheduleInternalCleanup(int sensorId, int userId,
@Nullable BaseClientMonitor.Callback callback) {
scheduleInternalCleanup(userId, callback);
scheduleInternalCleanup(userId, new BaseClientMonitor.CompositeCallback(callback,
mFingerprintStateCallback));
}
@Override
@@ -919,9 +918,8 @@ public class Fingerprint21 implements IHwBinder.DeathRecipient, ServiceProvider
@NonNull
@Override
public ITestSession createTestSession(int sensorId, @NonNull ITestSessionCallback callback,
@NonNull FingerprintStateCallback fingerprintStateCallback,
@NonNull String opPackageName) {
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.FingerprintSensorProperties;
import android.hardware.fingerprint.FingerprintSensorPropertiesInternal;
import android.hardware.fingerprint.FingerprintStateListener;
import android.hardware.fingerprint.IUdfpsOverlayController;
import android.os.Handler;
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.ClientMonitorCallbackConverter;
import com.android.server.biometrics.sensors.LockoutResetDispatcher;
import com.android.server.biometrics.sensors.fingerprint.FingerprintStateCallback;
import com.android.server.biometrics.sensors.fingerprint.GestureAvailabilityDispatcher;
import java.util.ArrayList;
@@ -270,6 +272,7 @@ public class Fingerprint21UdfpsMock extends Fingerprint21 implements TrustManage
}
public static Fingerprint21UdfpsMock newInstance(@NonNull Context context,
@NonNull FingerprintStateCallback fingerprintStateCallback,
@NonNull FingerprintSensorPropertiesInternal sensorProps,
@NonNull LockoutResetDispatcher lockoutResetDispatcher,
@NonNull GestureAvailabilityDispatcher gestureAvailabilityDispatcher) {
@@ -280,8 +283,8 @@ public class Fingerprint21UdfpsMock extends Fingerprint21 implements TrustManage
new TestableBiometricScheduler(TAG, gestureAvailabilityDispatcher);
final MockHalResultController controller =
new MockHalResultController(sensorProps.sensorId, context, handler, scheduler);
return new Fingerprint21UdfpsMock(context, sensorProps, scheduler, handler,
lockoutResetDispatcher, controller);
return new Fingerprint21UdfpsMock(context, fingerprintStateCallback, sensorProps, scheduler,
handler, lockoutResetDispatcher, controller);
}
private static abstract class FakeFingerRunnable implements Runnable {
@@ -400,17 +403,19 @@ public class Fingerprint21UdfpsMock extends Fingerprint21 implements TrustManage
// internal preemption logic is not run.
mFingerprint21.scheduleAuthenticate(mFingerprint21.mSensorProperties.sensorId, token,
operationId, user, cookie, listener, opPackageName, restricted, statsClient,
isKeyguard, null /* fingerprintStateCallback */);
isKeyguard);
}
}
private Fingerprint21UdfpsMock(@NonNull Context context,
@NonNull FingerprintStateCallback fingerprintStateCallback,
@NonNull FingerprintSensorPropertiesInternal sensorProps,
@NonNull TestableBiometricScheduler scheduler,
@NonNull Handler handler,
@NonNull LockoutResetDispatcher lockoutResetDispatcher,
@NonNull MockHalResultController controller) {
super(context, sensorProps, scheduler, handler, lockoutResetDispatcher, controller);
super(context, fingerprintStateCallback, sensorProps, scheduler, handler,
lockoutResetDispatcher, controller);
mScheduler = scheduler;
mScheduler.init(this);
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.HalClientMonitor;
import com.android.server.biometrics.sensors.LockoutResetDispatcher;
import com.android.server.biometrics.sensors.fingerprint.FingerprintStateCallback;
import com.android.server.biometrics.sensors.fingerprint.GestureAvailabilityDispatcher;
import org.junit.Before;
@@ -58,6 +59,8 @@ public class FingerprintProviderTest {
private UserManager mUserManager;
@Mock
private GestureAvailabilityDispatcher mGestureAvailabilityDispatcher;
@Mock
private FingerprintStateCallback mFingerprintStateCallback;
private SensorProps[] mSensorProps;
private LockoutResetDispatcher mLockoutResetDispatcher;
@@ -87,8 +90,8 @@ public class FingerprintProviderTest {
mLockoutResetDispatcher = new LockoutResetDispatcher(mContext);
mFingerprintProvider = new TestableFingerprintProvider(mContext, mSensorProps, TAG,
mLockoutResetDispatcher, mGestureAvailabilityDispatcher);
mFingerprintProvider = new TestableFingerprintProvider(mContext, mFingerprintStateCallback,
mSensorProps, TAG, mLockoutResetDispatcher, mGestureAvailabilityDispatcher);
}
@SuppressWarnings("rawtypes")
@@ -133,11 +136,12 @@ public class FingerprintProviderTest {
private static class TestableFingerprintProvider extends FingerprintProvider {
public TestableFingerprintProvider(@NonNull Context context,
@NonNull FingerprintStateCallback fingerprintStateCallback,
@NonNull SensorProps[] props,
@NonNull String halInstanceName,
@NonNull LockoutResetDispatcher lockoutResetDispatcher,
@NonNull GestureAvailabilityDispatcher gestureAvailabilityDispatcher) {
super(context, props, halInstanceName, lockoutResetDispatcher,
super(context, fingerprintStateCallback, props, halInstanceName, lockoutResetDispatcher,
gestureAvailabilityDispatcher);
}

View File

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