diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java index 227c9d4269152..85feac878c676 100644 --- a/core/java/android/provider/Settings.java +++ b/core/java/android/provider/Settings.java @@ -8654,9 +8654,10 @@ public final class Settings { "location_permissions_upgrade_to_q_mode"; /** - * Comma separated list of enabled overlay packages for all android.theme.customization.* - * categories. If there is no corresponding package included for a category, then all - * overlay packages in that category must be disabled. + * Map of android.theme.customization.* categories to the enabled overlay package for that + * category, formatted as a serialized {@link org.json.JSONObject}. If there is no + * corresponding package included for a category, then all overlay packages in that + * category must be disabled. * @hide */ @SystemApi @@ -8664,7 +8665,7 @@ public final class Settings { "theme_customization_overlay_packages"; private static final Validator THEME_CUSTOMIZATION_OVERLAY_PACKAGES_VALIDATOR = - new SettingsValidators.PackageNameListValidator(","); + SettingsValidators.JSON_OBJECT_VALIDATOR; /** * Controls whether aware is enabled. diff --git a/core/java/android/provider/SettingsValidators.java b/core/java/android/provider/SettingsValidators.java index 25e77867b757f..405121378d1f1 100644 --- a/core/java/android/provider/SettingsValidators.java +++ b/core/java/android/provider/SettingsValidators.java @@ -19,9 +19,13 @@ package android.provider; import android.annotation.Nullable; import android.content.ComponentName; import android.net.Uri; +import android.text.TextUtils; import com.android.internal.util.ArrayUtils; +import org.json.JSONException; +import org.json.JSONObject; + import java.util.Locale; /** @@ -162,6 +166,19 @@ public class SettingsValidators { } }; + /** {@link Validator} that checks whether a value is a valid {@link JSONObject}. */ + public static final Validator JSON_OBJECT_VALIDATOR = (value) -> { + if (TextUtils.isEmpty(value)) { + return false; + } + try { + new JSONObject(value); + return true; + } catch (JSONException e) { + return false; + } + }; + public interface Validator { /** * Returns whether the input value is valid. Subclasses should handle the case where the diff --git a/core/tests/coretests/src/android/provider/SettingsValidatorsTest.java b/core/tests/coretests/src/android/provider/SettingsValidatorsTest.java index 08f9de602684a..8081e9e6c67bd 100644 --- a/core/tests/coretests/src/android/provider/SettingsValidatorsTest.java +++ b/core/tests/coretests/src/android/provider/SettingsValidatorsTest.java @@ -16,6 +16,8 @@ package android.provider; +import static com.google.common.truth.Truth.assertThat; + import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; @@ -26,6 +28,8 @@ import android.provider.SettingsValidators.Validator; import androidx.test.filters.SmallTest; import androidx.test.runner.AndroidJUnit4; +import org.json.JSONException; +import org.json.JSONObject; import org.junit.Test; import org.junit.runner.RunWith; @@ -217,6 +221,31 @@ public class SettingsValidatorsTest { assertFalse(Settings.System.DATE_FORMAT_VALIDATOR.validate(null)); } + @Test + public void testJSONObjectValidator() throws JSONException { + Validator v = SettingsValidators.JSON_OBJECT_VALIDATOR; + + assertThat(v.validate(new JSONObject().toString())).isTrue(); + assertThat(v.validate("{}")).isTrue(); + assertThat(v.validate(new JSONObject().put("foo", "bar").toString())) + .isTrue(); + assertThat(v.validate("{\"foo\": \"bar\"}")).isTrue(); + + assertThat(v.validate("random string")).isFalse(); + assertThat(v.validate("random: string")).isFalse(); + assertThat(v.validate("{random: }")).isFalse(); + } + + @Test + public void testJSONObjectValidator_onNullValue_returnsFalse() { + assertThat(SettingsValidators.JSON_OBJECT_VALIDATOR.validate(null)).isFalse(); + } + + @Test + public void testJSONObjectValidator_onEmptyString_returnsFalse() { + assertThat(SettingsValidators.JSON_OBJECT_VALIDATOR.validate("")).isFalse(); + } + @Test public void ensureAllBackedUpSystemSettingsHaveValidators() { String offenders = getOffenders(concat(Settings.System.SETTINGS_TO_BACKUP,