Merge "Propogate SysUI's display state changes to face & fingerprint HAL." into udc-dev

This commit is contained in:
Joe Bolinger
2023-04-04 17:59:56 +00:00
committed by Android (Google) Code Review
19 changed files with 355 additions and 93 deletions

View File

@@ -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 {

View File

@@ -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) }

View File

@@ -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)
}

View File

@@ -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. */

View File

@@ -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;
@@ -116,16 +114,6 @@ public final class BiometricContextProvider implements BiometricContext {
private void subscribeBiometricContextListener(@NonNull IStatusBarService service) {
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;
@@ -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() + ", "

View File

@@ -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) {

View File

@@ -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();

View File

@@ -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();
}

View File

@@ -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();

View File

@@ -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

View File

@@ -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());
unsubscribeBiometricContext();
try {
mCancellationSignal.cancel();
} catch (RemoteException e) {
Slog.e(TAG, "Remote exception", e);
mCallback.onClientFinished(this, false /* success */);
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();
}

View File

@@ -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
@@ -146,6 +178,34 @@ 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<>();
@@ -153,15 +213,20 @@ public class BiometricContextProviderTest {
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();

View File

@@ -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
@@ -77,6 +84,25 @@ public class OperationContextExtTest {
assertThat(context.getOrderAndIncrement()).isEqualTo(-1);
}
@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 =
@@ -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() {

View File

@@ -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();
@@ -144,6 +147,28 @@ public class FaceAuthenticationClientTest {
verify(mHal, never()).authenticate(anyLong());
}
@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();

View File

@@ -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);

View File

@@ -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);

View File

@@ -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()));

View File

@@ -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);

View File

@@ -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()));