Home | History | Annotate | Download | only in os
      1 /*
      2  * Copyright (C) 2014 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 package android.os;
     18 
     19 import android.util.ArrayMap;
     20 import android.util.Log;
     21 
     22 import java.io.Serializable;
     23 import java.util.ArrayList;
     24 import java.util.Map;
     25 import java.util.Set;
     26 
     27 /**
     28  * A mapping from String values to various types.
     29  */
     30 public class BaseBundle {
     31     private static final String TAG = "Bundle";
     32     static final boolean DEBUG = false;
     33 
     34     static final int BUNDLE_MAGIC = 0x4C444E42; // 'B' 'N' 'D' 'L'
     35     static final Parcel EMPTY_PARCEL;
     36 
     37     static {
     38         EMPTY_PARCEL = Parcel.obtain();
     39     }
     40 
     41     // Invariant - exactly one of mMap / mParcelledData will be null
     42     // (except inside a call to unparcel)
     43 
     44     ArrayMap<String, Object> mMap = null;
     45 
     46     /*
     47      * If mParcelledData is non-null, then mMap will be null and the
     48      * data are stored as a Parcel containing a Bundle.  When the data
     49      * are unparcelled, mParcelledData willbe set to null.
     50      */
     51     Parcel mParcelledData = null;
     52 
     53     /**
     54      * The ClassLoader used when unparcelling data from mParcelledData.
     55      */
     56     private ClassLoader mClassLoader;
     57 
     58     /**
     59      * Constructs a new, empty Bundle that uses a specific ClassLoader for
     60      * instantiating Parcelable and Serializable objects.
     61      *
     62      * @param loader An explicit ClassLoader to use when instantiating objects
     63      * inside of the Bundle.
     64      * @param capacity Initial size of the ArrayMap.
     65      */
     66     BaseBundle(ClassLoader loader, int capacity) {
     67         mMap = capacity > 0 ?
     68                 new ArrayMap<String, Object>(capacity) : new ArrayMap<String, Object>();
     69         mClassLoader = loader == null ? getClass().getClassLoader() : loader;
     70     }
     71 
     72     /**
     73      * Constructs a new, empty Bundle.
     74      */
     75     BaseBundle() {
     76         this((ClassLoader) null, 0);
     77     }
     78 
     79     /**
     80      * Constructs a Bundle whose data is stored as a Parcel.  The data
     81      * will be unparcelled on first contact, using the assigned ClassLoader.
     82      *
     83      * @param parcelledData a Parcel containing a Bundle
     84      */
     85     BaseBundle(Parcel parcelledData) {
     86         readFromParcelInner(parcelledData);
     87     }
     88 
     89     BaseBundle(Parcel parcelledData, int length) {
     90         readFromParcelInner(parcelledData, length);
     91     }
     92 
     93     /**
     94      * Constructs a new, empty Bundle that uses a specific ClassLoader for
     95      * instantiating Parcelable and Serializable objects.
     96      *
     97      * @param loader An explicit ClassLoader to use when instantiating objects
     98      * inside of the Bundle.
     99      */
    100     BaseBundle(ClassLoader loader) {
    101         this(loader, 0);
    102     }
    103 
    104     /**
    105      * Constructs a new, empty Bundle sized to hold the given number of
    106      * elements. The Bundle will grow as needed.
    107      *
    108      * @param capacity the initial capacity of the Bundle
    109      */
    110     BaseBundle(int capacity) {
    111         this((ClassLoader) null, capacity);
    112     }
    113 
    114     /**
    115      * Constructs a Bundle containing a copy of the mappings from the given
    116      * Bundle.
    117      *
    118      * @param b a Bundle to be copied.
    119      */
    120     BaseBundle(BaseBundle b) {
    121         if (b.mParcelledData != null) {
    122             if (b.mParcelledData == EMPTY_PARCEL) {
    123                 mParcelledData = EMPTY_PARCEL;
    124             } else {
    125                 mParcelledData = Parcel.obtain();
    126                 mParcelledData.appendFrom(b.mParcelledData, 0, b.mParcelledData.dataSize());
    127                 mParcelledData.setDataPosition(0);
    128             }
    129         } else {
    130             mParcelledData = null;
    131         }
    132 
    133         if (b.mMap != null) {
    134             mMap = new ArrayMap<String, Object>(b.mMap);
    135         } else {
    136             mMap = null;
    137         }
    138 
    139         mClassLoader = b.mClassLoader;
    140     }
    141 
    142     /**
    143      * TODO: optimize this later (getting just the value part of a Bundle
    144      * with a single pair) once Bundle.forPair() above is implemented
    145      * with a special single-value Map implementation/serialization.
    146      *
    147      * Note: value in single-pair Bundle may be null.
    148      *
    149      * @hide
    150      */
    151     public String getPairValue() {
    152         unparcel();
    153         int size = mMap.size();
    154         if (size > 1) {
    155             Log.w(TAG, "getPairValue() used on Bundle with multiple pairs.");
    156         }
    157         if (size == 0) {
    158             return null;
    159         }
    160         Object o = mMap.valueAt(0);
    161         try {
    162             return (String) o;
    163         } catch (ClassCastException e) {
    164             typeWarning("getPairValue()", o, "String", e);
    165             return null;
    166         }
    167     }
    168 
    169     /**
    170      * Changes the ClassLoader this Bundle uses when instantiating objects.
    171      *
    172      * @param loader An explicit ClassLoader to use when instantiating objects
    173      * inside of the Bundle.
    174      */
    175     void setClassLoader(ClassLoader loader) {
    176         mClassLoader = loader;
    177     }
    178 
    179     /**
    180      * Return the ClassLoader currently associated with this Bundle.
    181      */
    182     ClassLoader getClassLoader() {
    183         return mClassLoader;
    184     }
    185 
    186     /**
    187      * If the underlying data are stored as a Parcel, unparcel them
    188      * using the currently assigned class loader.
    189      */
    190     /* package */ synchronized void unparcel() {
    191         if (mParcelledData == null) {
    192             if (DEBUG) Log.d(TAG, "unparcel " + Integer.toHexString(System.identityHashCode(this))
    193                     + ": no parcelled data");
    194             return;
    195         }
    196 
    197         if (mParcelledData == EMPTY_PARCEL) {
    198             if (DEBUG) Log.d(TAG, "unparcel " + Integer.toHexString(System.identityHashCode(this))
    199                     + ": empty");
    200             if (mMap == null) {
    201                 mMap = new ArrayMap<String, Object>(1);
    202             } else {
    203                 mMap.erase();
    204             }
    205             mParcelledData = null;
    206             return;
    207         }
    208 
    209         int N = mParcelledData.readInt();
    210         if (DEBUG) Log.d(TAG, "unparcel " + Integer.toHexString(System.identityHashCode(this))
    211                 + ": reading " + N + " maps");
    212         if (N < 0) {
    213             return;
    214         }
    215         if (mMap == null) {
    216             mMap = new ArrayMap<String, Object>(N);
    217         } else {
    218             mMap.erase();
    219             mMap.ensureCapacity(N);
    220         }
    221         mParcelledData.readArrayMapInternal(mMap, N, mClassLoader);
    222         mParcelledData.recycle();
    223         mParcelledData = null;
    224         if (DEBUG) Log.d(TAG, "unparcel " + Integer.toHexString(System.identityHashCode(this))
    225                 + " final map: " + mMap);
    226     }
    227 
    228     /**
    229      * @hide
    230      */
    231     public boolean isParcelled() {
    232         return mParcelledData != null;
    233     }
    234 
    235     /**
    236      * Returns the number of mappings contained in this Bundle.
    237      *
    238      * @return the number of mappings as an int.
    239      */
    240     public int size() {
    241         unparcel();
    242         return mMap.size();
    243     }
    244 
    245     /**
    246      * Returns true if the mapping of this Bundle is empty, false otherwise.
    247      */
    248     public boolean isEmpty() {
    249         unparcel();
    250         return mMap.isEmpty();
    251     }
    252 
    253     /**
    254      * Removes all elements from the mapping of this Bundle.
    255      */
    256     public void clear() {
    257         unparcel();
    258         mMap.clear();
    259     }
    260 
    261     /**
    262      * Returns true if the given key is contained in the mapping
    263      * of this Bundle.
    264      *
    265      * @param key a String key
    266      * @return true if the key is part of the mapping, false otherwise
    267      */
    268     public boolean containsKey(String key) {
    269         unparcel();
    270         return mMap.containsKey(key);
    271     }
    272 
    273     /**
    274      * Returns the entry with the given key as an object.
    275      *
    276      * @param key a String key
    277      * @return an Object, or null
    278      */
    279     public Object get(String key) {
    280         unparcel();
    281         return mMap.get(key);
    282     }
    283 
    284     /**
    285      * Removes any entry with the given key from the mapping of this Bundle.
    286      *
    287      * @param key a String key
    288      */
    289     public void remove(String key) {
    290         unparcel();
    291         mMap.remove(key);
    292     }
    293 
    294     /**
    295      * Inserts all mappings from the given PersistableBundle into this BaseBundle.
    296      *
    297      * @param bundle a PersistableBundle
    298      */
    299     public void putAll(PersistableBundle bundle) {
    300         unparcel();
    301         bundle.unparcel();
    302         mMap.putAll(bundle.mMap);
    303     }
    304 
    305     /**
    306      * Inserts all mappings from the given Map into this BaseBundle.
    307      *
    308      * @param map a Map
    309      */
    310     void putAll(Map map) {
    311         unparcel();
    312         mMap.putAll(map);
    313     }
    314 
    315     /**
    316      * Returns a Set containing the Strings used as keys in this Bundle.
    317      *
    318      * @return a Set of String keys
    319      */
    320     public Set<String> keySet() {
    321         unparcel();
    322         return mMap.keySet();
    323     }
    324 
    325     /**
    326      * Inserts a Boolean value into the mapping of this Bundle, replacing
    327      * any existing value for the given key.  Either key or value may be null.
    328      *
    329      * @param key a String, or null
    330      * @param value a Boolean, or null
    331      */
    332     public void putBoolean(String key, boolean value) {
    333         unparcel();
    334         mMap.put(key, value);
    335     }
    336 
    337     /**
    338      * Inserts a byte value into the mapping of this Bundle, replacing
    339      * any existing value for the given key.
    340      *
    341      * @param key a String, or null
    342      * @param value a byte
    343      */
    344     void putByte(String key, byte value) {
    345         unparcel();
    346         mMap.put(key, value);
    347     }
    348 
    349     /**
    350      * Inserts a char value into the mapping of this Bundle, replacing
    351      * any existing value for the given key.
    352      *
    353      * @param key a String, or null
    354      * @param value a char, or null
    355      */
    356     void putChar(String key, char value) {
    357         unparcel();
    358         mMap.put(key, value);
    359     }
    360 
    361     /**
    362      * Inserts a short value into the mapping of this Bundle, replacing
    363      * any existing value for the given key.
    364      *
    365      * @param key a String, or null
    366      * @param value a short
    367      */
    368     void putShort(String key, short value) {
    369         unparcel();
    370         mMap.put(key, value);
    371     }
    372 
    373     /**
    374      * Inserts an int value into the mapping of this Bundle, replacing
    375      * any existing value for the given key.
    376      *
    377      * @param key a String, or null
    378      * @param value an int, or null
    379      */
    380     public void putInt(String key, int value) {
    381         unparcel();
    382         mMap.put(key, value);
    383     }
    384 
    385     /**
    386      * Inserts a long value into the mapping of this Bundle, replacing
    387      * any existing value for the given key.
    388      *
    389      * @param key a String, or null
    390      * @param value a long
    391      */
    392     public void putLong(String key, long value) {
    393         unparcel();
    394         mMap.put(key, value);
    395     }
    396 
    397     /**
    398      * Inserts a float value into the mapping of this Bundle, replacing
    399      * any existing value for the given key.
    400      *
    401      * @param key a String, or null
    402      * @param value a float
    403      */
    404     void putFloat(String key, float value) {
    405         unparcel();
    406         mMap.put(key, value);
    407     }
    408 
    409     /**
    410      * Inserts a double value into the mapping of this Bundle, replacing
    411      * any existing value for the given key.
    412      *
    413      * @param key a String, or null
    414      * @param value a double
    415      */
    416     public void putDouble(String key, double value) {
    417         unparcel();
    418         mMap.put(key, value);
    419     }
    420 
    421     /**
    422      * Inserts a String value into the mapping of this Bundle, replacing
    423      * any existing value for the given key.  Either key or value may be null.
    424      *
    425      * @param key a String, or null
    426      * @param value a String, or null
    427      */
    428     public void putString(String key, String value) {
    429         unparcel();
    430         mMap.put(key, value);
    431     }
    432 
    433     /**
    434      * Inserts a CharSequence value into the mapping of this Bundle, replacing
    435      * any existing value for the given key.  Either key or value may be null.
    436      *
    437      * @param key a String, or null
    438      * @param value a CharSequence, or null
    439      */
    440     void putCharSequence(String key, CharSequence value) {
    441         unparcel();
    442         mMap.put(key, value);
    443     }
    444 
    445     /**
    446      * Inserts an ArrayList<Integer> value into the mapping of this Bundle, replacing
    447      * any existing value for the given key.  Either key or value may be null.
    448      *
    449      * @param key a String, or null
    450      * @param value an ArrayList<Integer> object, or null
    451      */
    452     void putIntegerArrayList(String key, ArrayList<Integer> value) {
    453         unparcel();
    454         mMap.put(key, value);
    455     }
    456 
    457     /**
    458      * Inserts an ArrayList<String> value into the mapping of this Bundle, replacing
    459      * any existing value for the given key.  Either key or value may be null.
    460      *
    461      * @param key a String, or null
    462      * @param value an ArrayList<String> object, or null
    463      */
    464     void putStringArrayList(String key, ArrayList<String> value) {
    465         unparcel();
    466         mMap.put(key, value);
    467     }
    468 
    469     /**
    470      * Inserts an ArrayList<CharSequence> value into the mapping of this Bundle, replacing
    471      * any existing value for the given key.  Either key or value may be null.
    472      *
    473      * @param key a String, or null
    474      * @param value an ArrayList<CharSequence> object, or null
    475      */
    476     void putCharSequenceArrayList(String key, ArrayList<CharSequence> value) {
    477         unparcel();
    478         mMap.put(key, value);
    479     }
    480 
    481     /**
    482      * Inserts a Serializable value into the mapping of this Bundle, replacing
    483      * any existing value for the given key.  Either key or value may be null.
    484      *
    485      * @param key a String, or null
    486      * @param value a Serializable object, or null
    487      */
    488     void putSerializable(String key, Serializable value) {
    489         unparcel();
    490         mMap.put(key, value);
    491     }
    492 
    493     /**
    494      * Inserts a boolean array value into the mapping of this Bundle, replacing
    495      * any existing value for the given key.  Either key or value may be null.
    496      *
    497      * @param key a String, or null
    498      * @param value a boolean array object, or null
    499      */
    500     public void putBooleanArray(String key, boolean[] value) {
    501         unparcel();
    502         mMap.put(key, value);
    503     }
    504 
    505     /**
    506      * Inserts a byte array value into the mapping of this Bundle, replacing
    507      * any existing value for the given key.  Either key or value may be null.
    508      *
    509      * @param key a String, or null
    510      * @param value a byte array object, or null
    511      */
    512     void putByteArray(String key, byte[] value) {
    513         unparcel();
    514         mMap.put(key, value);
    515     }
    516 
    517     /**
    518      * Inserts a short array value into the mapping of this Bundle, replacing
    519      * any existing value for the given key.  Either key or value may be null.
    520      *
    521      * @param key a String, or null
    522      * @param value a short array object, or null
    523      */
    524     void putShortArray(String key, short[] value) {
    525         unparcel();
    526         mMap.put(key, value);
    527     }
    528 
    529     /**
    530      * Inserts a char array value into the mapping of this Bundle, replacing
    531      * any existing value for the given key.  Either key or value may be null.
    532      *
    533      * @param key a String, or null
    534      * @param value a char array object, or null
    535      */
    536     void putCharArray(String key, char[] value) {
    537         unparcel();
    538         mMap.put(key, value);
    539     }
    540 
    541     /**
    542      * Inserts an int array value into the mapping of this Bundle, replacing
    543      * any existing value for the given key.  Either key or value may be null.
    544      *
    545      * @param key a String, or null
    546      * @param value an int array object, or null
    547      */
    548     public void putIntArray(String key, int[] value) {
    549         unparcel();
    550         mMap.put(key, value);
    551     }
    552 
    553     /**
    554      * Inserts a long array value into the mapping of this Bundle, replacing
    555      * any existing value for the given key.  Either key or value may be null.
    556      *
    557      * @param key a String, or null
    558      * @param value a long array object, or null
    559      */
    560     public void putLongArray(String key, long[] value) {
    561         unparcel();
    562         mMap.put(key, value);
    563     }
    564 
    565     /**
    566      * Inserts a float array value into the mapping of this Bundle, replacing
    567      * any existing value for the given key.  Either key or value may be null.
    568      *
    569      * @param key a String, or null
    570      * @param value a float array object, or null
    571      */
    572     void putFloatArray(String key, float[] value) {
    573         unparcel();
    574         mMap.put(key, value);
    575     }
    576 
    577     /**
    578      * Inserts a double array value into the mapping of this Bundle, replacing
    579      * any existing value for the given key.  Either key or value may be null.
    580      *
    581      * @param key a String, or null
    582      * @param value a double array object, or null
    583      */
    584     public void putDoubleArray(String key, double[] value) {
    585         unparcel();
    586         mMap.put(key, value);
    587     }
    588 
    589     /**
    590      * Inserts a String array value into the mapping of this Bundle, replacing
    591      * any existing value for the given key.  Either key or value may be null.
    592      *
    593      * @param key a String, or null
    594      * @param value a String array object, or null
    595      */
    596     public void putStringArray(String key, String[] value) {
    597         unparcel();
    598         mMap.put(key, value);
    599     }
    600 
    601     /**
    602      * Inserts a CharSequence array value into the mapping of this Bundle, replacing
    603      * any existing value for the given key.  Either key or value may be null.
    604      *
    605      * @param key a String, or null
    606      * @param value a CharSequence array object, or null
    607      */
    608     void putCharSequenceArray(String key, CharSequence[] value) {
    609         unparcel();
    610         mMap.put(key, value);
    611     }
    612 
    613     /**
    614      * Returns the value associated with the given key, or false if
    615      * no mapping of the desired type exists for the given key.
    616      *
    617      * @param key a String
    618      * @return a boolean value
    619      */
    620     public boolean getBoolean(String key) {
    621         unparcel();
    622         if (DEBUG) Log.d(TAG, "Getting boolean in "
    623                 + Integer.toHexString(System.identityHashCode(this)));
    624         return getBoolean(key, false);
    625     }
    626 
    627     // Log a message if the value was non-null but not of the expected type
    628     void typeWarning(String key, Object value, String className,
    629             Object defaultValue, ClassCastException e) {
    630         StringBuilder sb = new StringBuilder();
    631         sb.append("Key ");
    632         sb.append(key);
    633         sb.append(" expected ");
    634         sb.append(className);
    635         sb.append(" but value was a ");
    636         sb.append(value.getClass().getName());
    637         sb.append(".  The default value ");
    638         sb.append(defaultValue);
    639         sb.append(" was returned.");
    640         Log.w(TAG, sb.toString());
    641         Log.w(TAG, "Attempt to cast generated internal exception:", e);
    642     }
    643 
    644     void typeWarning(String key, Object value, String className,
    645             ClassCastException e) {
    646         typeWarning(key, value, className, "<null>", e);
    647     }
    648 
    649     /**
    650      * Returns the value associated with the given key, or defaultValue if
    651      * no mapping of the desired type exists for the given key.
    652      *
    653      * @param key a String
    654      * @param defaultValue Value to return if key does not exist
    655      * @return a boolean value
    656      */
    657     public boolean getBoolean(String key, boolean defaultValue) {
    658         unparcel();
    659         Object o = mMap.get(key);
    660         if (o == null) {
    661             return defaultValue;
    662         }
    663         try {
    664             return (Boolean) o;
    665         } catch (ClassCastException e) {
    666             typeWarning(key, o, "Boolean", defaultValue, e);
    667             return defaultValue;
    668         }
    669     }
    670 
    671     /**
    672      * Returns the value associated with the given key, or (byte) 0 if
    673      * no mapping of the desired type exists for the given key.
    674      *
    675      * @param key a String
    676      * @return a byte value
    677      */
    678     byte getByte(String key) {
    679         unparcel();
    680         return getByte(key, (byte) 0);
    681     }
    682 
    683     /**
    684      * Returns the value associated with the given key, or defaultValue if
    685      * no mapping of the desired type exists for the given key.
    686      *
    687      * @param key a String
    688      * @param defaultValue Value to return if key does not exist
    689      * @return a byte value
    690      */
    691     Byte getByte(String key, byte defaultValue) {
    692         unparcel();
    693         Object o = mMap.get(key);
    694         if (o == null) {
    695             return defaultValue;
    696         }
    697         try {
    698             return (Byte) o;
    699         } catch (ClassCastException e) {
    700             typeWarning(key, o, "Byte", defaultValue, e);
    701             return defaultValue;
    702         }
    703     }
    704 
    705     /**
    706      * Returns the value associated with the given key, or (char) 0 if
    707      * no mapping of the desired type exists for the given key.
    708      *
    709      * @param key a String
    710      * @return a char value
    711      */
    712     char getChar(String key) {
    713         unparcel();
    714         return getChar(key, (char) 0);
    715     }
    716 
    717     /**
    718      * Returns the value associated with the given key, or defaultValue if
    719      * no mapping of the desired type exists for the given key.
    720      *
    721      * @param key a String
    722      * @param defaultValue Value to return if key does not exist
    723      * @return a char value
    724      */
    725     char getChar(String key, char defaultValue) {
    726         unparcel();
    727         Object o = mMap.get(key);
    728         if (o == null) {
    729             return defaultValue;
    730         }
    731         try {
    732             return (Character) o;
    733         } catch (ClassCastException e) {
    734             typeWarning(key, o, "Character", defaultValue, e);
    735             return defaultValue;
    736         }
    737     }
    738 
    739     /**
    740      * Returns the value associated with the given key, or (short) 0 if
    741      * no mapping of the desired type exists for the given key.
    742      *
    743      * @param key a String
    744      * @return a short value
    745      */
    746     short getShort(String key) {
    747         unparcel();
    748         return getShort(key, (short) 0);
    749     }
    750 
    751     /**
    752      * Returns the value associated with the given key, or defaultValue if
    753      * no mapping of the desired type exists for the given key.
    754      *
    755      * @param key a String
    756      * @param defaultValue Value to return if key does not exist
    757      * @return a short value
    758      */
    759     short getShort(String key, short defaultValue) {
    760         unparcel();
    761         Object o = mMap.get(key);
    762         if (o == null) {
    763             return defaultValue;
    764         }
    765         try {
    766             return (Short) o;
    767         } catch (ClassCastException e) {
    768             typeWarning(key, o, "Short", defaultValue, e);
    769             return defaultValue;
    770         }
    771     }
    772 
    773     /**
    774      * Returns the value associated with the given key, or 0 if
    775      * no mapping of the desired type exists for the given key.
    776      *
    777      * @param key a String
    778      * @return an int value
    779      */
    780     public int getInt(String key) {
    781         unparcel();
    782         return getInt(key, 0);
    783     }
    784 
    785     /**
    786      * Returns the value associated with the given key, or defaultValue if
    787      * no mapping of the desired type exists for the given key.
    788      *
    789      * @param key a String
    790      * @param defaultValue Value to return if key does not exist
    791      * @return an int value
    792      */
    793    public int getInt(String key, int defaultValue) {
    794         unparcel();
    795         Object o = mMap.get(key);
    796         if (o == null) {
    797             return defaultValue;
    798         }
    799         try {
    800             return (Integer) o;
    801         } catch (ClassCastException e) {
    802             typeWarning(key, o, "Integer", defaultValue, e);
    803             return defaultValue;
    804         }
    805     }
    806 
    807     /**
    808      * Returns the value associated with the given key, or 0L if
    809      * no mapping of the desired type exists for the given key.
    810      *
    811      * @param key a String
    812      * @return a long value
    813      */
    814     public long getLong(String key) {
    815         unparcel();
    816         return getLong(key, 0L);
    817     }
    818 
    819     /**
    820      * Returns the value associated with the given key, or defaultValue if
    821      * no mapping of the desired type exists for the given key.
    822      *
    823      * @param key a String
    824      * @param defaultValue Value to return if key does not exist
    825      * @return a long value
    826      */
    827     public long getLong(String key, long defaultValue) {
    828         unparcel();
    829         Object o = mMap.get(key);
    830         if (o == null) {
    831             return defaultValue;
    832         }
    833         try {
    834             return (Long) o;
    835         } catch (ClassCastException e) {
    836             typeWarning(key, o, "Long", defaultValue, e);
    837             return defaultValue;
    838         }
    839     }
    840 
    841     /**
    842      * Returns the value associated with the given key, or 0.0f if
    843      * no mapping of the desired type exists for the given key.
    844      *
    845      * @param key a String
    846      * @return a float value
    847      */
    848     float getFloat(String key) {
    849         unparcel();
    850         return getFloat(key, 0.0f);
    851     }
    852 
    853     /**
    854      * Returns the value associated with the given key, or defaultValue if
    855      * no mapping of the desired type exists for the given key.
    856      *
    857      * @param key a String
    858      * @param defaultValue Value to return if key does not exist
    859      * @return a float value
    860      */
    861     float getFloat(String key, float defaultValue) {
    862         unparcel();
    863         Object o = mMap.get(key);
    864         if (o == null) {
    865             return defaultValue;
    866         }
    867         try {
    868             return (Float) o;
    869         } catch (ClassCastException e) {
    870             typeWarning(key, o, "Float", defaultValue, e);
    871             return defaultValue;
    872         }
    873     }
    874 
    875     /**
    876      * Returns the value associated with the given key, or 0.0 if
    877      * no mapping of the desired type exists for the given key.
    878      *
    879      * @param key a String
    880      * @return a double value
    881      */
    882     public double getDouble(String key) {
    883         unparcel();
    884         return getDouble(key, 0.0);
    885     }
    886 
    887     /**
    888      * Returns the value associated with the given key, or defaultValue if
    889      * no mapping of the desired type exists for the given key.
    890      *
    891      * @param key a String
    892      * @param defaultValue Value to return if key does not exist
    893      * @return a double value
    894      */
    895     public double getDouble(String key, double defaultValue) {
    896         unparcel();
    897         Object o = mMap.get(key);
    898         if (o == null) {
    899             return defaultValue;
    900         }
    901         try {
    902             return (Double) o;
    903         } catch (ClassCastException e) {
    904             typeWarning(key, o, "Double", defaultValue, e);
    905             return defaultValue;
    906         }
    907     }
    908 
    909     /**
    910      * Returns the value associated with the given key, or null if
    911      * no mapping of the desired type exists for the given key or a null
    912      * value is explicitly associated with the key.
    913      *
    914      * @param key a String, or null
    915      * @return a String value, or null
    916      */
    917     public String getString(String key) {
    918         unparcel();
    919         final Object o = mMap.get(key);
    920         try {
    921             return (String) o;
    922         } catch (ClassCastException e) {
    923             typeWarning(key, o, "String", e);
    924             return null;
    925         }
    926     }
    927 
    928     /**
    929      * Returns the value associated with the given key, or defaultValue if
    930      * no mapping of the desired type exists for the given key or if a null
    931      * value is explicitly associated with the given key.
    932      *
    933      * @param key a String, or null
    934      * @param defaultValue Value to return if key does not exist or if a null
    935      *     value is associated with the given key.
    936      * @return the String value associated with the given key, or defaultValue
    937      *     if no valid String object is currently mapped to that key.
    938      */
    939     public String getString(String key, String defaultValue) {
    940         final String s = getString(key);
    941         return (s == null) ? defaultValue : s;
    942     }
    943 
    944     /**
    945      * Returns the value associated with the given key, or null if
    946      * no mapping of the desired type exists for the given key or a null
    947      * value is explicitly associated with the key.
    948      *
    949      * @param key a String, or null
    950      * @return a CharSequence value, or null
    951      */
    952     CharSequence getCharSequence(String key) {
    953         unparcel();
    954         final Object o = mMap.get(key);
    955         try {
    956             return (CharSequence) o;
    957         } catch (ClassCastException e) {
    958             typeWarning(key, o, "CharSequence", e);
    959             return null;
    960         }
    961     }
    962 
    963     /**
    964      * Returns the value associated with the given key, or defaultValue if
    965      * no mapping of the desired type exists for the given key or if a null
    966      * value is explicitly associated with the given key.
    967      *
    968      * @param key a String, or null
    969      * @param defaultValue Value to return if key does not exist or if a null
    970      *     value is associated with the given key.
    971      * @return the CharSequence value associated with the given key, or defaultValue
    972      *     if no valid CharSequence object is currently mapped to that key.
    973      */
    974     CharSequence getCharSequence(String key, CharSequence defaultValue) {
    975         final CharSequence cs = getCharSequence(key);
    976         return (cs == null) ? defaultValue : cs;
    977     }
    978 
    979     /**
    980      * Returns the value associated with the given key, or null if
    981      * no mapping of the desired type exists for the given key or a null
    982      * value is explicitly associated with the key.
    983      *
    984      * @param key a String, or null
    985      * @return a Serializable value, or null
    986      */
    987     Serializable getSerializable(String key) {
    988         unparcel();
    989         Object o = mMap.get(key);
    990         if (o == null) {
    991             return null;
    992         }
    993         try {
    994             return (Serializable) o;
    995         } catch (ClassCastException e) {
    996             typeWarning(key, o, "Serializable", e);
    997             return null;
    998         }
    999     }
   1000 
   1001     /**
   1002      * Returns the value associated with the given key, or null if
   1003      * no mapping of the desired type exists for the given key or a null
   1004      * value is explicitly associated with the key.
   1005      *
   1006      * @param key a String, or null
   1007      * @return an ArrayList<String> value, or null
   1008      */
   1009     ArrayList<Integer> getIntegerArrayList(String key) {
   1010         unparcel();
   1011         Object o = mMap.get(key);
   1012         if (o == null) {
   1013             return null;
   1014         }
   1015         try {
   1016             return (ArrayList<Integer>) o;
   1017         } catch (ClassCastException e) {
   1018             typeWarning(key, o, "ArrayList<Integer>", e);
   1019             return null;
   1020         }
   1021     }
   1022 
   1023     /**
   1024      * Returns the value associated with the given key, or null if
   1025      * no mapping of the desired type exists for the given key or a null
   1026      * value is explicitly associated with the key.
   1027      *
   1028      * @param key a String, or null
   1029      * @return an ArrayList<String> value, or null
   1030      */
   1031     ArrayList<String> getStringArrayList(String key) {
   1032         unparcel();
   1033         Object o = mMap.get(key);
   1034         if (o == null) {
   1035             return null;
   1036         }
   1037         try {
   1038             return (ArrayList<String>) o;
   1039         } catch (ClassCastException e) {
   1040             typeWarning(key, o, "ArrayList<String>", e);
   1041             return null;
   1042         }
   1043     }
   1044 
   1045     /**
   1046      * Returns the value associated with the given key, or null if
   1047      * no mapping of the desired type exists for the given key or a null
   1048      * value is explicitly associated with the key.
   1049      *
   1050      * @param key a String, or null
   1051      * @return an ArrayList<CharSequence> value, or null
   1052      */
   1053     ArrayList<CharSequence> getCharSequenceArrayList(String key) {
   1054         unparcel();
   1055         Object o = mMap.get(key);
   1056         if (o == null) {
   1057             return null;
   1058         }
   1059         try {
   1060             return (ArrayList<CharSequence>) o;
   1061         } catch (ClassCastException e) {
   1062             typeWarning(key, o, "ArrayList<CharSequence>", e);
   1063             return null;
   1064         }
   1065     }
   1066 
   1067     /**
   1068      * Returns the value associated with the given key, or null if
   1069      * no mapping of the desired type exists for the given key or a null
   1070      * value is explicitly associated with the key.
   1071      *
   1072      * @param key a String, or null
   1073      * @return a boolean[] value, or null
   1074      */
   1075     public boolean[] getBooleanArray(String key) {
   1076         unparcel();
   1077         Object o = mMap.get(key);
   1078         if (o == null) {
   1079             return null;
   1080         }
   1081         try {
   1082             return (boolean[]) o;
   1083         } catch (ClassCastException e) {
   1084             typeWarning(key, o, "byte[]", e);
   1085             return null;
   1086         }
   1087     }
   1088 
   1089     /**
   1090      * Returns the value associated with the given key, or null if
   1091      * no mapping of the desired type exists for the given key or a null
   1092      * value is explicitly associated with the key.
   1093      *
   1094      * @param key a String, or null
   1095      * @return a byte[] value, or null
   1096      */
   1097     byte[] getByteArray(String key) {
   1098         unparcel();
   1099         Object o = mMap.get(key);
   1100         if (o == null) {
   1101             return null;
   1102         }
   1103         try {
   1104             return (byte[]) o;
   1105         } catch (ClassCastException e) {
   1106             typeWarning(key, o, "byte[]", e);
   1107             return null;
   1108         }
   1109     }
   1110 
   1111     /**
   1112      * Returns the value associated with the given key, or null if
   1113      * no mapping of the desired type exists for the given key or a null
   1114      * value is explicitly associated with the key.
   1115      *
   1116      * @param key a String, or null
   1117      * @return a short[] value, or null
   1118      */
   1119     short[] getShortArray(String key) {
   1120         unparcel();
   1121         Object o = mMap.get(key);
   1122         if (o == null) {
   1123             return null;
   1124         }
   1125         try {
   1126             return (short[]) o;
   1127         } catch (ClassCastException e) {
   1128             typeWarning(key, o, "short[]", e);
   1129             return null;
   1130         }
   1131     }
   1132 
   1133     /**
   1134      * Returns the value associated with the given key, or null if
   1135      * no mapping of the desired type exists for the given key or a null
   1136      * value is explicitly associated with the key.
   1137      *
   1138      * @param key a String, or null
   1139      * @return a char[] value, or null
   1140      */
   1141     char[] getCharArray(String key) {
   1142         unparcel();
   1143         Object o = mMap.get(key);
   1144         if (o == null) {
   1145             return null;
   1146         }
   1147         try {
   1148             return (char[]) o;
   1149         } catch (ClassCastException e) {
   1150             typeWarning(key, o, "char[]", e);
   1151             return null;
   1152         }
   1153     }
   1154 
   1155     /**
   1156      * Returns the value associated with the given key, or null if
   1157      * no mapping of the desired type exists for the given key or a null
   1158      * value is explicitly associated with the key.
   1159      *
   1160      * @param key a String, or null
   1161      * @return an int[] value, or null
   1162      */
   1163     public int[] getIntArray(String key) {
   1164         unparcel();
   1165         Object o = mMap.get(key);
   1166         if (o == null) {
   1167             return null;
   1168         }
   1169         try {
   1170             return (int[]) o;
   1171         } catch (ClassCastException e) {
   1172             typeWarning(key, o, "int[]", e);
   1173             return null;
   1174         }
   1175     }
   1176 
   1177     /**
   1178      * Returns the value associated with the given key, or null if
   1179      * no mapping of the desired type exists for the given key or a null
   1180      * value is explicitly associated with the key.
   1181      *
   1182      * @param key a String, or null
   1183      * @return a long[] value, or null
   1184      */
   1185     public long[] getLongArray(String key) {
   1186         unparcel();
   1187         Object o = mMap.get(key);
   1188         if (o == null) {
   1189             return null;
   1190         }
   1191         try {
   1192             return (long[]) o;
   1193         } catch (ClassCastException e) {
   1194             typeWarning(key, o, "long[]", e);
   1195             return null;
   1196         }
   1197     }
   1198 
   1199     /**
   1200      * Returns the value associated with the given key, or null if
   1201      * no mapping of the desired type exists for the given key or a null
   1202      * value is explicitly associated with the key.
   1203      *
   1204      * @param key a String, or null
   1205      * @return a float[] value, or null
   1206      */
   1207     float[] getFloatArray(String key) {
   1208         unparcel();
   1209         Object o = mMap.get(key);
   1210         if (o == null) {
   1211             return null;
   1212         }
   1213         try {
   1214             return (float[]) o;
   1215         } catch (ClassCastException e) {
   1216             typeWarning(key, o, "float[]", e);
   1217             return null;
   1218         }
   1219     }
   1220 
   1221     /**
   1222      * Returns the value associated with the given key, or null if
   1223      * no mapping of the desired type exists for the given key or a null
   1224      * value is explicitly associated with the key.
   1225      *
   1226      * @param key a String, or null
   1227      * @return a double[] value, or null
   1228      */
   1229     public double[] getDoubleArray(String key) {
   1230         unparcel();
   1231         Object o = mMap.get(key);
   1232         if (o == null) {
   1233             return null;
   1234         }
   1235         try {
   1236             return (double[]) o;
   1237         } catch (ClassCastException e) {
   1238             typeWarning(key, o, "double[]", e);
   1239             return null;
   1240         }
   1241     }
   1242 
   1243     /**
   1244      * Returns the value associated with the given key, or null if
   1245      * no mapping of the desired type exists for the given key or a null
   1246      * value is explicitly associated with the key.
   1247      *
   1248      * @param key a String, or null
   1249      * @return a String[] value, or null
   1250      */
   1251     public String[] getStringArray(String key) {
   1252         unparcel();
   1253         Object o = mMap.get(key);
   1254         if (o == null) {
   1255             return null;
   1256         }
   1257         try {
   1258             return (String[]) o;
   1259         } catch (ClassCastException e) {
   1260             typeWarning(key, o, "String[]", e);
   1261             return null;
   1262         }
   1263     }
   1264 
   1265     /**
   1266      * Returns the value associated with the given key, or null if
   1267      * no mapping of the desired type exists for the given key or a null
   1268      * value is explicitly associated with the key.
   1269      *
   1270      * @param key a String, or null
   1271      * @return a CharSequence[] value, or null
   1272      */
   1273     CharSequence[] getCharSequenceArray(String key) {
   1274         unparcel();
   1275         Object o = mMap.get(key);
   1276         if (o == null) {
   1277             return null;
   1278         }
   1279         try {
   1280             return (CharSequence[]) o;
   1281         } catch (ClassCastException e) {
   1282             typeWarning(key, o, "CharSequence[]", e);
   1283             return null;
   1284         }
   1285     }
   1286 
   1287     /**
   1288      * Writes the Bundle contents to a Parcel, typically in order for
   1289      * it to be passed through an IBinder connection.
   1290      * @param parcel The parcel to copy this bundle to.
   1291      */
   1292     void writeToParcelInner(Parcel parcel, int flags) {
   1293         if (mParcelledData != null) {
   1294             if (mParcelledData == EMPTY_PARCEL) {
   1295                 parcel.writeInt(0);
   1296             } else {
   1297                 int length = mParcelledData.dataSize();
   1298                 parcel.writeInt(length);
   1299                 parcel.writeInt(BUNDLE_MAGIC);
   1300                 parcel.appendFrom(mParcelledData, 0, length);
   1301             }
   1302         } else {
   1303             // Special case for empty bundles.
   1304             if (mMap == null || mMap.size() <= 0) {
   1305                 parcel.writeInt(0);
   1306                 return;
   1307             }
   1308             int lengthPos = parcel.dataPosition();
   1309             parcel.writeInt(-1); // dummy, will hold length
   1310             parcel.writeInt(BUNDLE_MAGIC);
   1311 
   1312             int startPos = parcel.dataPosition();
   1313             parcel.writeArrayMapInternal(mMap);
   1314             int endPos = parcel.dataPosition();
   1315 
   1316             // Backpatch length
   1317             parcel.setDataPosition(lengthPos);
   1318             int length = endPos - startPos;
   1319             parcel.writeInt(length);
   1320             parcel.setDataPosition(endPos);
   1321         }
   1322     }
   1323 
   1324     /**
   1325      * Reads the Parcel contents into this Bundle, typically in order for
   1326      * it to be passed through an IBinder connection.
   1327      * @param parcel The parcel to overwrite this bundle from.
   1328      */
   1329     void readFromParcelInner(Parcel parcel) {
   1330         int length = parcel.readInt();
   1331         if (length < 0) {
   1332             throw new RuntimeException("Bad length in parcel: " + length);
   1333         }
   1334         readFromParcelInner(parcel, length);
   1335     }
   1336 
   1337     private void readFromParcelInner(Parcel parcel, int length) {
   1338         if (length == 0) {
   1339             // Empty Bundle or end of data.
   1340             mParcelledData = EMPTY_PARCEL;
   1341             return;
   1342         }
   1343         int magic = parcel.readInt();
   1344         if (magic != BUNDLE_MAGIC) {
   1345             //noinspection ThrowableInstanceNeverThrown
   1346             throw new IllegalStateException("Bad magic number for Bundle: 0x"
   1347                     + Integer.toHexString(magic));
   1348         }
   1349 
   1350         // Advance within this Parcel
   1351         int offset = parcel.dataPosition();
   1352         parcel.setDataPosition(offset + length);
   1353 
   1354         Parcel p = Parcel.obtain();
   1355         p.setDataPosition(0);
   1356         p.appendFrom(parcel, offset, length);
   1357         if (DEBUG) Log.d(TAG, "Retrieving "  + Integer.toHexString(System.identityHashCode(this))
   1358                 + ": " + length + " bundle bytes starting at " + offset);
   1359         p.setDataPosition(0);
   1360 
   1361         mParcelledData = p;
   1362     }
   1363 }
   1364