summaryrefslogtreecommitdiff
path: root/framework/java
diff options
context:
space:
mode:
Diffstat (limited to 'framework/java')
-rw-r--r--framework/java/android/provider/DeviceConfig.java250
-rw-r--r--framework/java/android/provider/DeviceConfigDataStore.java61
-rw-r--r--framework/java/android/provider/DeviceConfigManager.java76
-rw-r--r--framework/java/android/provider/DeviceConfigServiceDataStore.java165
-rw-r--r--framework/java/android/provider/SettingsConfigDataStore.java105
-rw-r--r--framework/java/android/provider/WritableFlags.java5
-rw-r--r--framework/java/android/provider/aidl/IDeviceConfigManager.aidl18
7 files changed, 658 insertions, 22 deletions
diff --git a/framework/java/android/provider/DeviceConfig.java b/framework/java/android/provider/DeviceConfig.java
index 06d5572..6f169ac 100644
--- a/framework/java/android/provider/DeviceConfig.java
+++ b/framework/java/android/provider/DeviceConfig.java
@@ -17,6 +17,7 @@
package android.provider;
import static android.Manifest.permission.WRITE_ALLOWLISTED_DEVICE_CONFIG;
+import static android.Manifest.permission.READ_DEVICE_CONFIG;
import static android.Manifest.permission.WRITE_DEVICE_CONFIG;
import static android.Manifest.permission.READ_WRITE_SYNC_DISABLED_MODE_CONFIG;
@@ -31,6 +32,7 @@ import android.annotation.SystemApi;
import android.content.ContentResolver;
import android.database.ContentObserver;
import android.net.Uri;
+import com.android.modules.utils.build.SdkLevel;
import android.util.ArrayMap;
import android.util.Log;
import android.util.Pair;
@@ -45,12 +47,20 @@ import java.lang.annotation.Target;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
+import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.concurrent.Executor;
+import android.util.Log;
+
+import android.provider.aidl.IDeviceConfigManager;
+import android.provider.DeviceConfigServiceManager;
+import android.provider.DeviceConfigInitializer;
+import android.os.IBinder;
+
/**
* Device level configuration parameters which can be tuned by a separate configuration service.
* Namespaces that end in "_native" such as {@link #NAMESPACE_NETD_NATIVE} are intended to be used
@@ -60,6 +70,14 @@ import java.util.concurrent.Executor;
*/
@SystemApi
public final class DeviceConfig {
+
+ /**
+ * The name of the service that provides the logic to these APIs
+ *
+ * @hide
+ */
+ public static final String SERVICE_NAME = "device_config_updatable";
+
/**
* Namespace for all accessibility related features.
*
@@ -199,6 +217,14 @@ public final class DeviceConfig {
public static final String NAMESPACE_BLUETOOTH = "bluetooth";
/**
+ * Namespace for features relating to android core experiments team internal usage.
+ *
+ * @hide
+ */
+ @SystemApi
+ public static final String NAMESPACE_CORE_EXPERIMENTS_TEAM_INTERNAL = "core_experiments_team_internal";
+
+ /**
* Namespace for all camera-related features that are used at the native level.
*
* @hide
@@ -938,6 +964,27 @@ public final class DeviceConfig {
@SystemApi
public static final String NAMESPACE_REMOTE_AUTH = "remote_auth";
+
+ /**
+ * Namespace for tethering module native features.
+ * Flags defined in this namespace are only usable on
+ * {@link android.os.Build.VERSION_CODES#UPSIDE_DOWN_CAKE} and newer.
+ * On older Android releases, they will not be propagated to native code.
+ *
+ * @hide
+ */
+ @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
+ public static final String NAMESPACE_TETHERING_NATIVE =
+ "tethering_u_or_later_native";
+
+ /**
+ * Namespace for all near field communication (nfc) related features.
+ *
+ * @hide
+ */
+ @SystemApi
+ public static final String NAMESPACE_NFC = "nfc";
+
/**
* The modes that can be used when disabling syncs to the 'config' settings.
* @hide
@@ -974,7 +1021,7 @@ public final class DeviceConfig {
*/
@SystemApi
public static final int SYNC_DISABLED_MODE_UNTIL_REBOOT = 2;
-
+
private static final Object sLock = new Object();
@GuardedBy("sLock")
private static ArrayMap<OnPropertiesChangedListener, Pair<String, Executor>> sListeners =
@@ -983,6 +1030,11 @@ public final class DeviceConfig {
private static Map<String, Pair<ContentObserver, Integer>> sNamespaces = new HashMap<>();
private static final String TAG = "DeviceConfig";
+ private static final DeviceConfigDataStore sDataStore = new SettingsConfigDataStore();
+
+ private static final String DEVICE_CONFIG_OVERRIDES_NAMESPACE =
+ "device_config_overrides";
+
/**
* Interface for monitoring callback functions.
*
@@ -1043,6 +1095,8 @@ public final class DeviceConfig {
* Each call to {@link #setProperties(Properties)} is also atomic and ensures that either none
* or all of the change is picked up here, but never only part of it.
*
+ * If there are any local overrides applied, they will take precedence over underlying values.
+ *
* @param namespace The namespace containing the properties to look up.
* @param names The names of properties to look up, or empty to fetch all properties for the
* given namespace.
@@ -1056,9 +1110,80 @@ public final class DeviceConfig {
*/
@SystemApi
@NonNull
- public static Properties getProperties(@NonNull String namespace, @NonNull String ... names) {
- return new Properties(namespace,
- Settings.Config.getStrings(namespace, Arrays.asList(names)));
+ @RequiresPermission(READ_DEVICE_CONFIG)
+ public static Properties getProperties(@NonNull String namespace, @NonNull String... names) {
+ Properties propertiesWithoutOverrides =
+ getPropertiesWithoutOverrides(namespace, names);
+ if (SdkLevel.isAtLeastV()) {
+ return applyOverrides(propertiesWithoutOverrides);
+ } else {
+ return propertiesWithoutOverrides;
+ }
+ }
+
+ @NonNull
+ private static Properties getPropertiesWithoutOverrides(@NonNull String namespace,
+ @NonNull String... names) {
+ return sDataStore.getProperties(namespace, names);
+ }
+
+ private static Properties applyOverrides(@NonNull Properties properties) {
+ Properties overrides =
+ getPropertiesWithoutOverrides(DEVICE_CONFIG_OVERRIDES_NAMESPACE);
+ Map<String, String> newPropertiesMap = new HashMap<>();
+
+ HashSet<String> flags = new HashSet(properties.getKeyset());
+ for (String override : overrides.getKeyset()) {
+ String[] namespaceAndFlag = override.split(":");
+ if (properties.getNamespace().equals(namespaceAndFlag[0])) {
+ flags.add(namespaceAndFlag[1]);
+ }
+ }
+
+ for (String flag : flags) {
+ String override =
+ overrides.getString(properties.getNamespace() + ":" + flag, null);
+ if (override != null) {
+ newPropertiesMap.put(flag, override);
+ } else {
+ newPropertiesMap.put(flag, properties.getString(flag, null));
+ }
+ }
+ return new Properties(properties.getNamespace(), newPropertiesMap);
+ }
+
+ /**
+ * List all stored flags.
+ *
+ * The keys take the form {@code namespace/name}, and the values are the flag values.
+ *
+ * @hide
+ */
+ @SystemApi
+ @NonNull
+ public static Set<Properties> getAllProperties() {
+ Map<String, String> properties = sDataStore.getAllProperties();
+ Map<String, Map<String, String>> propertyMaps = new HashMap<>();
+ for (String flag : properties.keySet()) {
+ String[] namespaceAndFlag = flag.split("/");
+ String namespace = namespaceAndFlag[0];
+ String flagName = namespaceAndFlag[1];
+ String override =
+ getProperty(DEVICE_CONFIG_OVERRIDES_NAMESPACE, namespace + ":" + flagName);
+
+ String value = override != null ? override : properties.get(flag);
+
+ if (!propertyMaps.containsKey(namespace)) {
+ propertyMaps.put(namespace, new HashMap<>());
+ }
+ propertyMaps.get(namespace).put(flagName, value);
+ }
+
+ HashSet<Properties> result = new HashSet<>();
+ for (Map.Entry<String, Map<String, String>> entry : propertyMaps.entrySet()) {
+ result.add(new Properties(entry.getKey(), entry.getValue()));
+ }
+ return result;
}
/**
@@ -1072,6 +1197,7 @@ public final class DeviceConfig {
* @hide
*/
@SystemApi
+ @RequiresPermission(READ_DEVICE_CONFIG)
@Nullable
public static String getString(@NonNull String namespace, @NonNull String name,
@Nullable String defaultValue) {
@@ -1107,6 +1233,7 @@ public final class DeviceConfig {
* @hide
*/
@SystemApi
+ @RequiresPermission(READ_DEVICE_CONFIG)
public static int getInt(@NonNull String namespace, @NonNull String name, int defaultValue) {
String value = getProperty(namespace, name);
if (value == null) {
@@ -1131,6 +1258,7 @@ public final class DeviceConfig {
* @hide
*/
@SystemApi
+ @RequiresPermission(READ_DEVICE_CONFIG)
public static long getLong(@NonNull String namespace, @NonNull String name, long defaultValue) {
String value = getProperty(namespace, name);
if (value == null) {
@@ -1155,6 +1283,7 @@ public final class DeviceConfig {
* @hide
*/
@SystemApi
+ @RequiresPermission(READ_DEVICE_CONFIG)
public static float getFloat(@NonNull String namespace, @NonNull String name,
float defaultValue) {
String value = getProperty(namespace, name);
@@ -1170,6 +1299,82 @@ public final class DeviceConfig {
}
/**
+ * Set flag {@code namespace/name} to {@code value}, and ignores server-updates for this flag.
+ *
+ * Can still be called even if there is no underlying value set.
+ *
+ * Returns {@code true} if successful, or {@code false} if the storage implementation throws
+ * errors.
+ *
+ * @hide
+ */
+ @SystemApi
+ @RequiresPermission(WRITE_DEVICE_CONFIG)
+ public static boolean setLocalOverride(@NonNull String namespace, @NonNull String name,
+ @NonNull String value) {
+ return setProperty(DEVICE_CONFIG_OVERRIDES_NAMESPACE, namespace + ":" + name, value, false);
+ }
+
+ /**
+ * Clear all local sticky overrides.
+ *
+ * @hide
+ */
+ @SystemApi
+ @RequiresPermission(WRITE_DEVICE_CONFIG)
+ public static void clearAllLocalOverrides() {
+ Properties overrides = getProperties(DEVICE_CONFIG_OVERRIDES_NAMESPACE);
+ for (String overrideName : overrides.getKeyset()) {
+ deleteProperty(DEVICE_CONFIG_OVERRIDES_NAMESPACE, overrideName);
+ }
+ }
+
+ /**
+ * Clear local sticky override for flag {@code namespace/name}.
+ *
+ * @hide
+ */
+ @SystemApi
+ @RequiresPermission(WRITE_DEVICE_CONFIG)
+ public static void clearLocalOverride(@NonNull String namespace,
+ @NonNull String name) {
+ deleteProperty(DEVICE_CONFIG_OVERRIDES_NAMESPACE, namespace + ":" + name);
+ }
+
+ /**
+ * Return a map containing all flags that have been overridden.
+ *
+ * The keys of the outer map are namespaces. They keys of the inner maps are
+ * flag names. The values of the inner maps are the underlying flag values
+ * (not to be confused with their overridden values).
+ *
+ * @hide
+ */
+ @NonNull
+ @SystemApi
+ public static Map<String, Map<String, String>> getUnderlyingValuesForOverriddenFlags() {
+ Properties overrides = getProperties(DEVICE_CONFIG_OVERRIDES_NAMESPACE);
+ HashMap<String, Map<String, String>> result = new HashMap<>();
+ for (Map.Entry<String, String> entry : overrides.getPropertyValues().entrySet()) {
+ String[] namespaceAndFlag = entry.getKey().split(":");
+ String namespace = namespaceAndFlag[0];
+ String flag = namespaceAndFlag[1];
+
+ String actualValue =
+ getPropertiesWithoutOverrides(namespace, flag)
+ .getString(flag, null);
+ if (result.get(namespace) != null) {
+ result.get(namespace).put(flag, actualValue);
+ } else {
+ HashMap<String, String> innerMap = new HashMap<>();
+ innerMap.put(flag, actualValue);
+ result.put(namespace, innerMap);
+ }
+ }
+ return result;
+ }
+
+ /**
* Create a new property with the provided name and value in the provided namespace, or
* update the value of such a property if it already exists. The same name can exist in multiple
* namespaces and might have different values in any or all namespaces.
@@ -1193,7 +1398,7 @@ public final class DeviceConfig {
@RequiresPermission(anyOf = {WRITE_DEVICE_CONFIG, WRITE_ALLOWLISTED_DEVICE_CONFIG})
public static boolean setProperty(@NonNull String namespace, @NonNull String name,
@Nullable String value, boolean makeDefault) {
- return Settings.Config.putString(namespace, name, value, makeDefault);
+ return sDataStore.setProperty(namespace, name, value, makeDefault);
}
/**
@@ -1214,8 +1419,7 @@ public final class DeviceConfig {
@SystemApi
@RequiresPermission(anyOf = {WRITE_DEVICE_CONFIG, WRITE_ALLOWLISTED_DEVICE_CONFIG})
public static boolean setProperties(@NonNull Properties properties) throws BadConfigException {
- return Settings.Config.setStrings(properties.getNamespace(),
- properties.mMap);
+ return sDataStore.setProperties(properties);
}
/**
@@ -1230,7 +1434,7 @@ public final class DeviceConfig {
@SystemApi
@RequiresPermission(anyOf = {WRITE_DEVICE_CONFIG, WRITE_ALLOWLISTED_DEVICE_CONFIG})
public static boolean deleteProperty(@NonNull String namespace, @NonNull String name) {
- return Settings.Config.deleteString(namespace, name);
+ return sDataStore.deleteProperty(namespace, name);
}
/**
@@ -1261,7 +1465,7 @@ public final class DeviceConfig {
@SystemApi
@RequiresPermission(anyOf = {WRITE_DEVICE_CONFIG, WRITE_ALLOWLISTED_DEVICE_CONFIG})
public static void resetToDefaults(int resetMode, @Nullable String namespace) {
- Settings.Config.resetToDefaults(resetMode, namespace);
+ sDataStore.resetToDefaults(resetMode, namespace);
}
/**
@@ -1269,16 +1473,17 @@ public final class DeviceConfig {
* config values. This is intended for use during tests to prevent a sync operation clearing
* config values which could influence the outcome of the tests, i.e. by changing behavior.
*
- * @param syncDisabledMode the mode to use, see {@link #SYNC_DISABLED_MODE_NONE},
- * {@link #SYNC_DISABLED_MODE_PERSISTENT} and {@link #SYNC_DISABLED_MODE_UNTIL_REBOOT}
+ * @param syncDisabledMode the mode to use, see {@link Settings.Config#SYNC_DISABLED_MODE_NONE},
+ * {@link Settings.Config#SYNC_DISABLED_MODE_PERSISTENT} and {@link
+ * Settings.Config#SYNC_DISABLED_MODE_UNTIL_REBOOT}
*
* @see #getSyncDisabledMode()
* @hide
*/
@SystemApi
@RequiresPermission(anyOf = {WRITE_DEVICE_CONFIG, READ_WRITE_SYNC_DISABLED_MODE_CONFIG})
- public static void setSyncDisabledMode(@SyncDisabledMode int syncDisabledMode) {
- Settings.Config.setSyncDisabledMode(syncDisabledMode);
+ public static void setSyncDisabledMode(int syncDisabledMode) {
+ sDataStore.setSyncDisabledMode(syncDisabledMode);
}
/**
@@ -1290,7 +1495,7 @@ public final class DeviceConfig {
@SystemApi
@RequiresPermission(anyOf = {WRITE_DEVICE_CONFIG, READ_WRITE_SYNC_DISABLED_MODE_CONFIG})
public static int getSyncDisabledMode() {
- return Settings.Config.getSyncDisabledMode();
+ return sDataStore.getSyncDisabledMode();
}
/**
@@ -1364,7 +1569,7 @@ public final class DeviceConfig {
@NonNull ContentResolver resolver,
@NonNull @CallbackExecutor Executor executor,
@NonNull MonitorCallback callback) {
- Settings.Config.setMonitorCallback(resolver, executor, callback);
+ sDataStore.setMonitorCallback(resolver, executor, callback);
}
/**
@@ -1376,7 +1581,7 @@ public final class DeviceConfig {
@SystemApi
@RequiresPermission(Manifest.permission.MONITOR_DEVICE_CONFIG_ACCESS)
public static void clearMonitorCallback(@NonNull ContentResolver resolver) {
- Settings.Config.clearMonitorCallback(resolver);
+ sDataStore.clearMonitorCallback(resolver);
}
/**
@@ -1402,7 +1607,7 @@ public final class DeviceConfig {
}
}
};
- Settings.Config
+ sDataStore
.registerContentObserver(namespace, true, contentObserver);
sNamespaces.put(namespace, new Pair<>(contentObserver, 1));
}
@@ -1426,7 +1631,7 @@ public final class DeviceConfig {
sNamespaces.put(namespace, new Pair<>(namespaceCount.first, namespaceCount.second - 1));
} else {
// Decrementing a namespace to zero means we no longer need its ContentObserver.
- Settings.Config.unregisterContentObserver(namespaceCount.first);
+ sDataStore.unregisterContentObserver(namespaceCount.first);
sNamespaces.remove(namespace);
}
}
@@ -1655,6 +1860,15 @@ public final class DeviceConfig {
}
/**
+ * Returns a map with the underlying property values defined by this object
+ *
+ * @hide
+ */
+ public @NonNull Map<String, String> getPropertyValues() {
+ return new HashMap<>(mMap);
+ }
+
+ /**
* Builder class for the construction of {@link Properties} objects.
*/
public static final class Builder {
diff --git a/framework/java/android/provider/DeviceConfigDataStore.java b/framework/java/android/provider/DeviceConfigDataStore.java
new file mode 100644
index 0000000..bd9647c
--- /dev/null
+++ b/framework/java/android/provider/DeviceConfigDataStore.java
@@ -0,0 +1,61 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.provider;
+
+import android.annotation.CallbackExecutor;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.content.ContentResolver;
+import android.database.ContentObserver;
+import android.provider.DeviceConfig;
+
+import java.util.concurrent.Executor;
+import java.util.Map;
+
+/**
+ * @hide
+ */
+public interface DeviceConfigDataStore {
+ @NonNull Map<String, String> getAllProperties();
+
+ @NonNull DeviceConfig.Properties getProperties(@NonNull String namespace, @NonNull String ... names);
+
+ boolean setProperties(@NonNull DeviceConfig.Properties properties) throws
+ DeviceConfig.BadConfigException;
+
+ boolean setProperty(@NonNull String namespace, @NonNull String name,
+ @Nullable String value, boolean makeDefault);
+
+ boolean deleteProperty(@NonNull String namespace, @NonNull String name);
+
+ void resetToDefaults(int resetMode, @Nullable String namespace);
+
+ void setSyncDisabledMode(int syncDisabledMode);
+ int getSyncDisabledMode();
+
+ void setMonitorCallback(
+ @NonNull ContentResolver resolver,
+ @NonNull @CallbackExecutor Executor executor,
+ @NonNull DeviceConfig.MonitorCallback callback);
+
+ void clearMonitorCallback(@NonNull ContentResolver resolver);
+
+ void registerContentObserver(@NonNull String namespace, boolean notifyForescendants,
+ ContentObserver contentObserver);
+
+ void unregisterContentObserver(@NonNull ContentObserver contentObserver);
+}
diff --git a/framework/java/android/provider/DeviceConfigManager.java b/framework/java/android/provider/DeviceConfigManager.java
new file mode 100644
index 0000000..3e50b8a
--- /dev/null
+++ b/framework/java/android/provider/DeviceConfigManager.java
@@ -0,0 +1,76 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.provider;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+
+import android.annotation.SystemService;
+import android.os.RemoteException;
+import android.provider.aidl.IDeviceConfigManager;
+
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * @hide
+ */
+@SystemService(DeviceConfig.SERVICE_NAME)
+public class DeviceConfigManager {
+
+ private IDeviceConfigManager mService;
+
+ public DeviceConfigManager(@NonNull IDeviceConfigManager service) {
+ mService = service;
+ }
+
+ @NonNull
+ public DeviceConfig.Properties getProperties(@NonNull String namespace,
+ @NonNull String... names) {
+ try {
+ Map<String, String> map = mService.getProperties(namespace, names);
+ return new DeviceConfig.Properties(namespace, map);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ public boolean setProperties(@NonNull String namespace, @NonNull Map<String, String> values) {
+ try {
+ return mService.setProperties(namespace, values);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ public boolean setProperty(@NonNull String namespace, @NonNull String name,
+ @Nullable String value, boolean makeDefault) {
+ try {
+ return mService.setProperty(namespace, name, value, makeDefault);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ public boolean deleteProperty(@NonNull String namespace, @NonNull String name) {
+ try {
+ return mService.deleteProperty(namespace, name);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+}
diff --git a/framework/java/android/provider/DeviceConfigServiceDataStore.java b/framework/java/android/provider/DeviceConfigServiceDataStore.java
new file mode 100644
index 0000000..cdcd5a8
--- /dev/null
+++ b/framework/java/android/provider/DeviceConfigServiceDataStore.java
@@ -0,0 +1,165 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.provider;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.content.ContentResolver;
+import android.database.ContentObserver;
+import android.os.IBinder;
+import android.provider.aidl.IDeviceConfigManager;
+import android.util.Slog;
+
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.concurrent.Executor;
+
+/**
+ * @hide
+ */
+public class DeviceConfigServiceDataStore /*implements DeviceConfigDataStore*/ {
+
+ private static final boolean DEBUG = false;
+ private static final String TAG = "DeviceConfigServiceDataStore";
+ private static final Object mLock = new Object();
+
+ // TODO(b/265948914): finish implementation of this data store and make it actually implement
+ // the interface
+ private DeviceConfigManager mManager;
+
+ public DeviceConfigServiceDataStore() {
+
+ }
+
+ public DeviceConfigServiceDataStore(DeviceConfigManager deviceConfigManager) {
+ mManager = deviceConfigManager;
+ }
+
+ private @Nullable DeviceConfigManager createManagerIfNeeded() {
+ if (mManager != null) {
+ return mManager;
+ }
+ synchronized (mLock) {
+ if (mManager != null) {
+ return mManager;
+ }
+
+ IBinder binder = DeviceConfigInitializer.getDeviceConfigServiceManager()
+ .getDeviceConfigUpdatableServiceRegisterer()
+ .get();
+
+ if (binder != null) {
+ IDeviceConfigManager manager = IDeviceConfigManager.Stub.asInterface(
+ binder);
+ mManager = new DeviceConfigManager(manager);
+ }
+ return mManager;
+ }
+ }
+
+// @Override
+ @NonNull
+ public DeviceConfig.Properties getProperties(@NonNull String namespace,
+ @NonNull String... names) {
+ createManagerIfNeeded();
+
+ if (mManager == null) {
+ if(DEBUG) {
+ Slog.d(TAG, "ServiceDS - getProperties before ready " + namespace + " "
+ + Arrays.toString(names));
+ }
+ return new DeviceConfig.Properties(namespace, new HashMap<>());
+ }
+ return mManager.getProperties(namespace, names);
+ }
+
+// @Override
+ public boolean setProperties(@NonNull DeviceConfig.Properties properties)
+ throws DeviceConfig.BadConfigException {
+ createManagerIfNeeded();
+ if (mManager == null) {
+ if(DEBUG) {
+ Slog.d(TAG, "ServiceDS - setProperties before ready " + properties.getNamespace() + " " + properties);
+ }
+ return false;
+ }
+ return mManager.setProperties(properties.getNamespace(), properties.getPropertyValues());
+ }
+//
+// @Override
+ public boolean setProperty(@NonNull String namespace, @NonNull String name,
+ @Nullable String value, boolean makeDefault) {
+ createManagerIfNeeded();
+ if (mManager == null) {
+ if (DEBUG) {
+ Slog.d(TAG, "ServiceDS - setProperty before ready " + namespace + " " + name);
+ }
+ return false;
+ }
+ return mManager.setProperty(namespace, name, value, makeDefault);
+ }
+//
+// @Override
+ public boolean deleteProperty(@NonNull String namespace, @NonNull String name) {
+ createManagerIfNeeded();
+ if (mManager == null) {
+ if (DEBUG) {
+ Slog.d(TAG, "ServiceDS - setProperty before ready " + namespace + " " + name);
+ }
+ return false;
+ }
+ return mManager.deleteProperty(namespace, name);
+ }
+//
+// @Override
+ public void resetToDefaults(int resetMode, @Nullable String namespace) {
+// mManager.resetToDefaults(resetMode, namespace);
+ }
+//
+// @Override
+ public void setSyncDisabledMode(int syncDisabledMode) {
+// mManager.setSyncDisabledMode(syncDisabledMode);
+ }
+//
+// @Override
+ public int getSyncDisabledMode() {
+ // return mManager.getSyncDisabledMode();
+ return 0;
+ }
+//
+// @Override
+ public void setMonitorCallback(@NonNull ContentResolver resolver, @NonNull Executor executor,
+ @NonNull DeviceConfig.MonitorCallback callback) {
+// mManager.setMonitorCallback(resolver, executor, callback);
+ }
+//
+// @Override
+ public void clearMonitorCallback(@NonNull ContentResolver resolver) {
+// mManager.clearMonitorCallback(resolver);
+ }
+//
+// @Override
+ public void registerContentObserver(@NonNull String namespace, boolean notifyForDescendants,
+ ContentObserver contentObserver) {
+// mManager.registerContentObserver(namespace, notifyForescendants, contentObserver);
+ }
+//
+// @Override
+ public void unregisterContentObserver(@NonNull ContentObserver contentObserver) {
+// mManager.unregisterContentObserver(contentObserver);
+ }
+}
diff --git a/framework/java/android/provider/SettingsConfigDataStore.java b/framework/java/android/provider/SettingsConfigDataStore.java
new file mode 100644
index 0000000..33a880d
--- /dev/null
+++ b/framework/java/android/provider/SettingsConfigDataStore.java
@@ -0,0 +1,105 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.provider;
+
+import android.content.ContentResolver;
+import android.content.pm.PackageManager;
+import android.database.ContentObserver;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+
+import java.util.Arrays;
+import java.util.ArrayList;
+import java.util.concurrent.Executor;
+import java.util.HashMap;
+import java.util.Map;
+
+
+/**
+ * TODO: want to change the package of this class
+ *
+ * @hide
+ */
+public class SettingsConfigDataStore implements DeviceConfigDataStore {
+ @Override
+ public @NonNull Map<String, String> getAllProperties() {
+ return Settings.Config.getAllStrings();
+ }
+
+ @Override
+ public @NonNull DeviceConfig.Properties getProperties(@NonNull String namespace,
+ @NonNull String... names) {
+ return new DeviceConfig.Properties(namespace,
+ Settings.Config.getStrings(namespace, Arrays.asList(names)));
+ }
+
+ @Override
+ public boolean setProperties(@NonNull DeviceConfig.Properties properties)
+ throws DeviceConfig.BadConfigException {
+ return Settings.Config.setStrings(properties.getNamespace(),
+ properties.getPropertyValues());
+ }
+
+ @Override
+ public boolean setProperty(@NonNull String namespace, @NonNull String name,
+ @Nullable String value, boolean makeDefault) {
+ return Settings.Config.putString(namespace, name, value, makeDefault);
+ }
+
+ @Override
+ public boolean deleteProperty(@NonNull String namespace, @NonNull String name) {
+ return Settings.Config.deleteString(namespace, name);
+ }
+
+ @Override
+ public void resetToDefaults(int resetMode, @Nullable String namespace) {
+ Settings.Config.resetToDefaults(resetMode, namespace);
+ }
+
+ @Override
+ public void setSyncDisabledMode(int syncDisabledMode) {
+ Settings.Config.setSyncDisabledMode(syncDisabledMode);
+ }
+
+ @Override
+ public int getSyncDisabledMode() {
+ return Settings.Config.getSyncDisabledMode();
+ }
+
+ @Override
+ public void setMonitorCallback(@NonNull ContentResolver resolver, @NonNull Executor executor,
+ @NonNull DeviceConfig.MonitorCallback callback) {
+ Settings.Config.setMonitorCallback(resolver, executor, callback);
+ }
+
+ @Override
+ public void clearMonitorCallback(@NonNull ContentResolver resolver) {
+ Settings.Config.clearMonitorCallback(resolver);
+ }
+
+ @Override
+ public void registerContentObserver(@NonNull String namespace, boolean notifyForescendants,
+ ContentObserver contentObserver) {
+ Settings.Config.registerContentObserver(namespace, true, contentObserver);
+ }
+
+ @Override
+ public void unregisterContentObserver(@NonNull ContentObserver contentObserver) {
+ Settings.Config.unregisterContentObserver(contentObserver);
+ }
+}
diff --git a/framework/java/android/provider/WritableFlags.java b/framework/java/android/provider/WritableFlags.java
index b8c5b28..0219346 100644
--- a/framework/java/android/provider/WritableFlags.java
+++ b/framework/java/android/provider/WritableFlags.java
@@ -1460,10 +1460,8 @@ final class WritableFlags {
"privacy/camera_mic_icons_enabled",
"privacy/camera_toggle_enabled",
"privacy/data_sharing_update_period_millis",
- "privacy/location_access_check_enabled",
"privacy/location_access_check_delay_millis",
"privacy/location_access_check_periodic_interval_millis",
- "privacy/location_accuracy_enabled",
"privacy/location_indicators_enabled",
"privacy/location_indicators_show_system",
"privacy/location_indicators_small_enabled",
@@ -1475,7 +1473,6 @@ final class WritableFlags {
"privacy/param",
"privacy/param",
"privacy/permission_rationale_enabled",
- "privacy/permissions_hub_enabled",
"privacy/permissions_hub_subattribution_enabled",
"privacy/placeholder_safety_label_updates_enabled",
"privacy/privacy_attribution_tag_full_log_enabled",
@@ -1505,7 +1502,6 @@ final class WritableFlags {
"privacy/safety_label_changes_job_interval_millis",
"privacy/sc_accessibility_listener_enabled",
"privacy/sc_accessibility_source_enabled",
- "privacy/warning_banner_enabled",
"profcollect_native_boot/enable",
"remote_key_provisioning_native/enable_rkpd",
"rollback/containing",
@@ -1739,6 +1735,7 @@ final class WritableFlags {
"vpn/enable_pixel_ppn_feature",
"wallpaper_content/enabled",
"wearable_sensing/service_enabled_platforms",
+ "wearable_sensing/service_enabled",
"wear/ambient_auto_resume_timeout_max_reset_count",
"wear/bedtime_hard_mode_feature_enabled",
"wear/enable_backup_service_in_wear_framework",
diff --git a/framework/java/android/provider/aidl/IDeviceConfigManager.aidl b/framework/java/android/provider/aidl/IDeviceConfigManager.aidl
new file mode 100644
index 0000000..eef6e77
--- /dev/null
+++ b/framework/java/android/provider/aidl/IDeviceConfigManager.aidl
@@ -0,0 +1,18 @@
+package android.provider.aidl;
+
+/**
+ * {@hide}
+ */
+interface IDeviceConfigManager {
+// TODO(b/265948914): maybe rename this IDeviceConfigService ? ManagerService?
+
+ Map<String, String> getProperties(String namespace, in String[] names);
+
+ boolean setProperties(String namespace, in Map<String, String> values);
+
+ boolean setProperty(String namespace, String key, String value, boolean makeDefault);
+
+ boolean deleteProperty(String namespace, String key);
+
+ // TODO(b/265948914): add remaining methods
+}