Home | History | Annotate | Download | only in os
      1 /*
      2  * Copyright (C) 2007 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 import android.util.SparseArray;
     22 
     23 import java.io.Serializable;
     24 import java.util.ArrayList;
     25 import java.util.List;
     26 import java.util.Set;
     27 
     28 /**
     29  * A mapping from String values to various Parcelable types.
     30  *
     31  */
     32 public final class Bundle implements Parcelable, Cloneable {
     33     private static final String TAG = "Bundle";
     34     static final boolean DEBUG = false;
     35     public static final Bundle EMPTY;
     36 
     37     static final int BUNDLE_MAGIC = 0x4C444E42; // 'B' 'N' 'D' 'L'
     38     static final Parcel EMPTY_PARCEL;
     39 
     40     static {
     41         EMPTY = new Bundle();
     42         EMPTY.mMap = ArrayMap.EMPTY;
     43         EMPTY_PARCEL = Parcel.obtain();
     44     }
     45 
     46     // Invariant - exactly one of mMap / mParcelledData will be null
     47     // (except inside a call to unparcel)
     48 
     49     /* package */ ArrayMap<String, Object> mMap = null;
     50 
     51     /*
     52      * If mParcelledData is non-null, then mMap will be null and the
     53      * data are stored as a Parcel containing a Bundle.  When the data
     54      * are unparcelled, mParcelledData willbe set to null.
     55      */
     56     /* package */ Parcel mParcelledData = null;
     57 
     58     private boolean mHasFds = false;
     59     private boolean mFdsKnown = true;
     60     private boolean mAllowFds = true;
     61 
     62     /**
     63      * The ClassLoader used when unparcelling data from mParcelledData.
     64      */
     65     private ClassLoader mClassLoader;
     66 
     67     /**
     68      * Constructs a new, empty Bundle.
     69      */
     70     public Bundle() {
     71         mMap = new ArrayMap<String, Object>();
     72         mClassLoader = getClass().getClassLoader();
     73     }
     74 
     75     /**
     76      * Constructs a Bundle whose data is stored as a Parcel.  The data
     77      * will be unparcelled on first contact, using the assigned ClassLoader.
     78      *
     79      * @param parcelledData a Parcel containing a Bundle
     80      */
     81     Bundle(Parcel parcelledData) {
     82         readFromParcel(parcelledData);
     83     }
     84 
     85     /* package */ Bundle(Parcel parcelledData, int length) {
     86         readFromParcelInner(parcelledData, length);
     87     }
     88 
     89     /**
     90      * Constructs a new, empty Bundle that uses a specific ClassLoader for
     91      * instantiating Parcelable and Serializable objects.
     92      *
     93      * @param loader An explicit ClassLoader to use when instantiating objects
     94      * inside of the Bundle.
     95      */
     96     public Bundle(ClassLoader loader) {
     97         mMap = new ArrayMap<String, Object>();
     98         mClassLoader = loader;
     99     }
    100 
    101     /**
    102      * Constructs a new, empty Bundle sized to hold the given number of
    103      * elements. The Bundle will grow as needed.
    104      *
    105      * @param capacity the initial capacity of the Bundle
    106      */
    107     public Bundle(int capacity) {
    108         mMap = new ArrayMap<String, Object>(capacity);
    109         mClassLoader = getClass().getClassLoader();
    110     }
    111 
    112     /**
    113      * Constructs a Bundle containing a copy of the mappings from the given
    114      * Bundle.
    115      *
    116      * @param b a Bundle to be copied.
    117      */
    118     public Bundle(Bundle b) {
    119         if (b.mParcelledData != null) {
    120             if (b.mParcelledData == EMPTY_PARCEL) {
    121                 mParcelledData = EMPTY_PARCEL;
    122             } else {
    123                 mParcelledData = Parcel.obtain();
    124                 mParcelledData.appendFrom(b.mParcelledData, 0, b.mParcelledData.dataSize());
    125                 mParcelledData.setDataPosition(0);
    126             }
    127         } else {
    128             mParcelledData = null;
    129         }
    130 
    131         if (b.mMap != null) {
    132             mMap = new ArrayMap<String, Object>(b.mMap);
    133         } else {
    134             mMap = null;
    135         }
    136 
    137         mHasFds = b.mHasFds;
    138         mFdsKnown = b.mFdsKnown;
    139         mClassLoader = b.mClassLoader;
    140     }
    141 
    142     /**
    143      * Make a Bundle for a single key/value pair.
    144      *
    145      * @hide
    146      */
    147     public static Bundle forPair(String key, String value) {
    148         // TODO: optimize this case.
    149         Bundle b = new Bundle(1);
    150         b.putString(key, value);
    151         return b;
    152     }
    153 
    154     /**
    155      * TODO: optimize this later (getting just the value part of a Bundle
    156      * with a single pair) once Bundle.forPair() above is implemented
    157      * with a special single-value Map implementation/serialization.
    158      *
    159      * Note: value in single-pair Bundle may be null.
    160      *
    161      * @hide
    162      */
    163     public String getPairValue() {
    164         unparcel();
    165         int size = mMap.size();
    166         if (size > 1) {
    167             Log.w(TAG, "getPairValue() used on Bundle with multiple pairs.");
    168         }
    169         if (size == 0) {
    170             return null;
    171         }
    172         Object o = mMap.valueAt(0);
    173         try {
    174             return (String) o;
    175         } catch (ClassCastException e) {
    176             typeWarning("getPairValue()", o, "String", e);
    177             return null;
    178         }
    179     }
    180 
    181     /**
    182      * Changes the ClassLoader this Bundle uses when instantiating objects.
    183      *
    184      * @param loader An explicit ClassLoader to use when instantiating objects
    185      * inside of the Bundle.
    186      */
    187     public void setClassLoader(ClassLoader loader) {
    188         mClassLoader = loader;
    189     }
    190 
    191     /**
    192      * Return the ClassLoader currently associated with this Bundle.
    193      */
    194     public ClassLoader getClassLoader() {
    195         return mClassLoader;
    196     }
    197 
    198     /** @hide */
    199     public boolean setAllowFds(boolean allowFds) {
    200         boolean orig = mAllowFds;
    201         mAllowFds = allowFds;
    202         return orig;
    203     }
    204 
    205     /**
    206      * Clones the current Bundle. The internal map is cloned, but the keys and
    207      * values to which it refers are copied by reference.
    208      */
    209     @Override
    210     public Object clone() {
    211         return new Bundle(this);
    212     }
    213 
    214     /**
    215      * If the underlying data are stored as a Parcel, unparcel them
    216      * using the currently assigned class loader.
    217      */
    218     /* package */ synchronized void unparcel() {
    219         if (mParcelledData == null) {
    220             if (DEBUG) Log.d(TAG, "unparcel " + Integer.toHexString(System.identityHashCode(this))
    221                     + ": no parcelled data");
    222             return;
    223         }
    224 
    225         if (mParcelledData == EMPTY_PARCEL) {
    226             if (DEBUG) Log.d(TAG, "unparcel " + Integer.toHexString(System.identityHashCode(this))
    227                     + ": empty");
    228             if (mMap == null) {
    229                 mMap = new ArrayMap<String, Object>(1);
    230             } else {
    231                 mMap.erase();
    232             }
    233             mParcelledData = null;
    234             return;
    235         }
    236 
    237         int N = mParcelledData.readInt();
    238         if (DEBUG) Log.d(TAG, "unparcel " + Integer.toHexString(System.identityHashCode(this))
    239                 + ": reading " + N + " maps");
    240         if (N < 0) {
    241             return;
    242         }
    243         if (mMap == null) {
    244             mMap = new ArrayMap<String, Object>(N);
    245         } else {
    246             mMap.erase();
    247             mMap.ensureCapacity(N);
    248         }
    249         mParcelledData.readArrayMapInternal(mMap, N, mClassLoader);
    250         mParcelledData.recycle();
    251         mParcelledData = null;
    252         if (DEBUG) Log.d(TAG, "unparcel " + Integer.toHexString(System.identityHashCode(this))
    253                 + " final map: " + mMap);
    254     }
    255 
    256     /**
    257      * @hide
    258      */
    259     public boolean isParcelled() {
    260         return mParcelledData != null;
    261     }
    262 
    263     /**
    264      * Returns the number of mappings contained in this Bundle.
    265      *
    266      * @return the number of mappings as an int.
    267      */
    268     public int size() {
    269         unparcel();
    270         return mMap.size();
    271     }
    272 
    273     /**
    274      * Returns true if the mapping of this Bundle is empty, false otherwise.
    275      */
    276     public boolean isEmpty() {
    277         unparcel();
    278         return mMap.isEmpty();
    279     }
    280 
    281     /**
    282      * Removes all elements from the mapping of this Bundle.
    283      */
    284     public void clear() {
    285         unparcel();
    286         mMap.clear();
    287         mHasFds = false;
    288         mFdsKnown = true;
    289     }
    290 
    291     /**
    292      * Returns true if the given key is contained in the mapping
    293      * of this Bundle.
    294      *
    295      * @param key a String key
    296      * @return true if the key is part of the mapping, false otherwise
    297      */
    298     public boolean containsKey(String key) {
    299         unparcel();
    300         return mMap.containsKey(key);
    301     }
    302 
    303     /**
    304      * Returns the entry with the given key as an object.
    305      *
    306      * @param key a String key
    307      * @return an Object, or null
    308      */
    309     public Object get(String key) {
    310         unparcel();
    311         return mMap.get(key);
    312     }
    313 
    314     /**
    315      * Removes any entry with the given key from the mapping of this Bundle.
    316      *
    317      * @param key a String key
    318      */
    319     public void remove(String key) {
    320         unparcel();
    321         mMap.remove(key);
    322     }
    323 
    324     /**
    325      * Inserts all mappings from the given Bundle into this Bundle.
    326      *
    327      * @param map a Bundle
    328      */
    329     public void putAll(Bundle map) {
    330         unparcel();
    331         map.unparcel();
    332         mMap.putAll(map.mMap);
    333 
    334         // fd state is now known if and only if both bundles already knew
    335         mHasFds |= map.mHasFds;
    336         mFdsKnown = mFdsKnown && map.mFdsKnown;
    337     }
    338 
    339     /**
    340      * Returns a Set containing the Strings used as keys in this Bundle.
    341      *
    342      * @return a Set of String keys
    343      */
    344     public Set<String> keySet() {
    345         unparcel();
    346         return mMap.keySet();
    347     }
    348 
    349     /**
    350      * Reports whether the bundle contains any parcelled file descriptors.
    351      */
    352     public boolean hasFileDescriptors() {
    353         if (!mFdsKnown) {
    354             boolean fdFound = false;    // keep going until we find one or run out of data
    355 
    356             if (mParcelledData != null) {
    357                 if (mParcelledData.hasFileDescriptors()) {
    358                     fdFound = true;
    359                 }
    360             } else {
    361                 // It's been unparcelled, so we need to walk the map
    362                 for (int i=mMap.size()-1; i>=0; i--) {
    363                     Object obj = mMap.valueAt(i);
    364                     if (obj instanceof Parcelable) {
    365                         if ((((Parcelable)obj).describeContents()
    366                                 & Parcelable.CONTENTS_FILE_DESCRIPTOR) != 0) {
    367                             fdFound = true;
    368                             break;
    369                         }
    370                     } else if (obj instanceof Parcelable[]) {
    371                         Parcelable[] array = (Parcelable[]) obj;
    372                         for (int n = array.length - 1; n >= 0; n--) {
    373                             if ((array[n].describeContents()
    374                                     & Parcelable.CONTENTS_FILE_DESCRIPTOR) != 0) {
    375                                 fdFound = true;
    376                                 break;
    377                             }
    378                         }
    379                     } else if (obj instanceof SparseArray) {
    380                         SparseArray<? extends Parcelable> array =
    381                                 (SparseArray<? extends Parcelable>) obj;
    382                         for (int n = array.size() - 1; n >= 0; n--) {
    383                             if ((array.get(n).describeContents()
    384                                     & Parcelable.CONTENTS_FILE_DESCRIPTOR) != 0) {
    385                                 fdFound = true;
    386                                 break;
    387                             }
    388                         }
    389                     } else if (obj instanceof ArrayList) {
    390                         ArrayList array = (ArrayList) obj;
    391                         // an ArrayList here might contain either Strings or
    392                         // Parcelables; only look inside for Parcelables
    393                         if ((array.size() > 0)
    394                                 && (array.get(0) instanceof Parcelable)) {
    395                             for (int n = array.size() - 1; n >= 0; n--) {
    396                                 Parcelable p = (Parcelable) array.get(n);
    397                                 if (p != null && ((p.describeContents()
    398                                         & Parcelable.CONTENTS_FILE_DESCRIPTOR) != 0)) {
    399                                     fdFound = true;
    400                                     break;
    401                                 }
    402                             }
    403                         }
    404                     }
    405                 }
    406             }
    407 
    408             mHasFds = fdFound;
    409             mFdsKnown = true;
    410         }
    411         return mHasFds;
    412     }
    413 
    414     /**
    415      * Inserts a Boolean value into the mapping of this Bundle, replacing
    416      * any existing value for the given key.  Either key or value may be null.
    417      *
    418      * @param key a String, or null
    419      * @param value a Boolean, or null
    420      */
    421     public void putBoolean(String key, boolean value) {
    422         unparcel();
    423         mMap.put(key, value);
    424     }
    425 
    426     /**
    427      * Inserts a byte value into the mapping of this Bundle, replacing
    428      * any existing value for the given key.
    429      *
    430      * @param key a String, or null
    431      * @param value a byte
    432      */
    433     public void putByte(String key, byte value) {
    434         unparcel();
    435         mMap.put(key, value);
    436     }
    437 
    438     /**
    439      * Inserts a char value into the mapping of this Bundle, replacing
    440      * any existing value for the given key.
    441      *
    442      * @param key a String, or null
    443      * @param value a char, or null
    444      */
    445     public void putChar(String key, char value) {
    446         unparcel();
    447         mMap.put(key, value);
    448     }
    449 
    450     /**
    451      * Inserts a short value into the mapping of this Bundle, replacing
    452      * any existing value for the given key.
    453      *
    454      * @param key a String, or null
    455      * @param value a short
    456      */
    457     public void putShort(String key, short value) {
    458         unparcel();
    459         mMap.put(key, value);
    460     }
    461 
    462     /**
    463      * Inserts an int value into the mapping of this Bundle, replacing
    464      * any existing value for the given key.
    465      *
    466      * @param key a String, or null
    467      * @param value an int, or null
    468      */
    469     public void putInt(String key, int value) {
    470         unparcel();
    471         mMap.put(key, value);
    472     }
    473 
    474     /**
    475      * Inserts a long value into the mapping of this Bundle, replacing
    476      * any existing value for the given key.
    477      *
    478      * @param key a String, or null
    479      * @param value a long
    480      */
    481     public void putLong(String key, long value) {
    482         unparcel();
    483         mMap.put(key, value);
    484     }
    485 
    486     /**
    487      * Inserts a float value into the mapping of this Bundle, replacing
    488      * any existing value for the given key.
    489      *
    490      * @param key a String, or null
    491      * @param value a float
    492      */
    493     public void putFloat(String key, float value) {
    494         unparcel();
    495         mMap.put(key, value);
    496     }
    497 
    498     /**
    499      * Inserts a double value into the mapping of this Bundle, replacing
    500      * any existing value for the given key.
    501      *
    502      * @param key a String, or null
    503      * @param value a double
    504      */
    505     public void putDouble(String key, double value) {
    506         unparcel();
    507         mMap.put(key, value);
    508     }
    509 
    510     /**
    511      * Inserts a String value into the mapping of this Bundle, replacing
    512      * any existing value for the given key.  Either key or value may be null.
    513      *
    514      * @param key a String, or null
    515      * @param value a String, or null
    516      */
    517     public void putString(String key, String value) {
    518         unparcel();
    519         mMap.put(key, value);
    520     }
    521 
    522     /**
    523      * Inserts a CharSequence value into the mapping of this Bundle, replacing
    524      * any existing value for the given key.  Either key or value may be null.
    525      *
    526      * @param key a String, or null
    527      * @param value a CharSequence, or null
    528      */
    529     public void putCharSequence(String key, CharSequence value) {
    530         unparcel();
    531         mMap.put(key, value);
    532     }
    533 
    534     /**
    535      * Inserts a Parcelable value into the mapping of this Bundle, replacing
    536      * any existing value for the given key.  Either key or value may be null.
    537      *
    538      * @param key a String, or null
    539      * @param value a Parcelable object, or null
    540      */
    541     public void putParcelable(String key, Parcelable value) {
    542         unparcel();
    543         mMap.put(key, value);
    544         mFdsKnown = false;
    545     }
    546 
    547     /**
    548      * Inserts an array of Parcelable values into the mapping of this Bundle,
    549      * replacing any existing value for the given key.  Either key or value may
    550      * be null.
    551      *
    552      * @param key a String, or null
    553      * @param value an array of Parcelable objects, or null
    554      */
    555     public void putParcelableArray(String key, Parcelable[] value) {
    556         unparcel();
    557         mMap.put(key, value);
    558         mFdsKnown = false;
    559     }
    560 
    561     /**
    562      * Inserts a List of Parcelable values into the mapping of this Bundle,
    563      * replacing any existing value for the given key.  Either key or value may
    564      * be null.
    565      *
    566      * @param key a String, or null
    567      * @param value an ArrayList of Parcelable objects, or null
    568      */
    569     public void putParcelableArrayList(String key,
    570         ArrayList<? extends Parcelable> value) {
    571         unparcel();
    572         mMap.put(key, value);
    573         mFdsKnown = false;
    574     }
    575 
    576     /** {@hide} */
    577     public void putParcelableList(String key, List<? extends Parcelable> value) {
    578         unparcel();
    579         mMap.put(key, value);
    580         mFdsKnown = false;
    581     }
    582 
    583     /**
    584      * Inserts a SparceArray of Parcelable values into the mapping of this
    585      * Bundle, replacing any existing value for the given key.  Either key
    586      * or value may be null.
    587      *
    588      * @param key a String, or null
    589      * @param value a SparseArray of Parcelable objects, or null
    590      */
    591     public void putSparseParcelableArray(String key,
    592             SparseArray<? extends Parcelable> value) {
    593         unparcel();
    594         mMap.put(key, value);
    595         mFdsKnown = false;
    596     }
    597 
    598     /**
    599      * Inserts an ArrayList<Integer> value into the mapping of this Bundle, replacing
    600      * any existing value for the given key.  Either key or value may be null.
    601      *
    602      * @param key a String, or null
    603      * @param value an ArrayList<Integer> object, or null
    604      */
    605     public void putIntegerArrayList(String key, ArrayList<Integer> value) {
    606         unparcel();
    607         mMap.put(key, value);
    608     }
    609 
    610     /**
    611      * Inserts an ArrayList<String> value into the mapping of this Bundle, replacing
    612      * any existing value for the given key.  Either key or value may be null.
    613      *
    614      * @param key a String, or null
    615      * @param value an ArrayList<String> object, or null
    616      */
    617     public void putStringArrayList(String key, ArrayList<String> value) {
    618         unparcel();
    619         mMap.put(key, value);
    620     }
    621 
    622     /**
    623      * Inserts an ArrayList<CharSequence> value into the mapping of this Bundle, replacing
    624      * any existing value for the given key.  Either key or value may be null.
    625      *
    626      * @param key a String, or null
    627      * @param value an ArrayList<CharSequence> object, or null
    628      */
    629     public void putCharSequenceArrayList(String key, ArrayList<CharSequence> value) {
    630         unparcel();
    631         mMap.put(key, value);
    632     }
    633 
    634     /**
    635      * Inserts a Serializable value into the mapping of this Bundle, replacing
    636      * any existing value for the given key.  Either key or value may be null.
    637      *
    638      * @param key a String, or null
    639      * @param value a Serializable object, or null
    640      */
    641     public void putSerializable(String key, Serializable value) {
    642         unparcel();
    643         mMap.put(key, value);
    644     }
    645 
    646     /**
    647      * Inserts a boolean array value into the mapping of this Bundle, replacing
    648      * any existing value for the given key.  Either key or value may be null.
    649      *
    650      * @param key a String, or null
    651      * @param value a boolean array object, or null
    652      */
    653     public void putBooleanArray(String key, boolean[] value) {
    654         unparcel();
    655         mMap.put(key, value);
    656     }
    657 
    658     /**
    659      * Inserts a byte array value into the mapping of this Bundle, replacing
    660      * any existing value for the given key.  Either key or value may be null.
    661      *
    662      * @param key a String, or null
    663      * @param value a byte array object, or null
    664      */
    665     public void putByteArray(String key, byte[] value) {
    666         unparcel();
    667         mMap.put(key, value);
    668     }
    669 
    670     /**
    671      * Inserts a short array value into the mapping of this Bundle, replacing
    672      * any existing value for the given key.  Either key or value may be null.
    673      *
    674      * @param key a String, or null
    675      * @param value a short array object, or null
    676      */
    677     public void putShortArray(String key, short[] value) {
    678         unparcel();
    679         mMap.put(key, value);
    680     }
    681 
    682     /**
    683      * Inserts a char array value into the mapping of this Bundle, replacing
    684      * any existing value for the given key.  Either key or value may be null.
    685      *
    686      * @param key a String, or null
    687      * @param value a char array object, or null
    688      */
    689     public void putCharArray(String key, char[] value) {
    690         unparcel();
    691         mMap.put(key, value);
    692     }
    693 
    694     /**
    695      * Inserts an int array value into the mapping of this Bundle, replacing
    696      * any existing value for the given key.  Either key or value may be null.
    697      *
    698      * @param key a String, or null
    699      * @param value an int array object, or null
    700      */
    701     public void putIntArray(String key, int[] value) {
    702         unparcel();
    703         mMap.put(key, value);
    704     }
    705 
    706     /**
    707      * Inserts a long array value into the mapping of this Bundle, replacing
    708      * any existing value for the given key.  Either key or value may be null.
    709      *
    710      * @param key a String, or null
    711      * @param value a long array object, or null
    712      */
    713     public void putLongArray(String key, long[] value) {
    714         unparcel();
    715         mMap.put(key, value);
    716     }
    717 
    718     /**
    719      * Inserts a float array value into the mapping of this Bundle, replacing
    720      * any existing value for the given key.  Either key or value may be null.
    721      *
    722      * @param key a String, or null
    723      * @param value a float array object, or null
    724      */
    725     public void putFloatArray(String key, float[] value) {
    726         unparcel();
    727         mMap.put(key, value);
    728     }
    729 
    730     /**
    731      * Inserts a double array value into the mapping of this Bundle, replacing
    732      * any existing value for the given key.  Either key or value may be null.
    733      *
    734      * @param key a String, or null
    735      * @param value a double array object, or null
    736      */
    737     public void putDoubleArray(String key, double[] value) {
    738         unparcel();
    739         mMap.put(key, value);
    740     }
    741 
    742     /**
    743      * Inserts a String array value into the mapping of this Bundle, replacing
    744      * any existing value for the given key.  Either key or value may be null.
    745      *
    746      * @param key a String, or null
    747      * @param value a String array object, or null
    748      */
    749     public void putStringArray(String key, String[] value) {
    750         unparcel();
    751         mMap.put(key, value);
    752     }
    753 
    754     /**
    755      * Inserts a CharSequence array value into the mapping of this Bundle, replacing
    756      * any existing value for the given key.  Either key or value may be null.
    757      *
    758      * @param key a String, or null
    759      * @param value a CharSequence array object, or null
    760      */
    761     public void putCharSequenceArray(String key, CharSequence[] value) {
    762         unparcel();
    763         mMap.put(key, value);
    764     }
    765 
    766     /**
    767      * Inserts a Bundle value into the mapping of this Bundle, replacing
    768      * any existing value for the given key.  Either key or value may be null.
    769      *
    770      * @param key a String, or null
    771      * @param value a Bundle object, or null
    772      */
    773     public void putBundle(String key, Bundle value) {
    774         unparcel();
    775         mMap.put(key, value);
    776     }
    777 
    778     /**
    779      * Inserts an {@link IBinder} value into the mapping of this Bundle, replacing
    780      * any existing value for the given key.  Either key or value may be null.
    781      *
    782      * <p class="note">You should be very careful when using this function.  In many
    783      * places where Bundles are used (such as inside of Intent objects), the Bundle
    784      * can live longer inside of another process than the process that had originally
    785      * created it.  In that case, the IBinder you supply here will become invalid
    786      * when your process goes away, and no longer usable, even if a new process is
    787      * created for you later on.</p>
    788      *
    789      * @param key a String, or null
    790      * @param value an IBinder object, or null
    791      */
    792     public void putBinder(String key, IBinder value) {
    793         unparcel();
    794         mMap.put(key, value);
    795     }
    796 
    797     /**
    798      * Inserts an IBinder value into the mapping of this Bundle, replacing
    799      * any existing value for the given key.  Either key or value may be null.
    800      *
    801      * @param key a String, or null
    802      * @param value an IBinder object, or null
    803      *
    804      * @deprecated
    805      * @hide This is the old name of the function.
    806      */
    807     @Deprecated
    808     public void putIBinder(String key, IBinder value) {
    809         unparcel();
    810         mMap.put(key, value);
    811     }
    812 
    813     /**
    814      * Returns the value associated with the given key, or false if
    815      * no mapping of the desired type exists for the given key.
    816      *
    817      * @param key a String
    818      * @return a boolean value
    819      */
    820     public boolean getBoolean(String key) {
    821         unparcel();
    822         if (DEBUG) Log.d(TAG, "Getting boolean in "
    823                 + Integer.toHexString(System.identityHashCode(this)));
    824         return getBoolean(key, false);
    825     }
    826 
    827     // Log a message if the value was non-null but not of the expected type
    828     private void typeWarning(String key, Object value, String className,
    829         Object defaultValue, ClassCastException e) {
    830         StringBuilder sb = new StringBuilder();
    831         sb.append("Key ");
    832         sb.append(key);
    833         sb.append(" expected ");
    834         sb.append(className);
    835         sb.append(" but value was a ");
    836         sb.append(value.getClass().getName());
    837         sb.append(".  The default value ");
    838         sb.append(defaultValue);
    839         sb.append(" was returned.");
    840         Log.w(TAG, sb.toString());
    841         Log.w(TAG, "Attempt to cast generated internal exception:", e);
    842     }
    843 
    844     private void typeWarning(String key, Object value, String className,
    845         ClassCastException e) {
    846         typeWarning(key, value, className, "<null>", e);
    847     }
    848 
    849     /**
    850      * Returns the value associated with the given key, or defaultValue if
    851      * no mapping of the desired type exists for the given key.
    852      *
    853      * @param key a String
    854      * @param defaultValue Value to return if key does not exist
    855      * @return a boolean value
    856      */
    857     public boolean getBoolean(String key, boolean defaultValue) {
    858         unparcel();
    859         Object o = mMap.get(key);
    860         if (o == null) {
    861             return defaultValue;
    862         }
    863         try {
    864             return (Boolean) o;
    865         } catch (ClassCastException e) {
    866             typeWarning(key, o, "Boolean", defaultValue, e);
    867             return defaultValue;
    868         }
    869     }
    870 
    871     /**
    872      * Returns the value associated with the given key, or (byte) 0 if
    873      * no mapping of the desired type exists for the given key.
    874      *
    875      * @param key a String
    876      * @return a byte value
    877      */
    878     public byte getByte(String key) {
    879         unparcel();
    880         return getByte(key, (byte) 0);
    881     }
    882 
    883     /**
    884      * Returns the value associated with the given key, or defaultValue if
    885      * no mapping of the desired type exists for the given key.
    886      *
    887      * @param key a String
    888      * @param defaultValue Value to return if key does not exist
    889      * @return a byte value
    890      */
    891     public Byte getByte(String key, byte defaultValue) {
    892         unparcel();
    893         Object o = mMap.get(key);
    894         if (o == null) {
    895             return defaultValue;
    896         }
    897         try {
    898             return (Byte) o;
    899         } catch (ClassCastException e) {
    900             typeWarning(key, o, "Byte", defaultValue, e);
    901             return defaultValue;
    902         }
    903     }
    904 
    905     /**
    906      * Returns the value associated with the given key, or (char) 0 if
    907      * no mapping of the desired type exists for the given key.
    908      *
    909      * @param key a String
    910      * @return a char value
    911      */
    912     public char getChar(String key) {
    913         unparcel();
    914         return getChar(key, (char) 0);
    915     }
    916 
    917     /**
    918      * Returns the value associated with the given key, or defaultValue if
    919      * no mapping of the desired type exists for the given key.
    920      *
    921      * @param key a String
    922      * @param defaultValue Value to return if key does not exist
    923      * @return a char value
    924      */
    925     public char getChar(String key, char defaultValue) {
    926         unparcel();
    927         Object o = mMap.get(key);
    928         if (o == null) {
    929             return defaultValue;
    930         }
    931         try {
    932             return (Character) o;
    933         } catch (ClassCastException e) {
    934             typeWarning(key, o, "Character", defaultValue, e);
    935             return defaultValue;
    936         }
    937     }
    938 
    939     /**
    940      * Returns the value associated with the given key, or (short) 0 if
    941      * no mapping of the desired type exists for the given key.
    942      *
    943      * @param key a String
    944      * @return a short value
    945      */
    946     public short getShort(String key) {
    947         unparcel();
    948         return getShort(key, (short) 0);
    949     }
    950 
    951     /**
    952      * Returns the value associated with the given key, or defaultValue if
    953      * no mapping of the desired type exists for the given key.
    954      *
    955      * @param key a String
    956      * @param defaultValue Value to return if key does not exist
    957      * @return a short value
    958      */
    959     public short getShort(String key, short defaultValue) {
    960         unparcel();
    961         Object o = mMap.get(key);
    962         if (o == null) {
    963             return defaultValue;
    964         }
    965         try {
    966             return (Short) o;
    967         } catch (ClassCastException e) {
    968             typeWarning(key, o, "Short", defaultValue, e);
    969             return defaultValue;
    970         }
    971     }
    972 
    973     /**
    974      * Returns the value associated with the given key, or 0 if
    975      * no mapping of the desired type exists for the given key.
    976      *
    977      * @param key a String
    978      * @return an int value
    979      */
    980     public int getInt(String key) {
    981         unparcel();
    982         return getInt(key, 0);
    983     }
    984 
    985     /**
    986      * Returns the value associated with the given key, or defaultValue if
    987      * no mapping of the desired type exists for the given key.
    988      *
    989      * @param key a String
    990      * @param defaultValue Value to return if key does not exist
    991      * @return an int value
    992      */
    993     public int getInt(String key, int defaultValue) {
    994         unparcel();
    995         Object o = mMap.get(key);
    996         if (o == null) {
    997             return defaultValue;
    998         }
    999         try {
   1000             return (Integer) o;
   1001         } catch (ClassCastException e) {
   1002             typeWarning(key, o, "Integer", defaultValue, e);
   1003             return defaultValue;
   1004         }
   1005     }
   1006 
   1007     /**
   1008      * Returns the value associated with the given key, or 0L if
   1009      * no mapping of the desired type exists for the given key.
   1010      *
   1011      * @param key a String
   1012      * @return a long value
   1013      */
   1014     public long getLong(String key) {
   1015         unparcel();
   1016         return getLong(key, 0L);
   1017     }
   1018 
   1019     /**
   1020      * Returns the value associated with the given key, or defaultValue if
   1021      * no mapping of the desired type exists for the given key.
   1022      *
   1023      * @param key a String
   1024      * @param defaultValue Value to return if key does not exist
   1025      * @return a long value
   1026      */
   1027     public long getLong(String key, long defaultValue) {
   1028         unparcel();
   1029         Object o = mMap.get(key);
   1030         if (o == null) {
   1031             return defaultValue;
   1032         }
   1033         try {
   1034             return (Long) o;
   1035         } catch (ClassCastException e) {
   1036             typeWarning(key, o, "Long", defaultValue, e);
   1037             return defaultValue;
   1038         }
   1039     }
   1040 
   1041     /**
   1042      * Returns the value associated with the given key, or 0.0f if
   1043      * no mapping of the desired type exists for the given key.
   1044      *
   1045      * @param key a String
   1046      * @return a float value
   1047      */
   1048     public float getFloat(String key) {
   1049         unparcel();
   1050         return getFloat(key, 0.0f);
   1051     }
   1052 
   1053     /**
   1054      * Returns the value associated with the given key, or defaultValue if
   1055      * no mapping of the desired type exists for the given key.
   1056      *
   1057      * @param key a String
   1058      * @param defaultValue Value to return if key does not exist
   1059      * @return a float value
   1060      */
   1061     public float getFloat(String key, float defaultValue) {
   1062         unparcel();
   1063         Object o = mMap.get(key);
   1064         if (o == null) {
   1065             return defaultValue;
   1066         }
   1067         try {
   1068             return (Float) o;
   1069         } catch (ClassCastException e) {
   1070             typeWarning(key, o, "Float", defaultValue, e);
   1071             return defaultValue;
   1072         }
   1073     }
   1074 
   1075     /**
   1076      * Returns the value associated with the given key, or 0.0 if
   1077      * no mapping of the desired type exists for the given key.
   1078      *
   1079      * @param key a String
   1080      * @return a double value
   1081      */
   1082     public double getDouble(String key) {
   1083         unparcel();
   1084         return getDouble(key, 0.0);
   1085     }
   1086 
   1087     /**
   1088      * Returns the value associated with the given key, or defaultValue if
   1089      * no mapping of the desired type exists for the given key.
   1090      *
   1091      * @param key a String
   1092      * @param defaultValue Value to return if key does not exist
   1093      * @return a double value
   1094      */
   1095     public double getDouble(String key, double defaultValue) {
   1096         unparcel();
   1097         Object o = mMap.get(key);
   1098         if (o == null) {
   1099             return defaultValue;
   1100         }
   1101         try {
   1102             return (Double) o;
   1103         } catch (ClassCastException e) {
   1104             typeWarning(key, o, "Double", defaultValue, e);
   1105             return defaultValue;
   1106         }
   1107     }
   1108 
   1109     /**
   1110      * Returns the value associated with the given key, or null if
   1111      * no mapping of the desired type exists for the given key or a null
   1112      * value is explicitly associated with the key.
   1113      *
   1114      * @param key a String, or null
   1115      * @return a String value, or null
   1116      */
   1117     public String getString(String key) {
   1118         unparcel();
   1119         final Object o = mMap.get(key);
   1120         try {
   1121             return (String) o;
   1122         } catch (ClassCastException e) {
   1123             typeWarning(key, o, "String", e);
   1124             return null;
   1125         }
   1126     }
   1127 
   1128     /**
   1129      * Returns the value associated with the given key, or defaultValue if
   1130      * no mapping of the desired type exists for the given key.
   1131      *
   1132      * @param key a String, or null
   1133      * @param defaultValue Value to return if key does not exist
   1134      * @return the String value associated with the given key, or defaultValue
   1135      *     if no valid String object is currently mapped to that key.
   1136      */
   1137     public String getString(String key, String defaultValue) {
   1138         final String s = getString(key);
   1139         return (s == null) ? defaultValue : s;
   1140     }
   1141 
   1142     /**
   1143      * Returns the value associated with the given key, or null if
   1144      * no mapping of the desired type exists for the given key or a null
   1145      * value is explicitly associated with the key.
   1146      *
   1147      * @param key a String, or null
   1148      * @return a CharSequence value, or null
   1149      */
   1150     public CharSequence getCharSequence(String key) {
   1151         unparcel();
   1152         final Object o = mMap.get(key);
   1153         try {
   1154             return (CharSequence) o;
   1155         } catch (ClassCastException e) {
   1156             typeWarning(key, o, "CharSequence", e);
   1157             return null;
   1158         }
   1159     }
   1160 
   1161     /**
   1162      * Returns the value associated with the given key, or defaultValue if
   1163      * no mapping of the desired type exists for the given key.
   1164      *
   1165      * @param key a String, or null
   1166      * @param defaultValue Value to return if key does not exist
   1167      * @return the CharSequence value associated with the given key, or defaultValue
   1168      *     if no valid CharSequence object is currently mapped to that key.
   1169      */
   1170     public CharSequence getCharSequence(String key, CharSequence defaultValue) {
   1171         final CharSequence cs = getCharSequence(key);
   1172         return (cs == null) ? defaultValue : cs;
   1173     }
   1174 
   1175     /**
   1176      * Returns the value associated with the given key, or null if
   1177      * no mapping of the desired type exists for the given key or a null
   1178      * value is explicitly associated with the key.
   1179      *
   1180      * @param key a String, or null
   1181      * @return a Bundle value, or null
   1182      */
   1183     public Bundle getBundle(String key) {
   1184         unparcel();
   1185         Object o = mMap.get(key);
   1186         if (o == null) {
   1187             return null;
   1188         }
   1189         try {
   1190             return (Bundle) o;
   1191         } catch (ClassCastException e) {
   1192             typeWarning(key, o, "Bundle", e);
   1193             return null;
   1194         }
   1195     }
   1196 
   1197     /**
   1198      * Returns the value associated with the given key, or null if
   1199      * no mapping of the desired type exists for the given key or a null
   1200      * value is explicitly associated with the key.
   1201      *
   1202      * @param key a String, or null
   1203      * @return a Parcelable value, or null
   1204      */
   1205     public <T extends Parcelable> T getParcelable(String key) {
   1206         unparcel();
   1207         Object o = mMap.get(key);
   1208         if (o == null) {
   1209             return null;
   1210         }
   1211         try {
   1212             return (T) o;
   1213         } catch (ClassCastException e) {
   1214             typeWarning(key, o, "Parcelable", e);
   1215             return null;
   1216         }
   1217     }
   1218 
   1219     /**
   1220      * Returns the value associated with the given key, or null if
   1221      * no mapping of the desired type exists for the given key or a null
   1222      * value is explicitly associated with the key.
   1223      *
   1224      * @param key a String, or null
   1225      * @return a Parcelable[] value, or null
   1226      */
   1227     public Parcelable[] getParcelableArray(String key) {
   1228         unparcel();
   1229         Object o = mMap.get(key);
   1230         if (o == null) {
   1231             return null;
   1232         }
   1233         try {
   1234             return (Parcelable[]) o;
   1235         } catch (ClassCastException e) {
   1236             typeWarning(key, o, "Parcelable[]", e);
   1237             return null;
   1238         }
   1239     }
   1240 
   1241     /**
   1242      * Returns the value associated with the given key, or null if
   1243      * no mapping of the desired type exists for the given key or a null
   1244      * value is explicitly associated with the key.
   1245      *
   1246      * @param key a String, or null
   1247      * @return an ArrayList<T> value, or null
   1248      */
   1249     public <T extends Parcelable> ArrayList<T> getParcelableArrayList(String key) {
   1250         unparcel();
   1251         Object o = mMap.get(key);
   1252         if (o == null) {
   1253             return null;
   1254         }
   1255         try {
   1256             return (ArrayList<T>) o;
   1257         } catch (ClassCastException e) {
   1258             typeWarning(key, o, "ArrayList", e);
   1259             return null;
   1260         }
   1261     }
   1262 
   1263     /**
   1264      * Returns the value associated with the given key, or null if
   1265      * no mapping of the desired type exists for the given key or a null
   1266      * value is explicitly associated with the key.
   1267      *
   1268      * @param key a String, or null
   1269      *
   1270      * @return a SparseArray of T values, or null
   1271      */
   1272     public <T extends Parcelable> SparseArray<T> getSparseParcelableArray(String key) {
   1273         unparcel();
   1274         Object o = mMap.get(key);
   1275         if (o == null) {
   1276             return null;
   1277         }
   1278         try {
   1279             return (SparseArray<T>) o;
   1280         } catch (ClassCastException e) {
   1281             typeWarning(key, o, "SparseArray", e);
   1282             return null;
   1283         }
   1284     }
   1285 
   1286     /**
   1287      * Returns the value associated with the given key, or null if
   1288      * no mapping of the desired type exists for the given key or a null
   1289      * value is explicitly associated with the key.
   1290      *
   1291      * @param key a String, or null
   1292      * @return a Serializable value, or null
   1293      */
   1294     public Serializable getSerializable(String key) {
   1295         unparcel();
   1296         Object o = mMap.get(key);
   1297         if (o == null) {
   1298             return null;
   1299         }
   1300         try {
   1301             return (Serializable) o;
   1302         } catch (ClassCastException e) {
   1303             typeWarning(key, o, "Serializable", e);
   1304             return null;
   1305         }
   1306     }
   1307 
   1308     /**
   1309      * Returns the value associated with the given key, or null if
   1310      * no mapping of the desired type exists for the given key or a null
   1311      * value is explicitly associated with the key.
   1312      *
   1313      * @param key a String, or null
   1314      * @return an ArrayList<String> value, or null
   1315      */
   1316     public ArrayList<Integer> getIntegerArrayList(String key) {
   1317         unparcel();
   1318         Object o = mMap.get(key);
   1319         if (o == null) {
   1320             return null;
   1321         }
   1322         try {
   1323             return (ArrayList<Integer>) o;
   1324         } catch (ClassCastException e) {
   1325             typeWarning(key, o, "ArrayList<Integer>", e);
   1326             return null;
   1327         }
   1328     }
   1329 
   1330     /**
   1331      * Returns the value associated with the given key, or null if
   1332      * no mapping of the desired type exists for the given key or a null
   1333      * value is explicitly associated with the key.
   1334      *
   1335      * @param key a String, or null
   1336      * @return an ArrayList<String> value, or null
   1337      */
   1338     public ArrayList<String> getStringArrayList(String key) {
   1339         unparcel();
   1340         Object o = mMap.get(key);
   1341         if (o == null) {
   1342             return null;
   1343         }
   1344         try {
   1345             return (ArrayList<String>) o;
   1346         } catch (ClassCastException e) {
   1347             typeWarning(key, o, "ArrayList<String>", e);
   1348             return null;
   1349         }
   1350     }
   1351 
   1352     /**
   1353      * Returns the value associated with the given key, or null if
   1354      * no mapping of the desired type exists for the given key or a null
   1355      * value is explicitly associated with the key.
   1356      *
   1357      * @param key a String, or null
   1358      * @return an ArrayList<CharSequence> value, or null
   1359      */
   1360     public ArrayList<CharSequence> getCharSequenceArrayList(String key) {
   1361         unparcel();
   1362         Object o = mMap.get(key);
   1363         if (o == null) {
   1364             return null;
   1365         }
   1366         try {
   1367             return (ArrayList<CharSequence>) o;
   1368         } catch (ClassCastException e) {
   1369             typeWarning(key, o, "ArrayList<CharSequence>", e);
   1370             return null;
   1371         }
   1372     }
   1373 
   1374     /**
   1375      * Returns the value associated with the given key, or null if
   1376      * no mapping of the desired type exists for the given key or a null
   1377      * value is explicitly associated with the key.
   1378      *
   1379      * @param key a String, or null
   1380      * @return a boolean[] value, or null
   1381      */
   1382     public boolean[] getBooleanArray(String key) {
   1383         unparcel();
   1384         Object o = mMap.get(key);
   1385         if (o == null) {
   1386             return null;
   1387         }
   1388         try {
   1389             return (boolean[]) o;
   1390         } catch (ClassCastException e) {
   1391             typeWarning(key, o, "byte[]", e);
   1392             return null;
   1393         }
   1394     }
   1395 
   1396     /**
   1397      * Returns the value associated with the given key, or null if
   1398      * no mapping of the desired type exists for the given key or a null
   1399      * value is explicitly associated with the key.
   1400      *
   1401      * @param key a String, or null
   1402      * @return a byte[] value, or null
   1403      */
   1404     public byte[] getByteArray(String key) {
   1405         unparcel();
   1406         Object o = mMap.get(key);
   1407         if (o == null) {
   1408             return null;
   1409         }
   1410         try {
   1411             return (byte[]) o;
   1412         } catch (ClassCastException e) {
   1413             typeWarning(key, o, "byte[]", e);
   1414             return null;
   1415         }
   1416     }
   1417 
   1418     /**
   1419      * Returns the value associated with the given key, or null if
   1420      * no mapping of the desired type exists for the given key or a null
   1421      * value is explicitly associated with the key.
   1422      *
   1423      * @param key a String, or null
   1424      * @return a short[] value, or null
   1425      */
   1426     public short[] getShortArray(String key) {
   1427         unparcel();
   1428         Object o = mMap.get(key);
   1429         if (o == null) {
   1430             return null;
   1431         }
   1432         try {
   1433             return (short[]) o;
   1434         } catch (ClassCastException e) {
   1435             typeWarning(key, o, "short[]", e);
   1436             return null;
   1437         }
   1438     }
   1439 
   1440     /**
   1441      * Returns the value associated with the given key, or null if
   1442      * no mapping of the desired type exists for the given key or a null
   1443      * value is explicitly associated with the key.
   1444      *
   1445      * @param key a String, or null
   1446      * @return a char[] value, or null
   1447      */
   1448     public char[] getCharArray(String key) {
   1449         unparcel();
   1450         Object o = mMap.get(key);
   1451         if (o == null) {
   1452             return null;
   1453         }
   1454         try {
   1455             return (char[]) o;
   1456         } catch (ClassCastException e) {
   1457             typeWarning(key, o, "char[]", e);
   1458             return null;
   1459         }
   1460     }
   1461 
   1462     /**
   1463      * Returns the value associated with the given key, or null if
   1464      * no mapping of the desired type exists for the given key or a null
   1465      * value is explicitly associated with the key.
   1466      *
   1467      * @param key a String, or null
   1468      * @return an int[] value, or null
   1469      */
   1470     public int[] getIntArray(String key) {
   1471         unparcel();
   1472         Object o = mMap.get(key);
   1473         if (o == null) {
   1474             return null;
   1475         }
   1476         try {
   1477             return (int[]) o;
   1478         } catch (ClassCastException e) {
   1479             typeWarning(key, o, "int[]", e);
   1480             return null;
   1481         }
   1482     }
   1483 
   1484     /**
   1485      * Returns the value associated with the given key, or null if
   1486      * no mapping of the desired type exists for the given key or a null
   1487      * value is explicitly associated with the key.
   1488      *
   1489      * @param key a String, or null
   1490      * @return a long[] value, or null
   1491      */
   1492     public long[] getLongArray(String key) {
   1493         unparcel();
   1494         Object o = mMap.get(key);
   1495         if (o == null) {
   1496             return null;
   1497         }
   1498         try {
   1499             return (long[]) o;
   1500         } catch (ClassCastException e) {
   1501             typeWarning(key, o, "long[]", e);
   1502             return null;
   1503         }
   1504     }
   1505 
   1506     /**
   1507      * Returns the value associated with the given key, or null if
   1508      * no mapping of the desired type exists for the given key or a null
   1509      * value is explicitly associated with the key.
   1510      *
   1511      * @param key a String, or null
   1512      * @return a float[] value, or null
   1513      */
   1514     public float[] getFloatArray(String key) {
   1515         unparcel();
   1516         Object o = mMap.get(key);
   1517         if (o == null) {
   1518             return null;
   1519         }
   1520         try {
   1521             return (float[]) o;
   1522         } catch (ClassCastException e) {
   1523             typeWarning(key, o, "float[]", e);
   1524             return null;
   1525         }
   1526     }
   1527 
   1528     /**
   1529      * Returns the value associated with the given key, or null if
   1530      * no mapping of the desired type exists for the given key or a null
   1531      * value is explicitly associated with the key.
   1532      *
   1533      * @param key a String, or null
   1534      * @return a double[] value, or null
   1535      */
   1536     public double[] getDoubleArray(String key) {
   1537         unparcel();
   1538         Object o = mMap.get(key);
   1539         if (o == null) {
   1540             return null;
   1541         }
   1542         try {
   1543             return (double[]) o;
   1544         } catch (ClassCastException e) {
   1545             typeWarning(key, o, "double[]", e);
   1546             return null;
   1547         }
   1548     }
   1549 
   1550     /**
   1551      * Returns the value associated with the given key, or null if
   1552      * no mapping of the desired type exists for the given key or a null
   1553      * value is explicitly associated with the key.
   1554      *
   1555      * @param key a String, or null
   1556      * @return a String[] value, or null
   1557      */
   1558     public String[] getStringArray(String key) {
   1559         unparcel();
   1560         Object o = mMap.get(key);
   1561         if (o == null) {
   1562             return null;
   1563         }
   1564         try {
   1565             return (String[]) o;
   1566         } catch (ClassCastException e) {
   1567             typeWarning(key, o, "String[]", e);
   1568             return null;
   1569         }
   1570     }
   1571 
   1572     /**
   1573      * Returns the value associated with the given key, or null if
   1574      * no mapping of the desired type exists for the given key or a null
   1575      * value is explicitly associated with the key.
   1576      *
   1577      * @param key a String, or null
   1578      * @return a CharSequence[] value, or null
   1579      */
   1580     public CharSequence[] getCharSequenceArray(String key) {
   1581         unparcel();
   1582         Object o = mMap.get(key);
   1583         if (o == null) {
   1584             return null;
   1585         }
   1586         try {
   1587             return (CharSequence[]) o;
   1588         } catch (ClassCastException e) {
   1589             typeWarning(key, o, "CharSequence[]", e);
   1590             return null;
   1591         }
   1592     }
   1593 
   1594     /**
   1595      * Returns the value associated with the given key, or null if
   1596      * no mapping of the desired type exists for the given key or a null
   1597      * value is explicitly associated with the key.
   1598      *
   1599      * @param key a String, or null
   1600      * @return an IBinder value, or null
   1601      */
   1602     public IBinder getBinder(String key) {
   1603         unparcel();
   1604         Object o = mMap.get(key);
   1605         if (o == null) {
   1606             return null;
   1607         }
   1608         try {
   1609             return (IBinder) o;
   1610         } catch (ClassCastException e) {
   1611             typeWarning(key, o, "IBinder", e);
   1612             return null;
   1613         }
   1614     }
   1615 
   1616     /**
   1617      * Returns the value associated with the given key, or null if
   1618      * no mapping of the desired type exists for the given key or a null
   1619      * value is explicitly associated with the key.
   1620      *
   1621      * @param key a String, or null
   1622      * @return an IBinder value, or null
   1623      *
   1624      * @deprecated
   1625      * @hide This is the old name of the function.
   1626      */
   1627     @Deprecated
   1628     public IBinder getIBinder(String key) {
   1629         unparcel();
   1630         Object o = mMap.get(key);
   1631         if (o == null) {
   1632             return null;
   1633         }
   1634         try {
   1635             return (IBinder) o;
   1636         } catch (ClassCastException e) {
   1637             typeWarning(key, o, "IBinder", e);
   1638             return null;
   1639         }
   1640     }
   1641 
   1642     public static final Parcelable.Creator<Bundle> CREATOR =
   1643         new Parcelable.Creator<Bundle>() {
   1644         public Bundle createFromParcel(Parcel in) {
   1645             return in.readBundle();
   1646         }
   1647 
   1648         public Bundle[] newArray(int size) {
   1649             return new Bundle[size];
   1650         }
   1651     };
   1652 
   1653     /**
   1654      * Report the nature of this Parcelable's contents
   1655      */
   1656     public int describeContents() {
   1657         int mask = 0;
   1658         if (hasFileDescriptors()) {
   1659             mask |= Parcelable.CONTENTS_FILE_DESCRIPTOR;
   1660         }
   1661         return mask;
   1662     }
   1663 
   1664     /**
   1665      * Writes the Bundle contents to a Parcel, typically in order for
   1666      * it to be passed through an IBinder connection.
   1667      * @param parcel The parcel to copy this bundle to.
   1668      */
   1669     public void writeToParcel(Parcel parcel, int flags) {
   1670         final boolean oldAllowFds = parcel.pushAllowFds(mAllowFds);
   1671         try {
   1672             if (mParcelledData != null) {
   1673                 if (mParcelledData == EMPTY_PARCEL) {
   1674                     parcel.writeInt(0);
   1675                 } else {
   1676                     int length = mParcelledData.dataSize();
   1677                     parcel.writeInt(length);
   1678                     parcel.writeInt(BUNDLE_MAGIC);
   1679                     parcel.appendFrom(mParcelledData, 0, length);
   1680                 }
   1681             } else {
   1682                 // Special case for empty bundles.
   1683                 if (mMap == null || mMap.size() <= 0) {
   1684                     parcel.writeInt(0);
   1685                     return;
   1686                 }
   1687                 int lengthPos = parcel.dataPosition();
   1688                 parcel.writeInt(-1); // dummy, will hold length
   1689                 parcel.writeInt(BUNDLE_MAGIC);
   1690 
   1691                 int startPos = parcel.dataPosition();
   1692                 parcel.writeArrayMapInternal(mMap);
   1693                 int endPos = parcel.dataPosition();
   1694 
   1695                 // Backpatch length
   1696                 parcel.setDataPosition(lengthPos);
   1697                 int length = endPos - startPos;
   1698                 parcel.writeInt(length);
   1699                 parcel.setDataPosition(endPos);
   1700             }
   1701         } finally {
   1702             parcel.restoreAllowFds(oldAllowFds);
   1703         }
   1704     }
   1705 
   1706     /**
   1707      * Reads the Parcel contents into this Bundle, typically in order for
   1708      * it to be passed through an IBinder connection.
   1709      * @param parcel The parcel to overwrite this bundle from.
   1710      */
   1711     public void readFromParcel(Parcel parcel) {
   1712         int length = parcel.readInt();
   1713         if (length < 0) {
   1714             throw new RuntimeException("Bad length in parcel: " + length);
   1715         }
   1716         readFromParcelInner(parcel, length);
   1717     }
   1718 
   1719     void readFromParcelInner(Parcel parcel, int length) {
   1720         if (length == 0) {
   1721             // Empty Bundle or end of data.
   1722             mParcelledData = EMPTY_PARCEL;
   1723             mHasFds = false;
   1724             mFdsKnown = true;
   1725             return;
   1726         }
   1727         int magic = parcel.readInt();
   1728         if (magic != BUNDLE_MAGIC) {
   1729             //noinspection ThrowableInstanceNeverThrown
   1730             throw new IllegalStateException("Bad magic number for Bundle: 0x"
   1731                     + Integer.toHexString(magic));
   1732         }
   1733 
   1734         // Advance within this Parcel
   1735         int offset = parcel.dataPosition();
   1736         parcel.setDataPosition(offset + length);
   1737 
   1738         Parcel p = Parcel.obtain();
   1739         p.setDataPosition(0);
   1740         p.appendFrom(parcel, offset, length);
   1741         if (DEBUG) Log.d(TAG, "Retrieving "  + Integer.toHexString(System.identityHashCode(this))
   1742                 + ": " + length + " bundle bytes starting at " + offset);
   1743         p.setDataPosition(0);
   1744 
   1745         mParcelledData = p;
   1746         mHasFds = p.hasFileDescriptors();
   1747         mFdsKnown = true;
   1748     }
   1749 
   1750     @Override
   1751     public synchronized String toString() {
   1752         if (mParcelledData != null) {
   1753             if (mParcelledData == EMPTY_PARCEL) {
   1754                 return "Bundle[EMPTY_PARCEL]";
   1755             } else {
   1756                 return "Bundle[mParcelledData.dataSize=" +
   1757                         mParcelledData.dataSize() + "]";
   1758             }
   1759         }
   1760         return "Bundle[" + mMap.toString() + "]";
   1761     }
   1762 }
   1763