Add put/getBoolean/Array to PersistableBundle

Due to popular demand the methods putBoolean(), getBoolean(),
putBooleanArray() and getBooleanArray() have been added to
PersistableBundle.

Fixes bug 18390436.

Change-Id: Id133ba902aca774f98529e36ce560e873b88ad5b
diff --git a/api/current.txt b/api/current.txt
index 53aa4a2..1383a2f 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -21318,6 +21318,9 @@
     method public void clear();
     method public boolean containsKey(java.lang.String);
     method public java.lang.Object get(java.lang.String);
+    method public boolean getBoolean(java.lang.String);
+    method public boolean getBoolean(java.lang.String, boolean);
+    method public boolean[] getBooleanArray(java.lang.String);
     method public double getDouble(java.lang.String);
     method public double getDouble(java.lang.String, double);
     method public double[] getDoubleArray(java.lang.String);
@@ -21333,6 +21336,8 @@
     method public boolean isEmpty();
     method public java.util.Set<java.lang.String> keySet();
     method public void putAll(android.os.PersistableBundle);
+    method public void putBoolean(java.lang.String, boolean);
+    method public void putBooleanArray(java.lang.String, boolean[]);
     method public void putDouble(java.lang.String, double);
     method public void putDoubleArray(java.lang.String, double[]);
     method public void putInt(java.lang.String, int);
@@ -21478,9 +21483,6 @@
     method public java.lang.Object clone();
     method public int describeContents();
     method public android.os.IBinder getBinder(java.lang.String);
-    method public boolean getBoolean(java.lang.String);
-    method public boolean getBoolean(java.lang.String, boolean);
-    method public boolean[] getBooleanArray(java.lang.String);
     method public android.os.Bundle getBundle(java.lang.String);
     method public byte getByte(java.lang.String);
     method public java.lang.Byte getByte(java.lang.String, byte);
@@ -21511,8 +21513,6 @@
     method public boolean hasFileDescriptors();
     method public void putAll(android.os.Bundle);
     method public void putBinder(java.lang.String, android.os.IBinder);
-    method public void putBoolean(java.lang.String, boolean);
-    method public void putBooleanArray(java.lang.String, boolean[]);
     method public void putBundle(java.lang.String, android.os.Bundle);
     method public void putByte(java.lang.String, byte);
     method public void putByteArray(java.lang.String, byte[]);
diff --git a/core/java/android/os/BaseBundle.java b/core/java/android/os/BaseBundle.java
index 9589aac..1b02141b9 100644
--- a/core/java/android/os/BaseBundle.java
+++ b/core/java/android/os/BaseBundle.java
@@ -329,7 +329,7 @@
      * @param key a String, or null
      * @param value a Boolean, or null
      */
-    void putBoolean(String key, boolean value) {
+    public void putBoolean(String key, boolean value) {
         unparcel();
         mMap.put(key, value);
     }
@@ -497,7 +497,7 @@
      * @param key a String, or null
      * @param value a boolean array object, or null
      */
-    void putBooleanArray(String key, boolean[] value) {
+    public void putBooleanArray(String key, boolean[] value) {
         unparcel();
         mMap.put(key, value);
     }
@@ -617,7 +617,7 @@
      * @param key a String
      * @return a boolean value
      */
-    boolean getBoolean(String key) {
+    public boolean getBoolean(String key) {
         unparcel();
         if (DEBUG) Log.d(TAG, "Getting boolean in "
                 + Integer.toHexString(System.identityHashCode(this)));
@@ -654,7 +654,7 @@
      * @param defaultValue Value to return if key does not exist
      * @return a boolean value
      */
-    boolean getBoolean(String key, boolean defaultValue) {
+    public boolean getBoolean(String key, boolean defaultValue) {
         unparcel();
         Object o = mMap.get(key);
         if (o == null) {
@@ -1072,7 +1072,7 @@
      * @param key a String, or null
      * @return a boolean[] value, or null
      */
-    boolean[] getBooleanArray(String key) {
+    public boolean[] getBooleanArray(String key) {
         unparcel();
         Object o = mMap.get(key);
         if (o == null) {
diff --git a/core/java/android/os/Bundle.java b/core/java/android/os/Bundle.java
index a9aa570..c5c5372 100644
--- a/core/java/android/os/Bundle.java
+++ b/core/java/android/os/Bundle.java
@@ -252,18 +252,6 @@
     }
 
     /**
-     * Inserts a Boolean value into the mapping of this Bundle, replacing
-     * any existing value for the given key.  Either key or value may be null.
-     *
-     * @param key a String, or null
-     * @param value a Boolean, or null
-     */
-    @Override
-    public void putBoolean(String key, boolean value) {
-        super.putBoolean(key, value);
-    }
-
-    /**
      * Inserts a byte value into the mapping of this Bundle, replacing
      * any existing value for the given key.
      *
@@ -460,18 +448,6 @@
     }
 
     /**
-     * Inserts a boolean array value into the mapping of this Bundle, replacing
-     * any existing value for the given key.  Either key or value may be null.
-     *
-     * @param key a String, or null
-     * @param value a boolean array object, or null
-     */
-    @Override
-    public void putBooleanArray(String key, boolean[] value) {
-        super.putBooleanArray(key, value);
-    }
-
-    /**
      * Inserts a byte array value into the mapping of this Bundle, replacing
      * any existing value for the given key.  Either key or value may be null.
      *
@@ -579,31 +555,6 @@
     }
 
     /**
-     * Returns the value associated with the given key, or false if
-     * no mapping of the desired type exists for the given key.
-     *
-     * @param key a String
-     * @return a boolean value
-     */
-    @Override
-    public boolean getBoolean(String key) {
-        return super.getBoolean(key);
-    }
-
-    /**
-     * Returns the value associated with the given key, or defaultValue if
-     * no mapping of the desired type exists for the given key.
-     *
-     * @param key a String
-     * @param defaultValue Value to return if key does not exist
-     * @return a boolean value
-     */
-    @Override
-    public boolean getBoolean(String key, boolean defaultValue) {
-        return super.getBoolean(key, defaultValue);
-    }
-
-    /**
      * Returns the value associated with the given key, or (byte) 0 if
      * no mapping of the desired type exists for the given key.
      *
@@ -939,19 +890,6 @@
      * value is explicitly associated with the key.
      *
      * @param key a String, or null
-     * @return a boolean[] value, or null
-     */
-    @Override
-    public boolean[] getBooleanArray(String key) {
-        return super.getBooleanArray(key);
-    }
-
-    /**
-     * Returns the value associated with the given key, or null if
-     * no mapping of the desired type exists for the given key or a null
-     * value is explicitly associated with the key.
-     *
-     * @param key a String, or null
      * @return a byte[] value, or null
      */
     @Override
diff --git a/core/java/android/os/PersistableBundle.java b/core/java/android/os/PersistableBundle.java
index c01f688..3a44428 100644
--- a/core/java/android/os/PersistableBundle.java
+++ b/core/java/android/os/PersistableBundle.java
@@ -96,7 +96,8 @@
                     !(value instanceof Double) && !(value instanceof String) &&
                     !(value instanceof int[]) && !(value instanceof long[]) &&
                     !(value instanceof double[]) && !(value instanceof String[]) &&
-                    !(value instanceof PersistableBundle) && (value != null)) {
+                    !(value instanceof PersistableBundle) && (value != null) &&
+                    !(value instanceof Boolean) && !(value instanceof boolean[])) {
                 throw new IllegalArgumentException("Bad value in PersistableBundle key=" + key +
                         " value=" + value);
             }
diff --git a/core/java/com/android/internal/util/XmlUtils.java b/core/java/com/android/internal/util/XmlUtils.java
index e9baaa8..2bd607c 100644
--- a/core/java/com/android/internal/util/XmlUtils.java
+++ b/core/java/com/android/internal/util/XmlUtils.java
@@ -520,7 +520,7 @@
      * Flatten a String[] into an XmlSerializer.  The list can later be read back
      * with readThisStringArrayXml().
      *
-     * @param val The long array to be flattened.
+     * @param val The String array to be flattened.
      * @param name Name attribute to include with this array's tag, or null for
      *             none.
      * @param out XmlSerializer to write the array into.
@@ -556,6 +556,45 @@
     }
 
     /**
+     * Flatten a boolean[] into an XmlSerializer.  The list can later be read back
+     * with readThisBooleanArrayXml().
+     *
+     * @param val The boolean array to be flattened.
+     * @param name Name attribute to include with this array's tag, or null for
+     *             none.
+     * @param out XmlSerializer to write the array into.
+     *
+     * @see #writeMapXml
+     * @see #writeValueXml
+     * @see #readThisIntArrayXml
+     */
+    public static final void writeBooleanArrayXml(boolean[] val, String name, XmlSerializer out)
+            throws XmlPullParserException, java.io.IOException {
+
+        if (val == null) {
+            out.startTag(null, "null");
+            out.endTag(null, "null");
+            return;
+        }
+
+        out.startTag(null, "boolean-array");
+        if (name != null) {
+            out.attribute(null, "name", name);
+        }
+
+        final int N = val.length;
+        out.attribute(null, "num", Integer.toString(N));
+
+        for (int i=0; i<N; i++) {
+            out.startTag(null, "item");
+            out.attribute(null, "value", Boolean.toString(val[i]));
+            out.endTag(null, "item");
+        }
+
+        out.endTag(null, "boolean-array");
+    }
+
+    /**
      * Flatten an object's value into an XmlSerializer.  The value can later
      * be read back with readThisValueXml().
      *
@@ -636,6 +675,9 @@
         } else if (v instanceof String[]) {
             writeStringArrayXml((String[])v, name, out);
             return;
+        } else if (v instanceof boolean[]) {
+            writeBooleanArrayXml((boolean[])v, name, out);
+            return;
         } else if (v instanceof Map) {
             writeMapXml((Map)v, name, out);
             return;
@@ -1169,6 +1211,66 @@
     }
 
     /**
+     * Read a boolean[] object from an XmlPullParser.  The XML data could
+     * previously have been generated by writeBooleanArrayXml().  The XmlPullParser
+     * must be positioned <em>after</em> the tag that begins the list.
+     *
+     * @param parser The XmlPullParser from which to read the list data.
+     * @param endTag Name of the tag that will end the list, usually "string-array".
+     * @param name An array of one string, used to return the name attribute
+     *             of the list's tag.
+     *
+     * @return Returns a newly generated boolean[].
+     *
+     * @see #readListXml
+     */
+    public static final boolean[] readThisBooleanArrayXml(XmlPullParser parser, String endTag,
+            String[] name) throws XmlPullParserException, java.io.IOException {
+
+        int num;
+        try {
+            num = Integer.parseInt(parser.getAttributeValue(null, "num"));
+        } catch (NullPointerException e) {
+            throw new XmlPullParserException("Need num attribute in string-array");
+        } catch (NumberFormatException e) {
+            throw new XmlPullParserException("Not a number in num attribute in string-array");
+        }
+        parser.next();
+
+        boolean[] array = new boolean[num];
+        int i = 0;
+
+        int eventType = parser.getEventType();
+        do {
+            if (eventType == parser.START_TAG) {
+                if (parser.getName().equals("item")) {
+                    try {
+                        array[i] = Boolean.valueOf(parser.getAttributeValue(null, "value"));
+                    } catch (NullPointerException e) {
+                        throw new XmlPullParserException("Need value attribute in item");
+                    } catch (NumberFormatException e) {
+                        throw new XmlPullParserException("Not a number in value attribute in item");
+                    }
+                } else {
+                    throw new XmlPullParserException("Expected item tag at: " + parser.getName());
+                }
+            } else if (eventType == parser.END_TAG) {
+                if (parser.getName().equals(endTag)) {
+                    return array;
+                } else if (parser.getName().equals("item")) {
+                    i++;
+                } else {
+                    throw new XmlPullParserException("Expected " + endTag + " end tag at: " +
+                            parser.getName());
+                }
+            }
+            eventType = parser.next();
+        } while (eventType != parser.END_DOCUMENT);
+
+        throw new XmlPullParserException("Document ended before " + endTag + " end tag");
+    }
+
+    /**
      * Read a flattened object from an XmlPullParser.  The XML data could
      * previously have been written with writeMapXml(), writeListXml(), or
      * writeValueXml().  The XmlPullParser must be positioned <em>at</em> the
@@ -1259,6 +1361,11 @@
             name[0] = valueName;
             //System.out.println("Returning value for " + valueName + ": " + res);
             return res;
+        } else if (tagName.equals("boolean-array")) {
+            res = readThisBooleanArrayXml(parser, "boolean-array", name);
+            name[0] = valueName;
+            //System.out.println("Returning value for " + valueName + ": " + res);
+            return res;
         } else if (tagName.equals("map")) {
             parser.next();
             res = readThisMapXml(parser, "map", name);