Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 4f1483b1 authored by Chandru S's avatar Chandru S Committed by Automerger Merge Worker
Browse files

Merge "Add more unit tests for the current face auth logic in KUM" into...

Merge "Add more unit tests for the current face auth logic in KUM" into tm-qpr-dev am: 61852ac6 am: 9c663120

Original change: https://googleplex-android-review.googlesource.com/c/platform/frameworks/base/+/19507092



Change-Id: I5bfa4e38d36006aa1d7a534d1b8b9d49e6dc4a43
Signed-off-by: default avatarAutomerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
parents 3cb6c6d3 9c663120
Loading
Loading
Loading
Loading
+329 −10
Original line number Diff line number Diff line
@@ -16,6 +16,7 @@

package com.android.keyguard;

import static android.hardware.biometrics.BiometricFingerprintConstants.FINGERPRINT_ERROR_LOCKOUT;
import static android.telephony.SubscriptionManager.DATA_ROAMING_DISABLE;
import static android.telephony.SubscriptionManager.NAME_SOURCE_CARRIER_ID;

@@ -31,7 +32,6 @@ import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.atLeastOnce;
import static org.mockito.Mockito.clearInvocations;
import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.spy;
@@ -41,6 +41,7 @@ import static org.mockito.Mockito.when;

import android.app.Activity;
import android.app.ActivityManager;
import android.app.IActivityManager;
import android.app.admin.DevicePolicyManager;
import android.app.trust.IStrongAuthTracker;
import android.app.trust.TrustManager;
@@ -52,6 +53,7 @@ import android.content.IntentFilter;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.content.pm.ServiceInfo;
import android.content.pm.UserInfo;
import android.hardware.biometrics.BiometricConstants;
import android.hardware.biometrics.BiometricManager;
import android.hardware.biometrics.BiometricSourceType;
@@ -68,6 +70,7 @@ import android.os.Bundle;
import android.os.CancellationSignal;
import android.os.Handler;
import android.os.IRemoteCallback;
import android.os.RemoteException;
import android.os.UserHandle;
import android.os.UserManager;
import android.telephony.ServiceState;
@@ -182,6 +185,18 @@ public class KeyguardUpdateMonitorTest extends SysuiTestCase {
    private ActiveUnlockConfig mActiveUnlockConfig;
    @Mock
    private KeyguardUpdateMonitorLogger mKeyguardUpdateMonitorLogger;
    @Mock
    private IActivityManager mActivityService;

    private final int mCurrentUserId = 100;
    private final UserInfo mCurrentUserInfo = new UserInfo(mCurrentUserId, "Test user", 0);

    @Captor
    private ArgumentCaptor<IBiometricEnabledOnKeyguardCallback>
            mBiometricEnabledCallbackArgCaptor;
    @Captor
    private ArgumentCaptor<FaceManager.AuthenticationCallback> mAuthenticationCallbackCaptor;

    // Direct executor
    private Executor mBackgroundExecutor = Runnable::run;
    private Executor mMainExecutor = Runnable::run;
@@ -190,18 +205,16 @@ public class KeyguardUpdateMonitorTest extends SysuiTestCase {
    private TestableContext mSpiedContext;
    private MockitoSession mMockitoSession;
    private StatusBarStateController.StateListener mStatusBarStateListener;
    private IBiometricEnabledOnKeyguardCallback mBiometricEnabledOnKeyguardCallback;

    @Before
    public void setup() {
    public void setup() throws RemoteException {
        MockitoAnnotations.initMocks(this);
        mSpiedContext = spy(mContext);
        when(mPackageManager.hasSystemFeature(anyString())).thenReturn(true);
        when(mSpiedContext.getPackageManager()).thenReturn(mPackageManager);
        doAnswer(invocation -> {
            IBiometricEnabledOnKeyguardCallback callback = invocation.getArgument(0);
            callback.onChanged(true /* enabled */, KeyguardUpdateMonitor.getCurrentUser());
            return null;
        }).when(mBiometricManager).registerEnabledOnKeyguardCallback(any());
        when(mActivityService.getCurrentUser()).thenReturn(mCurrentUserInfo);
        when(mActivityService.getCurrentUserId()).thenReturn(mCurrentUserId);
        when(mFaceManager.isHardwareDetected()).thenReturn(true);
        when(mFaceManager.hasEnrolledTemplates()).thenReturn(true);
        when(mFaceManager.hasEnrolledTemplates(anyInt())).thenReturn(true);
@@ -262,13 +275,20 @@ public class KeyguardUpdateMonitorTest extends SysuiTestCase {
                .startMocking();
        ExtendedMockito.doReturn(SubscriptionManager.INVALID_SUBSCRIPTION_ID)
                .when(SubscriptionManager::getDefaultSubscriptionId);
        KeyguardUpdateMonitor.setCurrentUser(mCurrentUserId);
        ExtendedMockito.doReturn(KeyguardUpdateMonitor.getCurrentUser())
                .when(ActivityManager::getCurrentUser);
        ExtendedMockito.doReturn(mActivityService).when(ActivityManager::getService);

        mTestableLooper = TestableLooper.get(this);
        allowTestableLooperAsMainThread();
        mKeyguardUpdateMonitor = new TestableKeyguardUpdateMonitor(mSpiedContext);

        verify(mBiometricManager)
                .registerEnabledOnKeyguardCallback(mBiometricEnabledCallbackArgCaptor.capture());
        mBiometricEnabledOnKeyguardCallback = mBiometricEnabledCallbackArgCaptor.getValue();
        biometricsEnabledForCurrentUser();

        verify(mStatusBarStateController).addCallback(mStatusBarStateListenerCaptor.capture());
        mStatusBarStateListener = mStatusBarStateListenerCaptor.getValue();
        mKeyguardUpdateMonitor.registerCallback(mTestCallback);
@@ -718,7 +738,6 @@ public class KeyguardUpdateMonitorTest extends SysuiTestCase {
        verify(mLockPatternUtils).requireStrongAuth(anyInt(), anyInt());
    }


    @Test
    public void testFaceAndFingerprintLockout() {
        mKeyguardUpdateMonitor.dispatchStartedWakingUp();
@@ -924,6 +943,7 @@ public class KeyguardUpdateMonitorTest extends SysuiTestCase {

    @Test
    public void testSecondaryLockscreenRequirement() {
        KeyguardUpdateMonitor.setCurrentUser(UserHandle.myUserId());
        int user = KeyguardUpdateMonitor.getCurrentUser();
        String packageName = "fake.test.package";
        String cls = "FakeService";
@@ -1097,8 +1117,7 @@ public class KeyguardUpdateMonitorTest extends SysuiTestCase {
    @Test
    public void testShouldNotUpdateBiometricListeningStateOnStatusBarStateChange() {
        // GIVEN state for face auth should run aside from StatusBarState
        when(mDevicePolicyManager.getKeyguardDisabledFeatures(null,
                KeyguardUpdateMonitor.getCurrentUser())).thenReturn(0);
        biometricsNotDisabledThroughDevicePolicyManager();
        mStatusBarStateListener.onStateChanged(StatusBarState.SHADE_LOCKED);
        setKeyguardBouncerVisibility(false /* isVisible */);
        mKeyguardUpdateMonitor.dispatchStartedWakingUp();
@@ -1153,6 +1172,306 @@ public class KeyguardUpdateMonitorTest extends SysuiTestCase {
        verify(mTestCallback).showTrustGrantedMessage("Unlocked by wearable");
    }

    @Test
    public void testShouldListenForFace_whenFaceManagerNotAvailable_returnsFalse() {
        mFaceManager = null;
        mKeyguardUpdateMonitor = new TestableKeyguardUpdateMonitor(mSpiedContext);

        assertThat(mKeyguardUpdateMonitor.shouldListenForFace()).isFalse();
    }

    @Test
    public void testShouldListenForFace_whenFpIsLockedOut_returnsFalse() throws RemoteException {
        // Face auth should run when the following is true.
        keyguardNotGoingAway();
        bouncerFullyVisibleAndNotGoingToSleep();
        currentUserIsPrimary();
        strongAuthNotRequired();
        biometricsEnabledForCurrentUser();
        currentUserDoesNotHaveTrust();
        biometricsNotDisabledThroughDevicePolicyManager();
        userNotCurrentlySwitching();
        mTestableLooper.processAllMessages();

        // Fingerprint is locked out.
        fingerprintErrorLockedOut();

        assertThat(mKeyguardUpdateMonitor.shouldListenForFace()).isFalse();
    }

    @Test
    public void testShouldListenForFace_whenFaceIsAlreadyAuthenticated_returnsFalse()
            throws RemoteException {
        // Face auth should run when the following is true.
        bouncerFullyVisibleAndNotGoingToSleep();
        keyguardNotGoingAway();
        currentUserIsPrimary();
        strongAuthNotRequired();
        biometricsEnabledForCurrentUser();
        currentUserDoesNotHaveTrust();
        biometricsNotDisabledThroughDevicePolicyManager();
        userNotCurrentlySwitching();

        mTestableLooper.processAllMessages();

        assertThat(mKeyguardUpdateMonitor.shouldListenForFace()).isTrue();

        triggerSuccessfulFaceAuth();
        mTestableLooper.processAllMessages();

        assertThat(mKeyguardUpdateMonitor.shouldListenForFace()).isFalse();
    }

    @Test
    public void testShouldListenForFace_whenUserIsNotPrimary_returnsFalse() throws RemoteException {
        // This disables face auth
        when(mUserManager.isPrimaryUser()).thenReturn(false);
        mKeyguardUpdateMonitor =
                new TestableKeyguardUpdateMonitor(mSpiedContext);

        // Face auth should run when the following is true.
        keyguardNotGoingAway();
        bouncerFullyVisibleAndNotGoingToSleep();
        strongAuthNotRequired();
        biometricsEnabledForCurrentUser();
        currentUserDoesNotHaveTrust();
        biometricsNotDisabledThroughDevicePolicyManager();
        userNotCurrentlySwitching();
        mTestableLooper.processAllMessages();


        assertThat(mKeyguardUpdateMonitor.shouldListenForFace()).isFalse();
    }

    @Test
    public void testShouldListenForFace_whenStrongAuthDoesNotAllowScanning_returnsFalse()
            throws RemoteException {
        // Face auth should run when the following is true.
        keyguardNotGoingAway();
        bouncerFullyVisibleAndNotGoingToSleep();
        currentUserIsPrimary();
        biometricsEnabledForCurrentUser();
        currentUserDoesNotHaveTrust();
        biometricsNotDisabledThroughDevicePolicyManager();
        userNotCurrentlySwitching();

        // This disables face auth
        when(mStrongAuthTracker.getStrongAuthForUser(KeyguardUpdateMonitor.getCurrentUser()))
                .thenReturn(STRONG_AUTH_REQUIRED_AFTER_BOOT);
        mTestableLooper.processAllMessages();


        assertThat(mKeyguardUpdateMonitor.shouldListenForFace()).isFalse();
    }

    @Test
    public void testShouldListenForFace_whenBiometricsDisabledForUser_returnsFalse()
            throws RemoteException {
        // Face auth should run when the following is true.
        keyguardNotGoingAway();
        bouncerFullyVisibleAndNotGoingToSleep();
        currentUserIsPrimary();
        currentUserDoesNotHaveTrust();
        biometricsNotDisabledThroughDevicePolicyManager();
        biometricsEnabledForCurrentUser();
        userNotCurrentlySwitching();
        mTestableLooper.processAllMessages();

        assertThat(mKeyguardUpdateMonitor.shouldListenForFace()).isTrue();

        // This disables face auth
        biometricsDisabledForCurrentUser();
        mTestableLooper.processAllMessages();

        assertThat(mKeyguardUpdateMonitor.shouldListenForFace()).isFalse();
    }

    @Test
    public void testShouldListenForFace_whenUserCurrentlySwitching_returnsFalse()
            throws RemoteException {
        // Face auth should run when the following is true.
        keyguardNotGoingAway();
        bouncerFullyVisibleAndNotGoingToSleep();
        currentUserIsPrimary();
        currentUserDoesNotHaveTrust();
        biometricsNotDisabledThroughDevicePolicyManager();
        biometricsEnabledForCurrentUser();
        userNotCurrentlySwitching();
        mTestableLooper.processAllMessages();

        assertThat(mKeyguardUpdateMonitor.shouldListenForFace()).isTrue();

        userCurrentlySwitching();
        mTestableLooper.processAllMessages();

        assertThat(mKeyguardUpdateMonitor.shouldListenForFace()).isFalse();
    }

    @Test
    public void testShouldListenForFace_whenSecureCameraLaunched_returnsFalse()
            throws RemoteException {
        // Face auth should run when the following is true.
        keyguardNotGoingAway();
        bouncerFullyVisibleAndNotGoingToSleep();
        currentUserIsPrimary();
        currentUserDoesNotHaveTrust();
        biometricsNotDisabledThroughDevicePolicyManager();
        biometricsEnabledForCurrentUser();
        userNotCurrentlySwitching();
        mTestableLooper.processAllMessages();

        assertThat(mKeyguardUpdateMonitor.shouldListenForFace()).isTrue();

        secureCameraLaunched();
        mTestableLooper.processAllMessages();

        assertThat(mKeyguardUpdateMonitor.shouldListenForFace()).isFalse();
    }

    @Test
    public void testShouldListenForFace_whenOccludingAppRequestsFaceAuth_returnsTrue()
            throws RemoteException {
        // Face auth should run when the following is true.
        keyguardNotGoingAway();
        bouncerFullyVisibleAndNotGoingToSleep();
        currentUserIsPrimary();
        currentUserDoesNotHaveTrust();
        biometricsNotDisabledThroughDevicePolicyManager();
        biometricsEnabledForCurrentUser();
        userNotCurrentlySwitching();
        mTestableLooper.processAllMessages();

        secureCameraLaunched();

        assertThat(mKeyguardUpdateMonitor.shouldListenForFace()).isFalse();

        occludingAppRequestsFaceAuth();
        mTestableLooper.processAllMessages();

        assertThat(mKeyguardUpdateMonitor.shouldListenForFace()).isTrue();
    }

    @Test
    public void testShouldListenForFace_whenBouncerShowingAndDeviceIsAwake_returnsTrue()
            throws RemoteException {
        // Face auth should run when the following is true.
        keyguardNotGoingAway();
        currentUserIsPrimary();
        currentUserDoesNotHaveTrust();
        biometricsNotDisabledThroughDevicePolicyManager();
        biometricsEnabledForCurrentUser();
        userNotCurrentlySwitching();
        mTestableLooper.processAllMessages();

        assertThat(mKeyguardUpdateMonitor.shouldListenForFace()).isFalse();

        bouncerFullyVisibleAndNotGoingToSleep();
        mTestableLooper.processAllMessages();

        assertThat(mKeyguardUpdateMonitor.shouldListenForFace()).isTrue();
    }

    @Test
    public void testShouldListenForFace_whenAuthInterruptIsActive_returnsTrue()
            throws RemoteException {
        // Face auth should run when the following is true.
        keyguardNotGoingAway();
        currentUserIsPrimary();
        currentUserDoesNotHaveTrust();
        biometricsNotDisabledThroughDevicePolicyManager();
        biometricsEnabledForCurrentUser();
        userNotCurrentlySwitching();
        mTestableLooper.processAllMessages();

        assertThat(mKeyguardUpdateMonitor.shouldListenForFace()).isFalse();

        triggerAuthInterrupt();
        mTestableLooper.processAllMessages();

        assertThat(mKeyguardUpdateMonitor.shouldListenForFace()).isTrue();
    }

    private void triggerAuthInterrupt() {
        mKeyguardUpdateMonitor.onAuthInterruptDetected(true);
    }

    private void occludingAppRequestsFaceAuth() {
        mKeyguardUpdateMonitor.requestFaceAuthOnOccludingApp(true);
    }

    private void secureCameraLaunched() {
        mKeyguardUpdateMonitor.onCameraLaunched();
    }

    private void userCurrentlySwitching() {
        mKeyguardUpdateMonitor.setSwitchingUser(true);
    }

    private void fingerprintErrorLockedOut() {
        mKeyguardUpdateMonitor.mFingerprintAuthenticationCallback
                .onAuthenticationError(FINGERPRINT_ERROR_LOCKOUT, "Fingerprint locked out");
    }

    private void triggerSuccessfulFaceAuth() {
        mKeyguardUpdateMonitor.requestFaceAuth(true);
        verify(mFaceManager).authenticate(any(),
                any(),
                mAuthenticationCallbackCaptor.capture(),
                any(),
                anyInt(),
                anyBoolean());
        mAuthenticationCallbackCaptor.getValue()
                .onAuthenticationSucceeded(
                        new FaceManager.AuthenticationResult(null, null, mCurrentUserId, false));
    }

    private void currentUserIsPrimary() {
        when(mUserManager.isPrimaryUser()).thenReturn(true);
    }

    private void biometricsNotDisabledThroughDevicePolicyManager() {
        when(mDevicePolicyManager.getKeyguardDisabledFeatures(null,
                KeyguardUpdateMonitor.getCurrentUser())).thenReturn(0);
    }

    private void biometricsEnabledForCurrentUser() throws RemoteException {
        mBiometricEnabledOnKeyguardCallback.onChanged(true, KeyguardUpdateMonitor.getCurrentUser());
    }

    private void biometricsDisabledForCurrentUser() throws RemoteException {
        mBiometricEnabledOnKeyguardCallback.onChanged(
                false,
                KeyguardUpdateMonitor.getCurrentUser()
        );
    }

    private void strongAuthNotRequired() {
        when(mStrongAuthTracker.getStrongAuthForUser(KeyguardUpdateMonitor.getCurrentUser()))
                .thenReturn(0);
    }

    private void currentUserDoesNotHaveTrust() {
        mKeyguardUpdateMonitor.onTrustChanged(
                false,
                KeyguardUpdateMonitor.getCurrentUser(),
                -1,
                new ArrayList<>()
        );
    }

    private void userNotCurrentlySwitching() {
        mKeyguardUpdateMonitor.setSwitchingUser(false);
    }

    private void keyguardNotGoingAway() {
        mKeyguardUpdateMonitor.setKeyguardGoingAway(false);
    }

    private void bouncerFullyVisibleAndNotGoingToSleep() {
        mKeyguardUpdateMonitor.sendKeyguardBouncerChanged(true, true);
        mKeyguardUpdateMonitor.dispatchFinishedGoingToSleep(/* value doesn't matter */1);
    }

    private void setKeyguardBouncerVisibility(boolean isVisible) {
        mKeyguardUpdateMonitor.sendKeyguardBouncerChanged(isVisible, isVisible);
        mTestableLooper.processAllMessages();