diff options
author | Craig Mautner <cmautner@google.com> | 2014-04-23 18:48:56 +0000 |
---|---|---|
committer | Android (Google) Code Review <android-gerrit@google.com> | 2014-04-23 18:48:56 +0000 |
commit | 5723febadc1877c045389afffa111913698e32e2 (patch) | |
tree | 7e539b43d4fd61d73800c6172153d9fdb1026e78 | |
parent | 8a0fa6e823ddbdfd17869d52f838b1cc0a46bd2b (diff) | |
parent | 719e6b167041ffaffc2245f692714c8de191863f (diff) | |
download | frameworks_base-5723febadc1877c045389afffa111913698e32e2.zip frameworks_base-5723febadc1877c045389afffa111913698e32e2.tar.gz frameworks_base-5723febadc1877c045389afffa111913698e32e2.tar.bz2 |
Merge "Introduce PersistableBundle"
-rw-r--r-- | api/current.txt | 57 | ||||
-rw-r--r-- | core/java/android/os/Bundle.java | 771 | ||||
-rw-r--r-- | core/java/android/os/CommonBundle.java | 1384 | ||||
-rw-r--r-- | core/java/android/os/Parcel.java | 49 | ||||
-rw-r--r-- | core/java/android/os/PersistableBundle.java | 555 |
5 files changed, 2258 insertions, 558 deletions
diff --git a/api/current.txt b/api/current.txt index 1055c24..5c962a3 100644 --- a/api/current.txt +++ b/api/current.txt @@ -19256,11 +19256,12 @@ package android.os { field public static final int L = 10000; // 0x2710 } - public final class Bundle implements java.lang.Cloneable android.os.Parcelable { + public final class Bundle extends android.os.CommonBundle { ctor public Bundle(); ctor public Bundle(java.lang.ClassLoader); ctor public Bundle(int); ctor public Bundle(android.os.Bundle); + ctor public Bundle(android.os.PersistableBundle); method public void clear(); method public java.lang.Object clone(); method public boolean containsKey(java.lang.String); @@ -19298,6 +19299,7 @@ package android.os { method public T getParcelable(java.lang.String); method public android.os.Parcelable[] getParcelableArray(java.lang.String); method public java.util.ArrayList<T> getParcelableArrayList(java.lang.String); + method public android.os.PersistableBundle getPersistableBundle(java.lang.String); method public java.io.Serializable getSerializable(java.lang.String); method public short getShort(java.lang.String); method public short getShort(java.lang.String, short); @@ -19311,6 +19313,7 @@ package android.os { method public boolean isEmpty(); method public java.util.Set<java.lang.String> keySet(); method public void putAll(android.os.Bundle); + method public void putAll(android.os.PersistableBundle); 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[]); @@ -19334,6 +19337,7 @@ package android.os { method public void putParcelable(java.lang.String, android.os.Parcelable); method public void putParcelableArray(java.lang.String, android.os.Parcelable[]); method public void putParcelableArrayList(java.lang.String, java.util.ArrayList<? extends android.os.Parcelable>); + method public void putPersistableBundle(java.lang.String, android.os.PersistableBundle); method public void putSerializable(java.lang.String, java.io.Serializable); method public void putShort(java.lang.String, short); method public void putShortArray(java.lang.String, short[]); @@ -19362,6 +19366,9 @@ package android.os { method public abstract void onCancel(); } + abstract class CommonBundle implements java.lang.Cloneable android.os.Parcelable { + } + public class ConditionVariable { ctor public ConditionVariable(); ctor public ConditionVariable(boolean); @@ -19788,6 +19795,8 @@ package android.os { method public final void readMap(java.util.Map, java.lang.ClassLoader); method public final T readParcelable(java.lang.ClassLoader); method public final android.os.Parcelable[] readParcelableArray(java.lang.ClassLoader); + method public final android.os.PersistableBundle readPersistableBundle(); + method public final android.os.PersistableBundle readPersistableBundle(java.lang.ClassLoader); method public final java.io.Serializable readSerializable(); method public final android.util.SparseArray readSparseArray(java.lang.ClassLoader); method public final android.util.SparseBooleanArray readSparseBooleanArray(); @@ -19828,6 +19837,7 @@ package android.os { method public final void writeNoException(); method public final void writeParcelable(android.os.Parcelable, int); method public final void writeParcelableArray(T[], int); + method public final void writePersistableBundle(android.os.PersistableBundle); method public final void writeSerializable(java.io.Serializable); method public final void writeSparseArray(android.util.SparseArray<java.lang.Object>); method public final void writeSparseBooleanArray(android.util.SparseBooleanArray); @@ -19938,6 +19948,51 @@ package android.os { field public static final int PATTERN_SIMPLE_GLOB = 2; // 0x2 } + public final class PersistableBundle extends android.os.CommonBundle { + ctor public PersistableBundle(); + ctor public PersistableBundle(java.lang.ClassLoader); + ctor public PersistableBundle(int); + ctor public PersistableBundle(android.os.PersistableBundle); + method public void clear(); + method public java.lang.Object clone(); + method public boolean containsKey(java.lang.String); + method public int describeContents(); + method public java.lang.Object get(java.lang.String); + method public java.lang.ClassLoader getClassLoader(); + method public double getDouble(java.lang.String); + method public double getDouble(java.lang.String, double); + method public double[] getDoubleArray(java.lang.String); + method public int getInt(java.lang.String); + method public int getInt(java.lang.String, int); + method public int[] getIntArray(java.lang.String); + method public long getLong(java.lang.String); + method public long getLong(java.lang.String, long); + method public long[] getLongArray(java.lang.String); + method public android.os.PersistableBundle getPersistableBundle(java.lang.String); + method public java.lang.String getString(java.lang.String); + method public java.lang.String getString(java.lang.String, java.lang.String); + method public java.lang.String[] getStringArray(java.lang.String); + method public boolean isEmpty(); + method public java.util.Set<java.lang.String> keySet(); + method public void putAll(android.os.PersistableBundle); + method public void putDouble(java.lang.String, double); + method public void putDoubleArray(java.lang.String, double[]); + method public void putInt(java.lang.String, int); + method public void putIntArray(java.lang.String, int[]); + method public void putLong(java.lang.String, long); + method public void putLongArray(java.lang.String, long[]); + method public void putPersistableBundle(java.lang.String, android.os.PersistableBundle); + method public void putString(java.lang.String, java.lang.String); + method public void putStringArray(java.lang.String, java.lang.String[]); + method public void readFromParcel(android.os.Parcel); + method public void remove(java.lang.String); + method public void setClassLoader(java.lang.ClassLoader); + method public int size(); + method public void writeToParcel(android.os.Parcel, int); + field public static final android.os.Parcelable.Creator CREATOR; + field public static final android.os.PersistableBundle EMPTY; + } + public final class PowerManager { method public void goToSleep(long); method public boolean isInteractive(); diff --git a/core/java/android/os/Bundle.java b/core/java/android/os/Bundle.java index af57507..c85e418 100644 --- a/core/java/android/os/Bundle.java +++ b/core/java/android/os/Bundle.java @@ -17,7 +17,6 @@ package android.os; import android.util.ArrayMap; -import android.util.Log; import android.util.SparseArray; import java.io.Serializable; @@ -29,47 +28,25 @@ import java.util.Set; * A mapping from String values to various Parcelable types. * */ -public final class Bundle implements Parcelable, Cloneable { - private static final String TAG = "Bundle"; - static final boolean DEBUG = false; +public final class Bundle extends CommonBundle { public static final Bundle EMPTY; - - static final int BUNDLE_MAGIC = 0x4C444E42; // 'B' 'N' 'D' 'L' static final Parcel EMPTY_PARCEL; static { EMPTY = new Bundle(); EMPTY.mMap = ArrayMap.EMPTY; - EMPTY_PARCEL = Parcel.obtain(); + EMPTY_PARCEL = CommonBundle.EMPTY_PARCEL; } - // Invariant - exactly one of mMap / mParcelledData will be null - // (except inside a call to unparcel) - - /* package */ ArrayMap<String, Object> mMap = null; - - /* - * If mParcelledData is non-null, then mMap will be null and the - * data are stored as a Parcel containing a Bundle. When the data - * are unparcelled, mParcelledData willbe set to null. - */ - /* package */ Parcel mParcelledData = null; - private boolean mHasFds = false; private boolean mFdsKnown = true; private boolean mAllowFds = true; /** - * The ClassLoader used when unparcelling data from mParcelledData. - */ - private ClassLoader mClassLoader; - - /** * Constructs a new, empty Bundle. */ public Bundle() { - mMap = new ArrayMap<String, Object>(); - mClassLoader = getClass().getClassLoader(); + super(); } /** @@ -79,11 +56,17 @@ public final class Bundle implements Parcelable, Cloneable { * @param parcelledData a Parcel containing a Bundle */ Bundle(Parcel parcelledData) { - readFromParcel(parcelledData); + super(parcelledData); + + mHasFds = mParcelledData.hasFileDescriptors(); + mFdsKnown = true; } /* package */ Bundle(Parcel parcelledData, int length) { - readFromParcelInner(parcelledData, length); + super(parcelledData, length); + + mHasFds = mParcelledData.hasFileDescriptors(); + mFdsKnown = true; } /** @@ -94,8 +77,7 @@ public final class Bundle implements Parcelable, Cloneable { * inside of the Bundle. */ public Bundle(ClassLoader loader) { - mMap = new ArrayMap<String, Object>(); - mClassLoader = loader; + super(loader); } /** @@ -105,8 +87,7 @@ public final class Bundle implements Parcelable, Cloneable { * @param capacity the initial capacity of the Bundle */ public Bundle(int capacity) { - mMap = new ArrayMap<String, Object>(capacity); - mClassLoader = getClass().getClassLoader(); + super(capacity); } /** @@ -116,27 +97,20 @@ public final class Bundle implements Parcelable, Cloneable { * @param b a Bundle to be copied. */ public Bundle(Bundle b) { - if (b.mParcelledData != null) { - if (b.mParcelledData == EMPTY_PARCEL) { - mParcelledData = EMPTY_PARCEL; - } else { - mParcelledData = Parcel.obtain(); - mParcelledData.appendFrom(b.mParcelledData, 0, b.mParcelledData.dataSize()); - mParcelledData.setDataPosition(0); - } - } else { - mParcelledData = null; - } - - if (b.mMap != null) { - mMap = new ArrayMap<String, Object>(b.mMap); - } else { - mMap = null; - } + super(b); mHasFds = b.mHasFds; mFdsKnown = b.mFdsKnown; - mClassLoader = b.mClassLoader; + } + + /** + * Constructs a Bundle containing a copy of the mappings from the given + * PersistableBundle. + * + * @param b a Bundle to be copied. + */ + public Bundle(PersistableBundle b) { + super(b); } /** @@ -145,37 +119,17 @@ public final class Bundle implements Parcelable, Cloneable { * @hide */ public static Bundle forPair(String key, String value) { - // TODO: optimize this case. Bundle b = new Bundle(1); b.putString(key, value); return b; } /** - * TODO: optimize this later (getting just the value part of a Bundle - * with a single pair) once Bundle.forPair() above is implemented - * with a special single-value Map implementation/serialization. - * - * Note: value in single-pair Bundle may be null. - * * @hide */ + @Override public String getPairValue() { - unparcel(); - int size = mMap.size(); - if (size > 1) { - Log.w(TAG, "getPairValue() used on Bundle with multiple pairs."); - } - if (size == 0) { - return null; - } - Object o = mMap.valueAt(0); - try { - return (String) o; - } catch (ClassCastException e) { - typeWarning("getPairValue()", o, "String", e); - return null; - } + return super.getPairValue(); } /** @@ -184,15 +138,17 @@ public final class Bundle implements Parcelable, Cloneable { * @param loader An explicit ClassLoader to use when instantiating objects * inside of the Bundle. */ + @Override public void setClassLoader(ClassLoader loader) { - mClassLoader = loader; + super.setClassLoader(loader); } /** * Return the ClassLoader currently associated with this Bundle. */ + @Override public ClassLoader getClassLoader() { - return mClassLoader; + return super.getClassLoader(); } /** @hide */ @@ -212,52 +168,11 @@ public final class Bundle implements Parcelable, Cloneable { } /** - * If the underlying data are stored as a Parcel, unparcel them - * using the currently assigned class loader. - */ - /* package */ synchronized void unparcel() { - if (mParcelledData == null) { - if (DEBUG) Log.d(TAG, "unparcel " + Integer.toHexString(System.identityHashCode(this)) - + ": no parcelled data"); - return; - } - - if (mParcelledData == EMPTY_PARCEL) { - if (DEBUG) Log.d(TAG, "unparcel " + Integer.toHexString(System.identityHashCode(this)) - + ": empty"); - if (mMap == null) { - mMap = new ArrayMap<String, Object>(1); - } else { - mMap.erase(); - } - mParcelledData = null; - return; - } - - int N = mParcelledData.readInt(); - if (DEBUG) Log.d(TAG, "unparcel " + Integer.toHexString(System.identityHashCode(this)) - + ": reading " + N + " maps"); - if (N < 0) { - return; - } - if (mMap == null) { - mMap = new ArrayMap<String, Object>(N); - } else { - mMap.erase(); - mMap.ensureCapacity(N); - } - mParcelledData.readArrayMapInternal(mMap, N, mClassLoader); - mParcelledData.recycle(); - mParcelledData = null; - if (DEBUG) Log.d(TAG, "unparcel " + Integer.toHexString(System.identityHashCode(this)) - + " final map: " + mMap); - } - - /** * @hide */ + @Override public boolean isParcelled() { - return mParcelledData != null; + return super.isParcelled(); } /** @@ -265,25 +180,26 @@ public final class Bundle implements Parcelable, Cloneable { * * @return the number of mappings as an int. */ + @Override public int size() { - unparcel(); - return mMap.size(); + return super.size(); } /** * Returns true if the mapping of this Bundle is empty, false otherwise. */ + @Override public boolean isEmpty() { - unparcel(); - return mMap.isEmpty(); + return super.isEmpty(); } /** * Removes all elements from the mapping of this Bundle. */ + @Override public void clear() { - unparcel(); - mMap.clear(); + super.clear(); + mHasFds = false; mFdsKnown = true; } @@ -295,9 +211,9 @@ public final class Bundle implements Parcelable, Cloneable { * @param key a String key * @return true if the key is part of the mapping, false otherwise */ + @Override public boolean containsKey(String key) { - unparcel(); - return mMap.containsKey(key); + return super.containsKey(key); } /** @@ -306,9 +222,9 @@ public final class Bundle implements Parcelable, Cloneable { * @param key a String key * @return an Object, or null */ + @Override public Object get(String key) { - unparcel(); - return mMap.get(key); + return super.get(key); } /** @@ -316,24 +232,33 @@ public final class Bundle implements Parcelable, Cloneable { * * @param key a String key */ + @Override public void remove(String key) { - unparcel(); - mMap.remove(key); + super.remove(key); } /** * Inserts all mappings from the given Bundle into this Bundle. * - * @param map a Bundle + * @param bundle a Bundle */ - public void putAll(Bundle map) { + public void putAll(Bundle bundle) { unparcel(); - map.unparcel(); - mMap.putAll(map.mMap); + bundle.unparcel(); + mMap.putAll(bundle.mMap); // fd state is now known if and only if both bundles already knew - mHasFds |= map.mHasFds; - mFdsKnown = mFdsKnown && map.mFdsKnown; + mHasFds |= bundle.mHasFds; + mFdsKnown = mFdsKnown && bundle.mFdsKnown; + } + + /** + * Inserts all mappings from the given PersistableBundle into this Bundle. + * + * @param bundle a PersistableBundle + */ + public void putAll(PersistableBundle bundle) { + super.putAll(bundle); } /** @@ -341,9 +266,9 @@ public final class Bundle implements Parcelable, Cloneable { * * @return a Set of String keys */ + @Override public Set<String> keySet() { - unparcel(); - return mMap.keySet(); + return super.keySet(); } /** @@ -352,7 +277,7 @@ public final class Bundle implements Parcelable, Cloneable { public boolean hasFileDescriptors() { if (!mFdsKnown) { boolean fdFound = false; // keep going until we find one or run out of data - + if (mParcelledData != null) { if (mParcelledData.hasFileDescriptors()) { fdFound = true; @@ -390,8 +315,7 @@ public final class Bundle implements Parcelable, Cloneable { ArrayList array = (ArrayList) obj; // an ArrayList here might contain either Strings or // Parcelables; only look inside for Parcelables - if ((array.size() > 0) - && (array.get(0) instanceof Parcelable)) { + if (!array.isEmpty() && (array.get(0) instanceof Parcelable)) { for (int n = array.size() - 1; n >= 0; n--) { Parcelable p = (Parcelable) array.get(n); if (p != null && ((p.describeContents() @@ -410,7 +334,7 @@ public final class Bundle implements Parcelable, Cloneable { } return mHasFds; } - + /** * 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. @@ -418,9 +342,9 @@ public final class Bundle implements Parcelable, Cloneable { * @param key a String, or null * @param value a Boolean, or null */ + @Override public void putBoolean(String key, boolean value) { - unparcel(); - mMap.put(key, value); + super.putBoolean(key, value); } /** @@ -430,9 +354,9 @@ public final class Bundle implements Parcelable, Cloneable { * @param key a String, or null * @param value a byte */ + @Override public void putByte(String key, byte value) { - unparcel(); - mMap.put(key, value); + super.putByte(key, value); } /** @@ -442,9 +366,9 @@ public final class Bundle implements Parcelable, Cloneable { * @param key a String, or null * @param value a char, or null */ + @Override public void putChar(String key, char value) { - unparcel(); - mMap.put(key, value); + super.putChar(key, value); } /** @@ -454,9 +378,9 @@ public final class Bundle implements Parcelable, Cloneable { * @param key a String, or null * @param value a short */ + @Override public void putShort(String key, short value) { - unparcel(); - mMap.put(key, value); + super.putShort(key, value); } /** @@ -466,9 +390,9 @@ public final class Bundle implements Parcelable, Cloneable { * @param key a String, or null * @param value an int, or null */ + @Override public void putInt(String key, int value) { - unparcel(); - mMap.put(key, value); + super.putInt(key, value); } /** @@ -478,9 +402,9 @@ public final class Bundle implements Parcelable, Cloneable { * @param key a String, or null * @param value a long */ + @Override public void putLong(String key, long value) { - unparcel(); - mMap.put(key, value); + super.putLong(key, value); } /** @@ -490,9 +414,9 @@ public final class Bundle implements Parcelable, Cloneable { * @param key a String, or null * @param value a float */ + @Override public void putFloat(String key, float value) { - unparcel(); - mMap.put(key, value); + super.putFloat(key, value); } /** @@ -502,9 +426,9 @@ public final class Bundle implements Parcelable, Cloneable { * @param key a String, or null * @param value a double */ + @Override public void putDouble(String key, double value) { - unparcel(); - mMap.put(key, value); + super.putDouble(key, value); } /** @@ -514,9 +438,9 @@ public final class Bundle implements Parcelable, Cloneable { * @param key a String, or null * @param value a String, or null */ + @Override public void putString(String key, String value) { - unparcel(); - mMap.put(key, value); + super.putString(key, value); } /** @@ -526,9 +450,9 @@ public final class Bundle implements Parcelable, Cloneable { * @param key a String, or null * @param value a CharSequence, or null */ + @Override public void putCharSequence(String key, CharSequence value) { - unparcel(); - mMap.put(key, value); + super.putCharSequence(key, value); } /** @@ -567,7 +491,7 @@ public final class Bundle implements Parcelable, Cloneable { * @param value an ArrayList of Parcelable objects, or null */ public void putParcelableArrayList(String key, - ArrayList<? extends Parcelable> value) { + ArrayList<? extends Parcelable> value) { unparcel(); mMap.put(key, value); mFdsKnown = false; @@ -602,9 +526,9 @@ public final class Bundle implements Parcelable, Cloneable { * @param key a String, or null * @param value an ArrayList<Integer> object, or null */ + @Override public void putIntegerArrayList(String key, ArrayList<Integer> value) { - unparcel(); - mMap.put(key, value); + super.putIntegerArrayList(key, value); } /** @@ -614,9 +538,9 @@ public final class Bundle implements Parcelable, Cloneable { * @param key a String, or null * @param value an ArrayList<String> object, or null */ + @Override public void putStringArrayList(String key, ArrayList<String> value) { - unparcel(); - mMap.put(key, value); + super.putStringArrayList(key, value); } /** @@ -626,9 +550,9 @@ public final class Bundle implements Parcelable, Cloneable { * @param key a String, or null * @param value an ArrayList<CharSequence> object, or null */ + @Override public void putCharSequenceArrayList(String key, ArrayList<CharSequence> value) { - unparcel(); - mMap.put(key, value); + super.putCharSequenceArrayList(key, value); } /** @@ -638,9 +562,9 @@ public final class Bundle implements Parcelable, Cloneable { * @param key a String, or null * @param value a Serializable object, or null */ + @Override public void putSerializable(String key, Serializable value) { - unparcel(); - mMap.put(key, value); + super.putSerializable(key, value); } /** @@ -650,9 +574,9 @@ public final class Bundle implements Parcelable, Cloneable { * @param key a String, or null * @param value a boolean array object, or null */ + @Override public void putBooleanArray(String key, boolean[] value) { - unparcel(); - mMap.put(key, value); + super.putBooleanArray(key, value); } /** @@ -662,9 +586,9 @@ public final class Bundle implements Parcelable, Cloneable { * @param key a String, or null * @param value a byte array object, or null */ + @Override public void putByteArray(String key, byte[] value) { - unparcel(); - mMap.put(key, value); + super.putByteArray(key, value); } /** @@ -674,9 +598,9 @@ public final class Bundle implements Parcelable, Cloneable { * @param key a String, or null * @param value a short array object, or null */ + @Override public void putShortArray(String key, short[] value) { - unparcel(); - mMap.put(key, value); + super.putShortArray(key, value); } /** @@ -686,9 +610,9 @@ public final class Bundle implements Parcelable, Cloneable { * @param key a String, or null * @param value a char array object, or null */ + @Override public void putCharArray(String key, char[] value) { - unparcel(); - mMap.put(key, value); + super.putCharArray(key, value); } /** @@ -698,9 +622,9 @@ public final class Bundle implements Parcelable, Cloneable { * @param key a String, or null * @param value an int array object, or null */ + @Override public void putIntArray(String key, int[] value) { - unparcel(); - mMap.put(key, value); + super.putIntArray(key, value); } /** @@ -710,9 +634,9 @@ public final class Bundle implements Parcelable, Cloneable { * @param key a String, or null * @param value a long array object, or null */ + @Override public void putLongArray(String key, long[] value) { - unparcel(); - mMap.put(key, value); + super.putLongArray(key, value); } /** @@ -722,9 +646,9 @@ public final class Bundle implements Parcelable, Cloneable { * @param key a String, or null * @param value a float array object, or null */ + @Override public void putFloatArray(String key, float[] value) { - unparcel(); - mMap.put(key, value); + super.putFloatArray(key, value); } /** @@ -734,9 +658,9 @@ public final class Bundle implements Parcelable, Cloneable { * @param key a String, or null * @param value a double array object, or null */ + @Override public void putDoubleArray(String key, double[] value) { - unparcel(); - mMap.put(key, value); + super.putDoubleArray(key, value); } /** @@ -746,9 +670,9 @@ public final class Bundle implements Parcelable, Cloneable { * @param key a String, or null * @param value a String array object, or null */ + @Override public void putStringArray(String key, String[] value) { - unparcel(); - mMap.put(key, value); + super.putStringArray(key, value); } /** @@ -758,9 +682,9 @@ public final class Bundle implements Parcelable, Cloneable { * @param key a String, or null * @param value a CharSequence array object, or null */ + @Override public void putCharSequenceArray(String key, CharSequence[] value) { - unparcel(); - mMap.put(key, value); + super.putCharSequenceArray(key, value); } /** @@ -776,6 +700,17 @@ public final class Bundle implements Parcelable, Cloneable { } /** + * Inserts a PersistableBundle 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 Bundle object, or null + */ + public void putPersistableBundle(String key, PersistableBundle value) { + super.putPersistableBundle(key, value); + } + + /** * Inserts an {@link IBinder} value into the mapping of this Bundle, replacing * any existing value for the given key. Either key or value may be null. * @@ -817,33 +752,9 @@ public final class Bundle implements Parcelable, Cloneable { * @param key a String * @return a boolean value */ + @Override public boolean getBoolean(String key) { - unparcel(); - if (DEBUG) Log.d(TAG, "Getting boolean in " - + Integer.toHexString(System.identityHashCode(this))); - return getBoolean(key, false); - } - - // Log a message if the value was non-null but not of the expected type - private void typeWarning(String key, Object value, String className, - Object defaultValue, ClassCastException e) { - StringBuilder sb = new StringBuilder(); - sb.append("Key "); - sb.append(key); - sb.append(" expected "); - sb.append(className); - sb.append(" but value was a "); - sb.append(value.getClass().getName()); - sb.append(". The default value "); - sb.append(defaultValue); - sb.append(" was returned."); - Log.w(TAG, sb.toString()); - Log.w(TAG, "Attempt to cast generated internal exception:", e); - } - - private void typeWarning(String key, Object value, String className, - ClassCastException e) { - typeWarning(key, value, className, "<null>", e); + return super.getBoolean(key); } /** @@ -854,18 +765,9 @@ public final class Bundle implements Parcelable, Cloneable { * @param defaultValue Value to return if key does not exist * @return a boolean value */ + @Override public boolean getBoolean(String key, boolean defaultValue) { - unparcel(); - Object o = mMap.get(key); - if (o == null) { - return defaultValue; - } - try { - return (Boolean) o; - } catch (ClassCastException e) { - typeWarning(key, o, "Boolean", defaultValue, e); - return defaultValue; - } + return super.getBoolean(key, defaultValue); } /** @@ -875,9 +777,9 @@ public final class Bundle implements Parcelable, Cloneable { * @param key a String * @return a byte value */ + @Override public byte getByte(String key) { - unparcel(); - return getByte(key, (byte) 0); + return super.getByte(key); } /** @@ -888,18 +790,9 @@ public final class Bundle implements Parcelable, Cloneable { * @param defaultValue Value to return if key does not exist * @return a byte value */ + @Override public Byte getByte(String key, byte defaultValue) { - unparcel(); - Object o = mMap.get(key); - if (o == null) { - return defaultValue; - } - try { - return (Byte) o; - } catch (ClassCastException e) { - typeWarning(key, o, "Byte", defaultValue, e); - return defaultValue; - } + return super.getByte(key, defaultValue); } /** @@ -909,9 +802,9 @@ public final class Bundle implements Parcelable, Cloneable { * @param key a String * @return a char value */ + @Override public char getChar(String key) { - unparcel(); - return getChar(key, (char) 0); + return super.getChar(key); } /** @@ -922,18 +815,9 @@ public final class Bundle implements Parcelable, Cloneable { * @param defaultValue Value to return if key does not exist * @return a char value */ + @Override public char getChar(String key, char defaultValue) { - unparcel(); - Object o = mMap.get(key); - if (o == null) { - return defaultValue; - } - try { - return (Character) o; - } catch (ClassCastException e) { - typeWarning(key, o, "Character", defaultValue, e); - return defaultValue; - } + return super.getChar(key, defaultValue); } /** @@ -943,9 +827,9 @@ public final class Bundle implements Parcelable, Cloneable { * @param key a String * @return a short value */ + @Override public short getShort(String key) { - unparcel(); - return getShort(key, (short) 0); + return super.getShort(key); } /** @@ -956,18 +840,9 @@ public final class Bundle implements Parcelable, Cloneable { * @param defaultValue Value to return if key does not exist * @return a short value */ + @Override public short getShort(String key, short defaultValue) { - unparcel(); - Object o = mMap.get(key); - if (o == null) { - return defaultValue; - } - try { - return (Short) o; - } catch (ClassCastException e) { - typeWarning(key, o, "Short", defaultValue, e); - return defaultValue; - } + return super.getShort(key, defaultValue); } /** @@ -977,9 +852,9 @@ public final class Bundle implements Parcelable, Cloneable { * @param key a String * @return an int value */ + @Override public int getInt(String key) { - unparcel(); - return getInt(key, 0); + return super.getInt(key); } /** @@ -990,18 +865,9 @@ public final class Bundle implements Parcelable, Cloneable { * @param defaultValue Value to return if key does not exist * @return an int value */ + @Override public int getInt(String key, int defaultValue) { - unparcel(); - Object o = mMap.get(key); - if (o == null) { - return defaultValue; - } - try { - return (Integer) o; - } catch (ClassCastException e) { - typeWarning(key, o, "Integer", defaultValue, e); - return defaultValue; - } + return super.getInt(key, defaultValue); } /** @@ -1011,9 +877,9 @@ public final class Bundle implements Parcelable, Cloneable { * @param key a String * @return a long value */ + @Override public long getLong(String key) { - unparcel(); - return getLong(key, 0L); + return super.getLong(key); } /** @@ -1024,18 +890,9 @@ public final class Bundle implements Parcelable, Cloneable { * @param defaultValue Value to return if key does not exist * @return a long value */ + @Override public long getLong(String key, long defaultValue) { - unparcel(); - Object o = mMap.get(key); - if (o == null) { - return defaultValue; - } - try { - return (Long) o; - } catch (ClassCastException e) { - typeWarning(key, o, "Long", defaultValue, e); - return defaultValue; - } + return super.getLong(key, defaultValue); } /** @@ -1045,9 +902,9 @@ public final class Bundle implements Parcelable, Cloneable { * @param key a String * @return a float value */ + @Override public float getFloat(String key) { - unparcel(); - return getFloat(key, 0.0f); + return super.getFloat(key); } /** @@ -1058,18 +915,9 @@ public final class Bundle implements Parcelable, Cloneable { * @param defaultValue Value to return if key does not exist * @return a float value */ + @Override public float getFloat(String key, float defaultValue) { - unparcel(); - Object o = mMap.get(key); - if (o == null) { - return defaultValue; - } - try { - return (Float) o; - } catch (ClassCastException e) { - typeWarning(key, o, "Float", defaultValue, e); - return defaultValue; - } + return super.getFloat(key, defaultValue); } /** @@ -1079,9 +927,9 @@ public final class Bundle implements Parcelable, Cloneable { * @param key a String * @return a double value */ + @Override public double getDouble(String key) { - unparcel(); - return getDouble(key, 0.0); + return super.getDouble(key); } /** @@ -1092,18 +940,9 @@ public final class Bundle implements Parcelable, Cloneable { * @param defaultValue Value to return if key does not exist * @return a double value */ + @Override public double getDouble(String key, double defaultValue) { - unparcel(); - Object o = mMap.get(key); - if (o == null) { - return defaultValue; - } - try { - return (Double) o; - } catch (ClassCastException e) { - typeWarning(key, o, "Double", defaultValue, e); - return defaultValue; - } + return super.getDouble(key, defaultValue); } /** @@ -1114,15 +953,9 @@ public final class Bundle implements Parcelable, Cloneable { * @param key a String, or null * @return a String value, or null */ + @Override public String getString(String key) { - unparcel(); - final Object o = mMap.get(key); - try { - return (String) o; - } catch (ClassCastException e) { - typeWarning(key, o, "String", e); - return null; - } + return super.getString(key); } /** @@ -1134,9 +967,9 @@ public final class Bundle implements Parcelable, Cloneable { * @return the String value associated with the given key, or defaultValue * if no valid String object is currently mapped to that key. */ + @Override public String getString(String key, String defaultValue) { - final String s = getString(key); - return (s == null) ? defaultValue : s; + return super.getString(key, defaultValue); } /** @@ -1147,15 +980,9 @@ public final class Bundle implements Parcelable, Cloneable { * @param key a String, or null * @return a CharSequence value, or null */ + @Override public CharSequence getCharSequence(String key) { - unparcel(); - final Object o = mMap.get(key); - try { - return (CharSequence) o; - } catch (ClassCastException e) { - typeWarning(key, o, "CharSequence", e); - return null; - } + return super.getCharSequence(key); } /** @@ -1167,9 +994,9 @@ public final class Bundle implements Parcelable, Cloneable { * @return the CharSequence value associated with the given key, or defaultValue * if no valid CharSequence object is currently mapped to that key. */ + @Override public CharSequence getCharSequence(String key, CharSequence defaultValue) { - final CharSequence cs = getCharSequence(key); - return (cs == null) ? defaultValue : cs; + return super.getCharSequence(key, defaultValue); } /** @@ -1200,6 +1027,18 @@ public final class Bundle implements Parcelable, Cloneable { * value is explicitly associated with the key. * * @param key a String, or null + * @return a PersistableBundle value, or null + */ + public PersistableBundle getPersistableBundle(String key) { + return super.getPersistableBundle(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 Parcelable value, or null */ public <T extends Parcelable> T getParcelable(String key) { @@ -1291,18 +1130,9 @@ public final class Bundle implements Parcelable, Cloneable { * @param key a String, or null * @return a Serializable value, or null */ + @Override public Serializable getSerializable(String key) { - unparcel(); - Object o = mMap.get(key); - if (o == null) { - return null; - } - try { - return (Serializable) o; - } catch (ClassCastException e) { - typeWarning(key, o, "Serializable", e); - return null; - } + return super.getSerializable(key); } /** @@ -1313,18 +1143,9 @@ public final class Bundle implements Parcelable, Cloneable { * @param key a String, or null * @return an ArrayList<String> value, or null */ + @Override public ArrayList<Integer> getIntegerArrayList(String key) { - unparcel(); - Object o = mMap.get(key); - if (o == null) { - return null; - } - try { - return (ArrayList<Integer>) o; - } catch (ClassCastException e) { - typeWarning(key, o, "ArrayList<Integer>", e); - return null; - } + return super.getIntegerArrayList(key); } /** @@ -1335,18 +1156,9 @@ public final class Bundle implements Parcelable, Cloneable { * @param key a String, or null * @return an ArrayList<String> value, or null */ + @Override public ArrayList<String> getStringArrayList(String key) { - unparcel(); - Object o = mMap.get(key); - if (o == null) { - return null; - } - try { - return (ArrayList<String>) o; - } catch (ClassCastException e) { - typeWarning(key, o, "ArrayList<String>", e); - return null; - } + return super.getStringArrayList(key); } /** @@ -1357,18 +1169,9 @@ public final class Bundle implements Parcelable, Cloneable { * @param key a String, or null * @return an ArrayList<CharSequence> value, or null */ + @Override public ArrayList<CharSequence> getCharSequenceArrayList(String key) { - unparcel(); - Object o = mMap.get(key); - if (o == null) { - return null; - } - try { - return (ArrayList<CharSequence>) o; - } catch (ClassCastException e) { - typeWarning(key, o, "ArrayList<CharSequence>", e); - return null; - } + return super.getCharSequenceArrayList(key); } /** @@ -1379,18 +1182,9 @@ public final class Bundle implements Parcelable, Cloneable { * @param key a String, or null * @return a boolean[] value, or null */ + @Override public boolean[] getBooleanArray(String key) { - unparcel(); - Object o = mMap.get(key); - if (o == null) { - return null; - } - try { - return (boolean[]) o; - } catch (ClassCastException e) { - typeWarning(key, o, "byte[]", e); - return null; - } + return super.getBooleanArray(key); } /** @@ -1401,18 +1195,9 @@ public final class Bundle implements Parcelable, Cloneable { * @param key a String, or null * @return a byte[] value, or null */ + @Override public byte[] getByteArray(String key) { - unparcel(); - Object o = mMap.get(key); - if (o == null) { - return null; - } - try { - return (byte[]) o; - } catch (ClassCastException e) { - typeWarning(key, o, "byte[]", e); - return null; - } + return super.getByteArray(key); } /** @@ -1423,18 +1208,9 @@ public final class Bundle implements Parcelable, Cloneable { * @param key a String, or null * @return a short[] value, or null */ + @Override public short[] getShortArray(String key) { - unparcel(); - Object o = mMap.get(key); - if (o == null) { - return null; - } - try { - return (short[]) o; - } catch (ClassCastException e) { - typeWarning(key, o, "short[]", e); - return null; - } + return super.getShortArray(key); } /** @@ -1445,18 +1221,9 @@ public final class Bundle implements Parcelable, Cloneable { * @param key a String, or null * @return a char[] value, or null */ + @Override public char[] getCharArray(String key) { - unparcel(); - Object o = mMap.get(key); - if (o == null) { - return null; - } - try { - return (char[]) o; - } catch (ClassCastException e) { - typeWarning(key, o, "char[]", e); - return null; - } + return super.getCharArray(key); } /** @@ -1467,18 +1234,9 @@ public final class Bundle implements Parcelable, Cloneable { * @param key a String, or null * @return an int[] value, or null */ + @Override public int[] getIntArray(String key) { - unparcel(); - Object o = mMap.get(key); - if (o == null) { - return null; - } - try { - return (int[]) o; - } catch (ClassCastException e) { - typeWarning(key, o, "int[]", e); - return null; - } + return super.getIntArray(key); } /** @@ -1489,18 +1247,9 @@ public final class Bundle implements Parcelable, Cloneable { * @param key a String, or null * @return a long[] value, or null */ + @Override public long[] getLongArray(String key) { - unparcel(); - Object o = mMap.get(key); - if (o == null) { - return null; - } - try { - return (long[]) o; - } catch (ClassCastException e) { - typeWarning(key, o, "long[]", e); - return null; - } + return super.getLongArray(key); } /** @@ -1511,18 +1260,9 @@ public final class Bundle implements Parcelable, Cloneable { * @param key a String, or null * @return a float[] value, or null */ + @Override public float[] getFloatArray(String key) { - unparcel(); - Object o = mMap.get(key); - if (o == null) { - return null; - } - try { - return (float[]) o; - } catch (ClassCastException e) { - typeWarning(key, o, "float[]", e); - return null; - } + return super.getFloatArray(key); } /** @@ -1533,18 +1273,9 @@ public final class Bundle implements Parcelable, Cloneable { * @param key a String, or null * @return a double[] value, or null */ + @Override public double[] getDoubleArray(String key) { - unparcel(); - Object o = mMap.get(key); - if (o == null) { - return null; - } - try { - return (double[]) o; - } catch (ClassCastException e) { - typeWarning(key, o, "double[]", e); - return null; - } + return super.getDoubleArray(key); } /** @@ -1555,18 +1286,9 @@ public final class Bundle implements Parcelable, Cloneable { * @param key a String, or null * @return a String[] value, or null */ + @Override public String[] getStringArray(String key) { - unparcel(); - Object o = mMap.get(key); - if (o == null) { - return null; - } - try { - return (String[]) o; - } catch (ClassCastException e) { - typeWarning(key, o, "String[]", e); - return null; - } + return super.getStringArray(key); } /** @@ -1577,18 +1299,9 @@ public final class Bundle implements Parcelable, Cloneable { * @param key a String, or null * @return a CharSequence[] value, or null */ + @Override public CharSequence[] getCharSequenceArray(String key) { - unparcel(); - Object o = mMap.get(key); - if (o == null) { - return null; - } - try { - return (CharSequence[]) o; - } catch (ClassCastException e) { - typeWarning(key, o, "CharSequence[]", e); - return null; - } + return super.getCharSequenceArray(key); } /** @@ -1641,10 +1354,12 @@ public final class Bundle implements Parcelable, Cloneable { public static final Parcelable.Creator<Bundle> CREATOR = new Parcelable.Creator<Bundle>() { + @Override public Bundle createFromParcel(Parcel in) { return in.readBundle(); } + @Override public Bundle[] newArray(int size) { return new Bundle[size]; } @@ -1653,6 +1368,7 @@ public final class Bundle implements Parcelable, Cloneable { /** * Report the nature of this Parcelable's contents */ + @Override public int describeContents() { int mask = 0; if (hasFileDescriptors()) { @@ -1660,44 +1376,17 @@ public final class Bundle implements Parcelable, Cloneable { } return mask; } - + /** * Writes the Bundle contents to a Parcel, typically in order for * it to be passed through an IBinder connection. * @param parcel The parcel to copy this bundle to. */ + @Override public void writeToParcel(Parcel parcel, int flags) { final boolean oldAllowFds = parcel.pushAllowFds(mAllowFds); try { - if (mParcelledData != null) { - if (mParcelledData == EMPTY_PARCEL) { - parcel.writeInt(0); - } else { - int length = mParcelledData.dataSize(); - parcel.writeInt(length); - parcel.writeInt(BUNDLE_MAGIC); - parcel.appendFrom(mParcelledData, 0, length); - } - } else { - // Special case for empty bundles. - if (mMap == null || mMap.size() <= 0) { - parcel.writeInt(0); - return; - } - int lengthPos = parcel.dataPosition(); - parcel.writeInt(-1); // dummy, will hold length - parcel.writeInt(BUNDLE_MAGIC); - - int startPos = parcel.dataPosition(); - parcel.writeArrayMapInternal(mMap); - int endPos = parcel.dataPosition(); - - // Backpatch length - parcel.setDataPosition(lengthPos); - int length = endPos - startPos; - parcel.writeInt(length); - parcel.setDataPosition(endPos); - } + super.writeToParcelInner(parcel, flags); } finally { parcel.restoreAllowFds(oldAllowFds); } @@ -1709,41 +1398,8 @@ public final class Bundle implements Parcelable, Cloneable { * @param parcel The parcel to overwrite this bundle from. */ public void readFromParcel(Parcel parcel) { - int length = parcel.readInt(); - if (length < 0) { - throw new RuntimeException("Bad length in parcel: " + length); - } - readFromParcelInner(parcel, length); - } - - void readFromParcelInner(Parcel parcel, int length) { - if (length == 0) { - // Empty Bundle or end of data. - mParcelledData = EMPTY_PARCEL; - mHasFds = false; - mFdsKnown = true; - return; - } - int magic = parcel.readInt(); - if (magic != BUNDLE_MAGIC) { - //noinspection ThrowableInstanceNeverThrown - throw new IllegalStateException("Bad magic number for Bundle: 0x" - + Integer.toHexString(magic)); - } - - // Advance within this Parcel - int offset = parcel.dataPosition(); - parcel.setDataPosition(offset + length); - - Parcel p = Parcel.obtain(); - p.setDataPosition(0); - p.appendFrom(parcel, offset, length); - if (DEBUG) Log.d(TAG, "Retrieving " + Integer.toHexString(System.identityHashCode(this)) - + ": " + length + " bundle bytes starting at " + offset); - p.setDataPosition(0); - - mParcelledData = p; - mHasFds = p.hasFileDescriptors(); + super.readFromParcelInner(parcel); + mHasFds = mParcelledData.hasFileDescriptors(); mFdsKnown = true; } @@ -1759,4 +1415,5 @@ public final class Bundle implements Parcelable, Cloneable { } return "Bundle[" + mMap.toString() + "]"; } + } diff --git a/core/java/android/os/CommonBundle.java b/core/java/android/os/CommonBundle.java new file mode 100644 index 0000000..e11f170 --- /dev/null +++ b/core/java/android/os/CommonBundle.java @@ -0,0 +1,1384 @@ +/* + * Copyright (C) 2014 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.os; + +import android.util.ArrayMap; +import android.util.Log; +import android.util.SparseArray; + +import java.io.Serializable; +import java.util.ArrayList; +import java.util.List; +import java.util.Set; + +/** + * A mapping from String values to various types. + */ +abstract class CommonBundle implements Parcelable, Cloneable { + private static final String TAG = "Bundle"; + static final boolean DEBUG = false; + + static final int BUNDLE_MAGIC = 0x4C444E42; // 'B' 'N' 'D' 'L' + static final Parcel EMPTY_PARCEL; + + static { + EMPTY_PARCEL = Parcel.obtain(); + } + + // Invariant - exactly one of mMap / mParcelledData will be null + // (except inside a call to unparcel) + + ArrayMap<String, Object> mMap = null; + + /* + * If mParcelledData is non-null, then mMap will be null and the + * data are stored as a Parcel containing a Bundle. When the data + * are unparcelled, mParcelledData willbe set to null. + */ + Parcel mParcelledData = null; + + /** + * The ClassLoader used when unparcelling data from mParcelledData. + */ + private ClassLoader mClassLoader; + + /** + * Constructs a new, empty Bundle that uses a specific ClassLoader for + * instantiating Parcelable and Serializable objects. + * + * @param loader An explicit ClassLoader to use when instantiating objects + * inside of the Bundle. + * @param capacity Initial size of the ArrayMap. + */ + CommonBundle(ClassLoader loader, int capacity) { + mMap = capacity > 0 ? + new ArrayMap<String, Object>(capacity) : new ArrayMap<String, Object>(); + mClassLoader = loader == null ? getClass().getClassLoader() : loader; + } + + /** + * Constructs a new, empty Bundle. + */ + CommonBundle() { + this((ClassLoader) null, 0); + } + + /** + * Constructs a Bundle whose data is stored as a Parcel. The data + * will be unparcelled on first contact, using the assigned ClassLoader. + * + * @param parcelledData a Parcel containing a Bundle + */ + CommonBundle(Parcel parcelledData) { + readFromParcelInner(parcelledData); + } + + CommonBundle(Parcel parcelledData, int length) { + readFromParcelInner(parcelledData, length); + } + + /** + * Constructs a new, empty Bundle that uses a specific ClassLoader for + * instantiating Parcelable and Serializable objects. + * + * @param loader An explicit ClassLoader to use when instantiating objects + * inside of the Bundle. + */ + CommonBundle(ClassLoader loader) { + this(loader, 0); + } + + /** + * Constructs a new, empty Bundle sized to hold the given number of + * elements. The Bundle will grow as needed. + * + * @param capacity the initial capacity of the Bundle + */ + CommonBundle(int capacity) { + this((ClassLoader) null, capacity); + } + + /** + * Constructs a Bundle containing a copy of the mappings from the given + * Bundle. + * + * @param b a Bundle to be copied. + */ + CommonBundle(CommonBundle b) { + if (b.mParcelledData != null) { + if (b.mParcelledData == EMPTY_PARCEL) { + mParcelledData = EMPTY_PARCEL; + } else { + mParcelledData = Parcel.obtain(); + mParcelledData.appendFrom(b.mParcelledData, 0, b.mParcelledData.dataSize()); + mParcelledData.setDataPosition(0); + } + } else { + mParcelledData = null; + } + + if (b.mMap != null) { + mMap = new ArrayMap<String, Object>(b.mMap); + } else { + mMap = null; + } + + mClassLoader = b.mClassLoader; + } + + /** + * TODO: optimize this later (getting just the value part of a Bundle + * with a single pair) once Bundle.forPair() above is implemented + * with a special single-value Map implementation/serialization. + * + * Note: value in single-pair Bundle may be null. + * + * @hide + */ + String getPairValue() { + unparcel(); + int size = mMap.size(); + if (size > 1) { + Log.w(TAG, "getPairValue() used on Bundle with multiple pairs."); + } + if (size == 0) { + return null; + } + Object o = mMap.valueAt(0); + try { + return (String) o; + } catch (ClassCastException e) { + typeWarning("getPairValue()", o, "String", e); + return null; + } + } + + /** + * Changes the ClassLoader this Bundle uses when instantiating objects. + * + * @param loader An explicit ClassLoader to use when instantiating objects + * inside of the Bundle. + */ + void setClassLoader(ClassLoader loader) { + mClassLoader = loader; + } + + /** + * Return the ClassLoader currently associated with this Bundle. + */ + ClassLoader getClassLoader() { + return mClassLoader; + } + + /** + * If the underlying data are stored as a Parcel, unparcel them + * using the currently assigned class loader. + */ + /* package */ synchronized void unparcel() { + if (mParcelledData == null) { + if (DEBUG) Log.d(TAG, "unparcel " + Integer.toHexString(System.identityHashCode(this)) + + ": no parcelled data"); + return; + } + + if (mParcelledData == EMPTY_PARCEL) { + if (DEBUG) Log.d(TAG, "unparcel " + Integer.toHexString(System.identityHashCode(this)) + + ": empty"); + if (mMap == null) { + mMap = new ArrayMap<String, Object>(1); + } else { + mMap.erase(); + } + mParcelledData = null; + return; + } + + int N = mParcelledData.readInt(); + if (DEBUG) Log.d(TAG, "unparcel " + Integer.toHexString(System.identityHashCode(this)) + + ": reading " + N + " maps"); + if (N < 0) { + return; + } + if (mMap == null) { + mMap = new ArrayMap<String, Object>(N); + } else { + mMap.erase(); + mMap.ensureCapacity(N); + } + mParcelledData.readArrayMapInternal(mMap, N, mClassLoader); + mParcelledData.recycle(); + mParcelledData = null; + if (DEBUG) Log.d(TAG, "unparcel " + Integer.toHexString(System.identityHashCode(this)) + + " final map: " + mMap); + } + + /** + * @hide + */ + boolean isParcelled() { + return mParcelledData != null; + } + + /** + * Returns the number of mappings contained in this Bundle. + * + * @return the number of mappings as an int. + */ + int size() { + unparcel(); + return mMap.size(); + } + + /** + * Returns true if the mapping of this Bundle is empty, false otherwise. + */ + boolean isEmpty() { + unparcel(); + return mMap.isEmpty(); + } + + /** + * Removes all elements from the mapping of this Bundle. + */ + void clear() { + unparcel(); + mMap.clear(); + } + + /** + * Returns true if the given key is contained in the mapping + * of this Bundle. + * + * @param key a String key + * @return true if the key is part of the mapping, false otherwise + */ + boolean containsKey(String key) { + unparcel(); + return mMap.containsKey(key); + } + + /** + * Returns the entry with the given key as an object. + * + * @param key a String key + * @return an Object, or null + */ + Object get(String key) { + unparcel(); + return mMap.get(key); + } + + /** + * Removes any entry with the given key from the mapping of this Bundle. + * + * @param key a String key + */ + void remove(String key) { + unparcel(); + mMap.remove(key); + } + + /** + * Inserts all mappings from the given PersistableBundle into this CommonBundle. + * + * @param bundle a PersistableBundle + */ + void putAll(PersistableBundle bundle) { + unparcel(); + bundle.unparcel(); + mMap.putAll(bundle.mMap); + } + + /** + * Returns a Set containing the Strings used as keys in this Bundle. + * + * @return a Set of String keys + */ + Set<String> keySet() { + unparcel(); + return mMap.keySet(); + } + + /** + * 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 + */ + void putBoolean(String key, boolean value) { + unparcel(); + mMap.put(key, value); + } + + /** + * Inserts a byte value into the mapping of this Bundle, replacing + * any existing value for the given key. + * + * @param key a String, or null + * @param value a byte + */ + void putByte(String key, byte value) { + unparcel(); + mMap.put(key, value); + } + + /** + * Inserts a char value into the mapping of this Bundle, replacing + * any existing value for the given key. + * + * @param key a String, or null + * @param value a char, or null + */ + void putChar(String key, char value) { + unparcel(); + mMap.put(key, value); + } + + /** + * Inserts a short value into the mapping of this Bundle, replacing + * any existing value for the given key. + * + * @param key a String, or null + * @param value a short + */ + void putShort(String key, short value) { + unparcel(); + mMap.put(key, value); + } + + /** + * Inserts an int value into the mapping of this Bundle, replacing + * any existing value for the given key. + * + * @param key a String, or null + * @param value an int, or null + */ + void putInt(String key, int value) { + unparcel(); + mMap.put(key, value); + } + + /** + * Inserts a long value into the mapping of this Bundle, replacing + * any existing value for the given key. + * + * @param key a String, or null + * @param value a long + */ + void putLong(String key, long value) { + unparcel(); + mMap.put(key, value); + } + + /** + * Inserts a float value into the mapping of this Bundle, replacing + * any existing value for the given key. + * + * @param key a String, or null + * @param value a float + */ + void putFloat(String key, float value) { + unparcel(); + mMap.put(key, value); + } + + /** + * Inserts a double value into the mapping of this Bundle, replacing + * any existing value for the given key. + * + * @param key a String, or null + * @param value a double + */ + void putDouble(String key, double value) { + unparcel(); + mMap.put(key, value); + } + + /** + * Inserts a String 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 String, or null + */ + void putString(String key, String value) { + unparcel(); + mMap.put(key, value); + } + + /** + * Inserts a CharSequence 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 CharSequence, or null + */ + void putCharSequence(String key, CharSequence value) { + unparcel(); + mMap.put(key, value); + } + + /** + * Inserts an ArrayList<Integer> 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 an ArrayList<Integer> object, or null + */ + void putIntegerArrayList(String key, ArrayList<Integer> value) { + unparcel(); + mMap.put(key, value); + } + + /** + * Inserts an ArrayList<String> 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 an ArrayList<String> object, or null + */ + void putStringArrayList(String key, ArrayList<String> value) { + unparcel(); + mMap.put(key, value); + } + + /** + * Inserts an ArrayList<CharSequence> 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 an ArrayList<CharSequence> object, or null + */ + void putCharSequenceArrayList(String key, ArrayList<CharSequence> value) { + unparcel(); + mMap.put(key, value); + } + + /** + * Inserts a Serializable 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 Serializable object, or null + */ + void putSerializable(String key, Serializable value) { + unparcel(); + mMap.put(key, value); + } + + /** + * 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 + */ + void putBooleanArray(String key, boolean[] value) { + unparcel(); + mMap.put(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. + * + * @param key a String, or null + * @param value a byte array object, or null + */ + void putByteArray(String key, byte[] value) { + unparcel(); + mMap.put(key, value); + } + + /** + * Inserts a short 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 short array object, or null + */ + void putShortArray(String key, short[] value) { + unparcel(); + mMap.put(key, value); + } + + /** + * Inserts a char 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 char array object, or null + */ + void putCharArray(String key, char[] value) { + unparcel(); + mMap.put(key, value); + } + + /** + * Inserts an int 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 an int array object, or null + */ + void putIntArray(String key, int[] value) { + unparcel(); + mMap.put(key, value); + } + + /** + * Inserts a long 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 long array object, or null + */ + void putLongArray(String key, long[] value) { + unparcel(); + mMap.put(key, value); + } + + /** + * Inserts a float 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 float array object, or null + */ + void putFloatArray(String key, float[] value) { + unparcel(); + mMap.put(key, value); + } + + /** + * Inserts a double 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 double array object, or null + */ + void putDoubleArray(String key, double[] value) { + unparcel(); + mMap.put(key, value); + } + + /** + * Inserts a String 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 String array object, or null + */ + void putStringArray(String key, String[] value) { + unparcel(); + mMap.put(key, value); + } + + /** + * Inserts a CharSequence 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 CharSequence array object, or null + */ + void putCharSequenceArray(String key, CharSequence[] value) { + unparcel(); + mMap.put(key, value); + } + + /** + * Inserts a PersistableBundle 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 Bundle object, or null + */ + void putPersistableBundle(String key, PersistableBundle value) { + unparcel(); + mMap.put(key, value); + } + + /** + * 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 + */ + boolean getBoolean(String key) { + unparcel(); + if (DEBUG) Log.d(TAG, "Getting boolean in " + + Integer.toHexString(System.identityHashCode(this))); + return getBoolean(key, false); + } + + // Log a message if the value was non-null but not of the expected type + void typeWarning(String key, Object value, String className, + Object defaultValue, ClassCastException e) { + StringBuilder sb = new StringBuilder(); + sb.append("Key "); + sb.append(key); + sb.append(" expected "); + sb.append(className); + sb.append(" but value was a "); + sb.append(value.getClass().getName()); + sb.append(". The default value "); + sb.append(defaultValue); + sb.append(" was returned."); + Log.w(TAG, sb.toString()); + Log.w(TAG, "Attempt to cast generated internal exception:", e); + } + + void typeWarning(String key, Object value, String className, + ClassCastException e) { + typeWarning(key, value, className, "<null>", e); + } + + /** + * 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 + */ + boolean getBoolean(String key, boolean defaultValue) { + unparcel(); + Object o = mMap.get(key); + if (o == null) { + return defaultValue; + } + try { + return (Boolean) o; + } catch (ClassCastException e) { + typeWarning(key, o, "Boolean", defaultValue, e); + return defaultValue; + } + } + + /** + * Returns the value associated with the given key, or (byte) 0 if + * no mapping of the desired type exists for the given key. + * + * @param key a String + * @return a byte value + */ + byte getByte(String key) { + unparcel(); + return getByte(key, (byte) 0); + } + + /** + * 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 byte value + */ + Byte getByte(String key, byte defaultValue) { + unparcel(); + Object o = mMap.get(key); + if (o == null) { + return defaultValue; + } + try { + return (Byte) o; + } catch (ClassCastException e) { + typeWarning(key, o, "Byte", defaultValue, e); + return defaultValue; + } + } + + /** + * Returns the value associated with the given key, or (char) 0 if + * no mapping of the desired type exists for the given key. + * + * @param key a String + * @return a char value + */ + char getChar(String key) { + unparcel(); + return getChar(key, (char) 0); + } + + /** + * 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 char value + */ + char getChar(String key, char defaultValue) { + unparcel(); + Object o = mMap.get(key); + if (o == null) { + return defaultValue; + } + try { + return (Character) o; + } catch (ClassCastException e) { + typeWarning(key, o, "Character", defaultValue, e); + return defaultValue; + } + } + + /** + * Returns the value associated with the given key, or (short) 0 if + * no mapping of the desired type exists for the given key. + * + * @param key a String + * @return a short value + */ + short getShort(String key) { + unparcel(); + return getShort(key, (short) 0); + } + + /** + * 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 short value + */ + short getShort(String key, short defaultValue) { + unparcel(); + Object o = mMap.get(key); + if (o == null) { + return defaultValue; + } + try { + return (Short) o; + } catch (ClassCastException e) { + typeWarning(key, o, "Short", defaultValue, e); + return defaultValue; + } + } + + /** + * Returns the value associated with the given key, or 0 if + * no mapping of the desired type exists for the given key. + * + * @param key a String + * @return an int value + */ + int getInt(String key) { + unparcel(); + return getInt(key, 0); + } + + /** + * 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 an int value + */ + int getInt(String key, int defaultValue) { + unparcel(); + Object o = mMap.get(key); + if (o == null) { + return defaultValue; + } + try { + return (Integer) o; + } catch (ClassCastException e) { + typeWarning(key, o, "Integer", defaultValue, e); + return defaultValue; + } + } + + /** + * Returns the value associated with the given key, or 0L if + * no mapping of the desired type exists for the given key. + * + * @param key a String + * @return a long value + */ + long getLong(String key) { + unparcel(); + return getLong(key, 0L); + } + + /** + * 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 long value + */ + long getLong(String key, long defaultValue) { + unparcel(); + Object o = mMap.get(key); + if (o == null) { + return defaultValue; + } + try { + return (Long) o; + } catch (ClassCastException e) { + typeWarning(key, o, "Long", defaultValue, e); + return defaultValue; + } + } + + /** + * Returns the value associated with the given key, or 0.0f if + * no mapping of the desired type exists for the given key. + * + * @param key a String + * @return a float value + */ + float getFloat(String key) { + unparcel(); + return getFloat(key, 0.0f); + } + + /** + * 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 float value + */ + float getFloat(String key, float defaultValue) { + unparcel(); + Object o = mMap.get(key); + if (o == null) { + return defaultValue; + } + try { + return (Float) o; + } catch (ClassCastException e) { + typeWarning(key, o, "Float", defaultValue, e); + return defaultValue; + } + } + + /** + * Returns the value associated with the given key, or 0.0 if + * no mapping of the desired type exists for the given key. + * + * @param key a String + * @return a double value + */ + double getDouble(String key) { + unparcel(); + return getDouble(key, 0.0); + } + + /** + * 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 double value + */ + double getDouble(String key, double defaultValue) { + unparcel(); + Object o = mMap.get(key); + if (o == null) { + return defaultValue; + } + try { + return (Double) o; + } catch (ClassCastException e) { + typeWarning(key, o, "Double", defaultValue, e); + return defaultValue; + } + } + + /** + * 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 String value, or null + */ + String getString(String key) { + unparcel(); + final Object o = mMap.get(key); + try { + return (String) o; + } catch (ClassCastException e) { + typeWarning(key, o, "String", e); + return null; + } + } + + /** + * 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, or null + * @param defaultValue Value to return if key does not exist + * @return the String value associated with the given key, or defaultValue + * if no valid String object is currently mapped to that key. + */ + String getString(String key, String defaultValue) { + final String s = getString(key); + return (s == null) ? defaultValue : s; + } + + /** + * 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 CharSequence value, or null + */ + CharSequence getCharSequence(String key) { + unparcel(); + final Object o = mMap.get(key); + try { + return (CharSequence) o; + } catch (ClassCastException e) { + typeWarning(key, o, "CharSequence", e); + return null; + } + } + + /** + * 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, or null + * @param defaultValue Value to return if key does not exist + * @return the CharSequence value associated with the given key, or defaultValue + * if no valid CharSequence object is currently mapped to that key. + */ + CharSequence getCharSequence(String key, CharSequence defaultValue) { + final CharSequence cs = getCharSequence(key); + return (cs == null) ? defaultValue : cs; + } + + /** + * 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 Bundle value, or null + */ + PersistableBundle getPersistableBundle(String key) { + unparcel(); + Object o = mMap.get(key); + if (o == null) { + return null; + } + try { + return (PersistableBundle) o; + } catch (ClassCastException e) { + typeWarning(key, o, "Bundle", e); + return null; + } + } + + /** + * 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 Serializable value, or null + */ + Serializable getSerializable(String key) { + unparcel(); + Object o = mMap.get(key); + if (o == null) { + return null; + } + try { + return (Serializable) o; + } catch (ClassCastException e) { + typeWarning(key, o, "Serializable", e); + return null; + } + } + + /** + * 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 an ArrayList<String> value, or null + */ + ArrayList<Integer> getIntegerArrayList(String key) { + unparcel(); + Object o = mMap.get(key); + if (o == null) { + return null; + } + try { + return (ArrayList<Integer>) o; + } catch (ClassCastException e) { + typeWarning(key, o, "ArrayList<Integer>", e); + return null; + } + } + + /** + * 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 an ArrayList<String> value, or null + */ + ArrayList<String> getStringArrayList(String key) { + unparcel(); + Object o = mMap.get(key); + if (o == null) { + return null; + } + try { + return (ArrayList<String>) o; + } catch (ClassCastException e) { + typeWarning(key, o, "ArrayList<String>", e); + return null; + } + } + + /** + * 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 an ArrayList<CharSequence> value, or null + */ + ArrayList<CharSequence> getCharSequenceArrayList(String key) { + unparcel(); + Object o = mMap.get(key); + if (o == null) { + return null; + } + try { + return (ArrayList<CharSequence>) o; + } catch (ClassCastException e) { + typeWarning(key, o, "ArrayList<CharSequence>", e); + return null; + } + } + + /** + * 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 boolean[] value, or null + */ + boolean[] getBooleanArray(String key) { + unparcel(); + Object o = mMap.get(key); + if (o == null) { + return null; + } + try { + return (boolean[]) o; + } catch (ClassCastException e) { + typeWarning(key, o, "byte[]", e); + return null; + } + } + + /** + * 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 + */ + byte[] getByteArray(String key) { + unparcel(); + Object o = mMap.get(key); + if (o == null) { + return null; + } + try { + return (byte[]) o; + } catch (ClassCastException e) { + typeWarning(key, o, "byte[]", e); + return null; + } + } + + /** + * 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 short[] value, or null + */ + short[] getShortArray(String key) { + unparcel(); + Object o = mMap.get(key); + if (o == null) { + return null; + } + try { + return (short[]) o; + } catch (ClassCastException e) { + typeWarning(key, o, "short[]", e); + return null; + } + } + + /** + * 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 char[] value, or null + */ + char[] getCharArray(String key) { + unparcel(); + Object o = mMap.get(key); + if (o == null) { + return null; + } + try { + return (char[]) o; + } catch (ClassCastException e) { + typeWarning(key, o, "char[]", e); + return null; + } + } + + /** + * 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 an int[] value, or null + */ + int[] getIntArray(String key) { + unparcel(); + Object o = mMap.get(key); + if (o == null) { + return null; + } + try { + return (int[]) o; + } catch (ClassCastException e) { + typeWarning(key, o, "int[]", e); + return null; + } + } + + /** + * 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 long[] value, or null + */ + long[] getLongArray(String key) { + unparcel(); + Object o = mMap.get(key); + if (o == null) { + return null; + } + try { + return (long[]) o; + } catch (ClassCastException e) { + typeWarning(key, o, "long[]", e); + return null; + } + } + + /** + * 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 float[] value, or null + */ + float[] getFloatArray(String key) { + unparcel(); + Object o = mMap.get(key); + if (o == null) { + return null; + } + try { + return (float[]) o; + } catch (ClassCastException e) { + typeWarning(key, o, "float[]", e); + return null; + } + } + + /** + * 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 double[] value, or null + */ + double[] getDoubleArray(String key) { + unparcel(); + Object o = mMap.get(key); + if (o == null) { + return null; + } + try { + return (double[]) o; + } catch (ClassCastException e) { + typeWarning(key, o, "double[]", e); + return null; + } + } + + /** + * 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 String[] value, or null + */ + String[] getStringArray(String key) { + unparcel(); + Object o = mMap.get(key); + if (o == null) { + return null; + } + try { + return (String[]) o; + } catch (ClassCastException e) { + typeWarning(key, o, "String[]", e); + return null; + } + } + + /** + * 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 CharSequence[] value, or null + */ + CharSequence[] getCharSequenceArray(String key) { + unparcel(); + Object o = mMap.get(key); + if (o == null) { + return null; + } + try { + return (CharSequence[]) o; + } catch (ClassCastException e) { + typeWarning(key, o, "CharSequence[]", e); + return null; + } + } + + /** + * Writes the Bundle contents to a Parcel, typically in order for + * it to be passed through an IBinder connection. + * @param parcel The parcel to copy this bundle to. + */ + void writeToParcelInner(Parcel parcel, int flags) { + if (mParcelledData != null) { + if (mParcelledData == EMPTY_PARCEL) { + parcel.writeInt(0); + } else { + int length = mParcelledData.dataSize(); + parcel.writeInt(length); + parcel.writeInt(BUNDLE_MAGIC); + parcel.appendFrom(mParcelledData, 0, length); + } + } else { + // Special case for empty bundles. + if (mMap == null || mMap.size() <= 0) { + parcel.writeInt(0); + return; + } + int lengthPos = parcel.dataPosition(); + parcel.writeInt(-1); // dummy, will hold length + parcel.writeInt(BUNDLE_MAGIC); + + int startPos = parcel.dataPosition(); + parcel.writeArrayMapInternal(mMap); + int endPos = parcel.dataPosition(); + + // Backpatch length + parcel.setDataPosition(lengthPos); + int length = endPos - startPos; + parcel.writeInt(length); + parcel.setDataPosition(endPos); + } + } + + /** + * Reads the Parcel contents into this Bundle, typically in order for + * it to be passed through an IBinder connection. + * @param parcel The parcel to overwrite this bundle from. + */ + void readFromParcelInner(Parcel parcel) { + int length = parcel.readInt(); + if (length < 0) { + throw new RuntimeException("Bad length in parcel: " + length); + } + readFromParcelInner(parcel, length); + } + + private void readFromParcelInner(Parcel parcel, int length) { + if (length == 0) { + // Empty Bundle or end of data. + mParcelledData = EMPTY_PARCEL; + return; + } + int magic = parcel.readInt(); + if (magic != BUNDLE_MAGIC) { + //noinspection ThrowableInstanceNeverThrown + throw new IllegalStateException("Bad magic number for Bundle: 0x" + + Integer.toHexString(magic)); + } + + // Advance within this Parcel + int offset = parcel.dataPosition(); + parcel.setDataPosition(offset + length); + + Parcel p = Parcel.obtain(); + p.setDataPosition(0); + p.appendFrom(parcel, offset, length); + if (DEBUG) Log.d(TAG, "Retrieving " + Integer.toHexString(System.identityHashCode(this)) + + ": " + length + " bundle bytes starting at " + offset); + p.setDataPosition(0); + + mParcelledData = p; + } +} diff --git a/core/java/android/os/Parcel.java b/core/java/android/os/Parcel.java index 8e0ff08..95cb9f3 100644 --- a/core/java/android/os/Parcel.java +++ b/core/java/android/os/Parcel.java @@ -223,6 +223,7 @@ public final class Parcel { private static final int VAL_SPARSEBOOLEANARRAY = 22; private static final int VAL_BOOLEANARRAY = 23; private static final int VAL_CHARSEQUENCEARRAY = 24; + private static final int VAL_PERSISTABLEBUNDLE = 25; // The initial int32 in a Binder call's reply Parcel header: private static final int EX_SECURITY = -1; @@ -638,6 +639,19 @@ public final class Parcel { } /** + * Flatten a PersistableBundle into the parcel at the current dataPosition(), + * growing dataCapacity() if needed. + */ + public final void writePersistableBundle(PersistableBundle val) { + if (val == null) { + writeInt(-1); + return; + } + + val.writeToParcel(this, 0); + } + + /** * Flatten a List into the parcel at the current dataPosition(), growing * dataCapacity() if needed. The List values are written using * {@link #writeValue} and must follow the specification there. @@ -1256,6 +1270,9 @@ public final class Parcel { } else if (v instanceof Byte) { writeInt(VAL_BYTE); writeInt((Byte) v); + } else if (v instanceof PersistableBundle) { + writeInt(VAL_PERSISTABLEBUNDLE); + writePersistableBundle((PersistableBundle) v); } else { Class<?> clazz = v.getClass(); if (clazz.isArray() && clazz.getComponentType() == Object.class) { @@ -1633,6 +1650,35 @@ public final class Parcel { } /** + * Read and return a new Bundle object from the parcel at the current + * dataPosition(). Returns null if the previously written Bundle object was + * null. + */ + public final PersistableBundle readPersistableBundle() { + return readPersistableBundle(null); + } + + /** + * Read and return a new Bundle object from the parcel at the current + * dataPosition(), using the given class loader to initialize the class + * loader of the Bundle for later retrieval of Parcelable objects. + * Returns null if the previously written Bundle object was null. + */ + public final PersistableBundle readPersistableBundle(ClassLoader loader) { + int length = readInt(); + if (length < 0) { + if (Bundle.DEBUG) Log.d(TAG, "null bundle: length=" + length); + return null; + } + + final PersistableBundle bundle = new PersistableBundle(this, length); + if (loader != null) { + bundle.setClassLoader(loader); + } + return bundle; + } + + /** * Read and return a byte[] object from the parcel. */ public final byte[] createByteArray() { @@ -2082,6 +2128,9 @@ public final class Parcel { case VAL_BUNDLE: return readBundle(loader); // loading will be deferred + case VAL_PERSISTABLEBUNDLE: + return readPersistableBundle(loader); + default: int off = dataPosition() - 4; throw new RuntimeException( diff --git a/core/java/android/os/PersistableBundle.java b/core/java/android/os/PersistableBundle.java new file mode 100644 index 0000000..c2cd3be --- /dev/null +++ b/core/java/android/os/PersistableBundle.java @@ -0,0 +1,555 @@ +/* + * Copyright (C) 2014 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.os; + +import android.util.ArrayMap; + +import java.util.Set; + +/** + * A mapping from String values to various types that can be saved to persistent and later + * restored. + * + */ +public final class PersistableBundle extends CommonBundle { + public static final PersistableBundle EMPTY; + static final Parcel EMPTY_PARCEL; + + static { + EMPTY = new PersistableBundle(); + EMPTY.mMap = ArrayMap.EMPTY; + EMPTY_PARCEL = CommonBundle.EMPTY_PARCEL; + } + + /** + * Constructs a new, empty PersistableBundle. + */ + public PersistableBundle() { + super(); + } + + /** + * Constructs a PersistableBundle whose data is stored as a Parcel. The data + * will be unparcelled on first contact, using the assigned ClassLoader. + * + * @param parcelledData a Parcel containing a PersistableBundle + */ + PersistableBundle(Parcel parcelledData) { + super(parcelledData); + } + + /* package */ PersistableBundle(Parcel parcelledData, int length) { + super(parcelledData, length); + } + + /** + * Constructs a new, empty PersistableBundle that uses a specific ClassLoader for + * instantiating Parcelable and Serializable objects. + * + * @param loader An explicit ClassLoader to use when instantiating objects + * inside of the PersistableBundle. + */ + public PersistableBundle(ClassLoader loader) { + super(loader); + } + + /** + * Constructs a new, empty PersistableBundle sized to hold the given number of + * elements. The PersistableBundle will grow as needed. + * + * @param capacity the initial capacity of the PersistableBundle + */ + public PersistableBundle(int capacity) { + super(capacity); + } + + /** + * Constructs a PersistableBundle containing a copy of the mappings from the given + * PersistableBundle. + * + * @param b a PersistableBundle to be copied. + */ + public PersistableBundle(PersistableBundle b) { + super(b); + } + + /** + * Make a PersistableBundle for a single key/value pair. + * + * @hide + */ + public static PersistableBundle forPair(String key, String value) { + PersistableBundle b = new PersistableBundle(1); + b.putString(key, value); + return b; + } + + /** + * @hide + */ + @Override + public String getPairValue() { + return super.getPairValue(); + } + + /** + * Changes the ClassLoader this PersistableBundle uses when instantiating objects. + * + * @param loader An explicit ClassLoader to use when instantiating objects + * inside of the PersistableBundle. + */ + @Override + public void setClassLoader(ClassLoader loader) { + super.setClassLoader(loader); + } + + /** + * Return the ClassLoader currently associated with this PersistableBundle. + */ + @Override + public ClassLoader getClassLoader() { + return super.getClassLoader(); + } + + /** + * Clones the current PersistableBundle. The internal map is cloned, but the keys and + * values to which it refers are copied by reference. + */ + @Override + public Object clone() { + return new PersistableBundle(this); + } + + /** + * @hide + */ + @Override + public boolean isParcelled() { + return super.isParcelled(); + } + + /** + * Returns the number of mappings contained in this PersistableBundle. + * + * @return the number of mappings as an int. + */ + @Override + public int size() { + return super.size(); + } + + /** + * Returns true if the mapping of this PersistableBundle is empty, false otherwise. + */ + @Override + public boolean isEmpty() { + return super.isEmpty(); + } + + /** + * Removes all elements from the mapping of this PersistableBundle. + */ + @Override + public void clear() { + super.clear(); + } + + /** + * Returns true if the given key is contained in the mapping + * of this PersistableBundle. + * + * @param key a String key + * @return true if the key is part of the mapping, false otherwise + */ + @Override + public boolean containsKey(String key) { + return super.containsKey(key); + } + + /** + * Returns the entry with the given key as an object. + * + * @param key a String key + * @return an Object, or null + */ + @Override + public Object get(String key) { + return super.get(key); + } + + /** + * Removes any entry with the given key from the mapping of this PersistableBundle. + * + * @param key a String key + */ + @Override + public void remove(String key) { + super.remove(key); + } + + /** + * Inserts all mappings from the given PersistableBundle into this Bundle. + * + * @param bundle a PersistableBundle + */ + public void putAll(PersistableBundle bundle) { + super.putAll(bundle); + } + + /** + * Returns a Set containing the Strings used as keys in this PersistableBundle. + * + * @return a Set of String keys + */ + @Override + public Set<String> keySet() { + return super.keySet(); + } + + /** + * Inserts an int value into the mapping of this PersistableBundle, replacing + * any existing value for the given key. + * + * @param key a String, or null + * @param value an int, or null + */ + @Override + public void putInt(String key, int value) { + super.putInt(key, value); + } + + /** + * Inserts a long value into the mapping of this PersistableBundle, replacing + * any existing value for the given key. + * + * @param key a String, or null + * @param value a long + */ + @Override + public void putLong(String key, long value) { + super.putLong(key, value); + } + + /** + * Inserts a double value into the mapping of this PersistableBundle, replacing + * any existing value for the given key. + * + * @param key a String, or null + * @param value a double + */ + @Override + public void putDouble(String key, double value) { + super.putDouble(key, value); + } + + /** + * Inserts a String value into the mapping of this PersistableBundle, replacing + * any existing value for the given key. Either key or value may be null. + * + * @param key a String, or null + * @param value a String, or null + */ + @Override + public void putString(String key, String value) { + super.putString(key, value); + } + + /** + * Inserts an int array value into the mapping of this PersistableBundle, replacing + * any existing value for the given key. Either key or value may be null. + * + * @param key a String, or null + * @param value an int array object, or null + */ + @Override + public void putIntArray(String key, int[] value) { + super.putIntArray(key, value); + } + + /** + * Inserts a long array value into the mapping of this PersistableBundle, replacing + * any existing value for the given key. Either key or value may be null. + * + * @param key a String, or null + * @param value a long array object, or null + */ + @Override + public void putLongArray(String key, long[] value) { + super.putLongArray(key, value); + } + + /** + * Inserts a double array value into the mapping of this PersistableBundle, replacing + * any existing value for the given key. Either key or value may be null. + * + * @param key a String, or null + * @param value a double array object, or null + */ + @Override + public void putDoubleArray(String key, double[] value) { + super.putDoubleArray(key, value); + } + + /** + * Inserts a String array value into the mapping of this PersistableBundle, replacing + * any existing value for the given key. Either key or value may be null. + * + * @param key a String, or null + * @param value a String array object, or null + */ + @Override + public void putStringArray(String key, String[] value) { + super.putStringArray(key, value); + } + + /** + * Inserts a PersistableBundle 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 Bundle object, or null + */ + public void putPersistableBundle(String key, PersistableBundle value) { + super.putPersistableBundle(key, value); + } + + /** + * Returns the value associated with the given key, or 0 if + * no mapping of the desired type exists for the given key. + * + * @param key a String + * @return an int value + */ + @Override + public int getInt(String key) { + return super.getInt(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 an int value + */ + @Override + public int getInt(String key, int defaultValue) { + return super.getInt(key, defaultValue); + } + + /** + * Returns the value associated with the given key, or 0L if + * no mapping of the desired type exists for the given key. + * + * @param key a String + * @return a long value + */ + @Override + public long getLong(String key) { + return super.getLong(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 long value + */ + @Override + public long getLong(String key, long defaultValue) { + return super.getLong(key, defaultValue); + } + + /** + * Returns the value associated with the given key, or 0.0 if + * no mapping of the desired type exists for the given key. + * + * @param key a String + * @return a double value + */ + @Override + public double getDouble(String key) { + return super.getDouble(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 double value + */ + @Override + public double getDouble(String key, double defaultValue) { + return super.getDouble(key, defaultValue); + } + + /** + * 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 String value, or null + */ + @Override + public String getString(String key) { + return super.getString(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, or null + * @param defaultValue Value to return if key does not exist + * @return the String value associated with the given key, or defaultValue + * if no valid String object is currently mapped to that key. + */ + @Override + public String getString(String key, String defaultValue) { + return super.getString(key, defaultValue); + } + + /** + * 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 Bundle value, or null + */ + @Override + public PersistableBundle getPersistableBundle(String key) { + return super.getPersistableBundle(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 an int[] value, or null + */ + @Override + public int[] getIntArray(String key) { + return super.getIntArray(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 long[] value, or null + */ + @Override + public long[] getLongArray(String key) { + return super.getLongArray(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 double[] value, or null + */ + @Override + public double[] getDoubleArray(String key) { + return super.getDoubleArray(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 String[] value, or null + */ + @Override + public String[] getStringArray(String key) { + return super.getStringArray(key); + } + + public static final Parcelable.Creator<PersistableBundle> CREATOR = + new Parcelable.Creator<PersistableBundle>() { + @Override + public PersistableBundle createFromParcel(Parcel in) { + return in.readPersistableBundle(); + } + + @Override + public PersistableBundle[] newArray(int size) { + return new PersistableBundle[size]; + } + }; + + /** + * Report the nature of this Parcelable's contents + */ + @Override + public int describeContents() { + return 0; + } + + /** + * Writes the PersistableBundle contents to a Parcel, typically in order for + * it to be passed through an IBinder connection. + * @param parcel The parcel to copy this bundle to. + */ + @Override + public void writeToParcel(Parcel parcel, int flags) { + final boolean oldAllowFds = parcel.pushAllowFds(false); + try { + super.writeToParcelInner(parcel, flags); + } finally { + parcel.restoreAllowFds(oldAllowFds); + } + } + + /** + * Reads the Parcel contents into this PersistableBundle, typically in order for + * it to be passed through an IBinder connection. + * @param parcel The parcel to overwrite this bundle from. + */ + public void readFromParcel(Parcel parcel) { + super.readFromParcelInner(parcel); + } + + @Override + synchronized public String toString() { + if (mParcelledData != null) { + if (mParcelledData == EMPTY_PARCEL) { + return "PersistableBundle[EMPTY_PARCEL]"; + } else { + return "PersistableBundle[mParcelledData.dataSize=" + + mParcelledData.dataSize() + "]"; + } + } + return "PersistableBundle[" + mMap.toString() + "]"; + } + +} |