diff options
13 files changed, 226 insertions, 20 deletions
diff --git a/core/java/android/hardware/fingerprint/IUdfpsOverlayController.aidl b/core/java/android/hardware/fingerprint/IUdfpsOverlayController.aidl index 81c7d894ee09..d2cb5bfe6910 100644 --- a/core/java/android/hardware/fingerprint/IUdfpsOverlayController.aidl +++ b/core/java/android/hardware/fingerprint/IUdfpsOverlayController.aidl @@ -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); diff --git a/core/java/android/hardware/fingerprint/IUdfpsOverlayControllerCallback.aidl b/core/java/android/hardware/fingerprint/IUdfpsOverlayControllerCallback.aidl new file mode 100644 index 000000000000..51ada29f828f --- /dev/null +++ b/core/java/android/hardware/fingerprint/IUdfpsOverlayControllerCallback.aidl @@ -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(); +} diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java index edc9b8f7478f..0ffd7d215b49 100644 --- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java +++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java @@ -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 diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsControllerTest.java index f84aa5940e61..07686181649d 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsControllerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsControllerTest.java @@ -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( diff --git a/services/core/java/com/android/server/biometrics/sensors/AcquisitionClient.java b/services/core/java/com/android/server/biometrics/sensors/AcquisitionClient.java index b3580fb79042..93fea90cd89a 100644 --- a/services/core/java/com/android/server/biometrics/sensors/AcquisitionClient.java +++ b/services/core/java/com/android/server/biometrics/sensors/AcquisitionClient.java @@ -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 diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/UdfpsHelper.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/UdfpsHelper.java index 37f8e8c2c1ee..f0e45978c365 100644 --- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/UdfpsHelper.java +++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/UdfpsHelper.java @@ -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); } diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintAuthenticationClient.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintAuthenticationClient.java index f9527d9379bc..e2743f624c37 100644 --- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintAuthenticationClient.java +++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintAuthenticationClient.java @@ -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) { diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintDetectClient.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintDetectClient.java index bcd1b8bc9976..620a9cf3e6f2 100644 --- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintDetectClient.java +++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintDetectClient.java @@ -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) { diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintEnrollClient.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintEnrollClient.java index ae64c77f1365..63fa66cdca20 100644 --- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintEnrollClient.java +++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintEnrollClient.java @@ -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)); diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/FingerprintAuthenticationClient.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/FingerprintAuthenticationClient.java index 83a3d9492b22..db371125478d 100644 --- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/FingerprintAuthenticationClient.java +++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/FingerprintAuthenticationClient.java @@ -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()); diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/FingerprintDetectClient.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/FingerprintDetectClient.java index 8acb284667c7..db44aee1c0ed 100644 --- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/FingerprintDetectClient.java +++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/FingerprintDetectClient.java @@ -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) { diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/FingerprintEnrollClient.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/FingerprintEnrollClient.java index 33db64c3259b..41d23089a530 100644 --- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/FingerprintEnrollClient.java +++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/FingerprintEnrollClient.java @@ -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); diff --git a/services/tests/servicestests/src/com/android/server/biometrics/sensors/AcquisitionClientTest.java b/services/tests/servicestests/src/com/android/server/biometrics/sensors/AcquisitionClientTest.java new file mode 100644 index 000000000000..46f96364ff9e --- /dev/null +++ b/services/tests/servicestests/src/com/android/server/biometrics/sensors/AcquisitionClientTest.java @@ -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; + } + } +} |