Merge "Fix condition where FP would require confirmation" into sc-dev

This commit is contained in:
Kevin Chyn
2021-07-31 00:10:05 +00:00
committed by Android (Google) Code Review
4 changed files with 83 additions and 61 deletions

View File

@@ -93,6 +93,8 @@ public class AuthBiometricFaceToFingerprintView extends AuthBiometricFaceView {
@Nullable private ModalityListener mModalityListener;
@Nullable private FingerprintSensorPropertiesInternal mFingerprintSensorProps;
@Nullable private UdfpsDialogMeasureAdapter mUdfpsMeasureAdapter;
@Nullable @VisibleForTesting UdfpsIconController mUdfpsIconController;
public AuthBiometricFaceToFingerprintView(Context context) {
super(context);
@@ -107,6 +109,12 @@ public class AuthBiometricFaceToFingerprintView extends AuthBiometricFaceView {
super(context, attrs, injector);
}
@Override
protected void onFinishInflate() {
super.onFinishInflate();
mUdfpsIconController = new UdfpsIconController(mContext, mIconView, mIndicatorView);
}
@Modality
int getActiveSensorType() {
return mActiveSensorType;
@@ -167,36 +175,27 @@ public class AuthBiometricFaceToFingerprintView extends AuthBiometricFaceView {
return super.getStateForAfterError();
}
@Override
@NonNull
protected IconController getIconController() {
if (mActiveSensorType == TYPE_FINGERPRINT) {
if (!(mIconController instanceof UdfpsIconController)) {
mIconController = createUdfpsIconController();
}
return mIconController;
}
return super.getIconController();
}
@NonNull
protected IconController createUdfpsIconController() {
return new UdfpsIconController(getContext(), mIconView, mIndicatorView);
}
@Override
public void updateState(@BiometricState int newState) {
if (mState == STATE_HELP || mState == STATE_ERROR) {
@Modality final int currentType = mActiveSensorType;
mActiveSensorType = TYPE_FINGERPRINT;
if (mActiveSensorType == TYPE_FACE) {
if (newState == STATE_HELP || newState == STATE_ERROR) {
mActiveSensorType = TYPE_FINGERPRINT;
setRequireConfirmation(false);
mConfirmButton.setEnabled(false);
mConfirmButton.setVisibility(View.GONE);
setRequireConfirmation(false);
mConfirmButton.setEnabled(false);
mConfirmButton.setVisibility(View.GONE);
if (mModalityListener != null && currentType != mActiveSensorType) {
mModalityListener.onModalitySwitched(currentType, mActiveSensorType);
if (mModalityListener != null) {
mModalityListener.onModalitySwitched(TYPE_FACE, mActiveSensorType);
}
// Deactivate the face icon controller so it stops drawing to the view
mFaceIconController.deactivate();
// Then, activate this icon controller. We need to start in the "error" state
mUdfpsIconController.updateState(mState, newState);
}
} else { // Fingerprint
mUdfpsIconController.updateState(mState, newState);
}
super.updateState(newState);

View File

@@ -49,6 +49,7 @@ public class AuthBiometricFaceView extends AuthBiometricView {
protected Handler mHandler;
protected boolean mLastPulseLightToDark; // false = dark to light, true = light to dark
protected @BiometricState int mState;
protected boolean mDeactivated;
protected IconController(Context context, ImageView iconView, TextView textView) {
mContext = context;
@@ -67,6 +68,11 @@ public class AuthBiometricFaceView extends AuthBiometricView {
}
protected void animateIcon(int iconRes, boolean repeat) {
Log.d(TAG, "animateIcon, state: " + mState + ", deactivated: " + mDeactivated);
if (mDeactivated) {
return;
}
final AnimatedVectorDrawable icon =
(AnimatedVectorDrawable) mContext.getDrawable(iconRes);
mIconView.setImageDrawable(icon);
@@ -92,12 +98,26 @@ public class AuthBiometricFaceView extends AuthBiometricView {
@Override
public void onAnimationEnd(Drawable drawable) {
super.onAnimationEnd(drawable);
Log.d(TAG, "onAnimationEnd, mState: " + mState + ", deactivated: " + mDeactivated);
if (mDeactivated) {
return;
}
if (mState == STATE_AUTHENTICATING || mState == STATE_HELP) {
pulseInNextDirection();
}
}
protected void deactivate() {
mDeactivated = true;
}
protected void updateState(int lastState, int newState) {
if (mDeactivated) {
Log.w(TAG, "Ignoring updateState when deactivated: " + newState);
return;
}
final boolean lastStateIsErrorIcon =
lastState == STATE_ERROR || lastState == STATE_HELP;
@@ -142,7 +162,7 @@ public class AuthBiometricFaceView extends AuthBiometricView {
}
}
protected IconController mIconController;
@Nullable @VisibleForTesting IconController mFaceIconController;
public AuthBiometricFaceView(Context context) {
this(context, null);
@@ -157,6 +177,12 @@ public class AuthBiometricFaceView extends AuthBiometricView {
super(context, attrs, injector);
}
@Override
protected void onFinishInflate() {
super.onFinishInflate();
mFaceIconController = new IconController(mContext, mIconView, mIndicatorView);
}
@Override
protected int getDelayAfterAuthenticatedDurationMs() {
return HIDE_DELAY_MS;
@@ -187,17 +213,9 @@ public class AuthBiometricFaceView extends AuthBiometricView {
return true;
}
@NonNull
protected IconController getIconController() {
if (mIconController == null) {
mIconController = new IconController(mContext, mIconView, mIndicatorView);
}
return mIconController;
}
@Override
public void updateState(@BiometricState int newState) {
getIconController().updateState(mState, newState);
mFaceIconController.updateState(mState, newState);
if (newState == STATE_AUTHENTICATING_ANIMATING_IN ||
(newState == STATE_AUTHENTICATING && getSize() == AuthDialog.SIZE_MEDIUM)) {

View File

@@ -23,7 +23,6 @@ import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.inOrder;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.reset;
import static org.mockito.Mockito.verify;
@@ -50,7 +49,6 @@ import com.android.systemui.SysuiTestCase;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.InOrder;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
@@ -78,14 +76,16 @@ public class AuthBiometricFaceToFingerprintViewTest extends SysuiTestCase {
@Mock private TextView mIndicatorView;
@Mock private ImageView mIconView;
@Mock private View mIconHolderView;
@Mock private AuthBiometricFaceView.IconController mIconController;
@Mock private AuthBiometricFaceView.IconController mFaceIconController;
@Mock private AuthBiometricFaceToFingerprintView.UdfpsIconController mUdfpsIconController;
@Before
public void setup() {
MockitoAnnotations.initMocks(this);
mFaceToFpView = new TestableView(mContext);
mFaceToFpView.mIconController = mIconController;
mFaceToFpView.mFaceIconController = mFaceIconController;
mFaceToFpView.mUdfpsIconController = mUdfpsIconController;
mFaceToFpView.setCallback(mCallback);
mFaceToFpView.mNegativeButton = mNegativeButton;
@@ -99,20 +99,23 @@ public class AuthBiometricFaceToFingerprintViewTest extends SysuiTestCase {
@Test
public void testStateUpdated_whenDialogAnimatedIn() {
mFaceToFpView.onDialogAnimatedIn();
verify(mFaceToFpView.mIconController)
verify(mFaceToFpView.mFaceIconController)
.updateState(anyInt(), eq(AuthBiometricFaceToFingerprintView.STATE_AUTHENTICATING));
verify(mFaceToFpView.mUdfpsIconController, never()).updateState(anyInt(), anyInt());
}
@Test
public void testIconUpdatesState_whenDialogStateUpdated() {
mFaceToFpView.onDialogAnimatedIn();
verify(mFaceToFpView.mIconController)
verify(mFaceToFpView.mFaceIconController)
.updateState(anyInt(), eq(AuthBiometricFaceToFingerprintView.STATE_AUTHENTICATING));
verify(mFaceToFpView.mUdfpsIconController, never()).updateState(anyInt(), anyInt());
mFaceToFpView.updateState(AuthBiometricFaceView.STATE_AUTHENTICATED);
verify(mFaceToFpView.mIconController).updateState(
verify(mFaceToFpView.mFaceIconController).updateState(
eq(AuthBiometricFaceToFingerprintView.STATE_AUTHENTICATING),
eq(AuthBiometricFaceToFingerprintView.STATE_AUTHENTICATED));
verify(mFaceToFpView.mUdfpsIconController, never()).updateState(anyInt(), anyInt());
assertEquals(AuthBiometricFaceToFingerprintView.STATE_AUTHENTICATED, mFaceToFpView.mState);
}
@@ -120,21 +123,22 @@ public class AuthBiometricFaceToFingerprintViewTest extends SysuiTestCase {
@Test
public void testStateUpdated_whenSwitchToFingerprint() {
mFaceToFpView.onDialogAnimatedIn();
verify(mFaceToFpView.mIconController)
verify(mFaceToFpView.mFaceIconController)
.updateState(anyInt(), eq(AuthBiometricFaceToFingerprintView.STATE_AUTHENTICATING));
mFaceToFpView.updateState(AuthBiometricFaceToFingerprintView.STATE_ERROR);
mFaceToFpView.updateState(AuthBiometricFaceToFingerprintView.STATE_AUTHENTICATING);
InOrder order = inOrder(mFaceToFpView.mIconController);
order.verify(mFaceToFpView.mIconController).updateState(
verify(mFaceToFpView.mFaceIconController).deactivate();
verify(mFaceToFpView.mUdfpsIconController).updateState(
eq(AuthBiometricFaceToFingerprintView.STATE_AUTHENTICATING),
eq(AuthBiometricFaceToFingerprintView.STATE_ERROR));
order.verify(mFaceToFpView.mIconController).updateState(
verify(mConfirmButton).setVisibility(eq(View.GONE));
mFaceToFpView.updateState(AuthBiometricFaceToFingerprintView.STATE_AUTHENTICATING);
verify(mFaceToFpView.mUdfpsIconController).updateState(
eq(AuthBiometricFaceToFingerprintView.STATE_ERROR),
eq(AuthBiometricFaceToFingerprintView.STATE_AUTHENTICATING));
verify(mConfirmButton).setVisibility(eq(View.GONE));
}
@Test
@@ -172,7 +176,10 @@ public class AuthBiometricFaceToFingerprintViewTest extends SysuiTestCase {
eq(mContext.getString(R.string.fingerprint_dialog_use_fingerprint_instead)));
verify(mCallback).onAction(
eq(AuthBiometricView.Callback.ACTION_START_DELAYED_FINGERPRINT_SENSOR));
assertEquals(AuthBiometricFaceToFingerprintView.STATE_AUTHENTICATING, mFaceToFpView.mState);
// First we enter the error state, since we need to show the error animation/text. The
// error state is later cleared based on a timer, and we enter STATE_AUTHENTICATING.
assertEquals(AuthBiometricFaceToFingerprintView.STATE_ERROR, mFaceToFpView.mState);
}
@Test
@@ -185,13 +192,16 @@ public class AuthBiometricFaceToFingerprintViewTest extends SysuiTestCase {
eq(mContext.getString(R.string.fingerprint_dialog_use_fingerprint_instead)));
verify(mCallback).onAction(
eq(AuthBiometricView.Callback.ACTION_START_DELAYED_FINGERPRINT_SENSOR));
assertEquals(AuthBiometricFaceToFingerprintView.STATE_AUTHENTICATING, mFaceToFpView.mState);
// First we enter the error state, since we need to show the error animation/text. The
// error state is later cleared based on a timer, and we enter STATE_AUTHENTICATING.
assertEquals(AuthBiometricFaceToFingerprintView.STATE_ERROR, mFaceToFpView.mState);
}
@Test
public void testFingerprintOnlyStartsOnFirstError() {
mFaceToFpView.onDialogAnimatedIn();
verify(mFaceToFpView.mIconController)
verify(mFaceToFpView.mFaceIconController)
.updateState(anyInt(), eq(AuthBiometricFaceToFingerprintView.STATE_AUTHENTICATING));
mFaceToFpView.onDialogAnimatedIn();
@@ -260,11 +270,6 @@ public class AuthBiometricFaceToFingerprintViewTest extends SysuiTestCase {
protected int getDelayAfterAuthenticatedDurationMs() {
return 0;
}
@Override
protected IconController createUdfpsIconController() {
return AuthBiometricFaceToFingerprintViewTest.this.mIconController;
}
}
private class MockInjector extends AuthBiometricView.Injector {

View File

@@ -62,7 +62,7 @@ public class AuthBiometricFaceViewTest extends SysuiTestCase {
public void setup() {
MockitoAnnotations.initMocks(this);
mFaceView = new TestableFaceView(mContext);
mFaceView.mIconController = mock(TestableFaceView.TestableIconController.class);
mFaceView.mFaceIconController = mock(TestableFaceView.TestableIconController.class);
mFaceView.setCallback(mCallback);
mFaceView.mNegativeButton = mNegativeButton;
@@ -78,18 +78,18 @@ public class AuthBiometricFaceViewTest extends SysuiTestCase {
@Test
public void testStateUpdated_whenDialogAnimatedIn() {
mFaceView.onDialogAnimatedIn();
verify(mFaceView.mIconController)
verify(mFaceView.mFaceIconController)
.updateState(anyInt(), eq(AuthBiometricFaceView.STATE_AUTHENTICATING));
}
@Test
public void testIconUpdatesState_whenDialogStateUpdated() {
mFaceView.updateState(AuthBiometricFaceView.STATE_AUTHENTICATING);
verify(mFaceView.mIconController)
verify(mFaceView.mFaceIconController)
.updateState(anyInt(), eq(AuthBiometricFaceView.STATE_AUTHENTICATING));
mFaceView.updateState(AuthBiometricFaceView.STATE_AUTHENTICATED);
verify(mFaceView.mIconController).updateState(
verify(mFaceView.mFaceIconController).updateState(
eq(AuthBiometricFaceView.STATE_AUTHENTICATING),
eq(AuthBiometricFaceView.STATE_AUTHENTICATED));
}