diff options
12 files changed, 123 insertions, 20 deletions
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java index 37bd9b287ebd..9c61a8a3cd8b 100644 --- a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java @@ -1277,6 +1277,17 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab private final FaceAuthenticationListener mFaceAuthenticationListener = new FaceAuthenticationListener() { + public void onAuthenticatedChanged(boolean isAuthenticated) { + if (!isAuthenticated) { + for (int i = 0; i < mCallbacks.size(); i++) { + KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get(); + if (cb != null) { + cb.onFacesCleared(); + } + } + } + } + @Override public void onAuthEnrollmentStateChanged(boolean enrolled) { notifyAboutEnrollmentChange(TYPE_FACE); @@ -1961,7 +1972,7 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab protected void handleStartedGoingToSleep(int arg1) { Assert.isMainThread(); - clearBiometricRecognized(); + clearFingerprintRecognized(); for (int i = 0; i < mCallbacks.size(); i++) { KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get(); if (cb != null) { @@ -3010,7 +3021,7 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab void handleUserSwitching(int userId, Runnable resultCallback) { mLogger.logUserSwitching(userId, "from UserTracker"); Assert.isMainThread(); - clearBiometricRecognized(); + clearFingerprintRecognized(); boolean trustUsuallyManaged = mTrustManager.isTrustUsuallyManaged(userId); mLogger.logTrustUsuallyManagedUpdated(userId, mUserTrustIsUsuallyManaged.get(userId), trustUsuallyManaged, "userSwitching"); @@ -3560,25 +3571,30 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab return mServiceStates.get(subId); } - public void clearBiometricRecognized() { - clearBiometricRecognized(UserHandle.USER_NULL); + /** + * Resets the fingerprint authenticated state to false. + */ + public void clearFingerprintRecognized() { + clearFingerprintRecognized(UserHandle.USER_NULL); } - public void clearBiometricRecognizedWhenKeyguardDone(int unlockedUser) { - clearBiometricRecognized(unlockedUser); + /** + * Resets the fingerprint authenticated state to false. + */ + public void clearFingerprintRecognizedWhenKeyguardDone(int unlockedUser) { + clearFingerprintRecognized(unlockedUser); } - private void clearBiometricRecognized(int unlockedUser) { + private void clearFingerprintRecognized(int unlockedUser) { Assert.isMainThread(); mUserFingerprintAuthenticated.clear(); mTrustManager.clearAllBiometricRecognized(FINGERPRINT, unlockedUser); - mTrustManager.clearAllBiometricRecognized(FACE, unlockedUser); - mLogger.d("clearBiometricRecognized"); + mLogger.d("clearFingerprintRecognized"); for (int i = 0; i < mCallbacks.size(); i++) { KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get(); if (cb != null) { - cb.onBiometricsCleared(); + cb.onFingerprintsCleared(); } } } diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitorCallback.java b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitorCallback.java index 02dd3312c587..9d216dcede2b 100644 --- a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitorCallback.java +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitorCallback.java @@ -291,9 +291,14 @@ public class KeyguardUpdateMonitorCallback { public void onLogoutEnabledChanged() { } /** - * Called when authenticated biometrics are cleared. + * Called when authenticated fingerprint biometrics are cleared. */ - public void onBiometricsCleared() { } + public void onFingerprintsCleared() { } + + /** + * Called when authenticated face biometrics have cleared. + */ + public void onFacesCleared() { } /** * Called when the secondary lock screen requirement changes. diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeAuthRemover.java b/packages/SystemUI/src/com/android/systemui/doze/DozeAuthRemover.java index 9c13a8c82b11..3fac865ffb1d 100644 --- a/packages/SystemUI/src/com/android/systemui/doze/DozeAuthRemover.java +++ b/packages/SystemUI/src/com/android/systemui/doze/DozeAuthRemover.java @@ -43,7 +43,7 @@ public class DozeAuthRemover implements DozeMachine.Part { if (newState == DozeMachine.State.DOZE || newState == DozeMachine.State.DOZE_AOD) { int currentUser = mSelectedUserInteractor.getSelectedUserId(); if (mKeyguardUpdateMonitor.getUserUnlockedWithBiometric(currentUser)) { - mKeyguardUpdateMonitor.clearBiometricRecognized(); + mKeyguardUpdateMonitor.clearFingerprintRecognized(); } } } diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java index 30090874a480..b7260f2b2b94 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java +++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java @@ -2611,14 +2611,14 @@ public class KeyguardViewMediator implements CoreStartable, Dumpable, } if (mGoingToSleep) { - mUpdateMonitor.clearBiometricRecognizedWhenKeyguardDone(currentUser); + mUpdateMonitor.clearFingerprintRecognizedWhenKeyguardDone(currentUser); Log.i(TAG, "Device is going to sleep, aborting keyguardDone"); return; } setPendingLock(false); // user may have authenticated during the screen off animation handleHide(); - mUpdateMonitor.clearBiometricRecognizedWhenKeyguardDone(currentUser); + mUpdateMonitor.clearFingerprintRecognizedWhenKeyguardDone(currentUser); Trace.endSection(); } diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/DeviceEntryFaceAuthRepository.kt b/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/DeviceEntryFaceAuthRepository.kt index e47c44863980..eceaf6c3c4fd 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/DeviceEntryFaceAuthRepository.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/DeviceEntryFaceAuthRepository.kt @@ -326,7 +326,7 @@ constructor( it.selectionStatus == SelectionStatus.SELECTION_IN_PROGRESS }, ) - .flowOn(backgroundDispatcher) + .flowOn(mainDispatcher) // should revoke auth ASAP in the main thread .onEach { anyOfThemIsTrue -> if (anyOfThemIsTrue) { clearPendingAuthRequest("Resetting auth status") diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardFaceAuthInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardFaceAuthInteractor.kt index 5ed70b526f1b..046916aeb277 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardFaceAuthInteractor.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardFaceAuthInteractor.kt @@ -78,6 +78,9 @@ interface KeyguardFaceAuthInteractor { * flows. */ interface FaceAuthenticationListener { + /** Receive face isAuthenticated updates */ + fun onAuthenticatedChanged(isAuthenticated: Boolean) + /** Receive face authentication status updates */ fun onAuthenticationStatusChanged(status: FaceAuthenticationStatus) diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/SystemUIKeyguardFaceAuthInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/SystemUIKeyguardFaceAuthInteractor.kt index 532df4afebf7..fb20000471a2 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/SystemUIKeyguardFaceAuthInteractor.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/SystemUIKeyguardFaceAuthInteractor.kt @@ -16,8 +16,10 @@ package com.android.systemui.keyguard.domain.interactor +import android.app.trust.TrustManager import android.content.Context import android.hardware.biometrics.BiometricFaceConstants +import android.hardware.biometrics.BiometricSourceType import com.android.keyguard.FaceAuthUiEvent import com.android.keyguard.FaceWakeUpTriggersConfig import com.android.keyguard.KeyguardUpdateMonitor @@ -83,6 +85,7 @@ constructor( private val faceWakeUpTriggersConfig: FaceWakeUpTriggersConfig, private val powerInteractor: PowerInteractor, private val biometricSettingsRepository: BiometricSettingsRepository, + private val trustManager: TrustManager, ) : CoreStartable, KeyguardFaceAuthInteractor { private val listeners: MutableList<FaceAuthenticationListener> = mutableListOf() @@ -291,6 +294,20 @@ constructor( .onEach { running -> listeners.forEach { it.onRunningStateChanged(running) } } .flowOn(mainDispatcher) .launchIn(applicationScope) + repository.isAuthenticated + .sample(userRepository.selectedUserInfo, ::Pair) + .onEach { (isAuthenticated, userInfo) -> + if (!isAuthenticated) { + faceAuthenticationLogger.clearFaceRecognized() + trustManager.clearAllBiometricRecognized(BiometricSourceType.FACE, userInfo.id) + } + } + .flowOn(backgroundDispatcher) + .onEach { (isAuthenticated, _) -> + listeners.forEach { it.onAuthenticatedChanged(isAuthenticated) } + } + .flowOn(mainDispatcher) + .launchIn(applicationScope) biometricSettingsRepository.isFaceAuthEnrolledAndEnabled .onEach { enrolledAndEnabled -> diff --git a/packages/SystemUI/src/com/android/systemui/log/FaceAuthenticationLogger.kt b/packages/SystemUI/src/com/android/systemui/log/FaceAuthenticationLogger.kt index 8c5690b312ec..3c2facbc967a 100644 --- a/packages/SystemUI/src/com/android/systemui/log/FaceAuthenticationLogger.kt +++ b/packages/SystemUI/src/com/android/systemui/log/FaceAuthenticationLogger.kt @@ -132,6 +132,10 @@ constructor( logBuffer.log(TAG, DEBUG, "Face authentication failed") } + fun clearFaceRecognized() { + logBuffer.log(TAG, DEBUG, "Clear face recognized") + } + fun authenticationError( errorCode: Int, errString: CharSequence?, diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardStateControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardStateControllerImpl.java index 80c68023b4c8..756c440eca89 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardStateControllerImpl.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardStateControllerImpl.java @@ -484,7 +484,12 @@ public class KeyguardStateControllerImpl implements KeyguardStateController, Dum } @Override - public void onBiometricsCleared() { + public void onFingerprintsCleared() { + update(false /* alwaysUpdate */); + } + + @Override + public void onFacesCleared() { update(false /* alwaysUpdate */); } diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardFaceAuthInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardFaceAuthInteractorTest.kt index de12b8f91d20..4ab8e28bc232 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardFaceAuthInteractorTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardFaceAuthInteractorTest.kt @@ -17,8 +17,10 @@ package com.android.systemui.keyguard.domain.interactor +import android.app.trust.TrustManager import android.content.pm.UserInfo import android.hardware.biometrics.BiometricFaceConstants +import android.hardware.biometrics.BiometricSourceType import android.os.Handler import android.os.PowerManager import androidx.test.ext.junit.runners.AndroidJUnit4 @@ -62,6 +64,7 @@ import com.android.systemui.statusbar.policy.KeyguardStateController import com.android.systemui.user.data.model.SelectionStatus import com.android.systemui.user.data.repository.FakeUserRepository import com.android.systemui.user.domain.interactor.SelectedUserInteractor +import com.android.systemui.util.mockito.eq import com.android.systemui.util.mockito.whenever import com.android.systemui.util.time.FakeSystemClock import com.google.common.truth.Truth.assertThat @@ -74,8 +77,11 @@ import kotlinx.coroutines.test.runTest import org.junit.Before import org.junit.Test import org.junit.runner.RunWith +import org.mockito.ArgumentMatchers.anyInt import org.mockito.Mock import org.mockito.Mockito.mock +import org.mockito.Mockito.never +import org.mockito.Mockito.verify import org.mockito.MockitoAnnotations @OptIn(ExperimentalCoroutinesApi::class) @@ -99,7 +105,8 @@ class KeyguardFaceAuthInteractorTest : SysuiTestCase() { @Mock private lateinit var keyguardUpdateMonitor: KeyguardUpdateMonitor @Mock private lateinit var faceWakeUpTriggersConfig: FaceWakeUpTriggersConfig - @Mock private lateinit var mSelectedUserInteractor: SelectedUserInteractor + @Mock private lateinit var selectedUserInteractor: SelectedUserInteractor + @Mock private lateinit var trustManager: TrustManager @Before fun setup() { @@ -146,7 +153,7 @@ class KeyguardFaceAuthInteractorTest : SysuiTestCase() { keyguardUpdateMonitor, FakeTrustRepository(), testScope.backgroundScope, - mSelectedUserInteractor, + selectedUserInteractor, underTest, ) }, @@ -169,6 +176,7 @@ class KeyguardFaceAuthInteractorTest : SysuiTestCase() { faceWakeUpTriggersConfig, powerInteractor, fakeBiometricSettingsRepository, + trustManager, ) } @@ -498,6 +506,22 @@ class KeyguardFaceAuthInteractorTest : SysuiTestCase() { assertThat(faceAuthRepository.isLockedOut.value).isTrue() } + @Test + fun whenIsAuthenticatedFalse_clearFaceBiometrics() = + testScope.runTest { + underTest.start() + + faceAuthRepository.isAuthenticated.value = true + runCurrent() + verify(trustManager, never()) + .clearAllBiometricRecognized(eq(BiometricSourceType.FACE), anyInt()) + + faceAuthRepository.isAuthenticated.value = false + runCurrent() + + verify(trustManager).clearAllBiometricRecognized(eq(BiometricSourceType.FACE), anyInt()) + } + companion object { private const val primaryUserId = 1 private val primaryUser = UserInfo(primaryUserId, "test user", UserInfo.FLAG_PRIMARY) diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/KeyguardStateControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/KeyguardStateControllerTest.java index 01dad381efa0..479309c18c92 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/KeyguardStateControllerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/KeyguardStateControllerTest.java @@ -153,6 +153,36 @@ public class KeyguardStateControllerTest extends SysuiTestCase { } @Test + public void testCanSkipLockScreen_updateCalledOnFacesCleared() { + verify(mKeyguardUpdateMonitor).registerCallback(mUpdateCallbackCaptor.capture()); + + // Cannot skip after there's a password/pin/pattern + when(mLockPatternUtils.isSecure(anyInt())).thenReturn(true); + ((KeyguardStateControllerImpl) mKeyguardStateController).update(false /* alwaysUpdate */); + assertThat(mKeyguardStateController.canDismissLockScreen()).isFalse(); + + // Unless user is authenticated + when(mKeyguardUpdateMonitor.getUserCanSkipBouncer(anyInt())).thenReturn(true); + mUpdateCallbackCaptor.getValue().onFacesCleared(); + assertThat(mKeyguardStateController.canDismissLockScreen()).isTrue(); + } + + @Test + public void testCanSkipLockScreen_updateCalledOnFingerprintssCleared() { + verify(mKeyguardUpdateMonitor).registerCallback(mUpdateCallbackCaptor.capture()); + + // Cannot skip after there's a password/pin/pattern + when(mLockPatternUtils.isSecure(anyInt())).thenReturn(true); + ((KeyguardStateControllerImpl) mKeyguardStateController).update(false /* alwaysUpdate */); + assertThat(mKeyguardStateController.canDismissLockScreen()).isFalse(); + + // Unless user is authenticated + when(mKeyguardUpdateMonitor.getUserCanSkipBouncer(anyInt())).thenReturn(true); + mUpdateCallbackCaptor.getValue().onFingerprintsCleared(); + assertThat(mKeyguardStateController.canDismissLockScreen()).isTrue(); + } + + @Test public void testIsUnlocked() { // Is unlocked whenever the keyguard is not showing assertThat(mKeyguardStateController.isShowing()).isFalse(); diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/FakeDeviceEntryFaceAuthRepository.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/FakeDeviceEntryFaceAuthRepository.kt index e289083a2d9e..a1b6587be0b8 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/FakeDeviceEntryFaceAuthRepository.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/FakeDeviceEntryFaceAuthRepository.kt @@ -31,7 +31,6 @@ import kotlinx.coroutines.flow.filterNotNull @SysUISingleton class FakeDeviceEntryFaceAuthRepository @Inject constructor() : DeviceEntryFaceAuthRepository { - override val isAuthenticated = MutableStateFlow(false) override val canRunFaceAuth = MutableStateFlow(false) private val _authenticationStatus = MutableStateFlow<FaceAuthenticationStatus?>(null) |