summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--core/java/android/hardware/biometrics/IBiometricContextListener.aidl14
-rw-r--r--packages/SystemUI/src/com/android/systemui/biometrics/AuthController.java47
-rw-r--r--packages/SystemUI/src/com/android/systemui/biometrics/dagger/BiometricsModule.kt6
-rw-r--r--packages/SystemUI/src/com/android/systemui/biometrics/domain/interactor/LogContextInteractor.kt169
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthControllerTest.java90
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/biometrics/domain/interactor/LogContextInteractorImplTest.kt198
-rw-r--r--services/core/java/com/android/server/biometrics/AuthSession.java14
-rw-r--r--services/core/java/com/android/server/biometrics/BiometricService.java2
-rw-r--r--services/core/java/com/android/server/biometrics/log/BiometricContext.java30
-rw-r--r--services/core/java/com/android/server/biometrics/log/BiometricContextProvider.java148
-rw-r--r--services/core/java/com/android/server/biometrics/log/BiometricContextSessionInfo.java59
-rw-r--r--services/core/java/com/android/server/biometrics/log/BiometricFrameworkStatsLogger.java79
-rw-r--r--services/core/java/com/android/server/biometrics/log/BiometricLogger.java26
-rw-r--r--services/core/java/com/android/server/biometrics/log/OperationContextExt.java138
-rw-r--r--services/core/java/com/android/server/biometrics/sensors/HalClientMonitor.java6
-rw-r--r--services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceAuthenticationClient.java2
-rw-r--r--services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceDetectClient.java3
-rw-r--r--services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceEnrollClient.java3
-rw-r--r--services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintAuthenticationClient.java7
-rw-r--r--services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintDetectClient.java3
-rw-r--r--services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintEnrollClient.java6
-rw-r--r--services/tests/servicestests/src/com/android/server/biometrics/AuthSessionTest.java10
-rw-r--r--services/tests/servicestests/src/com/android/server/biometrics/BiometricServiceTest.java15
-rw-r--r--services/tests/servicestests/src/com/android/server/biometrics/log/BiometricContextProviderTest.java107
-rw-r--r--services/tests/servicestests/src/com/android/server/biometrics/log/BiometricLoggerTest.java5
-rw-r--r--services/tests/servicestests/src/com/android/server/biometrics/log/OperationContextExtTest.java137
-rw-r--r--services/tests/servicestests/src/com/android/server/biometrics/sensors/face/aidl/FaceAuthenticationClientTest.java6
-rw-r--r--services/tests/servicestests/src/com/android/server/biometrics/sensors/face/aidl/FaceDetectClientTest.java7
-rw-r--r--services/tests/servicestests/src/com/android/server/biometrics/sensors/face/aidl/FaceEnrollClientTest.java6
-rw-r--r--services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintAuthenticationClientTest.java42
-rw-r--r--services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintDetectClientTest.java7
-rw-r--r--services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintEnrollClientTest.java20
32 files changed, 1120 insertions, 292 deletions
diff --git a/core/java/android/hardware/biometrics/IBiometricContextListener.aidl b/core/java/android/hardware/biometrics/IBiometricContextListener.aidl
index 2e8e763b0ee4..18979a9f78eb 100644
--- a/core/java/android/hardware/biometrics/IBiometricContextListener.aidl
+++ b/core/java/android/hardware/biometrics/IBiometricContextListener.aidl
@@ -17,7 +17,7 @@ package android.hardware.biometrics;
/**
* A secondary communication channel from AuthController back to BiometricService for
- * events that are not associated with an autentication session. See
+ * events that are not associated with an authentication session. See
* {@link IBiometricSysuiReceiver} for events associated with a session.
*
* @hide
@@ -27,4 +27,16 @@ oneway interface IBiometricContextListener {
// These may be called while the device is still transitioning to the new state
// (i.e. about to become awake or enter doze)
void onDozeChanged(boolean isDozing, boolean isAwake);
+
+ @VintfStability
+ @Backing(type="int")
+ enum FoldState {
+ UNKNOWN = 0,
+ HALF_OPENED = 1,
+ FULLY_OPENED = 2,
+ FULLY_CLOSED = 3,
+ }
+
+ // Called when the fold state of the device changes.
+ void onFoldChanged(FoldState FoldState);
}
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/AuthController.java b/packages/SystemUI/src/com/android/systemui/biometrics/AuthController.java
index d03578531a99..a0f3ecb0634b 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/AuthController.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/AuthController.java
@@ -20,9 +20,6 @@ import static android.hardware.biometrics.BiometricAuthenticator.TYPE_FACE;
import static android.hardware.biometrics.BiometricAuthenticator.TYPE_FINGERPRINT;
import static android.hardware.fingerprint.FingerprintSensorProperties.TYPE_REAR;
-import static com.android.systemui.keyguard.WakefulnessLifecycle.WAKEFULNESS_AWAKE;
-import static com.android.systemui.keyguard.WakefulnessLifecycle.WAKEFULNESS_GOING_TO_SLEEP;
-
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.app.ActivityManager;
@@ -74,6 +71,7 @@ import com.android.internal.os.SomeArgs;
import com.android.internal.widget.LockPatternUtils;
import com.android.systemui.CoreStartable;
import com.android.systemui.biometrics.domain.interactor.BiometricPromptCredentialInteractor;
+import com.android.systemui.biometrics.domain.interactor.LogContextInteractor;
import com.android.systemui.biometrics.ui.viewmodel.CredentialViewModel;
import com.android.systemui.dagger.SysUISingleton;
import com.android.systemui.dagger.qualifiers.Background;
@@ -81,7 +79,6 @@ import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.doze.DozeReceiver;
import com.android.systemui.keyguard.WakefulnessLifecycle;
import com.android.systemui.keyguard.data.repository.BiometricType;
-import com.android.systemui.plugins.statusbar.StatusBarStateController;
import com.android.systemui.statusbar.CommandQueue;
import com.android.systemui.statusbar.VibratorHelper;
import com.android.systemui.util.concurrency.DelayableExecutor;
@@ -121,7 +118,6 @@ public class AuthController implements CoreStartable, CommandQueue.Callbacks,
private final Context mContext;
private final Execution mExecution;
private final CommandQueue mCommandQueue;
- private final StatusBarStateController mStatusBarStateController;
private final ActivityTaskManager mActivityTaskManager;
@Nullable private final FingerprintManager mFingerprintManager;
@Nullable private final FaceManager mFaceManager;
@@ -131,6 +127,7 @@ public class AuthController implements CoreStartable, CommandQueue.Callbacks,
// TODO: these should be migrated out once ready
@NonNull private final Provider<BiometricPromptCredentialInteractor> mBiometricPromptInteractor;
@NonNull private final Provider<CredentialViewModel> mCredentialViewModelProvider;
+ @NonNull private final LogContextInteractor mLogContextInteractor;
private final Display mDisplay;
private float mScaleFactor = 1f;
@@ -153,7 +150,6 @@ public class AuthController implements CoreStartable, CommandQueue.Callbacks,
@Nullable private UdfpsController mUdfpsController;
@Nullable private IUdfpsRefreshRateRequestCallback mUdfpsRefreshRateRequestCallback;
@Nullable private SideFpsController mSideFpsController;
- @Nullable private IBiometricContextListener mBiometricContextListener;
@Nullable private UdfpsLogger mUdfpsLogger;
@VisibleForTesting IBiometricSysuiReceiver mReceiver;
@VisibleForTesting @NonNull final BiometricDisplayListener mOrientationListener;
@@ -728,7 +724,7 @@ public class AuthController implements CoreStartable, CommandQueue.Callbacks,
@NonNull UserManager userManager,
@NonNull LockPatternUtils lockPatternUtils,
@NonNull UdfpsLogger udfpsLogger,
- @NonNull StatusBarStateController statusBarStateController,
+ @NonNull LogContextInteractor logContextInteractor,
@NonNull Provider<BiometricPromptCredentialInteractor> biometricPromptInteractor,
@NonNull Provider<CredentialViewModel> credentialViewModelProvider,
@NonNull InteractionJankMonitor jankMonitor,
@@ -756,6 +752,7 @@ public class AuthController implements CoreStartable, CommandQueue.Callbacks,
mFaceEnrolledForUser = new SparseBooleanArray();
mVibratorHelper = vibrator;
+ mLogContextInteractor = logContextInteractor;
mBiometricPromptInteractor = biometricPromptInteractor;
mCredentialViewModelProvider = credentialViewModelProvider;
@@ -770,25 +767,6 @@ public class AuthController implements CoreStartable, CommandQueue.Callbacks,
});
mWakefulnessLifecycle = wakefulnessLifecycle;
- mWakefulnessLifecycle.addObserver(new WakefulnessLifecycle.Observer() {
- @Override
- public void onFinishedWakingUp() {
- notifyDozeChanged(mStatusBarStateController.isDozing(), WAKEFULNESS_AWAKE);
- }
-
- @Override
- public void onStartedGoingToSleep() {
- notifyDozeChanged(mStatusBarStateController.isDozing(), WAKEFULNESS_GOING_TO_SLEEP);
- }
- });
-
- mStatusBarStateController = statusBarStateController;
- mStatusBarStateController.addCallback(new StatusBarStateController.StateListener() {
- @Override
- public void onDozingChanged(boolean isDozing) {
- notifyDozeChanged(isDozing, wakefulnessLifecycle.getWakefulness());
- }
- });
mFaceProps = mFaceManager != null ? mFaceManager.getSensorPropertiesInternal() : null;
int[] faceAuthLocation = context.getResources().getIntArray(
@@ -894,21 +872,7 @@ public class AuthController implements CoreStartable, CommandQueue.Callbacks,
@Override
public void setBiometricContextListener(IBiometricContextListener listener) {
- mBiometricContextListener = listener;
- notifyDozeChanged(mStatusBarStateController.isDozing(),
- mWakefulnessLifecycle.getWakefulness());
- }
-
- private void notifyDozeChanged(boolean isDozing,
- @WakefulnessLifecycle.Wakefulness int wakefullness) {
- if (mBiometricContextListener != null) {
- try {
- final boolean isAwake = wakefullness == WAKEFULNESS_AWAKE;
- mBiometricContextListener.onDozeChanged(isDozing, isAwake);
- } catch (RemoteException e) {
- Log.w(TAG, "failed to notify initial doze state");
- }
- }
+ mLogContextInteractor.addBiometricContextListener(listener);
}
/**
@@ -1274,7 +1238,6 @@ public class AuthController implements CoreStartable, CommandQueue.Callbacks,
PromptInfo promptInfo, boolean requireConfirmation, int userId, int[] sensorIds,
String opPackageName, boolean skipIntro, long operationId, long requestId,
@BiometricMultiSensorMode int multiSensorConfig,
-
@NonNull WakefulnessLifecycle wakefulnessLifecycle,
@NonNull UserManager userManager,
@NonNull LockPatternUtils lockPatternUtils) {
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/dagger/BiometricsModule.kt b/packages/SystemUI/src/com/android/systemui/biometrics/dagger/BiometricsModule.kt
index 7c0c3b710e66..6f8efba2e84f 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/dagger/BiometricsModule.kt
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/dagger/BiometricsModule.kt
@@ -20,6 +20,8 @@ import com.android.systemui.biometrics.data.repository.PromptRepository
import com.android.systemui.biometrics.data.repository.PromptRepositoryImpl
import com.android.systemui.biometrics.domain.interactor.CredentialInteractor
import com.android.systemui.biometrics.domain.interactor.CredentialInteractorImpl
+import com.android.systemui.biometrics.domain.interactor.LogContextInteractor
+import com.android.systemui.biometrics.domain.interactor.LogContextInteractorImpl
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.util.concurrency.ThreadFactory
import dagger.Binds
@@ -40,6 +42,10 @@ interface BiometricsModule {
@SysUISingleton
fun providesCredentialInteractor(impl: CredentialInteractorImpl): CredentialInteractor
+ @Binds
+ @SysUISingleton
+ fun bindsLogContextInteractor(impl: LogContextInteractorImpl): LogContextInteractor
+
companion object {
/** Background [Executor] for HAL related operations. */
@Provides
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/domain/interactor/LogContextInteractor.kt b/packages/SystemUI/src/com/android/systemui/biometrics/domain/interactor/LogContextInteractor.kt
new file mode 100644
index 000000000000..3b53eff9dfc5
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/domain/interactor/LogContextInteractor.kt
@@ -0,0 +1,169 @@
+/*
+ * Copyright (C) 2022 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.systemui.biometrics.domain.interactor
+
+import android.hardware.biometrics.IBiometricContextListener
+import android.util.Log
+import com.android.systemui.common.coroutine.ChannelExt.trySendWithFailureLogging
+import com.android.systemui.common.coroutine.ConflatedCallbackFlow.conflatedCallbackFlow
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.dagger.qualifiers.Application
+import com.android.systemui.keyguard.WakefulnessLifecycle
+import com.android.systemui.plugins.statusbar.StatusBarStateController
+import com.android.systemui.unfold.updates.FOLD_UPDATE_FINISH_CLOSED
+import com.android.systemui.unfold.updates.FOLD_UPDATE_FINISH_FULL_OPEN
+import com.android.systemui.unfold.updates.FOLD_UPDATE_FINISH_HALF_OPEN
+import com.android.systemui.unfold.updates.FoldStateProvider
+import javax.inject.Inject
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.Job
+import kotlinx.coroutines.cancel
+import kotlinx.coroutines.channels.awaitClose
+import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.SharingStarted
+import kotlinx.coroutines.flow.catch
+import kotlinx.coroutines.flow.combine
+import kotlinx.coroutines.flow.distinctUntilChanged
+import kotlinx.coroutines.flow.launchIn
+import kotlinx.coroutines.flow.onEach
+import kotlinx.coroutines.flow.shareIn
+import kotlinx.coroutines.launch
+
+/**
+ * Aggregates UI/device state that is not directly related to biometrics, but is often useful for
+ * logging or optimization purposes (fold state, screen state, etc.)
+ */
+interface LogContextInteractor {
+
+ /** If the device is dozing. */
+ val isDozing: Flow<Boolean>
+
+ /** If the device is currently awake with the screen on. */
+ val isAwake: Flow<Boolean>
+
+ /** Current device fold state, defined as [IBiometricContextListener.FoldState]. */
+ val foldState: Flow<Int>
+
+ /**
+ * Add a permanent context listener.
+ *
+ * Use this method for registering remote context listeners. Use the properties exposed via this
+ * class directly within SysUI.
+ */
+ fun addBiometricContextListener(listener: IBiometricContextListener): Job
+}
+
+@SysUISingleton
+class LogContextInteractorImpl
+@Inject
+constructor(
+ @Application private val applicationScope: CoroutineScope,
+ private val statusBarStateController: StatusBarStateController,
+ private val wakefulnessLifecycle: WakefulnessLifecycle,
+ private val foldProvider: FoldStateProvider,
+) : LogContextInteractor {
+
+ init {
+ foldProvider.start()
+ }
+
+ override val isDozing =
+ conflatedCallbackFlow {
+ val callback =
+ object : StatusBarStateController.StateListener {
+ override fun onDozingChanged(isDozing: Boolean) {
+ trySendWithFailureLogging(isDozing, TAG)
+ }
+ }
+
+ statusBarStateController.addCallback(callback)
+ trySendWithFailureLogging(statusBarStateController.isDozing, TAG)
+ awaitClose { statusBarStateController.removeCallback(callback) }
+ }
+ .distinctUntilChanged()
+
+ override val isAwake =
+ conflatedCallbackFlow {
+ val callback =
+ object : WakefulnessLifecycle.Observer {
+ override fun onFinishedWakingUp() {
+ trySendWithFailureLogging(true, TAG)
+ }
+
+ override fun onStartedGoingToSleep() {
+ trySendWithFailureLogging(false, TAG)
+ }
+ }
+
+ wakefulnessLifecycle.addObserver(callback)
+ trySendWithFailureLogging(wakefulnessLifecycle.isAwake, TAG)
+ awaitClose { wakefulnessLifecycle.removeObserver(callback) }
+ }
+ .distinctUntilChanged()
+
+ override val foldState: Flow<Int> =
+ conflatedCallbackFlow {
+ val callback =
+ object : FoldStateProvider.FoldUpdatesListener {
+ override fun onHingeAngleUpdate(angle: Float) {}
+
+ override fun onFoldUpdate(@FoldStateProvider.FoldUpdate update: Int) {
+ val loggedState =
+ when (update) {
+ FOLD_UPDATE_FINISH_HALF_OPEN ->
+ IBiometricContextListener.FoldState.HALF_OPENED
+ FOLD_UPDATE_FINISH_FULL_OPEN ->
+ IBiometricContextListener.FoldState.FULLY_OPENED
+ FOLD_UPDATE_FINISH_CLOSED ->
+ IBiometricContextListener.FoldState.FULLY_CLOSED
+ else -> null
+ }
+ if (loggedState != null) {
+ trySendWithFailureLogging(loggedState, TAG)
+ }
+ }
+ }
+
+ foldProvider.addCallback(callback)
+ trySendWithFailureLogging(IBiometricContextListener.FoldState.UNKNOWN, TAG)
+ awaitClose { foldProvider.removeCallback(callback) }
+ }
+ .shareIn(applicationScope, started = SharingStarted.Eagerly, replay = 1)
+
+ override fun addBiometricContextListener(listener: IBiometricContextListener): Job {
+ return applicationScope.launch {
+ combine(isDozing, isAwake) { doze, awake -> doze to awake }
+ .onEach { (doze, awake) -> listener.onDozeChanged(doze, awake) }
+ .catch { t -> Log.w(TAG, "failed to notify new doze state", t) }
+ .launchIn(this)
+
+ foldState
+ .onEach { state -> listener.onFoldChanged(state) }
+ .catch { t -> Log.w(TAG, "failed to notify new fold state", t) }
+ .launchIn(this)
+
+ listener.asBinder().linkToDeath({ cancel() }, 0)
+ }
+ }
+
+ companion object {
+ private const val TAG = "ContextRepositoryImpl"
+ }
+}
+
+private val WakefulnessLifecycle.isAwake: Boolean
+ get() = wakefulness == WakefulnessLifecycle.WAKEFULNESS_AWAKE
diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthControllerTest.java
index 30dc9c911876..67b293f44cf4 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthControllerTest.java
@@ -20,8 +20,6 @@ import static android.hardware.biometrics.BiometricAuthenticator.TYPE_FINGERPRIN
import static android.hardware.biometrics.BiometricManager.Authenticators;
import static android.hardware.biometrics.BiometricManager.BIOMETRIC_MULTI_SENSOR_FINGERPRINT_AND_FACE;
-import static com.android.systemui.keyguard.WakefulnessLifecycle.WAKEFULNESS_AWAKE;
-
import static com.google.common.truth.Truth.assertThat;
import static junit.framework.Assert.assertEquals;
@@ -35,12 +33,11 @@ import static org.mockito.ArgumentMatchers.anyLong;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.doAnswer;
-import static org.mockito.Mockito.inOrder;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.reset;
+import static org.mockito.Mockito.same;
import static org.mockito.Mockito.spy;
-import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
@@ -90,9 +87,9 @@ import com.android.internal.jank.InteractionJankMonitor;
import com.android.internal.widget.LockPatternUtils;
import com.android.systemui.SysuiTestCase;
import com.android.systemui.biometrics.domain.interactor.BiometricPromptCredentialInteractor;
+import com.android.systemui.biometrics.domain.interactor.LogContextInteractor;
import com.android.systemui.biometrics.ui.viewmodel.CredentialViewModel;
import com.android.systemui.keyguard.WakefulnessLifecycle;
-import com.android.systemui.plugins.statusbar.StatusBarStateController;
import com.android.systemui.statusbar.CommandQueue;
import com.android.systemui.statusbar.VibratorHelper;
import com.android.systemui.util.concurrency.DelayableExecutor;
@@ -108,7 +105,6 @@ import org.junit.runner.RunWith;
import org.mockito.AdditionalMatchers;
import org.mockito.ArgumentCaptor;
import org.mockito.Captor;
-import org.mockito.InOrder;
import org.mockito.Mock;
import org.mockito.junit.MockitoJUnit;
import org.mockito.junit.MockitoRule;
@@ -117,8 +113,6 @@ import java.util.ArrayList;
import java.util.List;
import java.util.Random;
-import javax.inject.Provider;
-
@RunWith(AndroidTestingRunner.class)
@RunWithLooper
@SmallTest
@@ -162,7 +156,7 @@ public class AuthControllerTest extends SysuiTestCase {
@Mock
private LockPatternUtils mLockPatternUtils;
@Mock
- private StatusBarStateController mStatusBarStateController;
+ private LogContextInteractor mLogContextInteractor;
@Mock
private UdfpsLogger mUdfpsLogger;
@Mock
@@ -178,10 +172,6 @@ public class AuthControllerTest extends SysuiTestCase {
private ArgumentCaptor<IFaceAuthenticatorsRegisteredCallback> mFaceAuthenticatorsRegisteredCaptor;
@Captor
private ArgumentCaptor<BiometricStateListener> mBiometricStateCaptor;
- @Captor
- private ArgumentCaptor<StatusBarStateController.StateListener> mStatusBarStateListenerCaptor;
- @Captor
- private ArgumentCaptor<WakefulnessLifecycle.Observer> mWakefullnessObserverCaptor;
private TestableContext mContextSpy;
private Execution mExecution;
@@ -253,10 +243,7 @@ public class AuthControllerTest extends SysuiTestCase {
when(mFaceManager.getSensorPropertiesInternal()).thenReturn(faceProps);
when(mVibratorHelper.hasVibrator()).thenReturn(true);
- mAuthController = new TestableAuthController(mContextSpy, mExecution, mCommandQueue,
- mActivityTaskManager, mWindowManager, mFingerprintManager, mFaceManager,
- () -> mUdfpsController, () -> mSideFpsController, mStatusBarStateController,
- mVibratorHelper);
+ mAuthController = new TestableAuthController(mContextSpy);
mAuthController.start();
verify(mFingerprintManager).addAuthenticatorsRegisteredCallback(
@@ -264,11 +251,6 @@ public class AuthControllerTest extends SysuiTestCase {
verify(mFaceManager).addAuthenticatorsRegisteredCallback(
mFaceAuthenticatorsRegisteredCaptor.capture());
- when(mStatusBarStateController.isDozing()).thenReturn(false);
- when(mWakefulnessLifecycle.getWakefulness()).thenReturn(WAKEFULNESS_AWAKE);
- verify(mStatusBarStateController).addCallback(mStatusBarStateListenerCaptor.capture());
- verify(mWakefulnessLifecycle).addObserver(mWakefullnessObserverCaptor.capture());
-
mFpAuthenticatorsRegisteredCaptor.getValue().onAllAuthenticatorsRegistered(fpProps);
mFaceAuthenticatorsRegisteredCaptor.getValue().onAllAuthenticatorsRegistered(faceProps);
@@ -286,10 +268,7 @@ public class AuthControllerTest extends SysuiTestCase {
reset(mFaceManager);
// This test requires an uninitialized AuthController.
- AuthController authController = new TestableAuthController(mContextSpy, mExecution,
- mCommandQueue, mActivityTaskManager, mWindowManager, mFingerprintManager,
- mFaceManager, () -> mUdfpsController, () -> mSideFpsController,
- mStatusBarStateController, mVibratorHelper);
+ AuthController authController = new TestableAuthController(mContextSpy);
authController.start();
verify(mFingerprintManager).addAuthenticatorsRegisteredCallback(
@@ -316,10 +295,7 @@ public class AuthControllerTest extends SysuiTestCase {
reset(mFaceManager);
// This test requires an uninitialized AuthController.
- AuthController authController = new TestableAuthController(mContextSpy, mExecution,
- mCommandQueue, mActivityTaskManager, mWindowManager, mFingerprintManager,
- mFaceManager, () -> mUdfpsController, () -> mSideFpsController,
- mStatusBarStateController, mVibratorHelper);
+ AuthController authController = new TestableAuthController(mContextSpy);
authController.start();
verify(mFingerprintManager).addAuthenticatorsRegisteredCallback(
@@ -809,37 +785,9 @@ public class AuthControllerTest extends SysuiTestCase {
}
@Test
- public void testForwardsDozeEvents() throws RemoteException {
- when(mStatusBarStateController.isDozing()).thenReturn(true);
- when(mWakefulnessLifecycle.getWakefulness()).thenReturn(WAKEFULNESS_AWAKE);
- mAuthController.setBiometricContextListener(mContextListener);
-
- mStatusBarStateListenerCaptor.getValue().onDozingChanged(true);
- mStatusBarStateListenerCaptor.getValue().onDozingChanged(false);
-
- InOrder order = inOrder(mContextListener);
- order.verify(mContextListener, times(2)).onDozeChanged(eq(true), eq(true));
- order.verify(mContextListener).onDozeChanged(eq(false), eq(true));
- order.verifyNoMoreInteractions();
- }
-
- @Test
- public void testForwardsWakeEvents() throws RemoteException {
- when(mStatusBarStateController.isDozing()).thenReturn(false);
- when(mWakefulnessLifecycle.getWakefulness()).thenReturn(WAKEFULNESS_AWAKE);
+ public void testSubscribesToLogContext() {
mAuthController.setBiometricContextListener(mContextListener);
-
- mWakefullnessObserverCaptor.getValue().onStartedGoingToSleep();
- mWakefullnessObserverCaptor.getValue().onFinishedGoingToSleep();
- mWakefullnessObserverCaptor.getValue().onStartedWakingUp();
- mWakefullnessObserverCaptor.getValue().onFinishedWakingUp();
- mWakefullnessObserverCaptor.getValue().onPostFinishedWakingUp();
-
- InOrder order = inOrder(mContextListener);
- order.verify(mContextListener).onDozeChanged(eq(false), eq(true));
- order.verify(mContextListener).onDozeChanged(eq(false), eq(false));
- order.verify(mContextListener).onDozeChanged(eq(false), eq(true));
- order.verifyNoMoreInteractions();
+ verify(mLogContextInteractor).addBiometricContextListener(same(mContextListener));
}
@Test
@@ -1001,23 +949,13 @@ public class AuthControllerTest extends SysuiTestCase {
private int mBuildCount = 0;
private PromptInfo mLastBiometricPromptInfo;
- TestableAuthController(Context context,
- Execution execution,
- CommandQueue commandQueue,
- ActivityTaskManager activityTaskManager,
- WindowManager windowManager,
- FingerprintManager fingerprintManager,
- FaceManager faceManager,
- Provider<UdfpsController> udfpsControllerFactory,
- Provider<SideFpsController> sidefpsControllerFactory,
- StatusBarStateController statusBarStateController,
- VibratorHelper vibratorHelper) {
- super(context, execution, commandQueue, activityTaskManager, windowManager,
- fingerprintManager, faceManager, udfpsControllerFactory,
- sidefpsControllerFactory, mDisplayManager, mWakefulnessLifecycle,
- mUserManager, mLockPatternUtils, mUdfpsLogger, statusBarStateController,
+ TestableAuthController(Context context) {
+ super(context, mExecution, mCommandQueue, mActivityTaskManager, mWindowManager,
+ mFingerprintManager, mFaceManager, () -> mUdfpsController,
+ () -> mSideFpsController, mDisplayManager, mWakefulnessLifecycle,
+ mUserManager, mLockPatternUtils, mUdfpsLogger, mLogContextInteractor,
() -> mBiometricPromptCredentialInteractor, () -> mCredentialViewModel,
- mInteractionJankMonitor, mHandler, mBackgroundExecutor, vibratorHelper);
+ mInteractionJankMonitor, mHandler, mBackgroundExecutor, mVibratorHelper);
}
@Override
diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/domain/interactor/LogContextInteractorImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/biometrics/domain/interactor/LogContextInteractorImplTest.kt
new file mode 100644
index 000000000000..3eb82a7d69bb
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/domain/interactor/LogContextInteractorImplTest.kt
@@ -0,0 +1,198 @@
+package com.android.systemui.biometrics.domain.interactor
+
+import android.hardware.biometrics.IBiometricContextListener
+import android.hardware.biometrics.IBiometricContextListener.FoldState
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.coroutines.collectLastValue
+import com.android.systemui.keyguard.WakefulnessLifecycle
+import com.android.systemui.plugins.statusbar.StatusBarStateController
+import com.android.systemui.unfold.updates.FOLD_UPDATE_FINISH_CLOSED
+import com.android.systemui.unfold.updates.FOLD_UPDATE_FINISH_FULL_OPEN
+import com.android.systemui.unfold.updates.FOLD_UPDATE_FINISH_HALF_OPEN
+import com.android.systemui.unfold.updates.FOLD_UPDATE_START_CLOSING
+import com.android.systemui.unfold.updates.FOLD_UPDATE_START_OPENING
+import com.android.systemui.unfold.updates.FoldStateProvider
+import com.android.systemui.util.mockito.whenever
+import com.android.systemui.util.mockito.withArgCaptor
+import com.google.common.truth.Truth.assertThat
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.test.TestScope
+import kotlinx.coroutines.test.runCurrent
+import kotlinx.coroutines.test.runTest
+import org.junit.Before
+import org.junit.Rule
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.JUnit4
+import org.mockito.Mock
+import org.mockito.Mockito.verify
+import org.mockito.junit.MockitoJUnit
+
+@OptIn(ExperimentalCoroutinesApi::class)
+@SmallTest
+@RunWith(JUnit4::class)
+class LogContextInteractorImplTest : SysuiTestCase() {
+
+ @JvmField @Rule var mockitoRule = MockitoJUnit.rule()
+
+ private val testScope = TestScope()
+
+ @Mock private lateinit var statusBarStateController: StatusBarStateController
+ @Mock private lateinit var wakefulnessLifecycle: WakefulnessLifecycle
+ @Mock private lateinit var foldProvider: FoldStateProvider
+
+ private lateinit var interactor: LogContextInteractorImpl
+
+ @Before
+ fun setup() {
+ interactor =
+ LogContextInteractorImpl(
+ testScope.backgroundScope,
+ statusBarStateController,
+ wakefulnessLifecycle,
+ foldProvider
+ )
+ }
+
+ @Test
+ fun isDozingChanges() =
+ testScope.runTest {
+ whenever(statusBarStateController.isDozing).thenReturn(true)
+
+ val isDozing = collectLastValue(interactor.isDozing)
+ runCurrent()
+ val listener = statusBarStateController.captureListener()
+
+ assertThat(isDozing()).isTrue()
+
+ listener.onDozingChanged(true)
+ listener.onDozingChanged(true)
+ listener.onDozingChanged(false)
+
+ assertThat(isDozing()).isFalse()
+ }
+
+ @Test
+ fun isAwakeChanges() =
+ testScope.runTest {
+ whenever(wakefulnessLifecycle.wakefulness)
+ .thenReturn(WakefulnessLifecycle.WAKEFULNESS_AWAKE)
+
+ val isAwake = collectLastValue(interactor.isAwake)
+ runCurrent()
+ val listener = wakefulnessLifecycle.captureObserver()
+
+ assertThat(isAwake()).isTrue()
+
+ listener.onStartedGoingToSleep()
+ listener.onFinishedGoingToSleep()
+ listener.onStartedWakingUp()
+
+ assertThat(isAwake()).isFalse()
+
+ listener.onFinishedWakingUp()
+ listener.onPostFinishedWakingUp()
+
+ assertThat(isAwake()).isTrue()
+ }
+
+ @Test
+ fun foldStateChanges() =
+ testScope.runTest {
+ val foldState = collectLastValue(interactor.foldState)
+ runCurrent()
+ val listener = foldProvider.captureListener()
+
+ listener.onFoldUpdate(FOLD_UPDATE_START_OPENING)
+ assertThat(foldState()).isEqualTo(FoldState.UNKNOWN)
+
+ listener.onFoldUpdate(FOLD_UPDATE_FINISH_HALF_OPEN)
+ assertThat(foldState()).isEqualTo(FoldState.HALF_OPENED)
+
+ listener.onFoldUpdate(FOLD_UPDATE_FINISH_FULL_OPEN)
+ assertThat(foldState()).isEqualTo(FoldState.FULLY_OPENED)
+
+ listener.onFoldUpdate(FOLD_UPDATE_START_CLOSING)
+ assertThat(foldState()).isEqualTo(FoldState.FULLY_OPENED)
+
+ listener.onFoldUpdate(FOLD_UPDATE_FINISH_CLOSED)
+ assertThat(foldState()).isEqualTo(FoldState.FULLY_CLOSED)
+ }
+
+ @Test
+ fun contextSubscriberChanges() =
+ testScope.runTest {
+ whenever(statusBarStateController.isDozing).thenReturn(false)
+ whenever(wakefulnessLifecycle.wakefulness)
+ .thenReturn(WakefulnessLifecycle.WAKEFULNESS_AWAKE)
+ runCurrent()
+
+ val foldListener = foldProvider.captureListener()
+ foldListener.onFoldUpdate(FOLD_UPDATE_START_CLOSING)
+ foldListener.onFoldUpdate(FOLD_UPDATE_FINISH_CLOSED)
+
+ var dozing: Boolean? = null
+ var awake: Boolean? = null
+ var folded: Int? = null
+ val job =
+ interactor.addBiometricContextListener(
+ object : IBiometricContextListener.Stub() {
+ override fun onDozeChanged(isDozing: Boolean, isAwake: Boolean) {
+ dozing = isDozing
+ awake = isAwake
+ }
+
+ override fun onFoldChanged(foldState: Int) {
+ folded = foldState
+ }
+ }
+ )
+ runCurrent()
+
+ val statusBarStateListener = statusBarStateController.captureListener()
+ val wakefullnessObserver = wakefulnessLifecycle.captureObserver()
+
+ assertThat(dozing).isFalse()
+ assertThat(awake).isTrue()
+ assertThat(folded).isEqualTo(FoldState.FULLY_CLOSED)
+
+ statusBarStateListener.onDozingChanged(true)
+ wakefullnessObserver.onStartedGoingToSleep()
+ foldListener.onFoldUpdate(FOLD_UPDATE_START_OPENING)
+ foldListener.onFoldUpdate(FOLD_UPDATE_FINISH_HALF_OPEN)
+ wakefullnessObserver.onFinishedGoingToSleep()
+ runCurrent()
+
+ assertThat(dozing).isTrue()
+ assertThat(awake).isFalse()
+ assertThat(folded).isEqualTo(FoldState.HALF_OPENED)
+
+ job.cancel()
+
+ // stale updates should be ignored
+ statusBarStateListener.onDozingChanged(false)
+ wakefullnessObserver.onFinishedWakingUp()
+ foldListener.onFoldUpdate(FOLD_UPDATE_FINISH_FULL_OPEN)
+ runCurrent()
+
+ assertThat(dozing).isTrue()
+ assertThat(awake).isFalse()
+ assertThat(folded).isEqualTo(FoldState.HALF_OPENED)
+ }
+}
+
+private fun StatusBarStateController.captureListener() =
+ withArgCaptor<StatusBarStateController.StateListener> {
+ verify(this@captureListener).addCallback(capture())
+ }
+
+private fun WakefulnessLifecycle.captureObserver() =
+ withArgCaptor<WakefulnessLifecycle.Observer> {
+ verify(this@captureObserver).addObserver(capture())
+ }
+
+private fun FoldStateProvider.captureListener() =
+ withArgCaptor<FoldStateProvider.FoldUpdatesListener> {
+ verify(this@captureListener).addCallback(capture())
+ }
diff --git a/services/core/java/com/android/server/biometrics/AuthSession.java b/services/core/java/com/android/server/biometrics/AuthSession.java
index 41ca13f5d5f5..7c8e6df4acdc 100644
--- a/services/core/java/com/android/server/biometrics/AuthSession.java
+++ b/services/core/java/com/android/server/biometrics/AuthSession.java
@@ -49,7 +49,6 @@ import android.hardware.biometrics.IBiometricSensorReceiver;
import android.hardware.biometrics.IBiometricServiceReceiver;
import android.hardware.biometrics.IBiometricSysuiReceiver;
import android.hardware.biometrics.PromptInfo;
-import android.hardware.biometrics.common.OperationContext;
import android.hardware.face.FaceManager;
import android.hardware.fingerprint.FingerprintManager;
import android.hardware.fingerprint.FingerprintSensorPropertiesInternal;
@@ -61,7 +60,9 @@ import android.util.Slog;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.statusbar.IStatusBarService;
import com.android.internal.util.FrameworkStatsLog;
+import com.android.server.biometrics.log.BiometricContext;
import com.android.server.biometrics.log.BiometricFrameworkStatsLogger;
+import com.android.server.biometrics.log.OperationContextExt;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
@@ -106,6 +107,7 @@ public final class AuthSession implements IBinder.DeathRecipient {
}
private final Context mContext;
+ @NonNull private final BiometricContext mBiometricContext;
private final IStatusBarService mStatusBarService;
@VisibleForTesting final IBiometricSysuiReceiver mSysuiReceiver;
private final KeyStore mKeyStore;
@@ -148,6 +150,7 @@ public final class AuthSession implements IBinder.DeathRecipient {
private long mAuthenticatedTimeMs;
AuthSession(@NonNull Context context,
+ @NonNull BiometricContext biometricContext,
@NonNull IStatusBarService statusBarService,
@NonNull IBiometricSysuiReceiver sysuiReceiver,
@NonNull KeyStore keystore,
@@ -166,6 +169,7 @@ public final class AuthSession implements IBinder.DeathRecipient {
@NonNull List<FingerprintSensorPropertiesInternal> fingerprintSensorProperties) {
Slog.d(TAG, "Creating AuthSession with: " + preAuthInfo);
mContext = context;
+ mBiometricContext = biometricContext;
mStatusBarService = statusBarService;
mSysuiReceiver = sysuiReceiver;
mKeyStore = keystore;
@@ -694,10 +698,8 @@ public final class AuthSession implements IBinder.DeathRecipient {
+ ", Latency: " + latency);
}
- final OperationContext operationContext = new OperationContext();
- operationContext.isCrypto = isCrypto();
BiometricFrameworkStatsLogger.getInstance().authenticate(
- operationContext,
+ mBiometricContext.updateContext(new OperationContextExt(), isCrypto()),
statsModality(),
BiometricsProtoEnums.ACTION_UNKNOWN,
BiometricsProtoEnums.CLIENT_BIOMETRIC_PROMPT,
@@ -726,10 +728,8 @@ public final class AuthSession implements IBinder.DeathRecipient {
+ ", Latency: " + latency);
}
// Auth canceled
- final OperationContext operationContext = new OperationContext();
- operationContext.isCrypto = isCrypto();
BiometricFrameworkStatsLogger.getInstance().error(
- operationContext,
+ mBiometricContext.updateContext(new OperationContextExt(), isCrypto()),
statsModality(),
BiometricsProtoEnums.ACTION_AUTHENTICATE,
BiometricsProtoEnums.CLIENT_BIOMETRIC_PROMPT,
diff --git a/services/core/java/com/android/server/biometrics/BiometricService.java b/services/core/java/com/android/server/biometrics/BiometricService.java
index d97195383778..c8d43e4c40c6 100644
--- a/services/core/java/com/android/server/biometrics/BiometricService.java
+++ b/services/core/java/com/android/server/biometrics/BiometricService.java
@@ -1314,7 +1314,7 @@ public class BiometricService extends SystemService {
}
final boolean debugEnabled = mInjector.isDebugEnabled(getContext(), userId);
- mAuthSession = new AuthSession(getContext(), mStatusBarService,
+ mAuthSession = new AuthSession(getContext(), mBiometricContext, mStatusBarService,
createSysuiReceiver(requestId), mKeyStore, mRandom,
createClientDeathReceiver(requestId), preAuthInfo, token, requestId,
operationId, userId, createBiometricSensorReceiver(requestId), receiver,
diff --git a/services/core/java/com/android/server/biometrics/log/BiometricContext.java b/services/core/java/com/android/server/biometrics/log/BiometricContext.java
index be04364dcff3..9199acb0db82 100644
--- a/services/core/java/com/android/server/biometrics/log/BiometricContext.java
+++ b/services/core/java/com/android/server/biometrics/log/BiometricContext.java
@@ -20,6 +20,7 @@ import android.annotation.NonNull;
import android.annotation.Nullable;
import android.content.Context;
import android.hardware.biometrics.common.OperationContext;
+import android.view.Surface;
import com.android.server.biometrics.sensors.AuthSessionCoordinator;
@@ -38,14 +39,14 @@ public interface BiometricContext {
}
/** Update the given context with the most recent values and return it. */
- OperationContext updateContext(@NonNull OperationContext operationContext,
+ OperationContextExt updateContext(@NonNull OperationContextExt operationContext,
boolean isCryptoOperation);
/** The session id for keyguard entry, if active, or null. */
- @Nullable Integer getKeyguardEntrySessionId();
+ @Nullable BiometricContextSessionInfo getKeyguardEntrySessionInfo();
/** The session id for biometric prompt usage, if active, or null. */
- @Nullable Integer getBiometricPromptSessionId();
+ @Nullable BiometricContextSessionInfo getBiometricPromptSessionInfo();
/** If the display is in AOD. */
boolean isAod();
@@ -53,16 +54,35 @@ public interface BiometricContext {
/** If the device is awake or is becoming awake. */
boolean isAwake();
+ /** If the display is on. */
+ boolean isDisplayOn();
+
+ /** Current dock state from {@link android.content.Intent#EXTRA_DOCK_STATE}. */
+ int getDockedState();
+
+ /**
+ * Current fold state from
+ * {@link android.hardware.biometrics.IBiometricContextListener.FoldState}.
+ */
+ int getFoldState();
+
+ /** Current device display rotation. */
+ @Surface.Rotation
+ int getCurrentRotation();
+
/**
* Subscribe to context changes.
*
+ * Note that this method only notifies for properties that are visible to the HAL.
+ *
* @param context context that will be modified when changed
* @param consumer callback when the context is modified
*/
- void subscribe(@NonNull OperationContext context, @NonNull Consumer<OperationContext> consumer);
+ void subscribe(@NonNull OperationContextExt context,
+ @NonNull Consumer<OperationContext> consumer);
/** Unsubscribe from context changes. */
- void unsubscribe(@NonNull OperationContext context);
+ void unsubscribe(@NonNull OperationContextExt context);
/** Obtains an AuthSessionCoordinator. */
AuthSessionCoordinator getAuthSessionCoordinator();
diff --git a/services/core/java/com/android/server/biometrics/log/BiometricContextProvider.java b/services/core/java/com/android/server/biometrics/log/BiometricContextProvider.java
index d456736e7e8b..b63e8e31f73f 100644
--- a/services/core/java/com/android/server/biometrics/log/BiometricContextProvider.java
+++ b/services/core/java/com/android/server/biometrics/log/BiometricContextProvider.java
@@ -19,10 +19,12 @@ package com.android.server.biometrics.log;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.app.StatusBarManager;
+import android.content.BroadcastReceiver;
import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
import android.hardware.biometrics.IBiometricContextListener;
import android.hardware.biometrics.common.OperationContext;
-import android.hardware.biometrics.common.OperationReason;
import android.hardware.display.AmbientDisplayConfiguration;
import android.os.Handler;
import android.os.RemoteException;
@@ -30,6 +32,8 @@ import android.os.ServiceManager;
import android.os.ServiceManager.ServiceNotFoundException;
import android.os.UserHandle;
import android.util.Slog;
+import android.view.Display;
+import android.view.WindowManager;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.logging.InstanceId;
@@ -42,7 +46,9 @@ import java.util.concurrent.ConcurrentHashMap;
import java.util.function.Consumer;
/**
- * A default provider for {@link BiometricContext}.
+ * A default provider for {@link BiometricContext} that aggregates device state from SysUI
+ * and packages it into an {@link android.hardware.biometrics.common.OperationContext} that can
+ * be propagated to the HAL.
*/
public final class BiometricContextProvider implements BiometricContext {
@@ -57,7 +63,8 @@ public final class BiometricContextProvider implements BiometricContext {
synchronized (BiometricContextProvider.class) {
if (sInstance == null) {
try {
- sInstance = new BiometricContextProvider(
+ sInstance = new BiometricContextProvider(context,
+ (WindowManager) context.getSystemService(Context.WINDOW_SERVICE),
new AmbientDisplayConfiguration(context),
IStatusBarService.Stub.asInterface(ServiceManager.getServiceOrThrow(
Context.STATUS_BAR_SERVICE)), null /* handler */,
@@ -71,24 +78,47 @@ public final class BiometricContextProvider implements BiometricContext {
}
@NonNull
- private final Map<OperationContext, Consumer<OperationContext>> mSubscribers =
+ private final Map<OperationContextExt, Consumer<OperationContext>> mSubscribers =
new ConcurrentHashMap<>();
@Nullable
- private final Map<Integer, InstanceId> mSession = new ConcurrentHashMap<>();
+ private final Map<Integer, BiometricContextSessionInfo> mSession = new ConcurrentHashMap<>();
private final AmbientDisplayConfiguration mAmbientDisplayConfiguration;
private final AuthSessionCoordinator mAuthSessionCoordinator;
+ private final WindowManager mWindowManager;
+ @Nullable private final Handler mHandler;
private boolean mIsAod = false;
private boolean mIsAwake = false;
+ private int mDockState = Intent.EXTRA_DOCK_STATE_UNDOCKED;
+ private int mFoldState = IBiometricContextListener.FoldState.UNKNOWN;
@VisibleForTesting
- public BiometricContextProvider(
+ final BroadcastReceiver mDockStateReceiver = new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ mDockState = intent.getIntExtra(Intent.EXTRA_DOCK_STATE,
+ Intent.EXTRA_DOCK_STATE_UNDOCKED);
+ // no need to notify, not sent to HAL
+ }
+ };
+
+ @VisibleForTesting
+ public BiometricContextProvider(@NonNull Context context,
+ @NonNull WindowManager windowManager,
@NonNull AmbientDisplayConfiguration ambientDisplayConfiguration,
@NonNull IStatusBarService service, @Nullable Handler handler,
- AuthSessionCoordinator authSessionCoordinator) {
+ @NonNull AuthSessionCoordinator authSessionCoordinator) {
+ mWindowManager = windowManager;
mAmbientDisplayConfiguration = ambientDisplayConfiguration;
mAuthSessionCoordinator = authSessionCoordinator;
+ mHandler = handler;
+
+ subscribeBiometricContextListener(service);
+ subscribeDockState(context);
+ }
+
+ private void subscribeBiometricContextListener(@NonNull IStatusBarService service) {
try {
service.setBiometicContextListener(new IBiometricContextListener.Stub() {
@Override
@@ -102,12 +132,10 @@ public final class BiometricContextProvider implements BiometricContext {
}
}
- private void notifyChanged() {
- if (handler != null) {
- handler.post(() -> notifySubscribers());
- } else {
- notifySubscribers();
- }
+ @Override
+ public void onFoldChanged(int foldState) {
+ mFoldState = foldState;
+ // no need to notify, not sent to HAL
}
private boolean isAodEnabled() {
@@ -117,13 +145,13 @@ public final class BiometricContextProvider implements BiometricContext {
service.registerSessionListener(SESSION_TYPES, new ISessionListener.Stub() {
@Override
public void onSessionStarted(int sessionType, InstanceId instance) {
- mSession.put(sessionType, instance);
+ mSession.put(sessionType, new BiometricContextSessionInfo(instance));
}
@Override
public void onSessionEnded(int sessionType, InstanceId instance) {
- final InstanceId id = mSession.remove(sessionType);
- if (id != null && instance != null && id.getId() != instance.getId()) {
+ final BiometricContextSessionInfo info = mSession.remove(sessionType);
+ if (info != null && instance != null && info.getId() != instance.getId()) {
Slog.w(TAG, "session id mismatch");
}
}
@@ -133,46 +161,28 @@ public final class BiometricContextProvider implements BiometricContext {
}
}
+ private void subscribeDockState(@NonNull Context context) {
+ final IntentFilter filter = new IntentFilter();
+ filter.addAction(Intent.ACTION_DOCK_EVENT);
+ context.registerReceiver(mDockStateReceiver, filter);
+ }
+
@Override
- public OperationContext updateContext(@NonNull OperationContext operationContext,
+ public OperationContextExt updateContext(@NonNull OperationContextExt operationContext,
boolean isCryptoOperation) {
- operationContext.isAod = isAod();
- operationContext.isCrypto = isCryptoOperation;
- setFirstSessionId(operationContext);
- return operationContext;
- }
-
- private void setFirstSessionId(@NonNull OperationContext operationContext) {
- Integer sessionId = getKeyguardEntrySessionId();
- if (sessionId != null) {
- operationContext.id = sessionId;
- operationContext.reason = OperationReason.KEYGUARD;
- return;
- }
-
- sessionId = getBiometricPromptSessionId();
- if (sessionId != null) {
- operationContext.id = sessionId;
- operationContext.reason = OperationReason.BIOMETRIC_PROMPT;
- return;
- }
-
- operationContext.id = 0;
- operationContext.reason = OperationReason.UNKNOWN;
+ return operationContext.update(this);
}
@Nullable
@Override
- public Integer getKeyguardEntrySessionId() {
- final InstanceId id = mSession.get(StatusBarManager.SESSION_KEYGUARD);
- return id != null ? id.getId() : null;
+ public BiometricContextSessionInfo getKeyguardEntrySessionInfo() {
+ return mSession.get(StatusBarManager.SESSION_KEYGUARD);
}
@Nullable
@Override
- public Integer getBiometricPromptSessionId() {
- final InstanceId id = mSession.get(StatusBarManager.SESSION_BIOMETRIC_PROMPT);
- return id != null ? id.getId() : null;
+ public BiometricContextSessionInfo getBiometricPromptSessionInfo() {
+ return mSession.get(StatusBarManager.SESSION_BIOMETRIC_PROMPT);
}
@Override
@@ -186,13 +196,33 @@ public final class BiometricContextProvider implements BiometricContext {
}
@Override
- public void subscribe(@NonNull OperationContext context,
+ public boolean isDisplayOn() {
+ return mWindowManager.getDefaultDisplay().getState() == Display.STATE_ON;
+ }
+
+ @Override
+ public int getDockedState() {
+ return mDockState;
+ }
+
+ @Override
+ public int getFoldState() {
+ return mFoldState;
+ }
+
+ @Override
+ public int getCurrentRotation() {
+ return mWindowManager.getDefaultDisplay().getRotation();
+ }
+
+ @Override
+ public void subscribe(@NonNull OperationContextExt context,
@NonNull Consumer<OperationContext> consumer) {
mSubscribers.put(context, consumer);
}
@Override
- public void unsubscribe(@NonNull OperationContext context) {
+ public void unsubscribe(@NonNull OperationContextExt context) {
mSubscribers.remove(context);
}
@@ -201,10 +231,28 @@ public final class BiometricContextProvider implements BiometricContext {
return mAuthSessionCoordinator;
}
+ private void notifyChanged() {
+ if (mHandler != null) {
+ mHandler.post(this::notifySubscribers);
+ } else {
+ notifySubscribers();
+ }
+ }
+
private void notifySubscribers() {
mSubscribers.forEach((context, consumer) -> {
- context.isAod = isAod();
- consumer.accept(context);
+ consumer.accept(context.update(this).toAidlContext());
});
}
+
+ @Override
+ public String toString() {
+ return "[keyguard session: " + getKeyguardEntrySessionInfo() + ", "
+ + "bp session: " + getBiometricPromptSessionInfo() + ", "
+ + "isAod: " + isAod() + ", "
+ + "isAwake: " + isAwake() + ", "
+ + "isDisplayOn: " + isDisplayOn() + ", "
+ + "dock: " + getDockedState() + ", "
+ + "rotation: " + getCurrentRotation() + "]";
+ }
}
diff --git a/services/core/java/com/android/server/biometrics/log/BiometricContextSessionInfo.java b/services/core/java/com/android/server/biometrics/log/BiometricContextSessionInfo.java
new file mode 100644
index 000000000000..70f589766c7c
--- /dev/null
+++ b/services/core/java/com/android/server/biometrics/log/BiometricContextSessionInfo.java
@@ -0,0 +1,59 @@
+/*
+ * Copyright (C) 2022 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.log;
+
+import android.annotation.NonNull;
+
+import com.android.internal.logging.InstanceId;
+
+import java.util.concurrent.atomic.AtomicInteger;
+
+/** State for an authentication session {@see com.android.internal.statusbar.ISessionListener}. */
+class BiometricContextSessionInfo {
+ private final InstanceId mId;
+ private final AtomicInteger mOrder = new AtomicInteger(0);
+
+ /** Wrap a session id with the initial state. */
+ BiometricContextSessionInfo(@NonNull InstanceId id) {
+ mId = id;
+ }
+
+ /** Get the session id. */
+ public int getId() {
+ return mId.getId();
+ }
+
+ /** Gets the current order counter for the session. */
+ public int getOrder() {
+ return mOrder.get();
+ }
+
+ /**
+ * Gets the current order counter for the session and increment the counter.
+ *
+ * This should be called by the framework after processing any logged events,
+ * such as success / failure, to preserve the order each event was processed in.
+ */
+ public int getOrderAndIncrement() {
+ return mOrder.getAndIncrement();
+ }
+
+ @Override
+ public String toString() {
+ return "[sid: " + mId.getId() + "]";
+ }
+}
diff --git a/services/core/java/com/android/server/biometrics/log/BiometricFrameworkStatsLogger.java b/services/core/java/com/android/server/biometrics/log/BiometricFrameworkStatsLogger.java
index 27a70c51f667..82444f0cc299 100644
--- a/services/core/java/com/android/server/biometrics/log/BiometricFrameworkStatsLogger.java
+++ b/services/core/java/com/android/server/biometrics/log/BiometricFrameworkStatsLogger.java
@@ -17,9 +17,10 @@
package com.android.server.biometrics.log;
import android.hardware.biometrics.BiometricsProtoEnums;
-import android.hardware.biometrics.common.OperationContext;
+import android.hardware.biometrics.IBiometricContextListener;
import android.hardware.biometrics.common.OperationReason;
import android.util.Slog;
+import android.view.Surface;
import com.android.internal.util.FrameworkStatsLog;
@@ -41,32 +42,38 @@ public class BiometricFrameworkStatsLogger {
}
/** {@see FrameworkStatsLog.BIOMETRIC_ACQUIRED}. */
- public void acquired(OperationContext operationContext,
+ public void acquired(OperationContextExt operationContext,
int statsModality, int statsAction, int statsClient, boolean isDebug,
int acquiredInfo, int vendorCode, int targetUserId) {
FrameworkStatsLog.write(FrameworkStatsLog.BIOMETRIC_ACQUIRED,
statsModality,
targetUserId,
- operationContext.isCrypto,
+ operationContext.isCrypto(),
statsAction,
statsClient,
acquiredInfo,
vendorCode,
isDebug,
-1 /* sensorId */,
- operationContext.id,
- sessionType(operationContext.reason),
- operationContext.isAod);
+ operationContext.getId(),
+ sessionType(operationContext.getReason()),
+ operationContext.isAod(),
+ operationContext.isDisplayOn(),
+ operationContext.getDockState(),
+ orientationType(operationContext.getOrientation()),
+ foldType(operationContext.getFoldState()),
+ operationContext.getOrderAndIncrement(),
+ BiometricsProtoEnums.WAKE_REASON_UNKNOWN);
}
/** {@see FrameworkStatsLog.BIOMETRIC_AUTHENTICATED}. */
- public void authenticate(OperationContext operationContext,
+ public void authenticate(OperationContextExt operationContext,
int statsModality, int statsAction, int statsClient, boolean isDebug, long latency,
int authState, boolean requireConfirmation, int targetUserId, float ambientLightLux) {
FrameworkStatsLog.write(FrameworkStatsLog.BIOMETRIC_AUTHENTICATED,
statsModality,
targetUserId,
- operationContext.isCrypto,
+ operationContext.isCrypto(),
statsClient,
requireConfirmation,
authState,
@@ -74,13 +81,19 @@ public class BiometricFrameworkStatsLogger {
isDebug,
-1 /* sensorId */,
ambientLightLux,
- operationContext.id,
- sessionType(operationContext.reason),
- operationContext.isAod);
+ operationContext.getId(),
+ sessionType(operationContext.getReason()),
+ operationContext.isAod(),
+ operationContext.isDisplayOn(),
+ operationContext.getDockState(),
+ orientationType(operationContext.getOrientation()),
+ foldType(operationContext.getFoldState()),
+ operationContext.getOrderAndIncrement(),
+ BiometricsProtoEnums.WAKE_REASON_UNKNOWN);
}
/** {@see FrameworkStatsLog.BIOMETRIC_AUTHENTICATED}. */
- public void authenticate(OperationContext operationContext,
+ public void authenticate(OperationContextExt operationContext,
int statsModality, int statsAction, int statsClient, boolean isDebug, long latency,
int authState, boolean requireConfirmation, int targetUserId, ALSProbe alsProbe) {
alsProbe.awaitNextLux((ambientLightLux) -> {
@@ -102,13 +115,13 @@ public class BiometricFrameworkStatsLogger {
}
/** {@see FrameworkStatsLog.BIOMETRIC_ERROR_OCCURRED}. */
- public void error(OperationContext operationContext,
+ public void error(OperationContextExt operationContext,
int statsModality, int statsAction, int statsClient, boolean isDebug, long latency,
int error, int vendorCode, int targetUserId) {
FrameworkStatsLog.write(FrameworkStatsLog.BIOMETRIC_ERROR_OCCURRED,
statsModality,
targetUserId,
- operationContext.isCrypto,
+ operationContext.isCrypto(),
statsAction,
statsClient,
error,
@@ -116,9 +129,15 @@ public class BiometricFrameworkStatsLogger {
isDebug,
sanitizeLatency(latency),
-1 /* sensorId */,
- operationContext.id,
- sessionType(operationContext.reason),
- operationContext.isAod);
+ operationContext.getId(),
+ sessionType(operationContext.getReason()),
+ operationContext.isAod(),
+ operationContext.isDisplayOn(),
+ operationContext.getDockState(),
+ orientationType(operationContext.getOrientation()),
+ foldType(operationContext.getFoldState()),
+ operationContext.getOrderAndIncrement(),
+ BiometricsProtoEnums.WAKE_REASON_UNKNOWN);
}
/** {@see FrameworkStatsLog.BIOMETRIC_SYSTEM_HEALTH_ISSUE_DETECTED}. */
@@ -154,4 +173,30 @@ public class BiometricFrameworkStatsLogger {
}
return BiometricsProtoEnums.SESSION_TYPE_UNKNOWN;
}
+
+ private static int orientationType(@Surface.Rotation int rotation) {
+ switch (rotation) {
+ case Surface.ROTATION_0:
+ return BiometricsProtoEnums.ORIENTATION_0;
+ case Surface.ROTATION_90:
+ return BiometricsProtoEnums.ORIENTATION_90;
+ case Surface.ROTATION_180:
+ return BiometricsProtoEnums.ORIENTATION_180;
+ case Surface.ROTATION_270:
+ return BiometricsProtoEnums.ORIENTATION_270;
+ }
+ return BiometricsProtoEnums.ORIENTATION_UNKNOWN;
+ }
+
+ private static int foldType(int foldType) {
+ switch (foldType) {
+ case IBiometricContextListener.FoldState.FULLY_CLOSED:
+ return BiometricsProtoEnums.FOLD_CLOSED;
+ case IBiometricContextListener.FoldState.FULLY_OPENED:
+ return BiometricsProtoEnums.FOLD_OPEN;
+ case IBiometricContextListener.FoldState.HALF_OPENED:
+ return BiometricsProtoEnums.FOLD_HALF_OPEN;
+ }
+ return BiometricsProtoEnums.FOLD_UNKNOWN;
+ }
}
diff --git a/services/core/java/com/android/server/biometrics/log/BiometricLogger.java b/services/core/java/com/android/server/biometrics/log/BiometricLogger.java
index 55fe854e1404..c76a2e38aabc 100644
--- a/services/core/java/com/android/server/biometrics/log/BiometricLogger.java
+++ b/services/core/java/com/android/server/biometrics/log/BiometricLogger.java
@@ -21,7 +21,6 @@ import android.content.Context;
import android.hardware.SensorManager;
import android.hardware.biometrics.BiometricConstants;
import android.hardware.biometrics.BiometricsProtoEnums;
-import android.hardware.biometrics.common.OperationContext;
import android.hardware.face.FaceManager;
import android.hardware.fingerprint.FingerprintManager;
import android.util.Slog;
@@ -118,7 +117,7 @@ public class BiometricLogger {
}
/** Log an acquisition event. */
- public void logOnAcquired(Context context, OperationContext operationContext,
+ public void logOnAcquired(Context context, OperationContextExt operationContext,
int acquiredInfo, int vendorCode, int targetUserId) {
if (!mShouldLogMetrics) {
return;
@@ -139,7 +138,7 @@ public class BiometricLogger {
if (DEBUG) {
Slog.v(TAG, "Acquired! Modality: " + mStatsModality
+ ", User: " + targetUserId
- + ", IsCrypto: " + operationContext.isCrypto
+ + ", IsCrypto: " + operationContext.isCrypto()
+ ", Action: " + mStatsAction
+ ", Client: " + mStatsClient
+ ", AcquiredInfo: " + acquiredInfo
@@ -150,13 +149,14 @@ public class BiometricLogger {
return;
}
- mSink.acquired(operationContext, mStatsModality, mStatsAction, mStatsClient,
+ mSink.acquired(operationContext,
+ mStatsModality, mStatsAction, mStatsClient,
Utils.isDebugEnabled(context, targetUserId),
acquiredInfo, vendorCode, targetUserId);
}
/** Log an error during an operation. */
- public void logOnError(Context context, OperationContext operationContext,
+ public void logOnError(Context context, OperationContextExt operationContext,
int error, int vendorCode, int targetUserId) {
if (!mShouldLogMetrics) {
return;
@@ -168,7 +168,7 @@ public class BiometricLogger {
if (DEBUG) {
Slog.v(TAG, "Error! Modality: " + mStatsModality
+ ", User: " + targetUserId
- + ", IsCrypto: " + operationContext.isCrypto
+ + ", IsCrypto: " + operationContext.isCrypto()
+ ", Action: " + mStatsAction
+ ", Client: " + mStatsClient
+ ", Error: " + error
@@ -182,15 +182,16 @@ public class BiometricLogger {
return;
}
- mSink.error(operationContext, mStatsModality, mStatsAction, mStatsClient,
+ mSink.error(operationContext,
+ mStatsModality, mStatsAction, mStatsClient,
Utils.isDebugEnabled(context, targetUserId), latency,
error, vendorCode, targetUserId);
}
/** Log authentication attempt. */
- public void logOnAuthenticated(Context context, OperationContext operationContext,
- boolean authenticated, boolean requireConfirmation,
- int targetUserId, boolean isBiometricPrompt) {
+ public void logOnAuthenticated(Context context, OperationContextExt operationContext,
+ boolean authenticated, boolean requireConfirmation, int targetUserId,
+ boolean isBiometricPrompt) {
if (!mShouldLogMetrics) {
return;
}
@@ -215,7 +216,7 @@ public class BiometricLogger {
if (DEBUG) {
Slog.v(TAG, "Authenticated! Modality: " + mStatsModality
+ ", User: " + targetUserId
- + ", IsCrypto: " + operationContext.isCrypto
+ + ", IsCrypto: " + operationContext.isCrypto()
+ ", Client: " + mStatsClient
+ ", RequireConfirmation: " + requireConfirmation
+ ", State: " + authState
@@ -229,7 +230,8 @@ public class BiometricLogger {
return;
}
- mSink.authenticate(operationContext, mStatsModality, mStatsAction, mStatsClient,
+ mSink.authenticate(operationContext,
+ mStatsModality, mStatsAction, mStatsClient,
Utils.isDebugEnabled(context, targetUserId),
latency, authState, requireConfirmation, targetUserId, mALSProbe);
}
diff --git a/services/core/java/com/android/server/biometrics/log/OperationContextExt.java b/services/core/java/com/android/server/biometrics/log/OperationContextExt.java
new file mode 100644
index 000000000000..42be95b7377a
--- /dev/null
+++ b/services/core/java/com/android/server/biometrics/log/OperationContextExt.java
@@ -0,0 +1,138 @@
+/*
+ * Copyright (C) 2022 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.log;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.content.Intent;
+import android.hardware.biometrics.IBiometricContextListener;
+import android.hardware.biometrics.common.OperationContext;
+import android.hardware.biometrics.common.OperationReason;
+import android.view.Surface;
+
+/**
+ * Wrapper around {@link OperationContext} to include properties that are not
+ * shared with the HAL.
+ *
+ * When useful, these properties should move to the wrapped object for use by HAL in
+ * future releases.
+ */
+public class OperationContextExt {
+
+ @NonNull private final OperationContext mAidlContext;
+ @Nullable private BiometricContextSessionInfo mSessionInfo;
+ private boolean mIsDisplayOn = false;
+ private int mDockState = Intent.EXTRA_DOCK_STATE_UNDOCKED;
+ @Surface.Rotation private int mOrientation = Surface.ROTATION_0;
+ private int mFoldState = IBiometricContextListener.FoldState.UNKNOWN;
+
+ /** Create a new empty context. */
+ public OperationContextExt() {
+ this(new OperationContext());
+ }
+
+ /** Create a wrapped context. */
+ public OperationContextExt(@NonNull OperationContext context) {
+ mAidlContext = context;
+ }
+
+ /** Gets the subset of the context that can be shared with the HAL. */
+ @NonNull
+ public OperationContext toAidlContext() {
+ return mAidlContext;
+ }
+
+ /** {@link OperationContext#id}. */
+ public int getId() {
+ return mAidlContext.id;
+ }
+
+ /** Gets the current order counter for the session and increment the counter. */
+ public int getOrderAndIncrement() {
+ final BiometricContextSessionInfo info = mSessionInfo;
+ return info != null ? info.getOrderAndIncrement() : -1;
+ }
+
+ /** {@link OperationContext#reason}. */
+ public byte getReason() {
+ return mAidlContext.reason;
+ }
+
+ /** If the screen is currently on. */
+ public boolean isDisplayOn() {
+ return mIsDisplayOn;
+ }
+
+ /** {@link OperationContext#isAod}. */
+ public boolean isAod() {
+ return mAidlContext.isAod;
+ }
+
+ /** {@link OperationContext#isCrypto}. */
+ public boolean isCrypto() {
+ return mAidlContext.isCrypto;
+ }
+
+ /** The dock state when this event occurred {@see Intent.EXTRA_DOCK_STATE_UNDOCKED}. */
+ public int getDockState() {
+ return mDockState;
+ }
+
+ /** The fold state of the device when this event occurred. */
+ public int getFoldState() {
+ return mFoldState;
+ }
+
+ /** The orientation of the device when this event occurred. */
+ @Surface.Rotation
+ public int getOrientation() {
+ return mOrientation;
+ }
+
+ /** Update this object with the latest values from the given context. */
+ OperationContextExt update(@NonNull BiometricContext biometricContext) {
+ mAidlContext.isAod = biometricContext.isAod();
+ setFirstSessionId(biometricContext);
+
+ mIsDisplayOn = biometricContext.isDisplayOn();
+ mDockState = biometricContext.getDockedState();
+ mFoldState = biometricContext.getFoldState();
+ mOrientation = biometricContext.getCurrentRotation();
+
+ return this;
+ }
+
+ private void setFirstSessionId(@NonNull BiometricContext biometricContext) {
+ mSessionInfo = biometricContext.getKeyguardEntrySessionInfo();
+ if (mSessionInfo != null) {
+ mAidlContext.id = mSessionInfo.getId();
+ mAidlContext.reason = OperationReason.KEYGUARD;
+ return;
+ }
+
+ mSessionInfo = biometricContext.getBiometricPromptSessionInfo();
+ if (mSessionInfo != null) {
+ mAidlContext.id = mSessionInfo.getId();
+ mAidlContext.reason = OperationReason.BIOMETRIC_PROMPT;
+ return;
+ }
+
+ // no session
+ mAidlContext.id = 0;
+ mAidlContext.reason = OperationReason.UNKNOWN;
+ }
+}
diff --git a/services/core/java/com/android/server/biometrics/sensors/HalClientMonitor.java b/services/core/java/com/android/server/biometrics/sensors/HalClientMonitor.java
index a6e89115400d..d0a4807d937e 100644
--- a/services/core/java/com/android/server/biometrics/sensors/HalClientMonitor.java
+++ b/services/core/java/com/android/server/biometrics/sensors/HalClientMonitor.java
@@ -19,11 +19,11 @@ package com.android.server.biometrics.sensors;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.content.Context;
-import android.hardware.biometrics.common.OperationContext;
import android.os.IBinder;
import com.android.server.biometrics.log.BiometricContext;
import com.android.server.biometrics.log.BiometricLogger;
+import com.android.server.biometrics.log.OperationContextExt;
import java.util.function.Supplier;
@@ -37,7 +37,7 @@ public abstract class HalClientMonitor<T> extends BaseClientMonitor {
protected final Supplier<T> mLazyDaemon;
@NonNull
- private final OperationContext mOperationContext = new OperationContext();
+ private final OperationContextExt mOperationContext = new OperationContextExt();
/**
* @param context system_server context
@@ -85,7 +85,7 @@ public abstract class HalClientMonitor<T> extends BaseClientMonitor {
unsubscribeBiometricContext();
}
- protected OperationContext getOperationContext() {
+ protected OperationContextExt getOperationContext() {
return getBiometricContext().updateContext(mOperationContext, isCryptoOperation());
}
diff --git a/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceAuthenticationClient.java b/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceAuthenticationClient.java
index b1cb257b2443..d8b825d2c0e5 100644
--- a/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceAuthenticationClient.java
+++ b/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceAuthenticationClient.java
@@ -164,7 +164,7 @@ class FaceAuthenticationClient extends AuthenticationClient<AidlSession>
if (session.hasContextMethods()) {
return session.getSession().authenticateWithContext(
- mOperationId, getOperationContext());
+ mOperationId, getOperationContext().toAidlContext());
} else {
return session.getSession().authenticate(mOperationId);
}
diff --git a/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceDetectClient.java b/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceDetectClient.java
index ded18100e458..506b2bc8d9db 100644
--- a/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceDetectClient.java
+++ b/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceDetectClient.java
@@ -115,7 +115,8 @@ public class FaceDetectClient extends AcquisitionClient<AidlSession> implements
final AidlSession session = getFreshDaemon();
if (session.hasContextMethods()) {
- return session.getSession().detectInteractionWithContext(getOperationContext());
+ return session.getSession().detectInteractionWithContext(
+ getOperationContext().toAidlContext());
} else {
return session.getSession().detectInteraction();
}
diff --git a/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceEnrollClient.java b/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceEnrollClient.java
index 5d62cde01a6f..792b52e7d658 100644
--- a/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceEnrollClient.java
+++ b/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceEnrollClient.java
@@ -199,7 +199,8 @@ public class FaceEnrollClient extends EnrollClient<AidlSession> {
if (session.hasContextMethods()) {
return session.getSession().enrollWithContext(
- hat, EnrollmentType.DEFAULT, features, mHwPreviewHandle, getOperationContext());
+ hat, EnrollmentType.DEFAULT, features, mHwPreviewHandle,
+ getOperationContext().toAidlContext());
} else {
return session.getSession().enroll(hat, EnrollmentType.DEFAULT, features,
mHwPreviewHandle);
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 11f45176dc45..9669950e236e 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
@@ -29,7 +29,6 @@ import android.hardware.biometrics.BiometricFingerprintConstants;
import android.hardware.biometrics.BiometricFingerprintConstants.FingerprintAcquired;
import android.hardware.biometrics.BiometricManager.Authenticators;
import android.hardware.biometrics.common.ICancellationSignal;
-import android.hardware.biometrics.common.OperationContext;
import android.hardware.biometrics.fingerprint.PointerContext;
import android.hardware.fingerprint.FingerprintSensorPropertiesInternal;
import android.hardware.fingerprint.ISidefpsController;
@@ -47,6 +46,7 @@ import com.android.internal.R;
import com.android.server.biometrics.log.BiometricContext;
import com.android.server.biometrics.log.BiometricLogger;
import com.android.server.biometrics.log.CallbackWithProbe;
+import com.android.server.biometrics.log.OperationContextExt;
import com.android.server.biometrics.log.Probe;
import com.android.server.biometrics.sensors.AuthSessionCoordinator;
import com.android.server.biometrics.sensors.AuthenticationClient;
@@ -333,7 +333,7 @@ class FingerprintAuthenticationClient extends AuthenticationClient<AidlSession>
private ICancellationSignal doAuthenticate() throws RemoteException {
final AidlSession session = getFreshDaemon();
- final OperationContext opContext = getOperationContext();
+ final OperationContextExt opContext = getOperationContext();
getBiometricContext().subscribe(opContext, ctx -> {
if (session.hasContextMethods()) {
try {
@@ -356,7 +356,8 @@ class FingerprintAuthenticationClient extends AuthenticationClient<AidlSession>
}
if (session.hasContextMethods()) {
- return session.getSession().authenticateWithContext(mOperationId, opContext);
+ return session.getSession().authenticateWithContext(
+ mOperationId, opContext.toAidlContext());
} else {
return session.getSession().authenticate(mOperationId);
}
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 52822347e96f..f6911ea29837 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
@@ -102,7 +102,8 @@ class FingerprintDetectClient extends AcquisitionClient<AidlSession> implements
final AidlSession session = getFreshDaemon();
if (session.hasContextMethods()) {
- return session.getSession().detectInteractionWithContext(getOperationContext());
+ return session.getSession().detectInteractionWithContext(
+ getOperationContext().toAidlContext());
} else {
return session.getSession().detectInteraction();
}
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 fa54983b31dc..2ac8b433b3af 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
@@ -24,7 +24,6 @@ import android.hardware.biometrics.BiometricFingerprintConstants;
import android.hardware.biometrics.BiometricFingerprintConstants.FingerprintAcquired;
import android.hardware.biometrics.BiometricStateListener;
import android.hardware.biometrics.common.ICancellationSignal;
-import android.hardware.biometrics.common.OperationContext;
import android.hardware.biometrics.fingerprint.PointerContext;
import android.hardware.fingerprint.Fingerprint;
import android.hardware.fingerprint.FingerprintManager;
@@ -42,6 +41,7 @@ import com.android.server.biometrics.HardwareAuthTokenUtils;
import com.android.server.biometrics.log.BiometricContext;
import com.android.server.biometrics.log.BiometricLogger;
import com.android.server.biometrics.log.CallbackWithProbe;
+import com.android.server.biometrics.log.OperationContextExt;
import com.android.server.biometrics.log.Probe;
import com.android.server.biometrics.sensors.BiometricNotificationUtils;
import com.android.server.biometrics.sensors.BiometricUtils;
@@ -185,9 +185,9 @@ class FingerprintEnrollClient extends EnrollClient<AidlSession> implements Udfps
HardwareAuthTokenUtils.toHardwareAuthToken(mHardwareAuthToken);
if (session.hasContextMethods()) {
- final OperationContext opContext = getOperationContext();
+ final OperationContextExt opContext = getOperationContext();
final ICancellationSignal cancel = session.getSession().enrollWithContext(
- hat, opContext);
+ hat, opContext.toAidlContext());
getBiometricContext().subscribe(opContext, ctx -> {
try {
session.getSession().onContextChanged(ctx);
diff --git a/services/tests/servicestests/src/com/android/server/biometrics/AuthSessionTest.java b/services/tests/servicestests/src/com/android/server/biometrics/AuthSessionTest.java
index e95924ad7109..4cdca268fc4b 100644
--- a/services/tests/servicestests/src/com/android/server/biometrics/AuthSessionTest.java
+++ b/services/tests/servicestests/src/com/android/server/biometrics/AuthSessionTest.java
@@ -62,6 +62,7 @@ import android.security.KeyStore;
import androidx.test.filters.SmallTest;
import com.android.internal.statusbar.IStatusBarService;
+import com.android.server.biometrics.log.BiometricContext;
import org.junit.Before;
import org.junit.Test;
@@ -81,6 +82,7 @@ public class AuthSessionTest {
private static final long TEST_REQUEST_ID = 22;
@Mock private Context mContext;
+ @Mock private BiometricContext mBiometricContext;
@Mock private ITrustManager mTrustManager;
@Mock private DevicePolicyManager mDevicePolicyManager;
@Mock private BiometricService.SettingObserver mSettingObserver;
@@ -102,6 +104,8 @@ public class AuthSessionTest {
public void setUp() throws Exception {
MockitoAnnotations.initMocks(this);
when(mClientReceiver.asBinder()).thenReturn(mock(Binder.class));
+ when(mBiometricContext.updateContext(any(), anyBoolean()))
+ .thenAnswer(invocation -> invocation.getArgument(0));
mRandom = new Random();
mToken = new Binder();
mSensors = new ArrayList<>();
@@ -437,9 +441,9 @@ public class AuthSessionTest {
final PreAuthInfo preAuthInfo = createPreAuthInfo(sensors, userId, promptInfo,
checkDevicePolicyManager);
- return new AuthSession(mContext, mStatusBarService, mSysuiReceiver, mKeyStore,
- mRandom, mClientDeathReceiver, preAuthInfo, mToken, requestId, operationId, userId,
- mSensorReceiver, mClientReceiver, TEST_PACKAGE, promptInfo,
+ return new AuthSession(mContext, mBiometricContext, mStatusBarService, mSysuiReceiver,
+ mKeyStore, mRandom, mClientDeathReceiver, preAuthInfo, mToken, requestId,
+ operationId, userId, mSensorReceiver, mClientReceiver, TEST_PACKAGE, promptInfo,
false /* debugEnabled */, mFingerprintSensorProps);
}
diff --git a/services/tests/servicestests/src/com/android/server/biometrics/BiometricServiceTest.java b/services/tests/servicestests/src/com/android/server/biometrics/BiometricServiceTest.java
index 0d6d1a2e93f9..7d6110e82139 100644
--- a/services/tests/servicestests/src/com/android/server/biometrics/BiometricServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/biometrics/BiometricServiceTest.java
@@ -19,6 +19,7 @@ package com.android.server.biometrics;
import static android.hardware.biometrics.BiometricAuthenticator.TYPE_FINGERPRINT;
import static android.hardware.biometrics.BiometricManager.Authenticators;
import static android.hardware.biometrics.BiometricManager.BIOMETRIC_MULTI_SENSOR_DEFAULT;
+import static android.view.DisplayAdjustments.DEFAULT_DISPLAY_ADJUSTMENTS;
import static com.android.server.biometrics.BiometricServiceStateProto.STATE_AUTHENTICATED_PENDING_SYSUI;
import static com.android.server.biometrics.BiometricServiceStateProto.STATE_AUTH_CALLED;
@@ -65,12 +66,16 @@ import android.hardware.biometrics.IBiometricServiceReceiver;
import android.hardware.biometrics.IBiometricSysuiReceiver;
import android.hardware.biometrics.PromptInfo;
import android.hardware.display.AmbientDisplayConfiguration;
+import android.hardware.display.DisplayManagerGlobal;
import android.hardware.fingerprint.FingerprintManager;
import android.os.Binder;
import android.os.IBinder;
import android.os.RemoteException;
import android.platform.test.annotations.Presubmit;
import android.security.KeyStore;
+import android.view.Display;
+import android.view.DisplayInfo;
+import android.view.WindowManager;
import androidx.test.InstrumentationRegistry;
import androidx.test.filters.SmallTest;
@@ -134,6 +139,8 @@ public class BiometricServiceTest {
@Mock
DevicePolicyManager mDevicePolicyManager;
@Mock
+ private WindowManager mWindowManager;
+ @Mock
private IStatusBarService mStatusBarService;
@Mock
private ISessionListener mSessionListener;
@@ -174,9 +181,13 @@ public class BiometricServiceTest {
when(mResources.getString(R.string.biometric_error_user_canceled))
.thenReturn(ERROR_USER_CANCELED);
+ when(mWindowManager.getDefaultDisplay()).thenReturn(
+ new Display(DisplayManagerGlobal.getInstance(), Display.DEFAULT_DISPLAY,
+ new DisplayInfo(), DEFAULT_DISPLAY_ADJUSTMENTS));
when(mAmbientDisplayConfiguration.alwaysOnEnabled(anyInt())).thenReturn(true);
- mBiometricContextProvider = new BiometricContextProvider(mAmbientDisplayConfiguration,
- mStatusBarService, null /* handler */, mAuthSessionCoordinator);
+ mBiometricContextProvider = new BiometricContextProvider(mContext, mWindowManager,
+ mAmbientDisplayConfiguration, mStatusBarService, null /* handler */,
+ mAuthSessionCoordinator);
when(mInjector.getBiometricContext(any())).thenReturn(mBiometricContextProvider);
final String[] config = {
diff --git a/services/tests/servicestests/src/com/android/server/biometrics/log/BiometricContextProviderTest.java b/services/tests/servicestests/src/com/android/server/biometrics/log/BiometricContextProviderTest.java
index 58f338c7a5bb..2ccdda81b755 100644
--- a/services/tests/servicestests/src/com/android/server/biometrics/log/BiometricContextProviderTest.java
+++ b/services/tests/servicestests/src/com/android/server/biometrics/log/BiometricContextProviderTest.java
@@ -16,6 +16,8 @@
package com.android.server.biometrics.log;
+import static android.view.DisplayAdjustments.DEFAULT_DISPLAY_ADJUSTMENTS;
+
import static com.google.common.truth.Truth.assertThat;
import static org.mockito.Mockito.any;
@@ -27,14 +29,22 @@ import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import android.app.StatusBarManager;
+import android.content.Intent;
import android.hardware.biometrics.IBiometricContextListener;
+import android.hardware.biometrics.IBiometricContextListener.FoldState;
import android.hardware.biometrics.common.OperationContext;
import android.hardware.biometrics.common.OperationReason;
import android.hardware.display.AmbientDisplayConfiguration;
+import android.hardware.display.DisplayManagerGlobal;
import android.os.RemoteException;
import android.platform.test.annotations.Presubmit;
+import android.testing.TestableContext;
+import android.view.Display;
+import android.view.DisplayInfo;
+import android.view.WindowManager;
import androidx.test.filters.SmallTest;
+import androidx.test.platform.app.InstrumentationRegistry;
import com.android.internal.logging.InstanceId;
import com.android.internal.statusbar.ISessionListener;
@@ -58,6 +68,9 @@ public class BiometricContextProviderTest {
@Rule
public final MockitoRule mockito = MockitoJUnit.rule();
+ @Rule
+ public TestableContext mContext = new TestableContext(
+ InstrumentationRegistry.getInstrumentation().getContext());
@Mock
private IStatusBarService mStatusBarService;
@@ -65,16 +78,22 @@ public class BiometricContextProviderTest {
private ISessionListener mSessionListener;
@Mock
private AmbientDisplayConfiguration mAmbientDisplayConfiguration;
+ @Mock
+ private WindowManager mWindowManager;
- private OperationContext mOpContext = new OperationContext();
+ private OperationContextExt mOpContext = new OperationContextExt();
private IBiometricContextListener mListener;
private BiometricContextProvider mProvider;
@Before
public void setup() throws RemoteException {
when(mAmbientDisplayConfiguration.alwaysOnEnabled(anyInt())).thenReturn(true);
- mProvider = new BiometricContextProvider(mAmbientDisplayConfiguration, mStatusBarService,
- null /* handler */, null /* authSessionCoordinator */);
+ when(mWindowManager.getDefaultDisplay()).thenReturn(
+ new Display(DisplayManagerGlobal.getInstance(), Display.DEFAULT_DISPLAY,
+ new DisplayInfo(), DEFAULT_DISPLAY_ADJUSTMENTS));
+ mProvider = new BiometricContextProvider(mContext, mWindowManager,
+ mAmbientDisplayConfiguration, mStatusBarService, null /* handler */,
+ null /* authSessionCoordinator */);
ArgumentCaptor<IBiometricContextListener> captor =
ArgumentCaptor.forClass(IBiometricContextListener.class);
verify(mStatusBarService).setBiometicContextListener(captor.capture());
@@ -112,11 +131,37 @@ public class BiometricContextProviderTest {
}
@Test
+ public void testGetDockedState() {
+ final List<Integer> states = List.of(Intent.EXTRA_DOCK_STATE_DESK,
+ Intent.EXTRA_DOCK_STATE_CAR, Intent.EXTRA_DOCK_STATE_UNDOCKED);
+
+ for (int state : states) {
+ final Intent intent = new Intent();
+ intent.putExtra(Intent.EXTRA_DOCK_STATE, state);
+ mProvider.mDockStateReceiver.onReceive(mContext, intent);
+
+ assertThat(mProvider.getDockedState()).isEqualTo(state);
+ }
+ }
+
+ @Test
+ public void testGetFoldState() throws RemoteException {
+ final List<Integer> states = List.of(FoldState.FULLY_CLOSED, FoldState.FULLY_OPENED,
+ FoldState.UNKNOWN, FoldState.HALF_OPENED);
+
+ for (int state : states) {
+ mListener.onFoldChanged(state);
+
+ assertThat(mProvider.getFoldState()).isEqualTo(state);
+ }
+ }
+
+ @Test
public void testSubscribesToAod() throws RemoteException {
final List<Boolean> actual = new ArrayList<>();
mProvider.subscribe(mOpContext, ctx -> {
- assertThat(ctx).isSameInstanceAs(mOpContext);
+ assertThat(ctx).isSameInstanceAs(mOpContext.toAidlContext());
assertThat(mProvider.isAod()).isEqualTo(ctx.isAod);
assertThat(mProvider.isAwake()).isFalse();
actual.add(ctx.isAod);
@@ -134,7 +179,7 @@ public class BiometricContextProviderTest {
final List<Boolean> actual = new ArrayList<>();
mProvider.subscribe(mOpContext, ctx -> {
- assertThat(ctx).isSameInstanceAs(mOpContext);
+ assertThat(ctx).isSameInstanceAs(mOpContext.toAidlContext());
assertThat(ctx.isAod).isFalse();
assertThat(mProvider.isAod()).isFalse();
actual.add(mProvider.isAwake());
@@ -162,7 +207,7 @@ public class BiometricContextProviderTest {
mListener.onDozeChanged(true /* isDozing */, false /* isAwake */);
verify(emptyConsumer, never()).accept(any());
- verify(nonEmptyConsumer).accept(same(mOpContext));
+ verify(nonEmptyConsumer).accept(same(mOpContext.toAidlContext()));
}
@Test
@@ -170,45 +215,47 @@ public class BiometricContextProviderTest {
final int keyguardSessionId = 10;
final int bpSessionId = 20;
- assertThat(mProvider.getBiometricPromptSessionId()).isNull();
- assertThat(mProvider.getKeyguardEntrySessionId()).isNull();
+ assertThat(mProvider.getBiometricPromptSessionInfo()).isNull();
+ assertThat(mProvider.getKeyguardEntrySessionInfo()).isNull();
mSessionListener.onSessionStarted(StatusBarManager.SESSION_KEYGUARD,
InstanceId.fakeInstanceId(keyguardSessionId));
- assertThat(mProvider.getBiometricPromptSessionId()).isNull();
- assertThat(mProvider.getKeyguardEntrySessionId()).isEqualTo(keyguardSessionId);
+ assertThat(mProvider.getBiometricPromptSessionInfo()).isNull();
+ assertThat(mProvider.getKeyguardEntrySessionInfo().getId()).isEqualTo(keyguardSessionId);
mSessionListener.onSessionStarted(StatusBarManager.SESSION_BIOMETRIC_PROMPT,
InstanceId.fakeInstanceId(bpSessionId));
- assertThat(mProvider.getBiometricPromptSessionId()).isEqualTo(bpSessionId);
- assertThat(mProvider.getKeyguardEntrySessionId()).isEqualTo(keyguardSessionId);
+ assertThat(mProvider.getBiometricPromptSessionInfo().getId()).isEqualTo(bpSessionId);
+ assertThat(mProvider.getKeyguardEntrySessionInfo().getId()).isEqualTo(keyguardSessionId);
mSessionListener.onSessionEnded(StatusBarManager.SESSION_KEYGUARD,
InstanceId.fakeInstanceId(keyguardSessionId));
- assertThat(mProvider.getBiometricPromptSessionId()).isEqualTo(bpSessionId);
- assertThat(mProvider.getKeyguardEntrySessionId()).isNull();
+ assertThat(mProvider.getBiometricPromptSessionInfo().getId()).isEqualTo(bpSessionId);
+ assertThat(mProvider.getKeyguardEntrySessionInfo()).isNull();
mSessionListener.onSessionEnded(StatusBarManager.SESSION_BIOMETRIC_PROMPT,
InstanceId.fakeInstanceId(bpSessionId));
- assertThat(mProvider.getBiometricPromptSessionId()).isNull();
- assertThat(mProvider.getKeyguardEntrySessionId()).isNull();
+ assertThat(mProvider.getBiometricPromptSessionInfo()).isNull();
+ assertThat(mProvider.getKeyguardEntrySessionInfo()).isNull();
}
@Test
public void testUpdate() throws RemoteException {
mListener.onDozeChanged(false /* isDozing */, false /* isAwake */);
- OperationContext context = mProvider.updateContext(mOpContext, false /* crypto */);
+
+ OperationContextExt context = mProvider.updateContext(mOpContext, false /* crypto */);
+ OperationContext aidlContext = context.toAidlContext();
// default state when nothing has been set
assertThat(context).isSameInstanceAs(mOpContext);
- assertThat(mOpContext.id).isEqualTo(0);
- assertThat(mOpContext.reason).isEqualTo(OperationReason.UNKNOWN);
- assertThat(mOpContext.isAod).isEqualTo(false);
- assertThat(mOpContext.isCrypto).isEqualTo(false);
+ assertThat(aidlContext.id).isEqualTo(0);
+ assertThat(aidlContext.reason).isEqualTo(OperationReason.UNKNOWN);
+ assertThat(aidlContext.isAod).isEqualTo(false);
+ assertThat(aidlContext.isCrypto).isEqualTo(false);
for (int type : List.of(StatusBarManager.SESSION_BIOMETRIC_PROMPT,
StatusBarManager.SESSION_KEYGUARD)) {
@@ -218,21 +265,23 @@ public class BiometricContextProviderTest {
mListener.onDozeChanged(aod /* isDozing */, false /* isAwake */);
mSessionListener.onSessionStarted(type, InstanceId.fakeInstanceId(id));
context = mProvider.updateContext(mOpContext, false /* crypto */);
+ aidlContext = context.toAidlContext();
assertThat(context).isSameInstanceAs(mOpContext);
- assertThat(mOpContext.id).isEqualTo(id);
- assertThat(mOpContext.reason).isEqualTo(reason(type));
- assertThat(mOpContext.isAod).isEqualTo(aod);
- assertThat(mOpContext.isCrypto).isEqualTo(false);
+ assertThat(aidlContext.id).isEqualTo(id);
+ assertThat(aidlContext.reason).isEqualTo(reason(type));
+ assertThat(aidlContext.isAod).isEqualTo(aod);
+ assertThat(aidlContext.isCrypto).isEqualTo(false);
mSessionListener.onSessionEnded(type, InstanceId.fakeInstanceId(id));
}
context = mProvider.updateContext(mOpContext, false /* crypto */);
+ aidlContext = context.toAidlContext();
assertThat(context).isSameInstanceAs(mOpContext);
- assertThat(mOpContext.id).isEqualTo(0);
- assertThat(mOpContext.reason).isEqualTo(OperationReason.UNKNOWN);
- assertThat(mOpContext.isAod).isEqualTo(false);
- assertThat(mOpContext.isCrypto).isEqualTo(false);
+ assertThat(aidlContext.id).isEqualTo(0);
+ assertThat(aidlContext.reason).isEqualTo(OperationReason.UNKNOWN);
+ assertThat(aidlContext.isAod).isEqualTo(false);
+ assertThat(aidlContext.isCrypto).isEqualTo(false);
}
private static byte reason(int type) {
diff --git a/services/tests/servicestests/src/com/android/server/biometrics/log/BiometricLoggerTest.java b/services/tests/servicestests/src/com/android/server/biometrics/log/BiometricLoggerTest.java
index 88a9646cac8a..81dcf4838b07 100644
--- a/services/tests/servicestests/src/com/android/server/biometrics/log/BiometricLoggerTest.java
+++ b/services/tests/servicestests/src/com/android/server/biometrics/log/BiometricLoggerTest.java
@@ -32,7 +32,6 @@ import android.hardware.Sensor;
import android.hardware.SensorEventListener;
import android.hardware.SensorManager;
import android.hardware.biometrics.BiometricsProtoEnums;
-import android.hardware.biometrics.common.OperationContext;
import android.hardware.input.InputSensorInfo;
import android.platform.test.annotations.Presubmit;
import android.testing.TestableContext;
@@ -70,12 +69,12 @@ public class BiometricLoggerTest {
@Mock
private BaseClientMonitor mClient;
- private OperationContext mOpContext;
+ private OperationContextExt mOpContext;
private BiometricLogger mLogger;
@Before
public void setUp() {
- mOpContext = new OperationContext();
+ mOpContext = new OperationContextExt();
mContext.addMockSystemService(SensorManager.class, mSensorManager);
when(mSensorManager.getDefaultSensor(Sensor.TYPE_LIGHT)).thenReturn(
new Sensor(new InputSensorInfo("", "", 0, 0, Sensor.TYPE_LIGHT, 0, 0, 0, 0, 0, 0,
diff --git a/services/tests/servicestests/src/com/android/server/biometrics/log/OperationContextExtTest.java b/services/tests/servicestests/src/com/android/server/biometrics/log/OperationContextExtTest.java
new file mode 100644
index 000000000000..c7962c82471a
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/biometrics/log/OperationContextExtTest.java
@@ -0,0 +1,137 @@
+/*
+ * Copyright (C) 2022 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.log;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.content.Intent;
+import android.hardware.biometrics.IBiometricContextListener;
+import android.hardware.biometrics.common.OperationContext;
+import android.hardware.biometrics.common.OperationReason;
+import android.platform.test.annotations.Presubmit;
+import android.view.Surface;
+
+import static org.mockito.Mockito.when;
+
+import androidx.test.filters.SmallTest;
+
+import com.android.internal.logging.InstanceId;
+
+import org.junit.Rule;
+import org.junit.Test;
+import org.mockito.Mock;
+import org.mockito.junit.MockitoJUnit;
+import org.mockito.junit.MockitoRule;
+
+@Presubmit
+@SmallTest
+public class OperationContextExtTest {
+
+ @Rule
+ public final MockitoRule mockito = MockitoJUnit.rule();
+
+ @Mock
+ private BiometricContext mBiometricContext;
+
+ @Test
+ public void hasAidlContext() {
+ OperationContextExt context = new OperationContextExt();
+ assertThat(context.toAidlContext()).isNotNull();
+
+ final OperationContext aidlContext = newAidlContext();
+
+ context = new OperationContextExt(aidlContext);
+ assertThat(context.toAidlContext()).isSameInstanceAs(aidlContext);
+
+ final int id = 5;
+ final byte reason = OperationReason.UNKNOWN;
+ aidlContext.id = id;
+ aidlContext.isAod = true;
+ aidlContext.isCrypto = true;
+ aidlContext.reason = reason;
+
+ assertThat(context.getId()).isEqualTo(id);
+ assertThat(context.isAod()).isTrue();
+ assertThat(context.isCrypto()).isTrue();
+ assertThat(context.getReason()).isEqualTo(reason);
+ }
+
+ @Test
+ public void hasNoOrderWithoutSession() {
+ OperationContextExt context = new OperationContextExt();
+ assertThat(context.getOrderAndIncrement()).isEqualTo(-1);
+ assertThat(context.getOrderAndIncrement()).isEqualTo(-1);
+ }
+
+ @Test
+ public void updatesFromSourceForKeyguard() {
+ final BiometricContextSessionInfo info =
+ new BiometricContextSessionInfo(InstanceId.fakeInstanceId(9));
+ when(mBiometricContext.getKeyguardEntrySessionInfo()).thenReturn(info);
+ updatesFromSource(info, OperationReason.KEYGUARD);
+ }
+
+ @Test
+ public void updatesFromSourceForBiometricPrompt() {
+ final BiometricContextSessionInfo info =
+ new BiometricContextSessionInfo(InstanceId.fakeInstanceId(9));
+ when(mBiometricContext.getBiometricPromptSessionInfo()).thenReturn(info);
+ updatesFromSource(info, OperationReason.BIOMETRIC_PROMPT);
+ }
+
+ @Test
+ public void updatesFromSourceWithoutSession() {
+ updatesFromSource(null, OperationReason.UNKNOWN);
+ }
+
+ private void updatesFromSource(BiometricContextSessionInfo sessionInfo, int sessionType) {
+ final int rotation = Surface.ROTATION_270;
+ final int foldState = IBiometricContextListener.FoldState.HALF_OPENED;
+ final int dockState = Intent.EXTRA_DOCK_STATE_CAR;
+
+ when(mBiometricContext.getCurrentRotation()).thenReturn(rotation);
+ when(mBiometricContext.getFoldState()).thenReturn(foldState);
+ when(mBiometricContext.getDockedState()).thenReturn(dockState);
+ when(mBiometricContext.isDisplayOn()).thenReturn(true);
+
+ final OperationContextExt context = new OperationContextExt(newAidlContext());
+
+ assertThat(context.update(mBiometricContext)).isSameInstanceAs(context);
+
+ if (sessionInfo != null) {
+ assertThat(context.getId()).isEqualTo(sessionInfo.getId());
+ final int order = context.getOrderAndIncrement();
+ assertThat(context.getOrderAndIncrement()).isEqualTo(order + 1);
+ } else {
+ assertThat(context.getId()).isEqualTo(0);
+ }
+ assertThat(context.getReason()).isEqualTo(sessionType);
+ assertThat(context.getDockState()).isEqualTo(dockState);
+ assertThat(context.getFoldState()).isEqualTo(foldState);
+ assertThat(context.getOrientation()).isEqualTo(rotation);
+ assertThat(context.isDisplayOn()).isTrue();
+ }
+
+ private static OperationContext newAidlContext() {
+ final OperationContext aidlContext = new OperationContext();
+ aidlContext.id = -1;
+ aidlContext.isAod = false;
+ aidlContext.isCrypto = false;
+ aidlContext.reason = 0;
+ return aidlContext;
+ }
+}
diff --git a/services/tests/servicestests/src/com/android/server/biometrics/sensors/face/aidl/FaceAuthenticationClientTest.java b/services/tests/servicestests/src/com/android/server/biometrics/sensors/face/aidl/FaceAuthenticationClientTest.java
index d10d7d433e7a..139910ba8926 100644
--- a/services/tests/servicestests/src/com/android/server/biometrics/sensors/face/aidl/FaceAuthenticationClientTest.java
+++ b/services/tests/servicestests/src/com/android/server/biometrics/sensors/face/aidl/FaceAuthenticationClientTest.java
@@ -31,7 +31,6 @@ import android.app.ActivityManager;
import android.app.ActivityTaskManager;
import android.content.ComponentName;
import android.hardware.biometrics.common.ICancellationSignal;
-import android.hardware.biometrics.common.OperationContext;
import android.hardware.biometrics.face.ISession;
import android.hardware.face.Face;
import android.os.IBinder;
@@ -44,6 +43,7 @@ import androidx.test.platform.app.InstrumentationRegistry;
import com.android.server.biometrics.log.BiometricContext;
import com.android.server.biometrics.log.BiometricLogger;
+import com.android.server.biometrics.log.OperationContextExt;
import com.android.server.biometrics.sensors.AuthSessionCoordinator;
import com.android.server.biometrics.sensors.ClientMonitorCallback;
import com.android.server.biometrics.sensors.ClientMonitorCallbackConverter;
@@ -96,7 +96,7 @@ public class FaceAuthenticationClientTest {
@Mock
private AuthSessionCoordinator mAuthSessionCoordinator;
@Captor
- private ArgumentCaptor<OperationContext> mOperationContextCaptor;
+ private ArgumentCaptor<OperationContextExt> mOperationContextCaptor;
@Rule
public final MockitoRule mockito = MockitoJUnit.rule();
@@ -126,7 +126,7 @@ public class FaceAuthenticationClientTest {
order.verify(mBiometricContext).updateContext(
mOperationContextCaptor.capture(), anyBoolean());
order.verify(mHal).authenticateWithContext(
- eq(OP_ID), same(mOperationContextCaptor.getValue()));
+ eq(OP_ID), same(mOperationContextCaptor.getValue().toAidlContext()));
verify(mHal, never()).authenticate(anyLong());
}
diff --git a/services/tests/servicestests/src/com/android/server/biometrics/sensors/face/aidl/FaceDetectClientTest.java b/services/tests/servicestests/src/com/android/server/biometrics/sensors/face/aidl/FaceDetectClientTest.java
index 25135c6670db..e0fdb8cfc74e 100644
--- a/services/tests/servicestests/src/com/android/server/biometrics/sensors/face/aidl/FaceDetectClientTest.java
+++ b/services/tests/servicestests/src/com/android/server/biometrics/sensors/face/aidl/FaceDetectClientTest.java
@@ -24,7 +24,6 @@ import static org.mockito.Mockito.same;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
-import android.hardware.biometrics.common.OperationContext;
import android.hardware.biometrics.face.ISession;
import android.os.IBinder;
import android.os.RemoteException;
@@ -36,6 +35,7 @@ import androidx.test.platform.app.InstrumentationRegistry;
import com.android.server.biometrics.log.BiometricContext;
import com.android.server.biometrics.log.BiometricLogger;
+import com.android.server.biometrics.log.OperationContextExt;
import com.android.server.biometrics.sensors.ClientMonitorCallback;
import com.android.server.biometrics.sensors.ClientMonitorCallbackConverter;
@@ -74,7 +74,7 @@ public class FaceDetectClientTest {
@Mock
private Sensor.HalSessionCallback mHalSessionCallback;
@Captor
- private ArgumentCaptor<OperationContext> mOperationContextCaptor;
+ private ArgumentCaptor<OperationContextExt> mOperationContextCaptor;
@Rule
public final MockitoRule mockito = MockitoJUnit.rule();
@@ -102,7 +102,8 @@ public class FaceDetectClientTest {
InOrder order = inOrder(mHal, mBiometricContext);
order.verify(mBiometricContext).updateContext(
mOperationContextCaptor.capture(), anyBoolean());
- order.verify(mHal).detectInteractionWithContext(same(mOperationContextCaptor.getValue()));
+ order.verify(mHal).detectInteractionWithContext(
+ same(mOperationContextCaptor.getValue().toAidlContext()));
verify(mHal, never()).detectInteraction();
}
diff --git a/services/tests/servicestests/src/com/android/server/biometrics/sensors/face/aidl/FaceEnrollClientTest.java b/services/tests/servicestests/src/com/android/server/biometrics/sensors/face/aidl/FaceEnrollClientTest.java
index 38e048bc1ba7..d75aca1ce480 100644
--- a/services/tests/servicestests/src/com/android/server/biometrics/sensors/face/aidl/FaceEnrollClientTest.java
+++ b/services/tests/servicestests/src/com/android/server/biometrics/sensors/face/aidl/FaceEnrollClientTest.java
@@ -25,7 +25,6 @@ import static org.mockito.Mockito.same;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
-import android.hardware.biometrics.common.OperationContext;
import android.hardware.biometrics.face.ISession;
import android.hardware.face.Face;
import android.os.IBinder;
@@ -38,6 +37,7 @@ import androidx.test.platform.app.InstrumentationRegistry;
import com.android.server.biometrics.log.BiometricContext;
import com.android.server.biometrics.log.BiometricLogger;
+import com.android.server.biometrics.log.OperationContextExt;
import com.android.server.biometrics.sensors.BiometricUtils;
import com.android.server.biometrics.sensors.ClientMonitorCallback;
import com.android.server.biometrics.sensors.ClientMonitorCallbackConverter;
@@ -80,7 +80,7 @@ public class FaceEnrollClientTest {
@Mock
private Sensor.HalSessionCallback mHalSessionCallback;
@Captor
- private ArgumentCaptor<OperationContext> mOperationContextCaptor;
+ private ArgumentCaptor<OperationContextExt> mOperationContextCaptor;
@Rule
public final MockitoRule mockito = MockitoJUnit.rule();
@@ -109,7 +109,7 @@ public class FaceEnrollClientTest {
order.verify(mBiometricContext).updateContext(
mOperationContextCaptor.capture(), anyBoolean());
order.verify(mHal).enrollWithContext(any(), anyByte(), any(), any(),
- same(mOperationContextCaptor.getValue()));
+ same(mOperationContextCaptor.getValue().toAidlContext()));
verify(mHal, never()).enroll(any(), anyByte(), any(), any());
}
diff --git a/services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintAuthenticationClientTest.java b/services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintAuthenticationClientTest.java
index 22c53d349c5f..20beed0f6e82 100644
--- a/services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintAuthenticationClientTest.java
+++ b/services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintAuthenticationClientTest.java
@@ -16,6 +16,8 @@
package com.android.server.biometrics.sensors.fingerprint.aidl;
+import static com.google.common.truth.Truth.assertThat;
+
import static org.mockito.ArgumentMatchers.anyBoolean;
import static org.mockito.Mockito.any;
import static org.mockito.Mockito.anyFloat;
@@ -57,6 +59,7 @@ import com.android.internal.R;
import com.android.server.biometrics.log.BiometricContext;
import com.android.server.biometrics.log.BiometricLogger;
import com.android.server.biometrics.log.CallbackWithProbe;
+import com.android.server.biometrics.log.OperationContextExt;
import com.android.server.biometrics.log.Probe;
import com.android.server.biometrics.sensors.AuthSessionCoordinator;
import com.android.server.biometrics.sensors.ClientMonitorCallback;
@@ -131,7 +134,7 @@ public class FingerprintAuthenticationClientTest {
@Mock
private Clock mClock;
@Captor
- private ArgumentCaptor<OperationContext> mOperationContextCaptor;
+ private ArgumentCaptor<OperationContextExt> mOperationContextCaptor;
@Captor
private ArgumentCaptor<Consumer<OperationContext>> mContextInjector;
private final TestLooper mLooper = new TestLooper();
@@ -164,7 +167,7 @@ public class FingerprintAuthenticationClientTest {
order.verify(mBiometricContext).updateContext(
mOperationContextCaptor.capture(), anyBoolean());
order.verify(mHal).authenticateWithContext(
- eq(OP_ID), same(mOperationContextCaptor.getValue()));
+ eq(OP_ID), same(mOperationContextCaptor.getValue().toAidlContext()));
verify(mHal, never()).authenticate(anyLong());
}
@@ -236,9 +239,14 @@ public class FingerprintAuthenticationClientTest {
final FingerprintAuthenticationClient client = createClient();
client.start(mCallback);
- verify(mHal).authenticateWithContext(eq(OP_ID), mOperationContextCaptor.capture());
- OperationContext opContext = mOperationContextCaptor.getValue();
- verify(mBiometricContext).subscribe(eq(opContext), mContextInjector.capture());
+ final ArgumentCaptor<OperationContext> captor =
+ ArgumentCaptor.forClass(OperationContext.class);
+ verify(mHal).authenticateWithContext(eq(OP_ID), captor.capture());
+ OperationContext opContext = captor.getValue();
+ verify(mBiometricContext).subscribe(
+ mOperationContextCaptor.capture(), mContextInjector.capture());
+ assertThat(mOperationContextCaptor.getValue().toAidlContext())
+ .isSameInstanceAs(opContext);
mContextInjector.getValue().accept(opContext);
verify(mLuxProbe, never()).enable();
@@ -282,9 +290,14 @@ public class FingerprintAuthenticationClientTest {
final FingerprintAuthenticationClient client = createClient();
client.start(mCallback);
- verify(mHal).authenticateWithContext(eq(OP_ID), mOperationContextCaptor.capture());
- OperationContext opContext = mOperationContextCaptor.getValue();
- verify(mBiometricContext).subscribe(eq(opContext), mContextInjector.capture());
+ final ArgumentCaptor<OperationContext> captor =
+ ArgumentCaptor.forClass(OperationContext.class);
+ verify(mHal).authenticateWithContext(eq(OP_ID), captor.capture());
+ OperationContext opContext = captor.getValue();
+ verify(mBiometricContext).subscribe(
+ mOperationContextCaptor.capture(), mContextInjector.capture());
+ assertThat(opContext).isSameInstanceAs(
+ mOperationContextCaptor.getValue().toAidlContext());
mContextInjector.getValue().accept(opContext);
verify(mLuxProbe, never()).enable();
@@ -310,16 +323,21 @@ public class FingerprintAuthenticationClientTest {
final FingerprintAuthenticationClient client = createClient();
client.start(mCallback);
- verify(mHal).authenticateWithContext(eq(OP_ID), mOperationContextCaptor.capture());
- OperationContext opContext = mOperationContextCaptor.getValue();
+ final ArgumentCaptor<OperationContext> captor =
+ ArgumentCaptor.forClass(OperationContext.class);
+ verify(mHal).authenticateWithContext(eq(OP_ID), captor.capture());
+ OperationContext opContext = captor.getValue();
// fake an update to the context
- verify(mBiometricContext).subscribe(eq(opContext), mContextInjector.capture());
+ verify(mBiometricContext).subscribe(
+ mOperationContextCaptor.capture(), mContextInjector.capture());
+ assertThat(opContext).isSameInstanceAs(
+ mOperationContextCaptor.getValue().toAidlContext());
mContextInjector.getValue().accept(opContext);
verify(mHal).onContextChanged(eq(opContext));
client.stopHalOperation();
- verify(mBiometricContext).unsubscribe(same(opContext));
+ verify(mBiometricContext).unsubscribe(same(mOperationContextCaptor.getValue()));
}
@Test
diff --git a/services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintDetectClientTest.java b/services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintDetectClientTest.java
index 4579fc15f661..2dbd8f69d694 100644
--- a/services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintDetectClientTest.java
+++ b/services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintDetectClientTest.java
@@ -24,7 +24,6 @@ import static org.mockito.Mockito.same;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
-import android.hardware.biometrics.common.OperationContext;
import android.hardware.biometrics.fingerprint.ISession;
import android.hardware.fingerprint.IUdfpsOverlayController;
import android.os.IBinder;
@@ -37,6 +36,7 @@ import androidx.test.platform.app.InstrumentationRegistry;
import com.android.server.biometrics.log.BiometricContext;
import com.android.server.biometrics.log.BiometricLogger;
+import com.android.server.biometrics.log.OperationContextExt;
import com.android.server.biometrics.sensors.ClientMonitorCallback;
import com.android.server.biometrics.sensors.ClientMonitorCallbackConverter;
@@ -77,7 +77,7 @@ public class FingerprintDetectClientTest {
@Mock
private Sensor.HalSessionCallback mHalSessionCallback;
@Captor
- private ArgumentCaptor<OperationContext> mOperationContextCaptor;
+ private ArgumentCaptor<OperationContextExt> mOperationContextCaptor;
@Rule
public final MockitoRule mockito = MockitoJUnit.rule();
@@ -107,7 +107,8 @@ public class FingerprintDetectClientTest {
InOrder order = inOrder(mHal, mBiometricContext);
order.verify(mBiometricContext).updateContext(
mOperationContextCaptor.capture(), anyBoolean());
- order.verify(mHal).detectInteractionWithContext(same(mOperationContextCaptor.getValue()));
+ order.verify(mHal).detectInteractionWithContext(
+ same(mOperationContextCaptor.getValue().toAidlContext()));
verify(mHal, never()).detectInteraction();
}
diff --git a/services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintEnrollClientTest.java b/services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintEnrollClientTest.java
index c3d478311423..26524d7df7c3 100644
--- a/services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintEnrollClientTest.java
+++ b/services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintEnrollClientTest.java
@@ -48,6 +48,7 @@ import androidx.test.platform.app.InstrumentationRegistry;
import com.android.server.biometrics.log.BiometricContext;
import com.android.server.biometrics.log.BiometricLogger;
import com.android.server.biometrics.log.CallbackWithProbe;
+import com.android.server.biometrics.log.OperationContextExt;
import com.android.server.biometrics.log.Probe;
import com.android.server.biometrics.sensors.BiometricUtils;
import com.android.server.biometrics.sensors.ClientMonitorCallback;
@@ -107,7 +108,7 @@ public class FingerprintEnrollClientTest {
@Mock
private Probe mLuxProbe;
@Captor
- private ArgumentCaptor<OperationContext> mOperationContextCaptor;
+ private ArgumentCaptor<OperationContextExt> mOperationContextCaptor;
@Captor
private ArgumentCaptor<PointerContext> mPointerContextCaptor;
@Captor
@@ -143,7 +144,8 @@ public class FingerprintEnrollClientTest {
InOrder order = inOrder(mHal, mBiometricContext);
order.verify(mBiometricContext).updateContext(
mOperationContextCaptor.capture(), anyBoolean());
- order.verify(mHal).enrollWithContext(any(), same(mOperationContextCaptor.getValue()));
+ order.verify(mHal).enrollWithContext(any(),
+ same(mOperationContextCaptor.getValue().toAidlContext()));
verify(mHal, never()).enroll(any());
}
@@ -234,16 +236,20 @@ public class FingerprintEnrollClientTest {
final FingerprintEnrollClient client = createClient();
client.start(mCallback);
- verify(mHal).enrollWithContext(any(), mOperationContextCaptor.capture());
- OperationContext opContext = mOperationContextCaptor.getValue();
+ final ArgumentCaptor<OperationContext> captor =
+ ArgumentCaptor.forClass(OperationContext.class);
+ verify(mHal).enrollWithContext(any(), captor.capture());
+ OperationContext opContext = captor.getValue();
// fake an update to the context
- verify(mBiometricContext).subscribe(eq(opContext), mContextInjector.capture());
- mContextInjector.getValue().accept(opContext);
+ verify(mBiometricContext).subscribe(
+ mOperationContextCaptor.capture(), mContextInjector.capture());
+ mContextInjector.getValue().accept(
+ mOperationContextCaptor.getValue().toAidlContext());
verify(mHal).onContextChanged(eq(opContext));
client.stopHalOperation();
- verify(mBiometricContext).unsubscribe(same(opContext));
+ verify(mBiometricContext).unsubscribe(same(mOperationContextCaptor.getValue()));
}
@Test