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

Commit cbd3466e authored by Eric Biggers's avatar Eric Biggers Committed by Android (Google) Code Review
Browse files

Merge changes Idf562f9f,I81e25db9,I242d3bdf into main

* changes:
  Merge together the two LockPatternUtilsTest
  LockPatternUtilsTest: don't call the real TrustManagerService
  LockPatternUtilsTest: use dependency injection for ILockSettings
parents d690a11a 843503ba
Loading
Loading
Loading
Loading
+6 −0
Original line number Diff line number Diff line
@@ -333,11 +333,17 @@ public class LockPatternUtils {

    @UnsupportedAppUsage
    public LockPatternUtils(Context context) {
        this(context, null);
    }

    @VisibleForTesting
    public LockPatternUtils(Context context, ILockSettings lockSettings) {
        mContext = context;
        mContentResolver = context.getContentResolver();

        Looper looper = Looper.myLooper();
        mHandler = looper != null ? new Handler(looper) : null;
        mLockSettingsService = lockSettings;
    }

    @UnsupportedAppUsage
+304 −0
Original line number Diff line number Diff line
@@ -16,20 +16,279 @@

package com.android.internal.widget;

import static android.app.admin.DevicePolicyManager.PASSWORD_QUALITY_MANAGED;
import static android.app.admin.DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED;

import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STRONG_AUTH_NOT_REQUIRED;
import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_LOCKOUT;
import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_USER_LOCKDOWN;
import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.SOME_AUTH_REQUIRED_AFTER_TRUSTAGENT_EXPIRED;

import static com.google.common.truth.Truth.assertThat;

import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotEquals;
import static org.junit.Assert.assertTrue;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.any;
import static org.mockito.Mockito.anyInt;
import static org.mockito.Mockito.anyString;
import static org.mockito.Mockito.doNothing;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;

import android.app.trust.TrustManager;
import android.content.ComponentName;
import android.content.Context;
import android.content.ContextWrapper;
import android.content.pm.UserInfo;
import android.os.Looper;
import android.os.RemoteException;
import android.os.UserHandle;
import android.os.UserManager;
import android.platform.test.annotations.IgnoreUnderRavenwood;
import android.platform.test.ravenwood.RavenwoodRule;
import android.provider.Settings;
import android.test.mock.MockContentResolver;

import androidx.test.InstrumentationRegistry;
import androidx.test.filters.SmallTest;
import androidx.test.runner.AndroidJUnit4;

import com.android.internal.util.test.FakeSettingsProvider;

import com.google.android.collect.Lists;

import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.ArgumentCaptor;

import java.nio.charset.StandardCharsets;
import java.util.List;

@RunWith(AndroidJUnit4.class)
@SmallTest
@IgnoreUnderRavenwood(blockedBy = LockPatternUtils.class)
public class LockPatternUtilsTest {
    @Rule
    public final RavenwoodRule mRavenwood = new RavenwoodRule();

    private ILockSettings mLockSettings;
    private static final int USER_ID = 1;
    private static final int DEMO_USER_ID = 5;

    private LockPatternUtils mLockPatternUtils;

    private void configureTest(boolean isSecure, boolean isDemoUser, int deviceDemoMode)
            throws Exception {
        mLockSettings = mock(ILockSettings.class);
        final Context context = spy(new ContextWrapper(InstrumentationRegistry.getTargetContext()));

        final MockContentResolver cr = new MockContentResolver(context);
        cr.addProvider(Settings.AUTHORITY, new FakeSettingsProvider());
        when(context.getContentResolver()).thenReturn(cr);
        Settings.Global.putInt(cr, Settings.Global.DEVICE_DEMO_MODE, deviceDemoMode);

        when(mLockSettings.getCredentialType(DEMO_USER_ID)).thenReturn(
                isSecure ? LockPatternUtils.CREDENTIAL_TYPE_PASSWORD
                         : LockPatternUtils.CREDENTIAL_TYPE_NONE);
        when(mLockSettings.getLong("lockscreen.password_type", PASSWORD_QUALITY_UNSPECIFIED,
                DEMO_USER_ID)).thenReturn((long) PASSWORD_QUALITY_MANAGED);
        when(mLockSettings.hasSecureLockScreen()).thenReturn(true);
        mLockPatternUtils = new LockPatternUtils(context, mLockSettings);

        final UserInfo userInfo = mock(UserInfo.class);
        when(userInfo.isDemo()).thenReturn(isDemoUser);
        final UserManager um = mock(UserManager.class);
        when(um.getUserInfo(DEMO_USER_ID)).thenReturn(userInfo);
        when(context.getSystemService(Context.USER_SERVICE)).thenReturn(um);
    }

    @Test
    public void isUserInLockDown() throws Exception {
        configureTest(true, false, 2);

        // GIVEN strong auth not required
        when(mLockSettings.getStrongAuthForUser(USER_ID)).thenReturn(STRONG_AUTH_NOT_REQUIRED);

        // THEN user isn't in lockdown
        assertFalse(mLockPatternUtils.isUserInLockdown(USER_ID));

        // GIVEN lockdown
        when(mLockSettings.getStrongAuthForUser(USER_ID)).thenReturn(
                STRONG_AUTH_REQUIRED_AFTER_USER_LOCKDOWN);

        // THEN user is in lockdown
        assertTrue(mLockPatternUtils.isUserInLockdown(USER_ID));

        // GIVEN lockdown and lockout
        when(mLockSettings.getStrongAuthForUser(USER_ID)).thenReturn(
                STRONG_AUTH_REQUIRED_AFTER_USER_LOCKDOWN | STRONG_AUTH_REQUIRED_AFTER_LOCKOUT);

        // THEN user is in lockdown
        assertTrue(mLockPatternUtils.isUserInLockdown(USER_ID));
    }

    @Test
    public void isLockScreenDisabled_isDemoUser_true() throws Exception {
        configureTest(false, true, 2);
        assertTrue(mLockPatternUtils.isLockScreenDisabled(DEMO_USER_ID));
    }

    @Test
    public void isLockScreenDisabled_isSecureAndDemoUser_false() throws Exception {
        configureTest(true, true, 2);
        assertFalse(mLockPatternUtils.isLockScreenDisabled(DEMO_USER_ID));
    }

    @Test
    public void isLockScreenDisabled_isNotDemoUser_false() throws Exception {
        configureTest(false, false, 2);
        assertFalse(mLockPatternUtils.isLockScreenDisabled(DEMO_USER_ID));
    }

    @Test
    public void isLockScreenDisabled_isNotInDemoMode_false() throws Exception {
        configureTest(false, true, 0);
        assertFalse(mLockPatternUtils.isLockScreenDisabled(DEMO_USER_ID));
    }

    @Test
    public void testAddWeakEscrowToken() throws RemoteException {
        ILockSettings ils = createTestLockSettings();
        byte[] testToken = "test_token".getBytes(StandardCharsets.UTF_8);
        int testUserId = 10;
        IWeakEscrowTokenActivatedListener listener = createWeakEscrowTokenListener();
        mLockPatternUtils.addWeakEscrowToken(testToken, testUserId, listener);
        verify(ils).addWeakEscrowToken(eq(testToken), eq(testUserId), eq(listener));
    }

    @Test
    public void testRegisterWeakEscrowTokenRemovedListener() throws RemoteException {
        ILockSettings ils = createTestLockSettings();
        IWeakEscrowTokenRemovedListener testListener = createTestAutoEscrowTokenRemovedListener();
        mLockPatternUtils.registerWeakEscrowTokenRemovedListener(testListener);
        verify(ils).registerWeakEscrowTokenRemovedListener(eq(testListener));
    }

    @Test
    public void testUnregisterWeakEscrowTokenRemovedListener() throws RemoteException {
        ILockSettings ils = createTestLockSettings();
        IWeakEscrowTokenRemovedListener testListener = createTestAutoEscrowTokenRemovedListener();
        mLockPatternUtils.unregisterWeakEscrowTokenRemovedListener(testListener);
        verify(ils).unregisterWeakEscrowTokenRemovedListener(eq(testListener));
    }

    @Test
    public void testRemoveAutoEscrowToken() throws RemoteException {
        ILockSettings ils = createTestLockSettings();
        int testUserId = 10;
        long testHandle = 100L;
        mLockPatternUtils.removeWeakEscrowToken(testHandle, testUserId);
        verify(ils).removeWeakEscrowToken(eq(testHandle), eq(testUserId));
    }

    @Test
    public void testIsAutoEscrowTokenActive() throws RemoteException {
        ILockSettings ils = createTestLockSettings();
        int testUserId = 10;
        long testHandle = 100L;
        mLockPatternUtils.isWeakEscrowTokenActive(testHandle, testUserId);
        verify(ils).isWeakEscrowTokenActive(eq(testHandle), eq(testUserId));
    }

    @Test
    public void testIsAutoEscrowTokenValid() throws RemoteException {
        ILockSettings ils = createTestLockSettings();
        int testUserId = 10;
        byte[] testToken = "test_token".getBytes(StandardCharsets.UTF_8);
        long testHandle = 100L;
        mLockPatternUtils.isWeakEscrowTokenValid(testHandle, testToken, testUserId);
        verify(ils).isWeakEscrowTokenValid(eq(testHandle), eq(testToken), eq(testUserId));
    }

    @Test
    public void testSetEnabledTrustAgents() throws RemoteException {
        int testUserId = 10;
        ILockSettings ils = createTestLockSettings();
        ArgumentCaptor<String> valueCaptor = ArgumentCaptor.forClass(String.class);
        doNothing().when(ils).setString(anyString(), valueCaptor.capture(), anyInt());
        List<ComponentName> enabledTrustAgents = Lists.newArrayList(
                ComponentName.unflattenFromString("com.android/.TrustAgent"),
                ComponentName.unflattenFromString("com.test/.TestAgent"));

        mLockPatternUtils.setEnabledTrustAgents(enabledTrustAgents, testUserId);

        assertThat(valueCaptor.getValue()).isEqualTo("com.android/.TrustAgent,com.test/.TestAgent");
    }

    @Test
    public void testGetEnabledTrustAgents() throws RemoteException {
        int testUserId = 10;
        ILockSettings ils = createTestLockSettings();
        when(ils.getString(anyString(), any(), anyInt())).thenReturn(
                "com.android/.TrustAgent,com.test/.TestAgent");

        List<ComponentName> trustAgents = mLockPatternUtils.getEnabledTrustAgents(testUserId);

        assertThat(trustAgents).containsExactly(
                ComponentName.unflattenFromString("com.android/.TrustAgent"),
                ComponentName.unflattenFromString("com.test/.TestAgent"));
    }

    @Test
    public void testSetKnownTrustAgents() throws RemoteException {
        int testUserId = 10;
        ILockSettings ils = createTestLockSettings();
        ArgumentCaptor<String> valueCaptor = ArgumentCaptor.forClass(String.class);
        doNothing().when(ils).setString(anyString(), valueCaptor.capture(), anyInt());
        List<ComponentName> knownTrustAgents = Lists.newArrayList(
                ComponentName.unflattenFromString("com.android/.TrustAgent"),
                ComponentName.unflattenFromString("com.test/.TestAgent"));

        mLockPatternUtils.setKnownTrustAgents(knownTrustAgents, testUserId);

        assertThat(valueCaptor.getValue()).isEqualTo("com.android/.TrustAgent,com.test/.TestAgent");
    }

    @Test
    public void testGetKnownTrustAgents() throws RemoteException {
        int testUserId = 10;
        ILockSettings ils = createTestLockSettings();
        when(ils.getString(anyString(), any(), anyInt())).thenReturn(
                "com.android/.TrustAgent,com.test/.TestAgent");

        List<ComponentName> trustAgents = mLockPatternUtils.getKnownTrustAgents(testUserId);

        assertThat(trustAgents).containsExactly(
                ComponentName.unflattenFromString("com.android/.TrustAgent"),
                ComponentName.unflattenFromString("com.test/.TestAgent"));
    }

    @Test
    public void isBiometricAllowedForUser_afterTrustagentExpired_returnsTrue()
            throws RemoteException {
        TestStrongAuthTracker tracker = createStrongAuthTracker();
        tracker.changeStrongAuth(SOME_AUTH_REQUIRED_AFTER_TRUSTAGENT_EXPIRED);

        assertTrue(tracker.isBiometricAllowedForUser(
                /* isStrongBiometric = */ true,
                DEMO_USER_ID));
    }

    @Test
    public void isBiometricAllowedForUser_afterLockout_returnsFalse()
            throws RemoteException {
        TestStrongAuthTracker tracker = createStrongAuthTracker();
        tracker.changeStrongAuth(STRONG_AUTH_REQUIRED_AFTER_LOCKOUT);

        assertFalse(tracker.isBiometricAllowedForUser(
                /* isStrongBiometric = */ true,
                DEMO_USER_ID));
    }

    @Test
    public void testUserFrp_isNotRegularUser() throws Exception {
@@ -56,4 +315,49 @@ public class LockPatternUtilsTest {
        assertNotEquals(UserHandle.USER_CURRENT, LockPatternUtils.USER_REPAIR_MODE);
        assertNotEquals(UserHandle.USER_CURRENT_OR_SELF, LockPatternUtils.USER_REPAIR_MODE);
    }

    private TestStrongAuthTracker createStrongAuthTracker() {
        final Context context = new ContextWrapper(InstrumentationRegistry.getTargetContext());
        return new TestStrongAuthTracker(context, Looper.getMainLooper());
    }

    private static class TestStrongAuthTracker extends LockPatternUtils.StrongAuthTracker {

        TestStrongAuthTracker(Context context, Looper looper) {
            super(context, looper);
        }

        public void changeStrongAuth(@StrongAuthFlags int strongAuthFlags) {
            handleStrongAuthRequiredChanged(strongAuthFlags, DEMO_USER_ID);
        }
    }

    private ILockSettings createTestLockSettings() {
        final Context context = spy(new ContextWrapper(InstrumentationRegistry.getTargetContext()));

        final TrustManager trustManager = mock(TrustManager.class);
        when(context.getSystemService(Context.TRUST_SERVICE)).thenReturn(trustManager);

        final ILockSettings ils = mock(ILockSettings.class);
        mLockPatternUtils = new LockPatternUtils(context, ils);
        return ils;
    }

    private IWeakEscrowTokenActivatedListener createWeakEscrowTokenListener() {
        return new IWeakEscrowTokenActivatedListener.Stub() {
            @Override
            public void onWeakEscrowTokenActivated(long handle, int userId) {
                // Do nothing.
            }
        };
    }

    private IWeakEscrowTokenRemovedListener createTestAutoEscrowTokenRemovedListener() {
        return new IWeakEscrowTokenRemovedListener.Stub() {
            @Override
            public void onWeakEscrowTokenRemoved(long handle, int userId) {
                // Do nothing.
            }
        };
    }
}
+0 −339

File deleted.

Preview size limit exceeded, changes collapsed.