Loading api/system-current.txt +7 −2 Original line number Diff line number Diff line Loading @@ -5845,6 +5845,7 @@ package android.provider { } public final class DeviceConfig { method @RequiresPermission(android.Manifest.permission.READ_DEVICE_CONFIG) public static void addOnPropertiesChangedListener(@NonNull String, @NonNull java.util.concurrent.Executor, @NonNull android.provider.DeviceConfig.OnPropertiesChangedListener); method @RequiresPermission(android.Manifest.permission.READ_DEVICE_CONFIG) public static void addOnPropertyChangedListener(@NonNull String, @NonNull java.util.concurrent.Executor, @NonNull android.provider.DeviceConfig.OnPropertyChangedListener); method @RequiresPermission(android.Manifest.permission.READ_DEVICE_CONFIG) public static boolean getBoolean(String, String, boolean); method @RequiresPermission(android.Manifest.permission.READ_DEVICE_CONFIG) public static float getFloat(String, String, float); Loading @@ -5852,7 +5853,8 @@ package android.provider { method @RequiresPermission(android.Manifest.permission.READ_DEVICE_CONFIG) public static long getLong(String, String, long); method @RequiresPermission(android.Manifest.permission.READ_DEVICE_CONFIG) public static String getProperty(String, String); method @RequiresPermission(android.Manifest.permission.READ_DEVICE_CONFIG) public static String getString(String, String, String); method public static void removeOnPropertyChangedListener(android.provider.DeviceConfig.OnPropertyChangedListener); method public static void removeOnPropertiesChangedListener(@NonNull android.provider.DeviceConfig.OnPropertiesChangedListener); method public static void removeOnPropertyChangedListener(@NonNull android.provider.DeviceConfig.OnPropertyChangedListener); method @RequiresPermission(android.Manifest.permission.WRITE_DEVICE_CONFIG) public static void resetToDefaults(int, @Nullable String); method @RequiresPermission(android.Manifest.permission.WRITE_DEVICE_CONFIG) public static boolean setProperty(String, String, String, boolean); field public static final String NAMESPACE_ACTIVITY_MANAGER = "activity_manager"; Loading Loading @@ -5887,8 +5889,11 @@ package android.provider { field public static final String NAMESPACE = "intelligence_attention"; } public static interface DeviceConfig.OnPropertiesChangedListener { method public void onPropertiesChanged(@NonNull android.provider.DeviceConfig.Properties); } public static interface DeviceConfig.OnPropertyChangedListener { method public default void onPropertiesChanged(@NonNull android.provider.DeviceConfig.Properties); method public void onPropertyChanged(String, String, String); } Loading api/test-current.txt +7 −2 Original line number Diff line number Diff line Loading @@ -2002,6 +2002,7 @@ package android.provider { } public final class DeviceConfig { method @RequiresPermission("android.permission.READ_DEVICE_CONFIG") public static void addOnPropertiesChangedListener(@NonNull String, @NonNull java.util.concurrent.Executor, @NonNull android.provider.DeviceConfig.OnPropertiesChangedListener); method @RequiresPermission("android.permission.READ_DEVICE_CONFIG") public static void addOnPropertyChangedListener(@NonNull String, @NonNull java.util.concurrent.Executor, @NonNull android.provider.DeviceConfig.OnPropertyChangedListener); method @RequiresPermission("android.permission.READ_DEVICE_CONFIG") public static boolean getBoolean(String, String, boolean); method @RequiresPermission("android.permission.READ_DEVICE_CONFIG") public static float getFloat(String, String, float); Loading @@ -2009,15 +2010,19 @@ package android.provider { method @RequiresPermission("android.permission.READ_DEVICE_CONFIG") public static long getLong(String, String, long); method @RequiresPermission("android.permission.READ_DEVICE_CONFIG") public static String getProperty(String, String); method @RequiresPermission("android.permission.READ_DEVICE_CONFIG") public static String getString(String, String, String); method public static void removeOnPropertyChangedListener(android.provider.DeviceConfig.OnPropertyChangedListener); method public static void removeOnPropertiesChangedListener(@NonNull android.provider.DeviceConfig.OnPropertiesChangedListener); method public static void removeOnPropertyChangedListener(@NonNull android.provider.DeviceConfig.OnPropertyChangedListener); method @RequiresPermission("android.permission.WRITE_DEVICE_CONFIG") public static void resetToDefaults(int, @Nullable String); method @RequiresPermission("android.permission.WRITE_DEVICE_CONFIG") public static boolean setProperty(String, String, String, boolean); field public static final String NAMESPACE_AUTOFILL = "autofill"; field public static final String NAMESPACE_CONTENT_CAPTURE = "content_capture"; } public static interface DeviceConfig.OnPropertiesChangedListener { method public void onPropertiesChanged(@NonNull android.provider.DeviceConfig.Properties); } public static interface DeviceConfig.OnPropertyChangedListener { method public default void onPropertiesChanged(@NonNull android.provider.DeviceConfig.Properties); method public void onPropertyChanged(String, String, String); } Loading core/java/android/provider/DeviceConfig.java +110 −27 Original line number Diff line number Diff line Loading @@ -30,6 +30,7 @@ import android.content.ContentResolver; import android.database.ContentObserver; import android.net.Uri; import android.provider.Settings.ResetMode; import android.util.ArrayMap; import android.util.Pair; import com.android.internal.annotations.GuardedBy; Loading Loading @@ -398,8 +399,11 @@ public final class DeviceConfig { private static final Object sLock = new Object(); @GuardedBy("sLock") private static Map<OnPropertyChangedListener, Pair<String, Executor>> sListeners = new HashMap<>(); private static ArrayMap<OnPropertyChangedListener, Pair<String, Executor>> sSingleListeners = new ArrayMap<>(); @GuardedBy("sLock") private static ArrayMap<OnPropertiesChangedListener, Pair<String, Executor>> sListeners = new ArrayMap<>(); @GuardedBy("sLock") private static Map<String, Pair<ContentObserver, Integer>> sNamespaces = new HashMap<>(); Loading Loading @@ -597,20 +601,58 @@ public final class DeviceConfig { @NonNull String namespace, @NonNull @CallbackExecutor Executor executor, @NonNull OnPropertyChangedListener onPropertyChangedListener) { // TODO enforce READ_DEVICE_CONFIG permission synchronized (sLock) { Pair<String, Executor> oldNamespace = sListeners.get(onPropertyChangedListener); Pair<String, Executor> oldNamespace = sSingleListeners.get(onPropertyChangedListener); if (oldNamespace == null) { // Brand new listener, add it to the list. sListeners.put(onPropertyChangedListener, new Pair<>(namespace, executor)); sSingleListeners.put(onPropertyChangedListener, new Pair<>(namespace, executor)); incrementNamespace(namespace); } else if (namespace.equals(oldNamespace.first)) { // Listener is already registered for this namespace, update executor just in case. sListeners.put(onPropertyChangedListener, new Pair<>(namespace, executor)); sSingleListeners.put(onPropertyChangedListener, new Pair<>(namespace, executor)); } else { // Update this listener from an old namespace to the new one. decrementNamespace(sListeners.get(onPropertyChangedListener).first); sListeners.put(onPropertyChangedListener, new Pair<>(namespace, executor)); decrementNamespace(sSingleListeners.get(onPropertyChangedListener).first); sSingleListeners.put(onPropertyChangedListener, new Pair<>(namespace, executor)); incrementNamespace(namespace); } } } /** * Add a listener for property changes. * <p> * This listener will be called whenever properties in the specified namespace change. Callbacks * will be made on the specified executor. Future calls to this method with the same listener * will replace the old namespace and executor. Remove the listener entirely by calling * {@link #removeOnPropertiesChangedListener(OnPropertiesChangedListener)}. * * @param namespace The namespace containing properties to monitor. * @param executor The executor which will be used to run callbacks. * @param onPropertiesChangedListener The listener to add. * @hide * @see #removeOnPropertiesChangedListener(OnPropertiesChangedListener) */ @SystemApi @TestApi @RequiresPermission(READ_DEVICE_CONFIG) public static void addOnPropertiesChangedListener( @NonNull String namespace, @NonNull @CallbackExecutor Executor executor, @NonNull OnPropertiesChangedListener onPropertiesChangedListener) { synchronized (sLock) { Pair<String, Executor> oldNamespace = sListeners.get(onPropertiesChangedListener); if (oldNamespace == null) { // Brand new listener, add it to the list. sListeners.put(onPropertiesChangedListener, new Pair<>(namespace, executor)); incrementNamespace(namespace); } else if (namespace.equals(oldNamespace.first)) { // Listener is already registered for this namespace, update executor just in case. sListeners.put(onPropertiesChangedListener, new Pair<>(namespace, executor)); } else { // Update this listener from an old namespace to the new one. decrementNamespace(sListeners.get(onPropertiesChangedListener).first); sListeners.put(onPropertiesChangedListener, new Pair<>(namespace, executor)); incrementNamespace(namespace); } } Loading @@ -627,11 +669,33 @@ public final class DeviceConfig { @SystemApi @TestApi public static void removeOnPropertyChangedListener( OnPropertyChangedListener onPropertyChangedListener) { @NonNull OnPropertyChangedListener onPropertyChangedListener) { Preconditions.checkNotNull(onPropertyChangedListener); synchronized (sLock) { if (sListeners.containsKey(onPropertyChangedListener)) { decrementNamespace(sListeners.get(onPropertyChangedListener).first); sListeners.remove(onPropertyChangedListener); if (sSingleListeners.containsKey(onPropertyChangedListener)) { decrementNamespace(sSingleListeners.get(onPropertyChangedListener).first); sSingleListeners.remove(onPropertyChangedListener); } } } /** * Remove a listener for property changes. The listener will receive no further notification of * property changes. * * @param onPropertiesChangedListener The listener to remove. * @hide * @see #addOnPropertiesChangedListener(String, Executor, OnPropertiesChangedListener) */ @SystemApi @TestApi public static void removeOnPropertiesChangedListener( @NonNull OnPropertiesChangedListener onPropertiesChangedListener) { Preconditions.checkNotNull(onPropertiesChangedListener); synchronized (sLock) { if (sListeners.containsKey(onPropertiesChangedListener)) { decrementNamespace(sListeners.get(onPropertiesChangedListener).first); sListeners.remove(onPropertiesChangedListener); } } } Loading Loading @@ -700,14 +764,30 @@ public final class DeviceConfig { final String name = pathSegments.get(2); final String value = getProperty(namespace, name); synchronized (sLock) { for (final OnPropertyChangedListener listener : sListeners.keySet()) { if (namespace.equals(sListeners.get(listener).first)) { sListeners.get(listener).second.execute(new Runnable() { // OnPropertiesChangedListeners for (int i = 0; i < sListeners.size(); i++) { if (namespace.equals(sListeners.valueAt(i).first)) { final int j = i; sListeners.valueAt(i).second.execute(new Runnable() { @Override public void run() { Map<String, String> propertyMap = new HashMap(1); propertyMap.put(name, value); listener.onPropertiesChanged(new Properties(namespace, propertyMap)); sListeners.keyAt(j) .onPropertiesChanged(new Properties(namespace, propertyMap)); } }); } } // OnPropertyChangedListeners for (int i = 0; i < sSingleListeners.size(); i++) { if (namespace.equals(sSingleListeners.valueAt(i).first)) { final int j = i; sSingleListeners.valueAt(i).second.execute(new Runnable() { @Override public void run() { sSingleListeners.keyAt(j).onPropertyChanged(namespace, name, value); } }); Loading @@ -717,7 +797,7 @@ public final class DeviceConfig { } /** * Interface for monitoring to properties. * Interface for monitoring single property changes. * <p> * Override {@link #onPropertyChanged(String, String, String)} to handle callbacks for changes. * Loading @@ -734,22 +814,25 @@ public final class DeviceConfig { * @param value The new value of the property which has changed. */ void onPropertyChanged(String namespace, String name, String value); } /** * Interface for monitoring changes to properties. * <p> * Override {@link #onPropertiesChanged(Properties)} to handle callbacks for changes. * * @hide */ @SystemApi @TestApi public interface OnPropertiesChangedListener { /** * Called when one or more properties have changed. * * @param properties Contains the complete collection of properties which have changed for a * single namespace. */ default void onPropertiesChanged(@NonNull Properties properties) { // During the transitional period, this method calls the old one to ensure legacy // callers continue to function as expected. Ignore this if you are implementing it for // yourself. String namespace = properties.getNamespace(); for (String name : properties.getKeyset()) { onPropertyChanged(namespace, name, properties.getString(name, null)); } } void onPropertiesChanged(@NonNull Properties properties); } /** Loading core/tests/coretests/src/android/provider/DeviceConfigTest.java +20 −22 Original line number Diff line number Diff line Loading @@ -16,6 +16,7 @@ package android.provider; import static android.provider.DeviceConfig.OnPropertiesChangedListener; import static android.provider.DeviceConfig.OnPropertyChangedListener; import static com.google.common.truth.Truth.assertThat; Loading Loading @@ -224,29 +225,31 @@ public class DeviceConfigTest { } @Test public void testListener_propertiesCallback() throws InterruptedException { public void testOnPropertiesChangedListener() throws InterruptedException { final CountDownLatch countDownLatch = new CountDownLatch(1); OnPropertyChangedListener changeListener = new OnPropertyChangedListener() { public void onPropertyChanged(String namespace, String name, String value) { // ignore legacy callback } @Override public void onPropertiesChanged(DeviceConfig.Properties properties) { OnPropertiesChangedListener changeListener = (properties) -> { assertThat(properties.getNamespace()).isEqualTo(sNamespace); assertThat(properties.getKeyset().size()).isEqualTo(1); assertThat(properties.getKeyset()).contains(sKey); assertThat(properties.getString(sKey, "default_value")).isEqualTo(sValue); countDownLatch.countDown(); } }; testListener(countDownLatch, changeListener); try { DeviceConfig.addOnPropertiesChangedListener(sNamespace, ActivityThread.currentApplication().getMainExecutor(), changeListener); DeviceConfig.setProperty(sNamespace, sKey, sValue, false); assertThat(countDownLatch.await( WAIT_FOR_PROPERTY_CHANGE_TIMEOUT_MILLIS, TimeUnit.MILLISECONDS)).isTrue(); } catch (InterruptedException e) { Assert.fail(e.getMessage()); } finally { DeviceConfig.removeOnPropertiesChangedListener(changeListener); } } @Test public void testListener_legacyCallback() throws InterruptedException { public void testOnPropertyChangedListener() throws InterruptedException { CountDownLatch countDownLatch = new CountDownLatch(1); OnPropertyChangedListener changeListener = (namespace, name, value) -> { Loading @@ -256,12 +259,6 @@ public class DeviceConfigTest { countDownLatch.countDown(); }; testListener(countDownLatch, changeListener); } private void testListener(CountDownLatch countDownLatch, OnPropertyChangedListener changeListener) { try { DeviceConfig.addOnPropertyChangedListener(sNamespace, ActivityThread.currentApplication().getMainExecutor(), changeListener); Loading @@ -273,6 +270,7 @@ public class DeviceConfigTest { } finally { DeviceConfig.removeOnPropertyChangedListener(changeListener); } } private static boolean deleteViaContentProvider(String namespace, String key) { Loading Loading
api/system-current.txt +7 −2 Original line number Diff line number Diff line Loading @@ -5845,6 +5845,7 @@ package android.provider { } public final class DeviceConfig { method @RequiresPermission(android.Manifest.permission.READ_DEVICE_CONFIG) public static void addOnPropertiesChangedListener(@NonNull String, @NonNull java.util.concurrent.Executor, @NonNull android.provider.DeviceConfig.OnPropertiesChangedListener); method @RequiresPermission(android.Manifest.permission.READ_DEVICE_CONFIG) public static void addOnPropertyChangedListener(@NonNull String, @NonNull java.util.concurrent.Executor, @NonNull android.provider.DeviceConfig.OnPropertyChangedListener); method @RequiresPermission(android.Manifest.permission.READ_DEVICE_CONFIG) public static boolean getBoolean(String, String, boolean); method @RequiresPermission(android.Manifest.permission.READ_DEVICE_CONFIG) public static float getFloat(String, String, float); Loading @@ -5852,7 +5853,8 @@ package android.provider { method @RequiresPermission(android.Manifest.permission.READ_DEVICE_CONFIG) public static long getLong(String, String, long); method @RequiresPermission(android.Manifest.permission.READ_DEVICE_CONFIG) public static String getProperty(String, String); method @RequiresPermission(android.Manifest.permission.READ_DEVICE_CONFIG) public static String getString(String, String, String); method public static void removeOnPropertyChangedListener(android.provider.DeviceConfig.OnPropertyChangedListener); method public static void removeOnPropertiesChangedListener(@NonNull android.provider.DeviceConfig.OnPropertiesChangedListener); method public static void removeOnPropertyChangedListener(@NonNull android.provider.DeviceConfig.OnPropertyChangedListener); method @RequiresPermission(android.Manifest.permission.WRITE_DEVICE_CONFIG) public static void resetToDefaults(int, @Nullable String); method @RequiresPermission(android.Manifest.permission.WRITE_DEVICE_CONFIG) public static boolean setProperty(String, String, String, boolean); field public static final String NAMESPACE_ACTIVITY_MANAGER = "activity_manager"; Loading Loading @@ -5887,8 +5889,11 @@ package android.provider { field public static final String NAMESPACE = "intelligence_attention"; } public static interface DeviceConfig.OnPropertiesChangedListener { method public void onPropertiesChanged(@NonNull android.provider.DeviceConfig.Properties); } public static interface DeviceConfig.OnPropertyChangedListener { method public default void onPropertiesChanged(@NonNull android.provider.DeviceConfig.Properties); method public void onPropertyChanged(String, String, String); } Loading
api/test-current.txt +7 −2 Original line number Diff line number Diff line Loading @@ -2002,6 +2002,7 @@ package android.provider { } public final class DeviceConfig { method @RequiresPermission("android.permission.READ_DEVICE_CONFIG") public static void addOnPropertiesChangedListener(@NonNull String, @NonNull java.util.concurrent.Executor, @NonNull android.provider.DeviceConfig.OnPropertiesChangedListener); method @RequiresPermission("android.permission.READ_DEVICE_CONFIG") public static void addOnPropertyChangedListener(@NonNull String, @NonNull java.util.concurrent.Executor, @NonNull android.provider.DeviceConfig.OnPropertyChangedListener); method @RequiresPermission("android.permission.READ_DEVICE_CONFIG") public static boolean getBoolean(String, String, boolean); method @RequiresPermission("android.permission.READ_DEVICE_CONFIG") public static float getFloat(String, String, float); Loading @@ -2009,15 +2010,19 @@ package android.provider { method @RequiresPermission("android.permission.READ_DEVICE_CONFIG") public static long getLong(String, String, long); method @RequiresPermission("android.permission.READ_DEVICE_CONFIG") public static String getProperty(String, String); method @RequiresPermission("android.permission.READ_DEVICE_CONFIG") public static String getString(String, String, String); method public static void removeOnPropertyChangedListener(android.provider.DeviceConfig.OnPropertyChangedListener); method public static void removeOnPropertiesChangedListener(@NonNull android.provider.DeviceConfig.OnPropertiesChangedListener); method public static void removeOnPropertyChangedListener(@NonNull android.provider.DeviceConfig.OnPropertyChangedListener); method @RequiresPermission("android.permission.WRITE_DEVICE_CONFIG") public static void resetToDefaults(int, @Nullable String); method @RequiresPermission("android.permission.WRITE_DEVICE_CONFIG") public static boolean setProperty(String, String, String, boolean); field public static final String NAMESPACE_AUTOFILL = "autofill"; field public static final String NAMESPACE_CONTENT_CAPTURE = "content_capture"; } public static interface DeviceConfig.OnPropertiesChangedListener { method public void onPropertiesChanged(@NonNull android.provider.DeviceConfig.Properties); } public static interface DeviceConfig.OnPropertyChangedListener { method public default void onPropertiesChanged(@NonNull android.provider.DeviceConfig.Properties); method public void onPropertyChanged(String, String, String); } Loading
core/java/android/provider/DeviceConfig.java +110 −27 Original line number Diff line number Diff line Loading @@ -30,6 +30,7 @@ import android.content.ContentResolver; import android.database.ContentObserver; import android.net.Uri; import android.provider.Settings.ResetMode; import android.util.ArrayMap; import android.util.Pair; import com.android.internal.annotations.GuardedBy; Loading Loading @@ -398,8 +399,11 @@ public final class DeviceConfig { private static final Object sLock = new Object(); @GuardedBy("sLock") private static Map<OnPropertyChangedListener, Pair<String, Executor>> sListeners = new HashMap<>(); private static ArrayMap<OnPropertyChangedListener, Pair<String, Executor>> sSingleListeners = new ArrayMap<>(); @GuardedBy("sLock") private static ArrayMap<OnPropertiesChangedListener, Pair<String, Executor>> sListeners = new ArrayMap<>(); @GuardedBy("sLock") private static Map<String, Pair<ContentObserver, Integer>> sNamespaces = new HashMap<>(); Loading Loading @@ -597,20 +601,58 @@ public final class DeviceConfig { @NonNull String namespace, @NonNull @CallbackExecutor Executor executor, @NonNull OnPropertyChangedListener onPropertyChangedListener) { // TODO enforce READ_DEVICE_CONFIG permission synchronized (sLock) { Pair<String, Executor> oldNamespace = sListeners.get(onPropertyChangedListener); Pair<String, Executor> oldNamespace = sSingleListeners.get(onPropertyChangedListener); if (oldNamespace == null) { // Brand new listener, add it to the list. sListeners.put(onPropertyChangedListener, new Pair<>(namespace, executor)); sSingleListeners.put(onPropertyChangedListener, new Pair<>(namespace, executor)); incrementNamespace(namespace); } else if (namespace.equals(oldNamespace.first)) { // Listener is already registered for this namespace, update executor just in case. sListeners.put(onPropertyChangedListener, new Pair<>(namespace, executor)); sSingleListeners.put(onPropertyChangedListener, new Pair<>(namespace, executor)); } else { // Update this listener from an old namespace to the new one. decrementNamespace(sListeners.get(onPropertyChangedListener).first); sListeners.put(onPropertyChangedListener, new Pair<>(namespace, executor)); decrementNamespace(sSingleListeners.get(onPropertyChangedListener).first); sSingleListeners.put(onPropertyChangedListener, new Pair<>(namespace, executor)); incrementNamespace(namespace); } } } /** * Add a listener for property changes. * <p> * This listener will be called whenever properties in the specified namespace change. Callbacks * will be made on the specified executor. Future calls to this method with the same listener * will replace the old namespace and executor. Remove the listener entirely by calling * {@link #removeOnPropertiesChangedListener(OnPropertiesChangedListener)}. * * @param namespace The namespace containing properties to monitor. * @param executor The executor which will be used to run callbacks. * @param onPropertiesChangedListener The listener to add. * @hide * @see #removeOnPropertiesChangedListener(OnPropertiesChangedListener) */ @SystemApi @TestApi @RequiresPermission(READ_DEVICE_CONFIG) public static void addOnPropertiesChangedListener( @NonNull String namespace, @NonNull @CallbackExecutor Executor executor, @NonNull OnPropertiesChangedListener onPropertiesChangedListener) { synchronized (sLock) { Pair<String, Executor> oldNamespace = sListeners.get(onPropertiesChangedListener); if (oldNamespace == null) { // Brand new listener, add it to the list. sListeners.put(onPropertiesChangedListener, new Pair<>(namespace, executor)); incrementNamespace(namespace); } else if (namespace.equals(oldNamespace.first)) { // Listener is already registered for this namespace, update executor just in case. sListeners.put(onPropertiesChangedListener, new Pair<>(namespace, executor)); } else { // Update this listener from an old namespace to the new one. decrementNamespace(sListeners.get(onPropertiesChangedListener).first); sListeners.put(onPropertiesChangedListener, new Pair<>(namespace, executor)); incrementNamespace(namespace); } } Loading @@ -627,11 +669,33 @@ public final class DeviceConfig { @SystemApi @TestApi public static void removeOnPropertyChangedListener( OnPropertyChangedListener onPropertyChangedListener) { @NonNull OnPropertyChangedListener onPropertyChangedListener) { Preconditions.checkNotNull(onPropertyChangedListener); synchronized (sLock) { if (sListeners.containsKey(onPropertyChangedListener)) { decrementNamespace(sListeners.get(onPropertyChangedListener).first); sListeners.remove(onPropertyChangedListener); if (sSingleListeners.containsKey(onPropertyChangedListener)) { decrementNamespace(sSingleListeners.get(onPropertyChangedListener).first); sSingleListeners.remove(onPropertyChangedListener); } } } /** * Remove a listener for property changes. The listener will receive no further notification of * property changes. * * @param onPropertiesChangedListener The listener to remove. * @hide * @see #addOnPropertiesChangedListener(String, Executor, OnPropertiesChangedListener) */ @SystemApi @TestApi public static void removeOnPropertiesChangedListener( @NonNull OnPropertiesChangedListener onPropertiesChangedListener) { Preconditions.checkNotNull(onPropertiesChangedListener); synchronized (sLock) { if (sListeners.containsKey(onPropertiesChangedListener)) { decrementNamespace(sListeners.get(onPropertiesChangedListener).first); sListeners.remove(onPropertiesChangedListener); } } } Loading Loading @@ -700,14 +764,30 @@ public final class DeviceConfig { final String name = pathSegments.get(2); final String value = getProperty(namespace, name); synchronized (sLock) { for (final OnPropertyChangedListener listener : sListeners.keySet()) { if (namespace.equals(sListeners.get(listener).first)) { sListeners.get(listener).second.execute(new Runnable() { // OnPropertiesChangedListeners for (int i = 0; i < sListeners.size(); i++) { if (namespace.equals(sListeners.valueAt(i).first)) { final int j = i; sListeners.valueAt(i).second.execute(new Runnable() { @Override public void run() { Map<String, String> propertyMap = new HashMap(1); propertyMap.put(name, value); listener.onPropertiesChanged(new Properties(namespace, propertyMap)); sListeners.keyAt(j) .onPropertiesChanged(new Properties(namespace, propertyMap)); } }); } } // OnPropertyChangedListeners for (int i = 0; i < sSingleListeners.size(); i++) { if (namespace.equals(sSingleListeners.valueAt(i).first)) { final int j = i; sSingleListeners.valueAt(i).second.execute(new Runnable() { @Override public void run() { sSingleListeners.keyAt(j).onPropertyChanged(namespace, name, value); } }); Loading @@ -717,7 +797,7 @@ public final class DeviceConfig { } /** * Interface for monitoring to properties. * Interface for monitoring single property changes. * <p> * Override {@link #onPropertyChanged(String, String, String)} to handle callbacks for changes. * Loading @@ -734,22 +814,25 @@ public final class DeviceConfig { * @param value The new value of the property which has changed. */ void onPropertyChanged(String namespace, String name, String value); } /** * Interface for monitoring changes to properties. * <p> * Override {@link #onPropertiesChanged(Properties)} to handle callbacks for changes. * * @hide */ @SystemApi @TestApi public interface OnPropertiesChangedListener { /** * Called when one or more properties have changed. * * @param properties Contains the complete collection of properties which have changed for a * single namespace. */ default void onPropertiesChanged(@NonNull Properties properties) { // During the transitional period, this method calls the old one to ensure legacy // callers continue to function as expected. Ignore this if you are implementing it for // yourself. String namespace = properties.getNamespace(); for (String name : properties.getKeyset()) { onPropertyChanged(namespace, name, properties.getString(name, null)); } } void onPropertiesChanged(@NonNull Properties properties); } /** Loading
core/tests/coretests/src/android/provider/DeviceConfigTest.java +20 −22 Original line number Diff line number Diff line Loading @@ -16,6 +16,7 @@ package android.provider; import static android.provider.DeviceConfig.OnPropertiesChangedListener; import static android.provider.DeviceConfig.OnPropertyChangedListener; import static com.google.common.truth.Truth.assertThat; Loading Loading @@ -224,29 +225,31 @@ public class DeviceConfigTest { } @Test public void testListener_propertiesCallback() throws InterruptedException { public void testOnPropertiesChangedListener() throws InterruptedException { final CountDownLatch countDownLatch = new CountDownLatch(1); OnPropertyChangedListener changeListener = new OnPropertyChangedListener() { public void onPropertyChanged(String namespace, String name, String value) { // ignore legacy callback } @Override public void onPropertiesChanged(DeviceConfig.Properties properties) { OnPropertiesChangedListener changeListener = (properties) -> { assertThat(properties.getNamespace()).isEqualTo(sNamespace); assertThat(properties.getKeyset().size()).isEqualTo(1); assertThat(properties.getKeyset()).contains(sKey); assertThat(properties.getString(sKey, "default_value")).isEqualTo(sValue); countDownLatch.countDown(); } }; testListener(countDownLatch, changeListener); try { DeviceConfig.addOnPropertiesChangedListener(sNamespace, ActivityThread.currentApplication().getMainExecutor(), changeListener); DeviceConfig.setProperty(sNamespace, sKey, sValue, false); assertThat(countDownLatch.await( WAIT_FOR_PROPERTY_CHANGE_TIMEOUT_MILLIS, TimeUnit.MILLISECONDS)).isTrue(); } catch (InterruptedException e) { Assert.fail(e.getMessage()); } finally { DeviceConfig.removeOnPropertiesChangedListener(changeListener); } } @Test public void testListener_legacyCallback() throws InterruptedException { public void testOnPropertyChangedListener() throws InterruptedException { CountDownLatch countDownLatch = new CountDownLatch(1); OnPropertyChangedListener changeListener = (namespace, name, value) -> { Loading @@ -256,12 +259,6 @@ public class DeviceConfigTest { countDownLatch.countDown(); }; testListener(countDownLatch, changeListener); } private void testListener(CountDownLatch countDownLatch, OnPropertyChangedListener changeListener) { try { DeviceConfig.addOnPropertyChangedListener(sNamespace, ActivityThread.currentApplication().getMainExecutor(), changeListener); Loading @@ -273,6 +270,7 @@ public class DeviceConfigTest { } finally { DeviceConfig.removeOnPropertyChangedListener(changeListener); } } private static boolean deleteViaContentProvider(String namespace, String key) { Loading