Add a DeviceConfig.Properties.Builder class.
Test: atest FrameworksCoreTests:DeviceConfigTest
atest SettingsProviderTest:DeviceConfigServiceTest
Bug: 136135417
Change-Id: I2e1b2d467ba0b0590ef216eb10d42f73ba1ccda0
diff --git a/api/system-current.txt b/api/system-current.txt
index 781364e..5279857 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -7110,6 +7110,16 @@
method @Nullable public String getString(@NonNull String, @Nullable String);
}
+ public static final class DeviceConfig.Properties.Builder {
+ ctor public DeviceConfig.Properties.Builder(@NonNull String);
+ method @NonNull public android.provider.DeviceConfig.Properties build();
+ method @NonNull public android.provider.DeviceConfig.Properties.Builder setBoolean(@NonNull String, boolean);
+ method @NonNull public android.provider.DeviceConfig.Properties.Builder setFloat(@NonNull String, float);
+ method @NonNull public android.provider.DeviceConfig.Properties.Builder setInt(@NonNull String, int);
+ method @NonNull public android.provider.DeviceConfig.Properties.Builder setLong(@NonNull String, long);
+ method @NonNull public android.provider.DeviceConfig.Properties.Builder setString(@NonNull String, @Nullable String);
+ }
+
public final class DocumentsContract {
method public static boolean isManageMode(@NonNull android.net.Uri);
method @NonNull public static android.net.Uri setManageMode(@NonNull android.net.Uri);
diff --git a/api/test-current.txt b/api/test-current.txt
index efb8538..00f66f1 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -2452,6 +2452,16 @@
method @Nullable public String getString(@NonNull String, @Nullable String);
}
+ public static final class DeviceConfig.Properties.Builder {
+ ctor public DeviceConfig.Properties.Builder(@NonNull String);
+ method @NonNull public android.provider.DeviceConfig.Properties build();
+ method @NonNull public android.provider.DeviceConfig.Properties.Builder setBoolean(@NonNull String, boolean);
+ method @NonNull public android.provider.DeviceConfig.Properties.Builder setFloat(@NonNull String, float);
+ method @NonNull public android.provider.DeviceConfig.Properties.Builder setInt(@NonNull String, int);
+ method @NonNull public android.provider.DeviceConfig.Properties.Builder setLong(@NonNull String, long);
+ method @NonNull public android.provider.DeviceConfig.Properties.Builder setString(@NonNull String, @Nullable String);
+ }
+
public final class MediaStore {
method @RequiresPermission(android.Manifest.permission.CLEAR_APP_USER_DATA) public static void deleteContributedMedia(android.content.Context, String, android.os.UserHandle) throws java.io.IOException;
method @RequiresPermission(android.Manifest.permission.CLEAR_APP_USER_DATA) public static long getContributedMediaSize(android.content.Context, String, android.os.UserHandle) throws java.io.IOException;
diff --git a/core/java/android/provider/DeviceConfig.java b/core/java/android/provider/DeviceConfig.java
index f8825ed..ef22d70 100644
--- a/core/java/android/provider/DeviceConfig.java
+++ b/core/java/android/provider/DeviceConfig.java
@@ -40,6 +40,7 @@
import com.android.internal.util.Preconditions;
import java.util.Arrays;
+import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@@ -734,19 +735,19 @@
List<String> pathSegments = uri.getPathSegments();
// pathSegments(0) is "config"
final String namespace = pathSegments.get(1);
- Map<String, String> propertyMap = new ArrayMap<>();
+ Properties.Builder propBuilder = new Properties.Builder(namespace);
try {
Properties allProperties = getProperties(namespace);
for (int i = 2; i < pathSegments.size(); ++i) {
String key = pathSegments.get(i);
- propertyMap.put(key, allProperties.getString(key, null));
+ propBuilder.setString(key, allProperties.getString(key, null));
}
} catch (SecurityException e) {
// Silently failing to not crash binder or listener threads.
Log.e(TAG, "OnPropertyChangedListener update failed: permission violation.");
return;
}
- Properties properties = new Properties(namespace, propertyMap);
+ Properties properties = propBuilder.build();
synchronized (sLock) {
for (int i = 0; i < sListeners.size(); i++) {
@@ -819,6 +820,7 @@
public static class Properties {
private final String mNamespace;
private final HashMap<String, String> mMap;
+ private Set<String> mKeyset;
/**
* Create a mapping of properties to values and the namespace they belong to.
@@ -849,7 +851,10 @@
*/
@NonNull
public Set<String> getKeyset() {
- return mMap.keySet();
+ if (mKeyset == null) {
+ mKeyset = Collections.unmodifiableSet(mMap.keySet());
+ }
+ return mKeyset;
}
/**
@@ -944,6 +949,93 @@
return defaultValue;
}
}
+
+ /**
+ * Builder class for the construction of {@link Properties} objects.
+ */
+ public static final class Builder {
+ @NonNull
+ private final String mNamespace;
+ @NonNull
+ private final Map<String, String> mKeyValues = new HashMap<>();
+
+ /**
+ * Create a new Builders for the specified namespace.
+ * @param namespace non null namespace.
+ */
+ public Builder(@NonNull String namespace) {
+ mNamespace = namespace;
+ }
+
+ /**
+ * Add a new property with the specified key and value.
+ * @param name non null name of the property.
+ * @param value nullable string value of the property.
+ * @return this Builder object
+ */
+ @NonNull
+ public Builder setString(@NonNull String name, @Nullable String value) {
+ mKeyValues.put(name, value);
+ return this;
+ }
+
+ /**
+ * Add a new property with the specified key and value.
+ * @param name non null name of the property.
+ * @param value nullable string value of the property.
+ * @return this Builder object
+ */
+ @NonNull
+ public Builder setBoolean(@NonNull String name, boolean value) {
+ mKeyValues.put(name, Boolean.toString(value));
+ return this;
+ }
+
+ /**
+ * Add a new property with the specified key and value.
+ * @param name non null name of the property.
+ * @param value int value of the property.
+ * @return this Builder object
+ */
+ @NonNull
+ public Builder setInt(@NonNull String name, int value) {
+ mKeyValues.put(name, Integer.toString(value));
+ return this;
+ }
+
+ /**
+ * Add a new property with the specified key and value.
+ * @param name non null name of the property.
+ * @param value long value of the property.
+ * @return this Builder object
+ */
+ @NonNull
+ public Builder setLong(@NonNull String name, long value) {
+ mKeyValues.put(name, Long.toString(value));
+ return this;
+ }
+
+ /**
+ * Add a new property with the specified key and value.
+ * @param name non null name of the property.
+ * @param value float value of the property.
+ * @return this Builder object
+ */
+ @NonNull
+ public Builder setFloat(@NonNull String name, float value) {
+ mKeyValues.put(name, Float.toString(value));
+ return this;
+ }
+
+ /**
+ * Create a new {@link Properties} object.
+ * @return non null Properties.
+ */
+ @NonNull
+ public Properties build() {
+ return new Properties(mNamespace, mKeyValues);
+ }
+ }
}
}
diff --git a/core/tests/coretests/src/android/provider/DeviceConfigTest.java b/core/tests/coretests/src/android/provider/DeviceConfigTest.java
index 2f91a09..ae835e4 100644
--- a/core/tests/coretests/src/android/provider/DeviceConfigTest.java
+++ b/core/tests/coretests/src/android/provider/DeviceConfigTest.java
@@ -33,9 +33,6 @@
import org.junit.Test;
import org.junit.runner.RunWith;
-import java.util.HashMap;
-import java.util.Map;
-
/** Tests that ensure appropriate settings are backed up. */
@Presubmit
@RunWith(AndroidJUnit4.class)
@@ -489,21 +486,19 @@
@Test
public void setProperties() throws DeviceConfig.BadConfigException {
- Map<String, String> keyValues = new HashMap<>();
- keyValues.put(KEY, VALUE);
- keyValues.put(KEY2, VALUE2);
+ Properties properties = new Properties.Builder(NAMESPACE).setString(KEY, VALUE)
+ .setString(KEY2, VALUE2).build();
- DeviceConfig.setProperties(new Properties(NAMESPACE, keyValues));
- Properties properties = DeviceConfig.getProperties(NAMESPACE);
+ DeviceConfig.setProperties(properties);
+ properties = DeviceConfig.getProperties(NAMESPACE);
assertThat(properties.getKeyset()).containsExactly(KEY, KEY2);
assertThat(properties.getString(KEY, DEFAULT_VALUE)).isEqualTo(VALUE);
assertThat(properties.getString(KEY2, DEFAULT_VALUE)).isEqualTo(VALUE2);
- Map<String, String> newKeyValues = new HashMap<>();
- newKeyValues.put(KEY, VALUE2);
- newKeyValues.put(KEY3, VALUE3);
+ properties = new Properties.Builder(NAMESPACE).setString(KEY, VALUE2)
+ .setString(KEY3, VALUE3).build();
- DeviceConfig.setProperties(new Properties(NAMESPACE, newKeyValues));
+ DeviceConfig.setProperties(properties);
properties = DeviceConfig.getProperties(NAMESPACE);
assertThat(properties.getKeyset()).containsExactly(KEY, KEY3);
assertThat(properties.getString(KEY, DEFAULT_VALUE)).isEqualTo(VALUE2);
@@ -515,17 +510,14 @@
@Test
public void setProperties_multipleNamespaces() throws DeviceConfig.BadConfigException {
- Map<String, String> keyValues = new HashMap<>();
- keyValues.put(KEY, VALUE);
- keyValues.put(KEY2, VALUE2);
-
- Map<String, String> keyValues2 = new HashMap<>();
- keyValues2.put(KEY2, VALUE);
- keyValues2.put(KEY3, VALUE2);
-
final String namespace2 = "namespace2";
- DeviceConfig.setProperties(new Properties(NAMESPACE, keyValues));
- DeviceConfig.setProperties(new Properties(namespace2, keyValues2));
+ Properties properties1 = new Properties.Builder(NAMESPACE).setString(KEY, VALUE)
+ .setString(KEY2, VALUE2).build();
+ Properties properties2 = new Properties.Builder(namespace2).setString(KEY2, VALUE)
+ .setString(KEY3, VALUE2).build();
+
+ DeviceConfig.setProperties(properties1);
+ DeviceConfig.setProperties(properties2);
Properties properties = DeviceConfig.getProperties(NAMESPACE);
assertThat(properties.getKeyset()).containsExactly(KEY, KEY2);
@@ -549,6 +541,26 @@
deleteViaContentProvider(namespace2, KEY3);
}
+ @Test
+ public void propertiesBuilder() {
+ boolean booleanValue = true;
+ int intValue = 123;
+ float floatValue = 4.56f;
+ long longValue = -789L;
+ String key4 = "key4";
+ String key5 = "key5";
+
+ Properties properties = new Properties.Builder(NAMESPACE).setString(KEY, VALUE)
+ .setBoolean(KEY2, booleanValue).setInt(KEY3, intValue).setLong(key4, longValue)
+ .setFloat(key5, floatValue).build();
+ assertThat(properties.getNamespace()).isEqualTo(NAMESPACE);
+ assertThat(properties.getString(KEY, "defaultValue")).isEqualTo(VALUE);
+ assertThat(properties.getBoolean(KEY2, false)).isEqualTo(booleanValue);
+ assertThat(properties.getInt(KEY3, 0)).isEqualTo(intValue);
+ assertThat(properties.getLong("key4", 0L)).isEqualTo(longValue);
+ assertThat(properties.getFloat("key5", 0f)).isEqualTo(floatValue);
+ }
+
// TODO(mpape): resolve b/142727848 and re-enable listener tests
// @Test
// public void onPropertiesChangedListener_setPropertyCallback() throws InterruptedException {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/util/DeviceConfigProxyFake.java b/packages/SystemUI/tests/src/com/android/systemui/util/DeviceConfigProxyFake.java
index 426aba0..260ff2d 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/util/DeviceConfigProxyFake.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/util/DeviceConfigProxyFake.java
@@ -69,8 +69,11 @@
}
for (Pair<Executor, OnPropertiesChangedListener> listener : mListeners) {
- listener.first.execute(() -> listener.second.onPropertiesChanged(
- new Properties(namespace, mProperties.get(namespace))));
+ Properties.Builder propBuilder = new Properties.Builder(namespace);
+ for (String key : mProperties.get(namespace).keySet()) {
+ propBuilder.setString(key, mProperties.get(namespace).get(key));
+ }
+ listener.first.execute(() -> listener.second.onPropertiesChanged(propBuilder.build()));
}
return true;
}
@@ -88,10 +91,12 @@
private Properties propsForNamespaceAndName(String namespace, String name) {
if (mProperties.containsKey(namespace) && mProperties.get(namespace).containsKey(name)) {
- return new Properties(namespace, mProperties.get(namespace));
+ return new Properties.Builder(namespace)
+ .setString(name, mProperties.get(namespace).get(name)).build();
}
if (mDefaultProperties.containsKey(namespace)) {
- return new Properties(namespace, mDefaultProperties.get(namespace));
+ return new Properties.Builder(namespace)
+ .setString(name, mDefaultProperties.get(namespace).get(name)).build();
}
return null;