diff options
19 files changed, 356 insertions, 94 deletions
diff --git a/core/java/android/hardware/biometrics/IBiometricContextListener.aidl b/core/java/android/hardware/biometrics/IBiometricContextListener.aidl index bf3df90c3e80..6ac658144164 100644 --- a/core/java/android/hardware/biometrics/IBiometricContextListener.aidl +++ b/core/java/android/hardware/biometrics/IBiometricContextListener.aidl @@ -23,11 +23,6 @@ package android.hardware.biometrics; * @hide */ oneway interface IBiometricContextListener { - // Called when aod or awake (screen on) status changes. - // 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 isAod, boolean isAwake); - @VintfStability @Backing(type="int") enum FoldState { 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 index 000213fabe0d..86940ca8581b 100644 --- a/packages/SystemUI/src/com/android/systemui/biometrics/domain/interactor/LogContextInteractor.kt +++ b/packages/SystemUI/src/com/android/systemui/biometrics/domain/interactor/LogContextInteractor.kt @@ -38,7 +38,6 @@ 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.map @@ -147,11 +146,6 @@ constructor( override fun addBiometricContextListener(listener: IBiometricContextListener): Job { return applicationScope.launch { - combine(isAod, isAwake) { doze, awake -> doze to awake } - .onEach { (aod, awake) -> listener.onDozeChanged(aod, 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) } 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 index 94489adc1bd4..1f2b64d7adbd 100644 --- 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 @@ -191,18 +191,11 @@ class LogContextInteractorImplTest : SysuiTestCase() { foldListener.onFoldUpdate(FOLD_UPDATE_FINISH_CLOSED) keyguardTransitionRepository.startTransitionTo(KeyguardState.AOD) - var aod: Boolean? = null - var awake: Boolean? = null var folded: Int? = null var displayState: Int? = null val job = interactor.addBiometricContextListener( object : IBiometricContextListener.Stub() { - override fun onDozeChanged(isAod: Boolean, isAwake: Boolean) { - aod = isAod - awake = isAwake - } - override fun onFoldChanged(foldState: Int) { folded = foldState } @@ -214,8 +207,6 @@ class LogContextInteractorImplTest : SysuiTestCase() { ) runCurrent() - assertThat(aod).isTrue() - assertThat(awake).isFalse() assertThat(folded).isEqualTo(FoldState.FULLY_CLOSED) assertThat(displayState).isEqualTo(AuthenticateOptions.DISPLAY_STATE_AOD) @@ -224,8 +215,6 @@ class LogContextInteractorImplTest : SysuiTestCase() { keyguardTransitionRepository.startTransitionTo(KeyguardState.LOCKSCREEN) runCurrent() - assertThat(aod).isFalse() - assertThat(awake).isTrue() assertThat(folded).isEqualTo(FoldState.HALF_OPENED) assertThat(displayState).isEqualTo(AuthenticateOptions.DISPLAY_STATE_LOCKSCREEN) @@ -236,8 +225,6 @@ class LogContextInteractorImplTest : SysuiTestCase() { keyguardTransitionRepository.startTransitionTo(KeyguardState.AOD) runCurrent() - assertThat(aod).isFalse() - assertThat(awake).isTrue() assertThat(folded).isEqualTo(FoldState.HALF_OPENED) assertThat(displayState).isEqualTo(AuthenticateOptions.DISPLAY_STATE_LOCKSCREEN) } 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 79ce6b48e2e7..3dcea19b6077 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.AuthenticateOptions; +import android.hardware.biometrics.IBiometricContextListener; import android.hardware.biometrics.common.OperationContext; import android.view.Surface; @@ -65,6 +66,7 @@ public interface BiometricContext { * Current fold state from * {@link android.hardware.biometrics.IBiometricContextListener.FoldState}. */ + @IBiometricContextListener.FoldState int getFoldState(); /** Current device display rotation. */ 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 dea8030fe6f8..21ade1bbbc4a 100644 --- a/services/core/java/com/android/server/biometrics/log/BiometricContextProvider.java +++ b/services/core/java/com/android/server/biometrics/log/BiometricContextProvider.java @@ -84,8 +84,6 @@ public final class BiometricContextProvider implements BiometricContext { 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; @@ -117,16 +115,6 @@ public final class BiometricContextProvider implements BiometricContext { try { service.setBiometicContextListener(new IBiometricContextListener.Stub() { @Override - public void onDozeChanged(boolean isAod, boolean isAwake) { - final boolean changed = (mIsAod != isAod) || (mIsAwake != isAwake); - if (changed) { - mIsAod = isAod; - mIsAwake = isAwake; - notifyChanged(); - } - } - - @Override public void onFoldChanged(int foldState) { mFoldState = foldState; // no need to notify, not sent to HAL @@ -185,12 +173,18 @@ public final class BiometricContextProvider implements BiometricContext { @Override public boolean isAod() { - return mIsAod; + return mDisplayState == AuthenticateOptions.DISPLAY_STATE_AOD; } @Override public boolean isAwake() { - return mIsAwake; + switch (mDisplayState) { + case AuthenticateOptions.DISPLAY_STATE_LOCKSCREEN: + case AuthenticateOptions.DISPLAY_STATE_SCREENSAVER: + case AuthenticateOptions.DISPLAY_STATE_UNKNOWN: + return true; + } + return false; } @Override @@ -252,7 +246,7 @@ public final class BiometricContextProvider implements BiometricContext { public String toString() { return "[keyguard session: " + getKeyguardEntrySessionInfo() + ", " + "bp session: " + getBiometricPromptSessionInfo() + ", " - + "isAod: " + isAod() + ", " + + "displayState: " + getDisplayState() + ", " + "isAwake: " + isAwake() + ", " + "isDisplayOn: " + isDisplayOn() + ", " + "dock: " + getDockedState() + ", " diff --git a/services/core/java/com/android/server/biometrics/log/OperationContextExt.java b/services/core/java/com/android/server/biometrics/log/OperationContextExt.java index 293433990cbd..d1de80b4761d 100644 --- a/services/core/java/com/android/server/biometrics/log/OperationContextExt.java +++ b/services/core/java/com/android/server/biometrics/log/OperationContextExt.java @@ -19,8 +19,10 @@ package com.android.server.biometrics.log; import android.annotation.NonNull; import android.annotation.Nullable; import android.content.Intent; +import android.hardware.biometrics.AuthenticateOptions; import android.hardware.biometrics.IBiometricContextListener; import android.hardware.biometrics.common.AuthenticateReason; +import android.hardware.biometrics.common.DisplayState; import android.hardware.biometrics.common.OperationContext; import android.hardware.biometrics.common.OperationReason; import android.hardware.biometrics.common.WakeReason; @@ -204,11 +206,17 @@ public class OperationContextExt { return mIsDisplayOn; } - /** {@link OperationContext#isAod}. */ + /** @deprecated prefer {@link #getDisplayState()} to {@link OperationContext#isAod}. */ public boolean isAod() { return mAidlContext.isAod; } + /** {@link OperationContext#displayState}. */ + @DisplayState + public int getDisplayState() { + return mAidlContext.displayState; + } + /** {@link OperationContext#isCrypto}. */ public boolean isCrypto() { return mAidlContext.isCrypto; @@ -233,6 +241,7 @@ public class OperationContextExt { /** Update this object with the latest values from the given context. */ OperationContextExt update(@NonNull BiometricContext biometricContext) { mAidlContext.isAod = biometricContext.isAod(); + mAidlContext.displayState = toAidlDisplayState(biometricContext.getDisplayState()); setFirstSessionId(biometricContext); mIsDisplayOn = biometricContext.isDisplayOn(); @@ -243,6 +252,21 @@ public class OperationContextExt { return this; } + @DisplayState + private static int toAidlDisplayState(@AuthenticateOptions.DisplayState int state) { + switch (state) { + case AuthenticateOptions.DISPLAY_STATE_AOD: + return DisplayState.AOD; + case AuthenticateOptions.DISPLAY_STATE_LOCKSCREEN: + return DisplayState.LOCKSCREEN; + case AuthenticateOptions.DISPLAY_STATE_NO_UI: + return DisplayState.NO_UI; + case AuthenticateOptions.DISPLAY_STATE_SCREENSAVER: + return DisplayState.SCREENSAVER; + } + return DisplayState.UNKNOWN; + } + private void setFirstSessionId(@NonNull BiometricContext biometricContext) { mSessionInfo = biometricContext.getKeyguardEntrySessionInfo(); if (mSessionInfo != null) { 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 84e2fb4a5966..7ae31b2a114d 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 @@ -40,6 +40,7 @@ import com.android.internal.annotations.VisibleForTesting; import com.android.server.biometrics.Utils; 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.AuthenticationClient; import com.android.server.biometrics.sensors.BiometricNotificationUtils; @@ -165,8 +166,17 @@ class FaceAuthenticationClient extends AuthenticationClient<AidlSession, FaceAut final AidlSession session = getFreshDaemon(); if (session.hasContextMethods()) { - return session.getSession().authenticateWithContext( - mOperationId, getOperationContext().toAidlContext(getOptions())); + final OperationContextExt opContext = getOperationContext(); + final ICancellationSignal cancel = session.getSession().authenticateWithContext( + mOperationId, opContext.toAidlContext(getOptions())); + getBiometricContext().subscribe(opContext, ctx -> { + try { + session.getSession().onContextChanged(ctx); + } catch (RemoteException e) { + Slog.e(TAG, "Unable to notify context changed", e); + } + }); + return cancel; } else { return session.getSession().authenticate(mOperationId); } @@ -174,6 +184,8 @@ class FaceAuthenticationClient extends AuthenticationClient<AidlSession, FaceAut @Override protected void stopHalOperation() { + unsubscribeBiometricContext(); + if (mCancellationSignal != null) { try { mCancellationSignal.cancel(); 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 fa23ccd482fb..9dc1782cea6f 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 @@ -31,6 +31,7 @@ import com.android.internal.annotations.VisibleForTesting; import com.android.server.biometrics.BiometricsProto; 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.AcquisitionClient; import com.android.server.biometrics.sensors.ClientMonitorCallback; import com.android.server.biometrics.sensors.ClientMonitorCallbackConverter; @@ -86,6 +87,8 @@ public class FaceDetectClient extends AcquisitionClient<AidlSession> implements @Override protected void stopHalOperation() { + unsubscribeBiometricContext(); + if (mCancellationSignal != null) { try { mCancellationSignal.cancel(); @@ -119,8 +122,17 @@ public class FaceDetectClient extends AcquisitionClient<AidlSession> implements final AidlSession session = getFreshDaemon(); if (session.hasContextMethods()) { - return session.getSession().detectInteractionWithContext( - getOperationContext().toAidlContext(mOptions)); + final OperationContextExt opContext = getOperationContext(); + final ICancellationSignal cancel = session.getSession().detectInteractionWithContext( + opContext.toAidlContext(mOptions)); + getBiometricContext().subscribe(opContext, ctx -> { + try { + session.getSession().onContextChanged(ctx); + } catch (RemoteException e) { + Slog.e(TAG, "Unable to notify context changed", e); + } + }); + return cancel; } 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 792b52e7d658..722c9afbeaf8 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 @@ -39,6 +39,7 @@ import com.android.server.biometrics.HardwareAuthTokenUtils; import com.android.server.biometrics.Utils; 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.BaseClientMonitor; import com.android.server.biometrics.sensors.BiometricNotificationUtils; import com.android.server.biometrics.sensors.BiometricUtils; @@ -198,9 +199,18 @@ public class FaceEnrollClient extends EnrollClient<AidlSession> { HardwareAuthTokenUtils.toHardwareAuthToken(mHardwareAuthToken); if (session.hasContextMethods()) { - return session.getSession().enrollWithContext( + final OperationContextExt opContext = getOperationContext(); + final ICancellationSignal cancel = session.getSession().enrollWithContext( hat, EnrollmentType.DEFAULT, features, mHwPreviewHandle, - getOperationContext().toAidlContext()); + opContext.toAidlContext()); + getBiometricContext().subscribe(opContext, ctx -> { + try { + session.getSession().onContextChanged(ctx); + } catch (RemoteException e) { + Slog.e(TAG, "Unable to notify context changed", e); + } + }); + return cancel; } else { return session.getSession().enroll(hat, EnrollmentType.DEFAULT, features, mHwPreviewHandle); @@ -209,6 +219,8 @@ public class FaceEnrollClient extends EnrollClient<AidlSession> { @Override protected void stopHalOperation() { + unsubscribeBiometricContext(); + if (mCancellationSignal != null) { try { mCancellationSignal.cancel(); 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 435e81d688bd..2bfc2391b948 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 @@ -262,6 +262,14 @@ class FingerprintAuthenticationClient final AidlSession session = getFreshDaemon(); final OperationContextExt opContext = getOperationContext(); + final ICancellationSignal cancel; + if (session.hasContextMethods()) { + cancel = session.getSession().authenticateWithContext( + mOperationId, opContext.toAidlContext(getOptions())); + } else { + cancel = session.getSession().authenticate(mOperationId); + } + getBiometricContext().subscribe(opContext, ctx -> { if (session.hasContextMethods()) { try { @@ -283,12 +291,7 @@ class FingerprintAuthenticationClient mALSProbeCallback.getProbe().enable(); } - if (session.hasContextMethods()) { - return session.getSession().authenticateWithContext( - mOperationId, opContext.toAidlContext(getOptions())); - } else { - return session.getSession().authenticate(mOperationId); - } + return cancel; } @Override 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 16d16fc95c5b..46f62d38b03e 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 @@ -31,6 +31,7 @@ import android.util.Slog; import com.android.server.biometrics.BiometricsProto; 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.AcquisitionClient; import com.android.server.biometrics.sensors.ClientMonitorCallback; import com.android.server.biometrics.sensors.ClientMonitorCallbackConverter; @@ -79,12 +80,15 @@ class FingerprintDetectClient extends AcquisitionClient<AidlSession> implements @Override protected void stopHalOperation() { mSensorOverlays.hide(getSensorId()); - - try { - mCancellationSignal.cancel(); - } catch (RemoteException e) { - Slog.e(TAG, "Remote exception", e); - mCallback.onClientFinished(this, false /* success */); + unsubscribeBiometricContext(); + + if (mCancellationSignal != null) { + try { + mCancellationSignal.cancel(); + } catch (RemoteException e) { + Slog.e(TAG, "Remote exception", e); + mCallback.onClientFinished(this, false /* success */); + } } } @@ -106,8 +110,17 @@ class FingerprintDetectClient extends AcquisitionClient<AidlSession> implements final AidlSession session = getFreshDaemon(); if (session.hasContextMethods()) { - return session.getSession().detectInteractionWithContext( - getOperationContext().toAidlContext(mOptions)); + final OperationContextExt opContext = getOperationContext(); + final ICancellationSignal cancel = session.getSession().detectInteractionWithContext( + opContext.toAidlContext(mOptions)); + getBiometricContext().subscribe(opContext, ctx -> { + try { + session.getSession().onContextChanged(ctx); + } catch (RemoteException e) { + Slog.e(TAG, "Unable to notify context changed", e); + } + }); + return cancel; } else { return session.getSession().detectInteraction(); } 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 e4aed975102c..07c6182569b2 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 @@ -30,6 +30,7 @@ import static org.mockito.Mockito.when; import android.app.StatusBarManager; import android.content.Intent; +import android.hardware.biometrics.AuthenticateOptions; import android.hardware.biometrics.IBiometricContextListener; import android.hardware.biometrics.IBiometricContextListener.FoldState; import android.hardware.biometrics.common.OperationContext; @@ -59,6 +60,7 @@ import org.mockito.junit.MockitoRule; import java.util.ArrayList; import java.util.List; +import java.util.Map; import java.util.function.Consumer; @Presubmit @@ -102,22 +104,52 @@ public class BiometricContextProviderTest { @Test public void testIsAod() throws RemoteException { - mListener.onDozeChanged(true /* isAod */, false /* isAwake */); - assertThat(mProvider.isAod()).isTrue(); - mListener.onDozeChanged(false /* isAod */, false /* isAwake */); - assertThat(mProvider.isAod()).isFalse(); + final Map<Integer, Boolean> expectedAod = Map.of( + AuthenticateOptions.DISPLAY_STATE_UNKNOWN, false, + AuthenticateOptions.DISPLAY_STATE_AOD, true, + AuthenticateOptions.DISPLAY_STATE_LOCKSCREEN, false, + AuthenticateOptions.DISPLAY_STATE_NO_UI, false, + AuthenticateOptions.DISPLAY_STATE_SCREENSAVER, false + ); + + for (Map.Entry<Integer, Boolean> entry : expectedAod.entrySet()) { + mListener.onDisplayStateChanged(entry.getKey()); + + assertThat(mProvider.isAod()).isEqualTo(entry.getValue()); + } } @Test public void testIsAwake() throws RemoteException { - mListener.onDozeChanged(false /* isAod */, true /* isAwake */); - assertThat(mProvider.isAwake()).isTrue(); - mListener.onDozeChanged(false /* isAod */, false /* isAwake */); - assertThat(mProvider.isAwake()).isFalse(); - mListener.onDozeChanged(true /* isAod */, true /* isAwake */); - assertThat(mProvider.isAwake()).isTrue(); - mListener.onDozeChanged(true /* isAod */, false /* isAwake */); - assertThat(mProvider.isAwake()).isFalse(); + final Map<Integer, Boolean> expectedAwake = Map.of( + AuthenticateOptions.DISPLAY_STATE_UNKNOWN, true, + AuthenticateOptions.DISPLAY_STATE_LOCKSCREEN, true, + AuthenticateOptions.DISPLAY_STATE_SCREENSAVER, true, + AuthenticateOptions.DISPLAY_STATE_NO_UI, false, + AuthenticateOptions.DISPLAY_STATE_AOD, false + ); + + for (Map.Entry<Integer, Boolean> entry : expectedAwake.entrySet()) { + mListener.onDisplayStateChanged(entry.getKey()); + + assertThat(mProvider.isAwake()).isEqualTo(entry.getValue()); + } + } + + @Test + public void testGetDisplayState() throws RemoteException { + final List<Integer> states = List.of( + AuthenticateOptions.DISPLAY_STATE_LOCKSCREEN, + AuthenticateOptions.DISPLAY_STATE_SCREENSAVER, + AuthenticateOptions.DISPLAY_STATE_NO_UI, + AuthenticateOptions.DISPLAY_STATE_AOD, + AuthenticateOptions.DISPLAY_STATE_UNKNOWN); + + for (int state : states) { + mListener.onDisplayStateChanged(state); + + assertThat(mProvider.getDisplayState()).isEqualTo(state); + } } @Test @@ -147,21 +179,54 @@ public class BiometricContextProviderTest { } @Test + public void testSubscribesToDisplayState() throws RemoteException { + final List<Integer> actual = new ArrayList<>(); + final List<Integer> expected = List.of(AuthenticateOptions.DISPLAY_STATE_AOD, + AuthenticateOptions.DISPLAY_STATE_LOCKSCREEN, + AuthenticateOptions.DISPLAY_STATE_AOD, + AuthenticateOptions.DISPLAY_STATE_AOD, + AuthenticateOptions.DISPLAY_STATE_NO_UI, + AuthenticateOptions.DISPLAY_STATE_LOCKSCREEN); + + mProvider.subscribe(mOpContext, ctx -> { + assertThat(ctx).isSameInstanceAs(mOpContext.toAidlContext()); + assertThat(mProvider.getDisplayState()).isEqualTo(ctx.displayState); + actual.add(ctx.displayState); + }); + + for (int v : expected) { + mListener.onDisplayStateChanged(v); + } + + assertThat(actual).containsExactly( + AuthenticateOptions.DISPLAY_STATE_AOD, + AuthenticateOptions.DISPLAY_STATE_LOCKSCREEN, + AuthenticateOptions.DISPLAY_STATE_AOD, + AuthenticateOptions.DISPLAY_STATE_NO_UI, + AuthenticateOptions.DISPLAY_STATE_LOCKSCREEN).inOrder(); + } + + @Test public void testSubscribesToAod() throws RemoteException { final List<Boolean> actual = new ArrayList<>(); mProvider.subscribe(mOpContext, ctx -> { assertThat(ctx).isSameInstanceAs(mOpContext.toAidlContext()); assertThat(mProvider.isAod()).isEqualTo(ctx.isAod); - assertThat(mProvider.isAwake()).isFalse(); actual.add(ctx.isAod); }); - for (boolean v : List.of(true, false, true, true, false, false)) { - mListener.onDozeChanged(v /* isDozing */, false /* isAwake */); + for (int v : List.of( + AuthenticateOptions.DISPLAY_STATE_AOD, + AuthenticateOptions.DISPLAY_STATE_LOCKSCREEN, + AuthenticateOptions.DISPLAY_STATE_AOD, + AuthenticateOptions.DISPLAY_STATE_AOD, + AuthenticateOptions.DISPLAY_STATE_NO_UI, + AuthenticateOptions.DISPLAY_STATE_LOCKSCREEN)) { + mListener.onDisplayStateChanged(v); } - assertThat(actual).containsExactly(true, false, true, false).inOrder(); + assertThat(actual).containsExactly(true, false, true, false, false).inOrder(); } @Test @@ -170,16 +235,20 @@ public class BiometricContextProviderTest { mProvider.subscribe(mOpContext, ctx -> { assertThat(ctx).isSameInstanceAs(mOpContext.toAidlContext()); - assertThat(ctx.isAod).isFalse(); - assertThat(mProvider.isAod()).isFalse(); actual.add(mProvider.isAwake()); }); - for (boolean v : List.of(true, false, true, true, false, false)) { - mListener.onDozeChanged(false /* isDozing */, v /* isAwake */); + for (int v : List.of( + AuthenticateOptions.DISPLAY_STATE_LOCKSCREEN, + AuthenticateOptions.DISPLAY_STATE_NO_UI, + AuthenticateOptions.DISPLAY_STATE_SCREENSAVER, + AuthenticateOptions.DISPLAY_STATE_LOCKSCREEN, + AuthenticateOptions.DISPLAY_STATE_AOD, + AuthenticateOptions.DISPLAY_STATE_NO_UI)) { + mListener.onDisplayStateChanged(v); } - assertThat(actual).containsExactly(true, false, true, false).inOrder(); + assertThat(actual).containsExactly(true, false, true, true, false, false).inOrder(); } @Test @@ -188,13 +257,13 @@ public class BiometricContextProviderTest { mProvider.subscribe(mOpContext, emptyConsumer); mProvider.unsubscribe(mOpContext); - mListener.onDozeChanged(true /* isDozing */, false /* isAwake */); + mListener.onDisplayStateChanged(AuthenticateOptions.DISPLAY_STATE_AOD); final Consumer<OperationContext> nonEmptyConsumer = mock(Consumer.class); mProvider.subscribe(mOpContext, nonEmptyConsumer); - mListener.onDozeChanged(false /* isDozing */, false /* isAwake */); + mListener.onDisplayStateChanged(AuthenticateOptions.DISPLAY_STATE_LOCKSCREEN); mProvider.unsubscribe(mOpContext); - mListener.onDozeChanged(true /* isDozing */, false /* isAwake */); + mListener.onDisplayStateChanged(AuthenticateOptions.DISPLAY_STATE_NO_UI); verify(emptyConsumer, never()).accept(any()); verify(nonEmptyConsumer).accept(same(mOpContext.toAidlContext())); @@ -235,7 +304,7 @@ public class BiometricContextProviderTest { @Test public void testUpdate() throws RemoteException { - mListener.onDozeChanged(false /* isDozing */, false /* isAwake */); + mListener.onDisplayStateChanged(AuthenticateOptions.DISPLAY_STATE_NO_UI); OperationContextExt context = mProvider.updateContext(mOpContext, false /* crypto */); OperationContext aidlContext = context.toAidlContext(); @@ -252,7 +321,8 @@ public class BiometricContextProviderTest { final int id = 40 + type; final boolean aod = (type & 1) == 0; - mListener.onDozeChanged(aod /* isDozing */, false /* isAwake */); + mListener.onDisplayStateChanged(aod ? AuthenticateOptions.DISPLAY_STATE_AOD + : AuthenticateOptions.DISPLAY_STATE_LOCKSCREEN); mSessionListener.onSessionStarted(type, InstanceId.fakeInstanceId(id)); context = mProvider.updateContext(mOpContext, false /* crypto */); aidlContext = context.toAidlContext(); 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 index c7962c82471a..c652b74f5848 100644 --- a/services/tests/servicestests/src/com/android/server/biometrics/log/OperationContextExtTest.java +++ b/services/tests/servicestests/src/com/android/server/biometrics/log/OperationContextExtTest.java @@ -19,7 +19,9 @@ package com.android.server.biometrics.log; import static com.google.common.truth.Truth.assertThat; import android.content.Intent; +import android.hardware.biometrics.AuthenticateOptions; import android.hardware.biometrics.IBiometricContextListener; +import android.hardware.biometrics.common.DisplayState; import android.hardware.biometrics.common.OperationContext; import android.hardware.biometrics.common.OperationReason; import android.platform.test.annotations.Presubmit; @@ -37,6 +39,8 @@ import org.mockito.Mock; import org.mockito.junit.MockitoJUnit; import org.mockito.junit.MockitoRule; +import java.util.Map; + @Presubmit @SmallTest public class OperationContextExtTest { @@ -59,15 +63,18 @@ public class OperationContextExtTest { final int id = 5; final byte reason = OperationReason.UNKNOWN; + final int displayState = DisplayState.NO_UI; aidlContext.id = id; aidlContext.isAod = true; aidlContext.isCrypto = true; aidlContext.reason = reason; + aidlContext.displayState = displayState; assertThat(context.getId()).isEqualTo(id); assertThat(context.isAod()).isTrue(); assertThat(context.isCrypto()).isTrue(); assertThat(context.getReason()).isEqualTo(reason); + assertThat(context.getDisplayState()).isEqualTo(displayState); } @Test @@ -78,6 +85,25 @@ public class OperationContextExtTest { } @Test + public void mapsDisplayStatesToAidl() { + final Map<Integer, Integer> map = Map.of( + AuthenticateOptions.DISPLAY_STATE_UNKNOWN, DisplayState.UNKNOWN, + AuthenticateOptions.DISPLAY_STATE_AOD, DisplayState.AOD, + AuthenticateOptions.DISPLAY_STATE_NO_UI, DisplayState.NO_UI, + AuthenticateOptions.DISPLAY_STATE_LOCKSCREEN, DisplayState.LOCKSCREEN, + AuthenticateOptions.DISPLAY_STATE_SCREENSAVER, DisplayState.SCREENSAVER, + 100, DisplayState.UNKNOWN + ); + + for (Map.Entry<Integer, Integer> entry : map.entrySet()) { + final OperationContextExt context = new OperationContextExt(newAidlContext()); + when(mBiometricContext.getDisplayState()).thenReturn(entry.getKey()); + assertThat(context.update(mBiometricContext).getDisplayState()) + .isEqualTo(entry.getValue()); + } + } + + @Test public void updatesFromSourceForKeyguard() { final BiometricContextSessionInfo info = new BiometricContextSessionInfo(InstanceId.fakeInstanceId(9)); @@ -102,11 +128,13 @@ public class OperationContextExtTest { final int rotation = Surface.ROTATION_270; final int foldState = IBiometricContextListener.FoldState.HALF_OPENED; final int dockState = Intent.EXTRA_DOCK_STATE_CAR; + final int displayState = AuthenticateOptions.DISPLAY_STATE_AOD; when(mBiometricContext.getCurrentRotation()).thenReturn(rotation); when(mBiometricContext.getFoldState()).thenReturn(foldState); when(mBiometricContext.getDockedState()).thenReturn(dockState); when(mBiometricContext.isDisplayOn()).thenReturn(true); + when(mBiometricContext.getDisplayState()).thenReturn(displayState); final OperationContextExt context = new OperationContextExt(newAidlContext()); @@ -124,6 +152,7 @@ public class OperationContextExtTest { assertThat(context.getFoldState()).isEqualTo(foldState); assertThat(context.getOrientation()).isEqualTo(rotation); assertThat(context.isDisplayOn()).isTrue(); + assertThat(context.getDisplayState()).isEqualTo(DisplayState.AOD); } private static OperationContext newAidlContext() { 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 6b0e33037af8..7468901a16af 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 @@ -68,6 +68,7 @@ import org.mockito.junit.MockitoRule; import java.util.ArrayList; import java.util.List; +import java.util.function.Consumer; @Presubmit @SmallTest @@ -106,6 +107,8 @@ public class FaceAuthenticationClientTest { private AuthSessionCoordinator mAuthSessionCoordinator; @Captor private ArgumentCaptor<OperationContextExt> mOperationContextCaptor; + @Captor + private ArgumentCaptor<Consumer<OperationContext>> mContextInjector; @Rule public final MockitoRule mockito = MockitoJUnit.rule(); @@ -145,6 +148,28 @@ public class FaceAuthenticationClientTest { } @Test + public void notifyHalWhenContextChanges() throws RemoteException { + final FaceAuthenticationClient client = createClient(); + client.start(mCallback); + + 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( + mOperationContextCaptor.capture(), mContextInjector.capture()); + assertThat(opContext).isSameInstanceAs( + mOperationContextCaptor.getValue().toAidlContext()); + mContextInjector.getValue().accept(opContext); + verify(mHal).onContextChanged(same(opContext)); + + client.stopHalOperation(); + verify(mBiometricContext).unsubscribe(same(mOperationContextCaptor.getValue())); + } + + @Test public void cancelsAuthWhenNotInForeground() throws Exception { final ActivityManager.RunningTaskInfo topTask = new ActivityManager.RunningTaskInfo(); topTask.topActivity = new ComponentName("other", "thing"); 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 0abfa7e6546d..c26eee97fbfe 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 @@ -56,6 +56,8 @@ import org.mockito.Mock; import org.mockito.junit.MockitoJUnit; import org.mockito.junit.MockitoRule; +import java.util.function.Consumer; + @Presubmit @SmallTest public class FaceDetectClientTest { @@ -84,6 +86,8 @@ public class FaceDetectClientTest { private Sensor.HalSessionCallback mHalSessionCallback; @Captor private ArgumentCaptor<OperationContextExt> mOperationContextCaptor; + @Captor + private ArgumentCaptor<Consumer<OperationContext>> mContextInjector; @Rule public final MockitoRule mockito = MockitoJUnit.rule(); @@ -121,6 +125,32 @@ public class FaceDetectClientTest { verify(mHal, never()).detectInteraction(); } + @Test + public void notifyHalWhenContextChanges() throws RemoteException { + final FaceDetectClient client = createClient(); + client.start(mCallback); + + final ArgumentCaptor<OperationContext> captor = + ArgumentCaptor.forClass(OperationContext.class); + verify(mHal).detectInteractionWithContext(captor.capture()); + OperationContext opContext = captor.getValue(); + + // fake an update to the context + verify(mBiometricContext).subscribe( + mOperationContextCaptor.capture(), mContextInjector.capture()); + assertThat(opContext).isSameInstanceAs( + mOperationContextCaptor.getValue().toAidlContext()); + mContextInjector.getValue().accept(opContext); + verify(mHal).onContextChanged(same(opContext)); + + client.stopHalOperation(); + verify(mBiometricContext).unsubscribe(same(mOperationContextCaptor.getValue())); + } + + private FaceDetectClient createClient() throws RemoteException { + return createClient(100 /* version */); + } + private FaceDetectClient createClient(int version) throws RemoteException { when(mHal.getInterfaceVersion()).thenReturn(version); 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 d75aca1ce480..54d116f07805 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 @@ -16,6 +16,8 @@ package com.android.server.biometrics.sensors.face.aidl; +import static com.google.common.truth.Truth.assertThat; + import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyBoolean; import static org.mockito.ArgumentMatchers.anyByte; @@ -25,6 +27,7 @@ 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; @@ -52,6 +55,8 @@ import org.mockito.Mock; import org.mockito.junit.MockitoJUnit; import org.mockito.junit.MockitoRule; +import java.util.function.Consumer; + @Presubmit @SmallTest public class FaceEnrollClientTest { @@ -81,6 +86,8 @@ public class FaceEnrollClientTest { private Sensor.HalSessionCallback mHalSessionCallback; @Captor private ArgumentCaptor<OperationContextExt> mOperationContextCaptor; + @Captor + private ArgumentCaptor<Consumer<OperationContext>> mContextInjector; @Rule public final MockitoRule mockito = MockitoJUnit.rule(); @@ -108,11 +115,38 @@ public class FaceEnrollClientTest { InOrder order = inOrder(mHal, mBiometricContext); order.verify(mBiometricContext).updateContext( mOperationContextCaptor.capture(), anyBoolean()); - order.verify(mHal).enrollWithContext(any(), anyByte(), any(), any(), - same(mOperationContextCaptor.getValue().toAidlContext())); + + final OperationContext aidlContext = mOperationContextCaptor.getValue().toAidlContext(); + order.verify(mHal).enrollWithContext(any(), anyByte(), any(), any(), same(aidlContext)); verify(mHal, never()).enroll(any(), anyByte(), any(), any()); } + @Test + public void notifyHalWhenContextChanges() throws RemoteException { + final FaceEnrollClient client = createClient(); + client.start(mCallback); + + final ArgumentCaptor<OperationContext> captor = + ArgumentCaptor.forClass(OperationContext.class); + verify(mHal).enrollWithContext(any(), anyByte(), any(), any(), captor.capture()); + OperationContext opContext = captor.getValue(); + + // fake an update to the context + verify(mBiometricContext).subscribe( + mOperationContextCaptor.capture(), mContextInjector.capture()); + assertThat(opContext).isSameInstanceAs( + mOperationContextCaptor.getValue().toAidlContext()); + mContextInjector.getValue().accept(opContext); + verify(mHal).onContextChanged(same(opContext)); + + client.stopHalOperation(); + verify(mBiometricContext).unsubscribe(same(mOperationContextCaptor.getValue())); + } + + private FaceEnrollClient createClient() throws RemoteException { + return createClient(200 /* version */); + } + private FaceEnrollClient createClient(int version) throws RemoteException { when(mHal.getInterfaceVersion()).thenReturn(version); 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 c6645003c7e2..f8f40fe44457 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 @@ -338,7 +338,7 @@ public class FingerprintAuthenticationClientTest { assertThat(opContext).isSameInstanceAs( mOperationContextCaptor.getValue().toAidlContext()); mContextInjector.getValue().accept(opContext); - verify(mHal).onContextChanged(eq(opContext)); + verify(mHal).onContextChanged(same(opContext)); client.stopHalOperation(); verify(mBiometricContext).unsubscribe(same(mOperationContextCaptor.getValue())); 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 c20cc392f5c0..6dfdd8712d66 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 @@ -55,6 +55,8 @@ import org.mockito.Mock; import org.mockito.junit.MockitoJUnit; import org.mockito.junit.MockitoRule; +import java.util.function.Consumer; + @Presubmit @SmallTest public class FingerprintDetectClientTest { @@ -83,6 +85,8 @@ public class FingerprintDetectClientTest { private Sensor.HalSessionCallback mHalSessionCallback; @Captor private ArgumentCaptor<OperationContextExt> mOperationContextCaptor; + @Captor + private ArgumentCaptor<Consumer<OperationContext>> mContextInjector; @Rule public final MockitoRule mockito = MockitoJUnit.rule(); @@ -121,6 +125,32 @@ public class FingerprintDetectClientTest { verify(mHal, never()).detectInteraction(); } + @Test + public void notifyHalWhenContextChanges() throws RemoteException { + final FingerprintDetectClient client = createClient(); + client.start(mCallback); + + final ArgumentCaptor<OperationContext> captor = + ArgumentCaptor.forClass(OperationContext.class); + verify(mHal).detectInteractionWithContext(captor.capture()); + OperationContext opContext = captor.getValue(); + + // fake an update to the context + verify(mBiometricContext).subscribe( + mOperationContextCaptor.capture(), mContextInjector.capture()); + assertThat(opContext).isSameInstanceAs( + mOperationContextCaptor.getValue().toAidlContext()); + mContextInjector.getValue().accept(opContext); + verify(mHal).onContextChanged(same(opContext)); + + client.stopHalOperation(); + verify(mBiometricContext).unsubscribe(same(mOperationContextCaptor.getValue())); + } + + private FingerprintDetectClient createClient() throws RemoteException { + return createClient(200 /* version */); + } + private FingerprintDetectClient createClient(int version) throws RemoteException { when(mHal.getInterfaceVersion()).thenReturn(version); 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 7646c401193f..3c89278c69b0 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 @@ -16,8 +16,6 @@ package com.android.server.biometrics.sensors.fingerprint.aidl; -import static android.hardware.biometrics.BiometricFingerprintConstants.FINGERPRINT_ACQUIRED_POWER_PRESSED; - import static org.mockito.ArgumentMatchers.anyBoolean; import static org.mockito.ArgumentMatchers.anyFloat; import static org.mockito.ArgumentMatchers.anyInt; @@ -110,8 +108,6 @@ public class FingerprintEnrollClientTest { @Captor private ArgumentCaptor<OperationContextExt> mOperationContextCaptor; @Captor - private ArgumentCaptor<PointerContext> mPointerContextCaptor; - @Captor private ArgumentCaptor<Consumer<OperationContext>> mContextInjector; @Rule @@ -246,7 +242,7 @@ public class FingerprintEnrollClientTest { mOperationContextCaptor.capture(), mContextInjector.capture()); mContextInjector.getValue().accept( mOperationContextCaptor.getValue().toAidlContext()); - verify(mHal).onContextChanged(eq(opContext)); + verify(mHal).onContextChanged(same(opContext)); client.stopHalOperation(); verify(mBiometricContext).unsubscribe(same(mOperationContextCaptor.getValue())); |