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

Commit b1c9ea25 authored by Lorenzo Colitti's avatar Lorenzo Colitti
Browse files

Make FakeSettingsProvider multiuser aware.

This allows reading and writing settings with the
{get,put}StringForUser methods.

Flag: TEST_ONLY
Test: new unit tests
Change-Id: Id21ed7bb4de689c0407b9ec40373c4e5bfcd821c
parent d66825df
Loading
Loading
Loading
Loading
+51 −6
Original line number Diff line number Diff line
@@ -16,10 +16,14 @@

package com.android.internal.util.test;

import static junit.framework.Assert.assertNull;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.fail;

import android.content.ContentProvider;
import android.os.Process;
import android.os.UserHandle;
import android.platform.test.annotations.DisabledOnRavenwood;
import android.platform.test.ravenwood.RavenwoodRule;
import android.provider.Settings;
@@ -42,6 +46,9 @@ public class FakeSettingsProviderTest {
    @Rule
    public final RavenwoodRule mRavenwood = new RavenwoodRule();

    private static final String SYSTEM_SETTING = Settings.System.SCREEN_BRIGHTNESS;
    private static final String SECURE_SETTING = Settings.Secure.BLUETOOTH_NAME;

    private MockContentResolver mCr;

    @Before
@@ -53,15 +60,53 @@ public class FakeSettingsProviderTest {
    @Test
    @SmallTest
    public void testBasicOperation() throws Exception {
        String settingName = Settings.System.SCREEN_BRIGHTNESS;

        try {
            Settings.System.getInt(mCr, settingName);
            Settings.System.getInt(mCr, SYSTEM_SETTING);
            fail("FakeSettingsProvider should start off empty.");
        } catch (Settings.SettingNotFoundException expected) {}
        } catch (Settings.SettingNotFoundException expected) {
            // Expected behaviour.
        }

        // Check that fake settings can be written and read back.
        Settings.System.putInt(mCr, settingName, 123);
        assertEquals(123, Settings.System.getInt(mCr, settingName));
        Settings.System.putInt(mCr, SYSTEM_SETTING, 123);
        assertEquals(123, Settings.System.getInt(mCr, SYSTEM_SETTING));
    }

    private void assertUserHandleUnsupported(UserHandle userHandle, String settingName) {
        try {
            Settings.Secure.putStringForUser(mCr, settingName, "currentUserSetting",
                    userHandle.getIdentifier());
            fail("UserHandle " + userHandle + " is unsupported and should throw");
        } catch (UnsupportedOperationException expected) {
            // Expected behaviour.
        }
    }

    @Test
    @SmallTest
    public void testMultiUserOperation() {
        Settings.Secure.putStringForUser(mCr, SECURE_SETTING, "user0Setting", 0);
        Settings.Secure.putStringForUser(mCr, SECURE_SETTING, "user1Setting", 1);
        assertEquals("user0Setting", Settings.Secure.getStringForUser(mCr, SECURE_SETTING, 0));
        assertEquals("user1Setting", Settings.Secure.getStringForUser(mCr, SECURE_SETTING, 1));
        assertNull(Settings.Secure.getStringForUser(mCr, SECURE_SETTING, 2));

        final int currentUserId = UserHandle.getUserId(Process.myUid());
        Settings.Secure.putStringForUser(mCr, SECURE_SETTING, "currentUserSetting", currentUserId);
        assertEquals("currentUserSetting", Settings.Secure.getString(mCr, SECURE_SETTING));

        Settings.Secure.putString(mCr, SECURE_SETTING, "newValue");
        assertEquals("newValue",
                Settings.Secure.getStringForUser(mCr, SECURE_SETTING, currentUserId));

        Settings.Secure.putString(mCr, SECURE_SETTING, "newValue2");
        assertEquals("newValue2",
                Settings.Secure.getStringForUser(mCr, SECURE_SETTING, UserHandle.USER_CURRENT));

        Settings.Secure.putStringForUser(mCr, SECURE_SETTING, "newValue3", UserHandle.USER_CURRENT);
        assertEquals("newValue3", Settings.Secure.getString(mCr, SECURE_SETTING));

        assertUserHandleUnsupported(UserHandle.ALL, SECURE_SETTING);
        assertUserHandleUnsupported(UserHandle.CURRENT_OR_SELF, SECURE_SETTING);
    }
}
+38 −14
Original line number Diff line number Diff line
@@ -18,11 +18,14 @@ package com.android.internal.util.test;

import android.net.Uri;
import android.os.Bundle;
import android.os.Process;
import android.os.UserHandle;
import android.provider.Settings;
import android.test.mock.MockContentProvider;
import android.util.ArrayMap;
import android.util.Log;

import java.util.HashMap;
import java.util.Map;

/**
 * Fake for system settings.
@@ -69,12 +72,19 @@ public class FakeSettingsProvider extends MockContentProvider {
    private static final String TAG = FakeSettingsProvider.class.getSimpleName();
    private static final boolean DBG = false;
    private static final String[] TABLES = { "system", "secure", "global" };
    private static final Map<String, String> EMPTY_MAP = Map.of();

    private final HashMap<String, HashMap<String, String>> mTables = new HashMap<>();
    /**
     * Stores settings values. Keyed by:
     * - Table name (e.g., "system")
     * - User ID (e.g., USER_SYSTEM)
     * - Setting name (e.g., "screen_brightness")
     */
    private final Map<String, Map<Integer, Map<String, String>>> mDb = new ArrayMap<>();

    public FakeSettingsProvider() {
        for (int i = 0; i < TABLES.length; i++) {
            mTables.put(TABLES[i], new HashMap<String, String>());
            mDb.put(TABLES[i], new ArrayMap<>());
        }
    }

@@ -116,27 +126,41 @@ public class FakeSettingsProvider extends MockContentProvider {

        Bundle out = new Bundle();
        String value;
        int userId = extras.getInt(Settings.CALL_METHOD_USER_KEY);
        if (userId == UserHandle.USER_CURRENT) {
            userId = UserHandle.getUserId(Process.myUid());
        }
        if (userId < 0) {
            throw new UnsupportedOperationException("userId " + userId + " is not a real user");
        }
        switch (op) {
            case "GET":
                value = mTables.get(table).get(arg);
                value = mDb.get(table).getOrDefault(userId, EMPTY_MAP).get(arg);
                if (value != null) {
                    if (DBG) {
                        Log.d(TAG, String.format("Returning fake setting %s.%s = %s",
                                table, arg, value));
                    }
                    out.putString(Settings.NameValueTable.VALUE, value);
                }
                if (DBG) {
                    Log.d(TAG, String.format("Returning fake setting %d:%s.%s = %s",
                            userId, table, arg, (value == null) ? "null" : "\"" + value + "\""));
                }
                break;
            case "PUT":
                value = extras.getString(Settings.NameValueTable.VALUE, null);
                final boolean changed;
                if (value != null) {
                    changed = !value.equals(mDb.get(table)
                            .computeIfAbsent(userId, (u) -> new ArrayMap<>())
                            .put(arg, value));
                    if (DBG) {
                    Log.d(TAG, String.format("Inserting fake setting %s.%s = %s",
                            table, arg, value));
                        Log.d(TAG, String.format("Inserting fake setting %d:%s.%s = \"%s\"",
                                userId, table, arg, value));
                    }
                if (value != null) {
                    mTables.get(table).put(arg, value);
                } else {
                    mTables.get(table).remove(arg);
                    changed = mDb.get(table).getOrDefault(userId, EMPTY_MAP).remove(arg) != null;
                    if (DBG) {
                        Log.d(TAG, String.format("Removing fake setting %d:%s.%s", userId, table,
                                arg));
                    }
                }
                break;
            default: