diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java index f07d9ce215636..98946ac5b0eec 100644 --- a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java @@ -214,7 +214,8 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab * If no cancel signal has been received after this amount of time, set the biometric running * state to stopped to allow Keyguard to retry authentication. */ - private static final int DEFAULT_CANCEL_SIGNAL_TIMEOUT = 3000; + @VisibleForTesting + protected static final int DEFAULT_CANCEL_SIGNAL_TIMEOUT = 3000; private static final ComponentName FALLBACK_HOME_COMPONENT = new ComponentName( "com.android.settings", "com.android.settings.FallbackHome"); @@ -332,10 +333,15 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab private static final int HAL_ERROR_RETRY_TIMEOUT = 500; // ms private static final int HAL_ERROR_RETRY_MAX = 20; - private final Runnable mFpCancelNotReceived = this::onFingerprintCancelNotReceived; + @VisibleForTesting + protected final Runnable mFpCancelNotReceived = this::onFingerprintCancelNotReceived; private final Runnable mFaceCancelNotReceived = this::onFaceCancelNotReceived; + @VisibleForTesting + protected Handler getHandler() { + return mHandler; + } private final Handler mHandler; private SparseBooleanArray mBiometricEnabledForUser = new SparseBooleanArray(); @@ -723,6 +729,11 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab private void handleFingerprintAuthFailed() { Assert.isMainThread(); + if (mHandler.hasCallbacks(mFpCancelNotReceived)) { + Log.d(TAG, "handleFingerprintAuthFailed()" + + " triggered while waiting for cancellation, removing watchdog"); + mHandler.removeCallbacks(mFpCancelNotReceived); + } for (int i = 0; i < mCallbacks.size(); i++) { KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get(); if (cb != null) { @@ -753,6 +764,11 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab private void handleFingerprintAuthenticated(int authUserId, boolean isStrongBiometric) { Trace.beginSection("KeyGuardUpdateMonitor#handlerFingerPrintAuthenticated"); + if (mHandler.hasCallbacks(mFpCancelNotReceived)) { + Log.d(TAG, "handleFingerprintAuthenticated()" + + " triggered while waiting for cancellation, removing watchdog"); + mHandler.removeCallbacks(mFpCancelNotReceived); + } try { final int userId; try { diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java index 8d27f2422f66a..c67737136b3b2 100644 --- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java +++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java @@ -22,6 +22,7 @@ import static android.telephony.SubscriptionManager.NAME_SOURCE_CARRIER_ID; import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.SOME_AUTH_REQUIRED_AFTER_USER_REQUEST; import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_BOOT; +import static com.android.keyguard.KeyguardUpdateMonitor.DEFAULT_CANCEL_SIGNAL_TIMEOUT; import static com.google.common.truth.Truth.assertThat; @@ -109,6 +110,7 @@ import org.mockito.Captor; import org.mockito.Mock; import org.mockito.MockitoAnnotations; import org.mockito.MockitoSession; +import org.mockito.internal.util.reflection.FieldSetter; import java.util.ArrayList; import java.util.Arrays; @@ -200,9 +202,10 @@ public class KeyguardUpdateMonitorTest extends SysuiTestCase { private ArgumentCaptor mCancellationSignalCaptor; // Direct executor - private Executor mBackgroundExecutor = Runnable::run; - private Executor mMainExecutor = Runnable::run; + private final Executor mBackgroundExecutor = Runnable::run; + private final Executor mMainExecutor = Runnable::run; private TestableLooper mTestableLooper; + private Handler mHandler; private TestableKeyguardUpdateMonitor mKeyguardUpdateMonitor; private TestableContext mSpiedContext; private MockitoSession mMockitoSession; @@ -291,6 +294,13 @@ public class KeyguardUpdateMonitorTest extends SysuiTestCase { mBiometricEnabledOnKeyguardCallback = mBiometricEnabledCallbackArgCaptor.getValue(); biometricsEnabledForCurrentUser(); + mHandler = spy(mKeyguardUpdateMonitor.getHandler()); + try { + FieldSetter.setField(mKeyguardUpdateMonitor, + KeyguardUpdateMonitor.class.getDeclaredField("mHandler"), mHandler); + } catch (NoSuchFieldException e) { + + } verify(mStatusBarStateController).addCallback(mStatusBarStateListenerCaptor.capture()); mStatusBarStateListener = mStatusBarStateListenerCaptor.getValue(); mKeyguardUpdateMonitor.registerCallback(mTestCallback); @@ -330,7 +340,7 @@ public class KeyguardUpdateMonitorTest extends SysuiTestCase { when(mTelephonyManager.getActiveModemCount()).thenReturn(1); when(mTelephonyManager.getSimState(anyInt())).thenReturn(state); - when(mSubscriptionManager.getSubscriptionIds(anyInt())).thenReturn(new int[] { subId }); + when(mSubscriptionManager.getSubscriptionIds(anyInt())).thenReturn(new int[]{subId}); KeyguardUpdateMonitor testKUM = new TestableKeyguardUpdateMonitor(mSpiedContext); @@ -505,7 +515,7 @@ public class KeyguardUpdateMonitorTest extends SysuiTestCase { // Even SimState Loaded, still need ACTION_SERVICE_STATE turn on mTelephonyCapable assertThat(mKeyguardUpdateMonitor.mTelephonyCapable).isFalse(); - Intent intentServiceState = new Intent(Intent.ACTION_SERVICE_STATE); + Intent intentServiceState = new Intent(Intent.ACTION_SERVICE_STATE); intentSimState.putExtra(Intent.EXTRA_SIM_STATE , Intent.SIM_STATE_LOADED); mKeyguardUpdateMonitor.mBroadcastReceiver.onReceive(getContext() @@ -520,7 +530,7 @@ public class KeyguardUpdateMonitorTest extends SysuiTestCase { mTestableLooper.processAllMessages(); verify(mFingerprintManager).authenticate(any(), any(), any(), any(), anyInt(), anyInt(), - anyInt()); + anyInt()); verify(mFingerprintManager, never()).detectFingerprint(any(), any(), anyInt()); } @@ -791,7 +801,8 @@ public class KeyguardUpdateMonitorTest extends SysuiTestCase { public void testBiometricsCleared_whenUserSwitches() throws Exception { final IRemoteCallback reply = new IRemoteCallback.Stub() { @Override - public void sendResult(Bundle data) {} // do nothing + public void sendResult(Bundle data) { + } // do nothing }; final BiometricAuthenticated dummyAuthentication = new BiometricAuthenticated(true /* authenticated */, true /* strong */); @@ -809,7 +820,8 @@ public class KeyguardUpdateMonitorTest extends SysuiTestCase { public void testMultiUserJankMonitor_whenUserSwitches() throws Exception { final IRemoteCallback reply = new IRemoteCallback.Stub() { @Override - public void sendResult(Bundle data) {} // do nothing + public void sendResult(Bundle data) { + } // do nothing }; mKeyguardUpdateMonitor.handleUserSwitchComplete(10 /* user */); verify(mInteractionJankMonitor).end(InteractionJankMonitor.CUJ_USER_SWITCH); @@ -1499,6 +1511,34 @@ public class KeyguardUpdateMonitorTest extends SysuiTestCase { assertThat(cancelSignal.isCanceled()).isTrue(); } + @Test + public void testFingerprintCanAuth_whenCancellationNotReceivedAndAuthFailed() { + mKeyguardUpdateMonitor.dispatchStartedWakingUp(); + mTestableLooper.processAllMessages(); + mKeyguardUpdateMonitor.onKeyguardVisibilityChanged(true); + + verify(mFaceManager).authenticate(any(), any(), any(), any(), anyInt(), anyBoolean()); + verify(mFingerprintManager).authenticate(any(), any(), any(), any(), anyInt(), anyInt(), + anyInt()); + + mKeyguardUpdateMonitor.onFaceAuthenticated(0, false); + // Make sure keyguard is going away after face auth attempt, and that it calls + // updateBiometricStateListeningState. + mKeyguardUpdateMonitor.onKeyguardVisibilityChanged(false); + mTestableLooper.processAllMessages(); + + verify(mHandler).postDelayed(mKeyguardUpdateMonitor.mFpCancelNotReceived, + DEFAULT_CANCEL_SIGNAL_TIMEOUT); + + mKeyguardUpdateMonitor.onFingerprintAuthenticated(0, true); + mTestableLooper.processAllMessages(); + + verify(mHandler, times(1)).removeCallbacks(mKeyguardUpdateMonitor.mFpCancelNotReceived); + mKeyguardUpdateMonitor.dispatchStartedGoingToSleep(0 /* why */); + mTestableLooper.processAllMessages(); + assertThat(mKeyguardUpdateMonitor.shouldListenForFingerprint(anyBoolean())).isEqualTo(true); + } + private void fingerprintIsNotEnrolled() { when(mFingerprintManager.hasEnrolledTemplates(mCurrentUserId)).thenReturn(false); }