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