Doze: Use Settings.Global.DEVICE_IDLE_CONSTANTS instead of hardcoded constants

This will allow gservices to tweak the settings and experiment
with different values for various doze constants.

The values are encoded in a string as a key=value list. Ex:

inactive_to=5000,idle_factor=0.01

Bug:21640379
Change-Id: Ie98a0e4893f9b46a64d961d6c5c5169b8b8ad742
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 167d8e5..f2d3e71 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -7087,6 +7087,36 @@
                 BLUETOOTH_SAP_PRIORITY_PREFIX = "bluetooth_sap_priority_";
 
         /**
+         * Device Idle (Doze) specific settings.
+         * This is encoded as a key=value list, separated by commas. Ex:
+         *
+         * "inactive_timeout=60000,sensing_timeout=400000"
+         *
+         * The following keys are supported:
+         *
+         * <pre>
+         * inactive_to                      (long)
+         * sensing_to                       (long)
+         * motion_inactive_to               (long)
+         * idle_after_inactive_to           (long)
+         * idle_pending_to                  (long)
+         * max_idle_pending_to              (long)
+         * idle_pending_factor              (float)
+         * idle_to                          (long)
+         * max_idle_to                      (long)
+         * idle_factor                      (float)
+         * min_time_to_alarm                (long)
+         * max_temp_app_whitelist_duration  (long)
+         * </pre>
+         *
+         * <p>
+         * Type: string
+         * @hide
+         * @see com.android.server.DeviceIdleController.Constants
+         */
+        public static final String DEVICE_IDLE_CONSTANTS = "device_idle_constants";
+
+        /**
          * Get the key that retrieves a bluetooth headset's priority.
          * @hide
          */
diff --git a/core/java/android/util/KeyValueListParser.java b/core/java/android/util/KeyValueListParser.java
new file mode 100644
index 0000000..4abdde0
--- /dev/null
+++ b/core/java/android/util/KeyValueListParser.java
@@ -0,0 +1,114 @@
+/*
+ * Copyright (C) 2015 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.util;
+
+import android.text.TextUtils;
+
+/**
+ * Parses a list of key=value pairs, separated by some delimiter, and puts the results in
+ * an internal Map. Values can be then queried by key, or if not found, a default value
+ * can be used.
+ * @hide
+ */
+public class KeyValueListParser {
+    private final ArrayMap<String, String> mValues = new ArrayMap<>();
+    private final TextUtils.StringSplitter mSplitter;
+
+    /**
+     * Constructs a new KeyValueListParser. This can be reused for different strings
+     * by calling {@link #setString(String)}.
+     * @param delim The delimiter that separates key=value pairs.
+     */
+    public KeyValueListParser(char delim) {
+        mSplitter = new TextUtils.SimpleStringSplitter(delim);
+    }
+
+    /**
+     * Resets the parser with a new string to parse. The string is expected to be in the following
+     * format:
+     * <pre>key1=value,key2=value,key3=value</pre>
+     *
+     * where the delimiter is a comma.
+     *
+     * @param str the string to parse.
+     * @throws IllegalArgumentException if the string is malformed.
+     */
+    public void setString(String str) throws IllegalArgumentException {
+        mValues.clear();
+        if (str != null) {
+            mSplitter.setString(str);
+            for (String pair : mSplitter) {
+                int sep = pair.indexOf('=');
+                if (sep < 0) {
+                    mValues.clear();
+                    throw new IllegalArgumentException(
+                            "'" + pair + "' in '" + str + "' is not a valid key-value pair");
+                }
+                mValues.put(pair.substring(0, sep).trim(), pair.substring(sep + 1).trim());
+            }
+        }
+    }
+
+    /**
+     * Get the value for key as a long.
+     * @param key The key to lookup.
+     * @param def The value to return if the key was not found, or the value was not a long.
+     * @return the long value associated with the key.
+     */
+    public long getLong(String key, long def) {
+        String value = mValues.get(key);
+        if (value != null) {
+            try {
+                return Long.parseLong(value);
+            } catch (NumberFormatException e) {
+                // fallthrough
+            }
+        }
+        return def;
+    }
+
+    /**
+     * Get the value for key as a float.
+     * @param key The key to lookup.
+     * @param def The value to return if the key was not found, or the value was not a float.
+     * @return the float value associated with the key.
+     */
+    public float getFloat(String key, float def) {
+        String value = mValues.get(key);
+        if (value != null) {
+            try {
+                return Float.parseFloat(value);
+            } catch (NumberFormatException e) {
+                // fallthrough
+            }
+        }
+        return def;
+    }
+
+    /**
+     * Get the value for key as a string.
+     * @param key The key to lookup.
+     * @param def The value to return if the key was not found.
+     * @return the string value associated with the key.
+     */
+    public String getString(String key, String def) {
+        String value = mValues.get(key);
+        if (value != null) {
+            return value;
+        }
+        return def;
+    }
+}