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

Commit d926ae08 authored by Matt Pape's avatar Matt Pape Committed by Android (Google) Code Review
Browse files

Merge "Add DeviceConfig.Properties and return it from change listener."

parents 0304cf83 1013d298
Loading
Loading
Loading
Loading
+11 −0
Original line number Diff line number Diff line
@@ -5881,6 +5881,7 @@ package android.provider {
  }
  public static interface DeviceConfig.OnPropertyChangedListener {
    method public default void onPropertiesChanged(@NonNull android.provider.DeviceConfig.Properties);
    method public void onPropertyChanged(String, String, String);
  }
@@ -5890,6 +5891,16 @@ package android.provider {
    field public static final String PROPERTY_PERMISSIONS_HUB_ENABLED = "permissions_hub_enabled";
  }
  public static class DeviceConfig.Properties {
    method public boolean getBoolean(@NonNull String, boolean);
    method public float getFloat(@NonNull String, float);
    method public int getInt(@NonNull String, int);
    method @NonNull public java.util.Set<java.lang.String> getKeyset();
    method public long getLong(@NonNull String, long);
    method @NonNull public String getNamespace();
    method @Nullable public String getString(@NonNull String, @Nullable String);
  }
  public static interface DeviceConfig.Rollback {
    field public static final String BOOT_NAMESPACE = "rollback_boot";
    field public static final String ENABLE_ROLLBACK_TIMEOUT = "enable_rollback_timeout";
+11 −0
Original line number Diff line number Diff line
@@ -1992,6 +1992,7 @@ package android.provider {
  }

  public static interface DeviceConfig.OnPropertyChangedListener {
    method public default void onPropertiesChanged(@NonNull android.provider.DeviceConfig.Properties);
    method public void onPropertyChanged(String, String, String);
  }

@@ -2000,6 +2001,16 @@ package android.provider {
    field public static final String PROPERTY_LOCATION_ACCESS_CHECK_ENABLED = "location_access_check_enabled";
  }

  public static class DeviceConfig.Properties {
    method public boolean getBoolean(@NonNull String, boolean);
    method public float getFloat(@NonNull String, float);
    method public int getInt(@NonNull String, int);
    method @NonNull public java.util.Set<java.lang.String> getKeyset();
    method public long getLong(@NonNull String, long);
    method @NonNull public String getNamespace();
    method @Nullable public String getString(@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;
+151 −5
Original line number Diff line number Diff line
@@ -33,10 +33,12 @@ import android.provider.Settings.ResetMode;
import android.util.Pair;

import com.android.internal.annotations.GuardedBy;
import com.android.internal.util.Preconditions;

import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.Executor;

/**
@@ -664,16 +666,18 @@ public final class DeviceConfig {
    private static void handleChange(Uri uri) {
        List<String> pathSegments = uri.getPathSegments();
        // pathSegments(0) is "config"
        String namespace = pathSegments.get(1);
        String name = pathSegments.get(2);
        String value = getProperty(namespace, name);
        final String namespace = pathSegments.get(1);
        final String name = pathSegments.get(2);
        final String value = getProperty(namespace, name);
        synchronized (sLock) {
            for (OnPropertyChangedListener listener : sListeners.keySet()) {
            for (final OnPropertyChangedListener listener : sListeners.keySet()) {
                if (namespace.equals(sListeners.get(listener).first)) {
                    sListeners.get(listener).second.execute(new Runnable() {
                        @Override
                        public void run() {
                            listener.onPropertyChanged(namespace, name, value);
                            Map<String, String> propertyMap = new HashMap(1);
                            propertyMap.put(name, value);
                            listener.onPropertiesChanged(new Properties(namespace, propertyMap));
                        }

                    });
@@ -700,5 +704,147 @@ public final class DeviceConfig {
         * @param value     The new value of the property which has changed.
         */
        void onPropertyChanged(String namespace, String name, String value);

        /**
         * 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));
            }
        }
    }

    /**
     * A mapping of properties to values, as well as a single namespace which they all belong to.
     *
     * @hide
     */
    @SystemApi
    @TestApi
    public static class Properties {
        private final String mNamespace;
        private final HashMap<String, String> mMap;

        /**
         * Create a mapping of properties to values and the namespace they belong to.
         *
         * @param namespace The namespace these properties belong to.
         * @param keyValueMap A map between property names and property values.
         */
        Properties(@NonNull String namespace, @Nullable Map<String, String> keyValueMap) {
            Preconditions.checkNotNull(namespace);
            mNamespace = namespace;
            mMap = new HashMap();
            if (keyValueMap != null) {
                mMap.putAll(keyValueMap);
            }
        }

        /**
         * @return the namespace all properties within this instance belong to.
         */
        @NonNull
        public String getNamespace() {
            return mNamespace;
        }

        /**
         * @return the non-null set of property names.
         */
        @NonNull
        public Set<String> getKeyset() {
            return mMap.keySet();
        }

        /**
         * Look up the String value of a property.
         *
         * @param name         The name of the property to look up.
         * @param defaultValue The value to return if the property has not been defined.
         * @return the corresponding value, or defaultValue if none exists.
         */
        @Nullable
        public String getString(@NonNull String name, @Nullable String defaultValue) {
            Preconditions.checkNotNull(name);
            String value = mMap.get(name);
            return value != null ? value : defaultValue;
        }

        /**
         * Look up the boolean value of a property.
         *
         * @param name         The name of the property to look up.
         * @param defaultValue The value to return if the property has not been defined.
         * @return the corresponding value, or defaultValue if none exists.
         */
        public boolean getBoolean(@NonNull String name, boolean defaultValue) {
            Preconditions.checkNotNull(name);
            String value = mMap.get(name);
            return value != null ? Boolean.parseBoolean(value) : defaultValue;
        }

        /**
         * Look up the int value of a property.
         *
         * @param name         The name of the property to look up.
         * @param defaultValue The value to return if the property has not been defined or fails to
         *                     parse into an int.
         * @return the corresponding value, or defaultValue if no valid int is available.
         */
        public int getInt(@NonNull String name, int defaultValue) {
            Preconditions.checkNotNull(name);
            String value = mMap.get(name);
            try {
                return Integer.parseInt(value);
            } catch (NumberFormatException e) {
                return defaultValue;
            }
        }

        /**
         * Look up the long value of a property.
         *
         * @param name         The name of the property to look up.
         * @param defaultValue The value to return if the property has not been defined. or fails to
         *                     parse into a long.
         * @return the corresponding value, or defaultValue if no valid long is available.
         */
        public long getLong(@NonNull String name, long defaultValue) {
            Preconditions.checkNotNull(name);
            String value = mMap.get(name);
            try {
                return Long.parseLong(value);
            } catch (NumberFormatException e) {
                return defaultValue;
            }
        }

        /**
         * Look up the int value of a property.
         *
         * @param name         The name of the property to look up.
         * @param defaultValue The value to return if the property has not been defined. or fails to
         *                     parse into a float.
         * @return the corresponding value, or defaultValue if no valid float is available.
         */
        public float getFloat(@NonNull String name, float defaultValue) {
            Preconditions.checkNotNull(name);
            String value = mMap.get(name);
            try {
                return Float.parseFloat(value);
            } catch (NumberFormatException e) {
                return defaultValue;
            } catch (NullPointerException e) {
                return defaultValue;
            }
        }
    }
}
+32 −2
Original line number Diff line number Diff line
@@ -30,6 +30,7 @@ import androidx.test.filters.SmallTest;
import androidx.test.runner.AndroidJUnit4;

import org.junit.After;
import org.junit.Assert;
import org.junit.Test;
import org.junit.runner.RunWith;

@@ -223,7 +224,29 @@ public class DeviceConfigTest {
    }

    @Test
    public void testListener() throws InterruptedException {
    public void testListener_propertiesCallback() 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) {
                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);
    }

    @Test
    public void testListener_legacyCallback() throws InterruptedException {
        CountDownLatch countDownLatch = new CountDownLatch(1);

        OnPropertyChangedListener changeListener = (namespace, name, value) -> {
@@ -233,16 +256,23 @@ public class DeviceConfigTest {
            countDownLatch.countDown();
        };

        testListener(countDownLatch, changeListener);

    }

    private void testListener(CountDownLatch countDownLatch,
            OnPropertyChangedListener changeListener) {
        try {
            DeviceConfig.addOnPropertyChangedListener(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.removeOnPropertyChangedListener(changeListener);
        }

    }

    private static boolean deleteViaContentProvider(String namespace, String key) {