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

Commit 3ba65a2d authored by Lorenzo Colitti's avatar Lorenzo Colitti Committed by Android (Google) Code Review
Browse files

Merge "Add callback support to FakeSettingsProvider." into main

parents f6a30104 e7e7f513
Loading
Loading
Loading
Loading
+52 −1
Original line number Diff line number Diff line
@@ -16,6 +16,7 @@

package com.android.internal.util.test;

import static junit.framework.Assert.assertFalse;
import static junit.framework.Assert.assertNull;

import static org.junit.Assert.assertEquals;
@@ -37,6 +38,8 @@ import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;

import java.util.ArrayList;

/**
 * Unit tests for FakeSettingsProvider.
 */
@@ -52,10 +55,13 @@ public class FakeSettingsProviderTest {

    private MockContentResolver mCr;

    private ArrayList<String> mCallbacks;

    @Before
    public void setUp() throws Exception {
        FakeSettingsProvider.clearSettingsProvider();
        mCr = new MockContentResolver();
        mCr.addProvider(Settings.AUTHORITY, new FakeSettingsProvider());
        mCallbacks = new ArrayList<>();
    }

    private void assertSystemSettingNotFound(String name) {
@@ -70,6 +76,7 @@ public class FakeSettingsProviderTest {
    @Test
    @SmallTest
    public void testBasicOperation() throws Exception {
        mCr.addProvider(Settings.AUTHORITY, new FakeSettingsProvider());
        assertSystemSettingNotFound(SYSTEM_SETTING);

        // Check that fake settings can be written and read back.
@@ -101,6 +108,7 @@ public class FakeSettingsProviderTest {
    @Test
    @SmallTest
    public void testMultiUserOperation() {
        mCr.addProvider(Settings.AUTHORITY, new FakeSettingsProvider());
        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));
@@ -135,4 +143,47 @@ public class FakeSettingsProviderTest {
        assertEquals("newGlobalSetting", Settings.Global.getStringForUser(mCr, GLOBAL_SETTING, 42));

    }

    private void assertCallbackReceived(String expectedCallback) {
        assertFalse("No callbacks received", mCallbacks.isEmpty());
        assertEquals(expectedCallback, mCallbacks.removeFirst());
    }

    private void assertNoCallbackReceived() {
        assertEquals(0, mCallbacks.size());
    }

    @Test
    @SmallTest
    public void testCallbacks() {
        mCr.addProvider(Settings.AUTHORITY, new FakeSettingsProvider((userId, uri) ->
                mCallbacks.add(userId + ":" + uri.toString())));

        Settings.Secure.putStringForUser(mCr, SECURE_SETTING, "value", 1);
        assertCallbackReceived("1:content://settings/secure/bluetooth_name");

        Settings.Secure.putStringForUser(mCr, SECURE_SETTING, "newvalue", 1);
        assertCallbackReceived("1:content://settings/secure/bluetooth_name");

        Settings.Secure.putStringForUser(mCr, SECURE_SETTING, "value", 2);
        assertCallbackReceived("2:content://settings/secure/bluetooth_name");

        // Callback is not called if value doesn't change.
        Settings.Secure.putStringForUser(mCr, SECURE_SETTING, "newvalue", 1);
        assertNoCallbackReceived();

        Settings.Secure.putStringForUser(mCr, SECURE_SETTING, null, 2);
        assertCallbackReceived("2:content://settings/secure/bluetooth_name");

        Settings.Secure.putStringForUser(mCr, SECURE_SETTING, null, 1);
        assertCallbackReceived("1:content://settings/secure/bluetooth_name");

        Settings.Secure.putStringForUser(mCr, SECURE_SETTING, null, 1);
        assertNoCallbackReceived();

        final int currentUserId = UserHandle.getUserId(Process.myUid());
        Settings.System.putString(mCr, SYSTEM_SETTING, "value");
        assertCallbackReceived(currentUserId + ":" + "content://settings/system/screen_brightness");

    }
}
+19 −9
Original line number Diff line number Diff line
@@ -16,6 +16,7 @@

package com.android.internal.util.test;

import android.annotation.NonNull;
import android.net.Uri;
import android.os.Bundle;
import android.os.UserHandle;
@@ -25,6 +26,7 @@ import android.util.ArrayMap;
import android.util.Log;

import java.util.Map;
import java.util.Objects;

/**
 * Fake for system settings.
@@ -58,13 +60,6 @@ import java.util.Map;
 * class only fetches the content provider from the passed-in ContentResolver the first time it's
 * used, and after that stores it in a per-process static. If this needs to be used in this case,
 * then call {@link #clearSettingsProvider()} before and after using this.
 *
 * TODO: evaluate implementing settings change notifications. This would require:
 *
 * 1. Making ContentResolver#registerContentObserver non-final and overriding it in
 *    MockContentResolver.
 * 2. Making FakeSettingsProvider take a ContentResolver argument.
 * 3. Calling ContentResolver#notifyChange(getUriFor(table, arg), ...) on every settings change.
 */
public class FakeSettingsProvider extends MockContentProvider {

@@ -81,10 +76,23 @@ public class FakeSettingsProvider extends MockContentProvider {
     */
    private final Map<String, Map<Integer, Map<String, String>>> mDb = new ArrayMap<>();

    public FakeSettingsProvider() {
    public interface Callback {
        /** Called whenever a setting's value changes. */
        void onUriChanged(int userId, Uri uri);
    }

    private final Callback mCallback;

    public FakeSettingsProvider(@NonNull Callback callback) {
        Objects.requireNonNull(callback);
        for (int i = 0; i < TABLES.length; i++) {
            mDb.put(TABLES[i], new ArrayMap<>());
        }
        mCallback = callback;
    }

    public FakeSettingsProvider() {
        this((user, uri) -> {});
    }

    private Uri getUriFor(String table, String key) {
@@ -160,7 +168,8 @@ public class FakeSettingsProvider extends MockContentProvider {
                value = extras.getString(Settings.NameValueTable.VALUE, null);
                final boolean changed;
                if (value != null) {
                    changed = !value.equals(mDb.get(table)
                    changed = !value.equals(
                            mDb.get(table)
                            .computeIfAbsent(userId, (u) -> new ArrayMap<>())
                            .put(arg, value));
                    if (DBG) {
@@ -175,6 +184,7 @@ public class FakeSettingsProvider extends MockContentProvider {
                                arg));
                    }
                }
                if (changed) mCallback.onUriChanged(userId, getUriFor(table, arg));
                break;
            default:
                throw new UnsupportedOperationException("Unknown command " + method);