Hide Udfps Overlay together with system transitions
Prevent the UDFPS overlay from showing when system dialogs are
expected to be closed. Since the UDFPS affordances are not
actually shown in the application's window, we should nicely
hide the UDFPS overlay together with the system transitions.
1) Adds IUdfpsOverlayControllerCallback for SysUI to notify
FingerprintService of per-session events.
2) Adds AcquisitionClient#onUserCanceled, which notifies the
caller of ERROR_USER_CANCELED, and then cancels the HAL
request
Bug: 178403701
Test: Enroll, swipe up. UDFPS affordances animate away together
with the activity. BiometricScheduler logs also indicate
enrollment canceled.
Test: atest AcquisitionClientTest
Test: atest UdfpsControllerTest
Change-Id: I0b2c9eb20ef0686e426ea12896769e4df077cadb
This commit is contained in:
@@ -15,6 +15,8 @@
|
||||
*/
|
||||
package android.hardware.fingerprint;
|
||||
|
||||
import android.hardware.fingerprint.IUdfpsOverlayControllerCallback;
|
||||
|
||||
/**
|
||||
* Interface for interacting with the under-display fingerprint sensor (UDFPS) overlay.
|
||||
* @hide
|
||||
@@ -28,7 +30,7 @@ oneway interface IUdfpsOverlayController {
|
||||
const int REASON_AUTH_FPM_OTHER = 5; // Other FingerprintManager usage
|
||||
|
||||
// Shows the overlay.
|
||||
void showUdfpsOverlay(int sensorId, int reason);
|
||||
void showUdfpsOverlay(int sensorId, int reason, IUdfpsOverlayControllerCallback callback);
|
||||
|
||||
// Hides the overlay.
|
||||
void hideUdfpsOverlay(int sensorId);
|
||||
|
||||
@@ -0,0 +1,24 @@
|
||||
/*
|
||||
* 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 android.hardware.fingerprint;
|
||||
|
||||
/**
|
||||
* @hide
|
||||
*/
|
||||
oneway interface IUdfpsOverlayControllerCallback {
|
||||
// Notify system_server if the user cancels a UDFPS-related operation (enroll, auth)
|
||||
void onUserCanceled();
|
||||
}
|
||||
@@ -20,7 +20,10 @@ import static com.android.internal.util.Preconditions.checkArgument;
|
||||
import static com.android.internal.util.Preconditions.checkNotNull;
|
||||
|
||||
import android.annotation.SuppressLint;
|
||||
import android.content.BroadcastReceiver;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.IntentFilter;
|
||||
import android.content.res.Resources;
|
||||
import android.graphics.PixelFormat;
|
||||
import android.graphics.Point;
|
||||
@@ -29,6 +32,8 @@ import android.hardware.fingerprint.FingerprintManager;
|
||||
import android.hardware.fingerprint.FingerprintSensorPropertiesInternal;
|
||||
import android.hardware.fingerprint.IUdfpsOverlayController;
|
||||
import android.os.SystemClock;
|
||||
import android.hardware.fingerprint.IUdfpsOverlayControllerCallback;
|
||||
import android.os.RemoteException;
|
||||
import android.util.Log;
|
||||
import android.view.Gravity;
|
||||
import android.view.LayoutInflater;
|
||||
@@ -110,10 +115,13 @@ public class UdfpsController implements DozeReceiver, HbmCallback {
|
||||
private static class ServerRequest {
|
||||
// Reason the overlay has been requested. See IUdfpsOverlayController for definitions.
|
||||
final int mRequestReason;
|
||||
@NonNull final IUdfpsOverlayControllerCallback mCallback;
|
||||
@Nullable final UdfpsEnrollHelper mEnrollHelper;
|
||||
|
||||
ServerRequest(int requestReason, @Nullable UdfpsEnrollHelper enrollHelper) {
|
||||
ServerRequest(int requestReason, @NonNull IUdfpsOverlayControllerCallback callback,
|
||||
@Nullable UdfpsEnrollHelper enrollHelper) {
|
||||
mRequestReason = requestReason;
|
||||
mCallback = callback;
|
||||
mEnrollHelper = enrollHelper;
|
||||
}
|
||||
|
||||
@@ -128,11 +136,20 @@ public class UdfpsController implements DozeReceiver, HbmCallback {
|
||||
mEnrollHelper.onEnrollmentHelp();
|
||||
}
|
||||
}
|
||||
|
||||
void onUserCanceled() {
|
||||
try {
|
||||
mCallback.onUserCanceled();
|
||||
} catch (RemoteException e) {
|
||||
Log.e(TAG, "Remote exception", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public class UdfpsOverlayController extends IUdfpsOverlayController.Stub {
|
||||
@Override
|
||||
public void showUdfpsOverlay(int sensorId, int reason) {
|
||||
public void showUdfpsOverlay(int sensorId, int reason,
|
||||
@NonNull IUdfpsOverlayControllerCallback callback) {
|
||||
final UdfpsEnrollHelper enrollHelper;
|
||||
if (reason == IUdfpsOverlayController.REASON_ENROLL_FIND_SENSOR
|
||||
|| reason == IUdfpsOverlayController.REASON_ENROLL_ENROLLING) {
|
||||
@@ -141,7 +158,7 @@ public class UdfpsController implements DozeReceiver, HbmCallback {
|
||||
enrollHelper = null;
|
||||
}
|
||||
|
||||
mServerRequest = new ServerRequest(reason, enrollHelper);
|
||||
mServerRequest = new ServerRequest(reason, callback, enrollHelper);
|
||||
updateOverlay();
|
||||
}
|
||||
|
||||
@@ -195,6 +212,19 @@ public class UdfpsController implements DozeReceiver, HbmCallback {
|
||||
return (float) Math.sqrt(Math.pow(vx, 2.0) + Math.pow(vy, 2.0));
|
||||
}
|
||||
|
||||
private final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
|
||||
@Override
|
||||
public void onReceive(Context context, Intent intent) {
|
||||
if (mServerRequest != null
|
||||
&& Intent.ACTION_CLOSE_SYSTEM_DIALOGS.equals(intent.getAction())) {
|
||||
Log.d(TAG, "ACTION_CLOSE_SYSTEM_DIALOGS received");
|
||||
mServerRequest.onUserCanceled();
|
||||
mServerRequest = null;
|
||||
updateOverlay();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@SuppressLint("ClickableViewAccessibility")
|
||||
private final UdfpsView.OnTouchListener mOnTouchListener = (view, event) -> {
|
||||
UdfpsView udfpsView = (UdfpsView) view;
|
||||
@@ -310,6 +340,10 @@ public class UdfpsController implements DozeReceiver, HbmCallback {
|
||||
mCoreLayoutParams.privateFlags = WindowManager.LayoutParams.PRIVATE_FLAG_TRUSTED_OVERLAY;
|
||||
|
||||
mFingerprintManager.setUdfpsOverlayController(new UdfpsOverlayController());
|
||||
|
||||
final IntentFilter filter = new IntentFilter();
|
||||
filter.addAction(Intent.ACTION_CLOSE_SYSTEM_DIALOGS);
|
||||
context.registerReceiver(mBroadcastReceiver, filter);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
|
||||
@@ -31,6 +31,7 @@ import android.hardware.fingerprint.FingerprintManager;
|
||||
import android.hardware.fingerprint.FingerprintSensorProperties;
|
||||
import android.hardware.fingerprint.FingerprintSensorPropertiesInternal;
|
||||
import android.hardware.fingerprint.IUdfpsOverlayController;
|
||||
import android.hardware.fingerprint.IUdfpsOverlayControllerCallback;
|
||||
import android.os.PowerManager;
|
||||
import android.os.RemoteException;
|
||||
import android.testing.AndroidTestingRunner;
|
||||
@@ -89,6 +90,8 @@ public class UdfpsControllerTest extends SysuiTestCase {
|
||||
private StatusBarStateController mStatusBarStateController;
|
||||
@Mock
|
||||
private StatusBar mStatusBar;
|
||||
@Mock
|
||||
private IUdfpsOverlayControllerCallback mUdfpsOverlayControllerCallback;
|
||||
|
||||
private FakeExecutor mFgExecutor;
|
||||
|
||||
@@ -152,7 +155,7 @@ public class UdfpsControllerTest extends SysuiTestCase {
|
||||
@Test
|
||||
public void dozeTimeTick() throws RemoteException {
|
||||
mOverlayController.showUdfpsOverlay(TEST_UDFPS_SENSOR_ID,
|
||||
IUdfpsOverlayController.REASON_AUTH_FPM_KEYGUARD);
|
||||
IUdfpsOverlayController.REASON_AUTH_FPM_KEYGUARD, mUdfpsOverlayControllerCallback);
|
||||
mFgExecutor.runAllReady();
|
||||
mUdfpsController.dozeTimeTick();
|
||||
verify(mUdfpsView).dozeTimeTick();
|
||||
@@ -161,7 +164,7 @@ public class UdfpsControllerTest extends SysuiTestCase {
|
||||
@Test
|
||||
public void showUdfpsOverlay_addsViewToWindow() throws RemoteException {
|
||||
mOverlayController.showUdfpsOverlay(TEST_UDFPS_SENSOR_ID,
|
||||
IUdfpsOverlayController.REASON_AUTH_FPM_KEYGUARD);
|
||||
IUdfpsOverlayController.REASON_AUTH_FPM_KEYGUARD, mUdfpsOverlayControllerCallback);
|
||||
mFgExecutor.runAllReady();
|
||||
verify(mWindowManager).addView(eq(mUdfpsView), any());
|
||||
}
|
||||
@@ -169,7 +172,7 @@ public class UdfpsControllerTest extends SysuiTestCase {
|
||||
@Test
|
||||
public void hideUdfpsOverlay_removesViewFromWindow() throws RemoteException {
|
||||
mOverlayController.showUdfpsOverlay(TEST_UDFPS_SENSOR_ID,
|
||||
IUdfpsOverlayController.REASON_AUTH_FPM_KEYGUARD);
|
||||
IUdfpsOverlayController.REASON_AUTH_FPM_KEYGUARD, mUdfpsOverlayControllerCallback);
|
||||
mOverlayController.hideUdfpsOverlay(TEST_UDFPS_SENSOR_ID);
|
||||
mFgExecutor.runAllReady();
|
||||
verify(mWindowManager).removeView(eq(mUdfpsView));
|
||||
@@ -183,7 +186,7 @@ public class UdfpsControllerTest extends SysuiTestCase {
|
||||
|
||||
// GIVEN that the overlay is showing
|
||||
mOverlayController.showUdfpsOverlay(TEST_UDFPS_SENSOR_ID,
|
||||
IUdfpsOverlayController.REASON_AUTH_FPM_KEYGUARD);
|
||||
IUdfpsOverlayController.REASON_AUTH_FPM_KEYGUARD, mUdfpsOverlayControllerCallback);
|
||||
mFgExecutor.runAllReady();
|
||||
// WHEN ACTION_DOWN is received
|
||||
verify(mUdfpsView).setOnTouchListener(mTouchListenerCaptor.capture());
|
||||
@@ -205,7 +208,7 @@ public class UdfpsControllerTest extends SysuiTestCase {
|
||||
public void aodInterrupt() throws RemoteException {
|
||||
// GIVEN that the overlay is showing
|
||||
mOverlayController.showUdfpsOverlay(TEST_UDFPS_SENSOR_ID,
|
||||
IUdfpsOverlayController.REASON_AUTH_FPM_KEYGUARD);
|
||||
IUdfpsOverlayController.REASON_AUTH_FPM_KEYGUARD, mUdfpsOverlayControllerCallback);
|
||||
mFgExecutor.runAllReady();
|
||||
// WHEN fingerprint is requested because of AOD interrupt
|
||||
mUdfpsController.onAodInterrupt(0, 0, 2f, 3f);
|
||||
@@ -221,7 +224,7 @@ public class UdfpsControllerTest extends SysuiTestCase {
|
||||
public void cancelAodInterrupt() throws RemoteException {
|
||||
// GIVEN AOD interrupt
|
||||
mOverlayController.showUdfpsOverlay(TEST_UDFPS_SENSOR_ID,
|
||||
IUdfpsOverlayController.REASON_AUTH_FPM_KEYGUARD);
|
||||
IUdfpsOverlayController.REASON_AUTH_FPM_KEYGUARD, mUdfpsOverlayControllerCallback);
|
||||
mFgExecutor.runAllReady();
|
||||
mUdfpsController.onAodInterrupt(0, 0, 0f, 0f);
|
||||
// WHEN it is cancelled
|
||||
@@ -234,7 +237,7 @@ public class UdfpsControllerTest extends SysuiTestCase {
|
||||
public void aodInterruptTimeout() throws RemoteException {
|
||||
// GIVEN AOD interrupt
|
||||
mOverlayController.showUdfpsOverlay(TEST_UDFPS_SENSOR_ID,
|
||||
IUdfpsOverlayController.REASON_AUTH_FPM_KEYGUARD);
|
||||
IUdfpsOverlayController.REASON_AUTH_FPM_KEYGUARD, mUdfpsOverlayControllerCallback);
|
||||
mFgExecutor.runAllReady();
|
||||
mUdfpsController.onAodInterrupt(0, 0, 0f, 0f);
|
||||
// WHEN it times out
|
||||
@@ -247,7 +250,7 @@ public class UdfpsControllerTest extends SysuiTestCase {
|
||||
@Test
|
||||
public void registersAndUnregistersViewForCallbacks() throws RemoteException {
|
||||
mOverlayController.showUdfpsOverlay(TEST_UDFPS_SENSOR_ID,
|
||||
IUdfpsOverlayController.REASON_AUTH_FPM_KEYGUARD);
|
||||
IUdfpsOverlayController.REASON_AUTH_FPM_KEYGUARD, mUdfpsOverlayControllerCallback);
|
||||
mFgExecutor.runAllReady();
|
||||
verify(mStatusBarStateController).addCallback(mUdfpsController.mStatusBarStateListener);
|
||||
verify(mStatusBar).addExpansionChangedListener(
|
||||
|
||||
@@ -80,6 +80,18 @@ public abstract class AcquisitionClient<T> extends HalClientMonitor<T> implement
|
||||
onErrorInternal(errorCode, vendorCode, true /* finish */);
|
||||
}
|
||||
|
||||
/**
|
||||
* Notifies the caller that the operation was canceled by the user. Note that the actual
|
||||
* operation still needs to wait for the HAL to send ERROR_CANCELED.
|
||||
*/
|
||||
public void onUserCanceled() {
|
||||
// Send USER_CANCELED, but do not finish. Wait for the HAL to respond with ERROR_CANCELED,
|
||||
// which then finishes the AcquisitionClient's lifecycle.
|
||||
onErrorInternal(BiometricConstants.BIOMETRIC_ERROR_USER_CANCELED, 0 /* vendorCode */,
|
||||
false /* finish */);
|
||||
stopHalOperation();
|
||||
}
|
||||
|
||||
protected void onErrorInternal(int errorCode, int vendorCode, boolean finish) {
|
||||
// In some cases, the framework will send an error to the caller before a true terminal
|
||||
// case (success, failure, or error) is received from the HAL (e.g. versions of fingerprint
|
||||
|
||||
@@ -22,9 +22,12 @@ import android.content.Context;
|
||||
import android.hardware.biometrics.fingerprint.V2_1.IBiometricsFingerprint;
|
||||
import android.hardware.fingerprint.FingerprintManager;
|
||||
import android.hardware.fingerprint.IUdfpsOverlayController;
|
||||
import android.hardware.fingerprint.IUdfpsOverlayControllerCallback;
|
||||
import android.os.RemoteException;
|
||||
import android.util.Slog;
|
||||
|
||||
import com.android.server.biometrics.sensors.AcquisitionClient;
|
||||
|
||||
/**
|
||||
* Contains helper methods for under-display fingerprint HIDL.
|
||||
*/
|
||||
@@ -77,12 +80,22 @@ public class UdfpsHelper {
|
||||
}
|
||||
|
||||
public static void showUdfpsOverlay(int sensorId, int reason,
|
||||
@Nullable IUdfpsOverlayController udfpsOverlayController) {
|
||||
@Nullable IUdfpsOverlayController udfpsOverlayController,
|
||||
@NonNull AcquisitionClient<?> client) {
|
||||
if (udfpsOverlayController == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
final IUdfpsOverlayControllerCallback callback =
|
||||
new IUdfpsOverlayControllerCallback.Stub() {
|
||||
@Override
|
||||
public void onUserCanceled() {
|
||||
client.onUserCanceled();
|
||||
}
|
||||
};
|
||||
|
||||
try {
|
||||
udfpsOverlayController.showUdfpsOverlay(sensorId, reason);
|
||||
udfpsOverlayController.showUdfpsOverlay(sensorId, reason, callback);
|
||||
} catch (RemoteException e) {
|
||||
Slog.e(TAG, "Remote exception when showing the UDFPS overlay", e);
|
||||
}
|
||||
|
||||
@@ -89,7 +89,7 @@ class FingerprintAuthenticationClient extends AuthenticationClient<ISession> imp
|
||||
@Override
|
||||
protected void startHalOperation() {
|
||||
UdfpsHelper.showUdfpsOverlay(getSensorId(), Utils.getUdfpsAuthReason(this),
|
||||
mUdfpsOverlayController);
|
||||
mUdfpsOverlayController, this);
|
||||
try {
|
||||
mCancellationSignal = getFreshDaemon().authenticate(mSequentialId, mOperationId);
|
||||
} catch (RemoteException e) {
|
||||
|
||||
@@ -72,7 +72,7 @@ class FingerprintDetectClient extends AcquisitionClient<ISession> {
|
||||
protected void startHalOperation() {
|
||||
UdfpsHelper.showUdfpsOverlay(getSensorId(),
|
||||
IUdfpsOverlayController.REASON_AUTH_FPM_KEYGUARD,
|
||||
mUdfpsOverlayController);
|
||||
mUdfpsOverlayController, this);
|
||||
try {
|
||||
mCancellationSignal = getFreshDaemon().detectInteraction(mSequentialId);
|
||||
} catch (RemoteException e) {
|
||||
|
||||
@@ -121,7 +121,7 @@ class FingerprintEnrollClient extends EnrollClient<ISession> implements Udfps {
|
||||
protected void startHalOperation() {
|
||||
UdfpsHelper.showUdfpsOverlay(getSensorId(),
|
||||
UdfpsHelper.getReasonFromEnrollReason(mEnrollReason),
|
||||
mUdfpsOverlayController);
|
||||
mUdfpsOverlayController, this);
|
||||
try {
|
||||
mCancellationSignal = getFreshDaemon().enroll(mSequentialId,
|
||||
HardwareAuthTokenUtils.toHardwareAuthToken(mHardwareAuthToken));
|
||||
|
||||
@@ -120,7 +120,7 @@ class FingerprintAuthenticationClient extends AuthenticationClient<IBiometricsFi
|
||||
@Override
|
||||
protected void startHalOperation() {
|
||||
UdfpsHelper.showUdfpsOverlay(getSensorId(), Utils.getUdfpsAuthReason(this),
|
||||
mUdfpsOverlayController);
|
||||
mUdfpsOverlayController, this);
|
||||
try {
|
||||
// GroupId was never used. In fact, groupId is always the same as userId.
|
||||
getFreshDaemon().authenticate(mOperationId, getTargetUserId());
|
||||
|
||||
@@ -85,7 +85,7 @@ class FingerprintDetectClient extends AcquisitionClient<IBiometricsFingerprint>
|
||||
protected void startHalOperation() {
|
||||
UdfpsHelper.showUdfpsOverlay(getSensorId(),
|
||||
IUdfpsOverlayController.REASON_AUTH_FPM_KEYGUARD,
|
||||
mUdfpsOverlayController);
|
||||
mUdfpsOverlayController, this);
|
||||
try {
|
||||
getFreshDaemon().authenticate(0 /* operationId */, getTargetUserId());
|
||||
} catch (RemoteException e) {
|
||||
|
||||
@@ -84,7 +84,7 @@ public class FingerprintEnrollClient extends EnrollClient<IBiometricsFingerprint
|
||||
protected void startHalOperation() {
|
||||
UdfpsHelper.showUdfpsOverlay(getSensorId(),
|
||||
UdfpsHelper.getReasonFromEnrollReason(mEnrollReason),
|
||||
mUdfpsOverlayController);
|
||||
mUdfpsOverlayController, this);
|
||||
try {
|
||||
// GroupId was never used. In fact, groupId is always the same as userId.
|
||||
getFreshDaemon().enroll(mHardwareAuthToken, getTargetUserId(), mTimeoutSec);
|
||||
|
||||
@@ -0,0 +1,118 @@
|
||||
/*
|
||||
* 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.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.ArgumentMatchers.anyBoolean;
|
||||
import static org.mockito.ArgumentMatchers.anyInt;
|
||||
import static org.mockito.ArgumentMatchers.eq;
|
||||
import static org.mockito.Mockito.never;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.verifyNoMoreInteractions;
|
||||
|
||||
import android.content.Context;
|
||||
import android.hardware.biometrics.BiometricConstants;
|
||||
import android.os.IBinder;
|
||||
import android.platform.test.annotations.Presubmit;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.test.filters.SmallTest;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.MockitoAnnotations;
|
||||
|
||||
@Presubmit
|
||||
@SmallTest
|
||||
public class AcquisitionClientTest {
|
||||
|
||||
private static final int TEST_SENSOR_ID = 100;
|
||||
|
||||
@Mock
|
||||
private Context mContext;
|
||||
@Mock
|
||||
private IBinder mToken;
|
||||
@Mock
|
||||
private ClientMonitorCallbackConverter mClientCallback;
|
||||
@Mock
|
||||
private BaseClientMonitor.Callback mSchedulerCallback;
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
MockitoAnnotations.initMocks(this);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUserCanceled() throws Exception {
|
||||
// Start an AcquisitionClient
|
||||
final TestAcquisitionClient client = new TestAcquisitionClient(mContext, Object::new,
|
||||
mToken, mClientCallback);
|
||||
client.start(mSchedulerCallback);
|
||||
assertTrue(client.mHalOperationRunning);
|
||||
verify(mSchedulerCallback).onClientStarted(eq(client));
|
||||
|
||||
// Pretend that it got canceled by the user.
|
||||
client.onUserCanceled();
|
||||
verify(mSchedulerCallback, never()).onClientFinished(any(), anyBoolean());
|
||||
verify(mClientCallback).onError(eq(TEST_SENSOR_ID),
|
||||
anyInt(),
|
||||
eq(BiometricConstants.BIOMETRIC_ERROR_USER_CANCELED),
|
||||
eq(0) /* vendorCode */);
|
||||
assertFalse(client.mHalOperationRunning);
|
||||
|
||||
// Pretend that the HAL responded with ERROR_CANCELED
|
||||
client.onError(BiometricConstants.BIOMETRIC_ERROR_CANCELED, 0 /* vendorCode */);
|
||||
verifyNoMoreInteractions(mClientCallback);
|
||||
verify(mSchedulerCallback).onClientFinished(eq(client), anyBoolean());
|
||||
}
|
||||
|
||||
private static class TestAcquisitionClient extends AcquisitionClient<Object> {
|
||||
boolean mHalOperationRunning;
|
||||
|
||||
public TestAcquisitionClient(@NonNull Context context,
|
||||
@NonNull LazyDaemon<Object> lazyDaemon, @NonNull IBinder token,
|
||||
@NonNull ClientMonitorCallbackConverter callback) {
|
||||
super(context, lazyDaemon, token, callback, 0 /* userId */, "Test", 0 /* cookie */,
|
||||
TEST_SENSOR_ID /* sensorId */, 0 /* statsModality */, 0 /* statsAction */,
|
||||
0 /* statsClient */);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void start(@NonNull Callback callback) {
|
||||
super.start(callback);
|
||||
startHalOperation();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void stopHalOperation() {
|
||||
mHalOperationRunning = false;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void startHalOperation() {
|
||||
mHalOperationRunning = true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getProtoEnum() {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user