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>();
    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 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      * @param key a String, or null
    749      * @param value an IBinder object, or null
    750      *
    751      * @deprecated
    752      * @hide
    753      */
    754     @Deprecated
    755     public void putIBinder(String key, IBinder value) {
    756         unparcel();
    757         mMap.put(key, value);
    758     }
    759 
    760     /**
    761      * Returns the value associated with the given key, or false if
    762      * no mapping of the desired type exists for the given key.
    763      *
    764      * @param key a String
    765      * @return a boolean value
    766      */
    767     public boolean getBoolean(String key) {
    768         unparcel();
    769         return getBoolean(key, false);
    770     }
    771 
    772     // Log a message if the value was non-null but not of the expected type
    773     private void typeWarning(String key, Object value, String className,
    774         Object defaultValue, ClassCastException e) {
    775         StringBuilder sb = new StringBuilder();
    776         sb.append("Key ");
    777         sb.append(key);
    778         sb.append(" expected ");
    779         sb.append(className);
    780         sb.append(" but value was a ");
    781         sb.append(value.getClass().getName());
    782         sb.append(".  The default value ");
    783         sb.append(defaultValue);
    784         sb.append(" was returned.");
    785         Log.w(LOG_TAG, sb.toString());
    786         Log.w(LOG_TAG, "Attempt to cast generated internal exception:", e);
    787     }
    788 
    789     private void typeWarning(String key, Object value, String className,
    790         ClassCastException e) {
    791         typeWarning(key, value, className, "<null>", e);
    792     }
    793 
    794     /**
    795      * Returns the value associated with the given key, or defaultValue if
    796      * no mapping of the desired type exists for the given key.
    797      *
    798      * @param key a String
    799      * @return a boolean value
    800      */
    801     public boolean getBoolean(String key, boolean defaultValue) {
    802         unparcel();
    803         Object o = mMap.get(key);
    804         if (o == null) {
    805             return defaultValue;
    806         }
    807         try {
    808             return (Boolean) o;
    809         } catch (ClassCastException e) {
    810             typeWarning(key, o, "Boolean", defaultValue, e);
    811             return defaultValue;
    812         }
    813     }
    814 
    815     /**
    816      * Returns the value associated with the given key, or (byte) 0 if
    817      * no mapping of the desired type exists for the given key.
    818      *
    819      * @param key a String
    820      * @return a byte value
    821      */
    822     public byte getByte(String key) {
    823         unparcel();
    824         return getByte(key, (byte) 0);
    825     }
    826 
    827     /**
    828      * Returns the value associated with the given key, or defaultValue if
    829      * no mapping of the desired type exists for the given key.
    830      *
    831      * @param key a String
    832      * @return a byte value
    833      */
    834     public Byte getByte(String key, byte defaultValue) {
    835         unparcel();
    836         Object o = mMap.get(key);
    837         if (o == null) {
    838             return defaultValue;
    839         }
    840         try {
    841             return (Byte) o;
    842         } catch (ClassCastException e) {
    843             typeWarning(key, o, "Byte", defaultValue, e);
    844             return defaultValue;
    845         }
    846     }
    847 
    848     /**
    849      * Returns the value associated with the given key, or false if
    850      * no mapping of the desired type exists for the given key.
    851      *
    852      * @param key a String
    853      * @return a char value
    854      */
    855     public char getChar(String key) {
    856         unparcel();
    857         return getChar(key, (char) 0);
    858     }
    859 
    860     /**
    861      * Returns the value associated with the given key, or (char) 0 if
    862      * no mapping of the desired type exists for the given key.
    863      *
    864      * @param key a String
    865      * @return a char value
    866      */
    867     public char getChar(String key, char defaultValue) {
    868         unparcel();
    869         Object o = mMap.get(key);
    870         if (o == null) {
    871             return defaultValue;
    872         }
    873         try {
    874             return (Character) o;
    875         } catch (ClassCastException e) {
    876             typeWarning(key, o, "Character", defaultValue, e);
    877             return defaultValue;
    878         }
    879     }
    880 
    881     /**
    882      * Returns the value associated with the given key, or (short) 0 if
    883      * no mapping of the desired type exists for the given key.
    884      *
    885      * @param key a String
    886      * @return a short value
    887      */
    888     public short getShort(String key) {
    889         unparcel();
    890         return getShort(key, (short) 0);
    891     }
    892 
    893     /**
    894      * Returns the value associated with the given key, or defaultValue if
    895      * no mapping of the desired type exists for the given key.
    896      *
    897      * @param key a String
    898      * @return a short value
    899      */
    900     public short getShort(String key, short defaultValue) {
    901         unparcel();
    902         Object o = mMap.get(key);
    903         if (o == null) {
    904             return defaultValue;
    905         }
    906         try {
    907             return (Short) o;
    908         } catch (ClassCastException e) {
    909             typeWarning(key, o, "Short", defaultValue, e);
    910             return defaultValue;
    911         }
    912     }
    913 
    914     /**
    915      * Returns the value associated with the given key, or 0 if
    916      * no mapping of the desired type exists for the given key.
    917      *
    918      * @param key a String
    919      * @return an int value
    920      */
    921     public int getInt(String key) {
    922         unparcel();
    923         return getInt(key, 0);
    924     }
    925 
    926     /**
    927      * Returns the value associated with the given key, or defaultValue if
    928      * no mapping of the desired type exists for the given key.
    929      *
    930      * @param key a String
    931      * @return an int value
    932      */
    933     public int getInt(String key, int defaultValue) {
    934         unparcel();
    935         Object o = mMap.get(key);
    936         if (o == null) {
    937             return defaultValue;
    938         }
    939         try {
    940             return (Integer) o;
    941         } catch (ClassCastException e) {
    942             typeWarning(key, o, "Integer", defaultValue, e);
    943             return defaultValue;
    944         }
    945     }
    946 
    947     /**
    948      * Returns the value associated with the given key, or 0L if
    949      * no mapping of the desired type exists for the given key.
    950      *
    951      * @param key a String
    952      * @return a long value
    953      */
    954     public long getLong(String key) {
    955         unparcel();
    956         return getLong(key, 0L);
    957     }
    958 
    959     /**
    960      * Returns the value associated with the given key, or defaultValue if
    961      * no mapping of the desired type exists for the given key.
    962      *
    963      * @param key a String
    964      * @return a long value
    965      */
    966     public long getLong(String key, long defaultValue) {
    967         unparcel();
    968         Object o = mMap.get(key);
    969         if (o == null) {
    970             return defaultValue;
    971         }
    972         try {
    973             return (Long) o;
    974         } catch (ClassCastException e) {
    975             typeWarning(key, o, "Long", defaultValue, e);
    976             return defaultValue;
    977         }
    978     }
    979 
    980     /**
    981      * Returns the value associated with the given key, or 0.0f if
    982      * no mapping of the desired type exists for the given key.
    983      *
    984      * @param key a String
    985      * @return a float value
    986      */
    987     public float getFloat(String key) {
    988         unparcel();
    989         return getFloat(key, 0.0f);
    990     }
    991 
    992     /**
    993      * Returns the value associated with the given key, or defaultValue if
    994      * no mapping of the desired type exists for the given key.
    995      *
    996      * @param key a String
    997      * @return a float value
    998      */
    999     public float getFloat(String key, float defaultValue) {
   1000         unparcel();
   1001         Object o = mMap.get(key);
   1002         if (o == null) {
   1003             return defaultValue;
   1004         }
   1005         try {
   1006             return (Float) o;
   1007         } catch (ClassCastException e) {
   1008             typeWarning(key, o, "Float", defaultValue, e);
   1009             return defaultValue;
   1010         }
   1011     }
   1012 
   1013     /**
   1014      * Returns the value associated with the given key, or 0.0 if
   1015      * no mapping of the desired type exists for the given key.
   1016      *
   1017      * @param key a String
   1018      * @return a double value
   1019      */
   1020     public double getDouble(String key) {
   1021         unparcel();
   1022         return getDouble(key, 0.0);
   1023     }
   1024 
   1025     /**
   1026      * Returns the value associated with the given key, or defaultValue if
   1027      * no mapping of the desired type exists for the given key.
   1028      *
   1029      * @param key a String
   1030      * @return a double value
   1031      */
   1032     public double getDouble(String key, double defaultValue) {
   1033         unparcel();
   1034         Object o = mMap.get(key);
   1035         if (o == null) {
   1036             return defaultValue;
   1037         }
   1038         try {
   1039             return (Double) o;
   1040         } catch (ClassCastException e) {
   1041             typeWarning(key, o, "Double", defaultValue, e);
   1042             return defaultValue;
   1043         }
   1044     }
   1045 
   1046     /**
   1047      * Returns the value associated with the given key, or null if
   1048      * no mapping of the desired type exists for the given key or a null
   1049      * value is explicitly associated with the key.
   1050      *
   1051      * @param key a String, or null
   1052      * @return a String value, or null
   1053      */
   1054     public String getString(String key) {
   1055         unparcel();
   1056         Object o = mMap.get(key);
   1057         if (o == null) {
   1058             return null;
   1059         }
   1060         try {
   1061             return (String) o;
   1062         } catch (ClassCastException e) {
   1063             typeWarning(key, o, "String", e);
   1064             return null;
   1065         }
   1066     }
   1067 
   1068     /**
   1069      * Returns the value associated with the given key, or defaultValue if
   1070      * no mapping of the desired type exists for the given key.
   1071      *
   1072      * @param key a String, or null
   1073      * @param defaultValue Value to return if key does not exist
   1074      * @return a String value, or null
   1075      */
   1076     public String getString(String key, String defaultValue) {
   1077         unparcel();
   1078         Object o = mMap.get(key);
   1079         if (o == null) {
   1080             return defaultValue;
   1081         }
   1082         try {
   1083             return (String) o;
   1084         } catch (ClassCastException e) {
   1085             typeWarning(key, o, "String", e);
   1086             return defaultValue;
   1087         }
   1088     }
   1089 
   1090     /**
   1091      * Returns the value associated with the given key, or null if
   1092      * no mapping of the desired type exists for the given key or a null
   1093      * value is explicitly associated with the key.
   1094      *
   1095      * @param key a String, or null
   1096      * @return a CharSequence value, or null
   1097      */
   1098     public CharSequence getCharSequence(String key) {
   1099         unparcel();
   1100         Object o = mMap.get(key);
   1101         if (o == null) {
   1102             return null;
   1103         }
   1104         try {
   1105             return (CharSequence) o;
   1106         } catch (ClassCastException e) {
   1107             typeWarning(key, o, "CharSequence", e);
   1108             return null;
   1109         }
   1110     }
   1111 
   1112     /**
   1113      * Returns the value associated with the given key, or defaultValue if
   1114      * no mapping of the desired type exists for the given key.
   1115      *
   1116      * @param key a String, or null
   1117      * @param defaultValue Value to return if key does not exist
   1118      * @return a CharSequence value, or null
   1119      */
   1120     public CharSequence getCharSequence(String key, CharSequence defaultValue) {
   1121         unparcel();
   1122         Object o = mMap.get(key);
   1123         if (o == null) {
   1124             return defaultValue;
   1125         }
   1126         try {
   1127             return (CharSequence) o;
   1128         } catch (ClassCastException e) {
   1129             typeWarning(key, o, "CharSequence", e);
   1130             return defaultValue;
   1131         }
   1132     }
   1133 
   1134     /**
   1135      * Returns the value associated with the given key, or null if
   1136      * no mapping of the desired type exists for the given key or a null
   1137      * value is explicitly associated with the key.
   1138      *
   1139      * @param key a String, or null
   1140      * @return a Bundle value, or null
   1141      */
   1142     public Bundle getBundle(String key) {
   1143         unparcel();
   1144         Object o = mMap.get(key);
   1145         if (o == null) {
   1146             return null;
   1147         }
   1148         try {
   1149             return (Bundle) o;
   1150         } catch (ClassCastException e) {
   1151             typeWarning(key, o, "Bundle", e);
   1152             return null;
   1153         }
   1154     }
   1155 
   1156     /**
   1157      * Returns the value associated with the given key, or null if
   1158      * no mapping of the desired type exists for the given key or a null
   1159      * value is explicitly associated with the key.
   1160      *
   1161      * @param key a String, or null
   1162      * @return a Parcelable value, or null
   1163      */
   1164     public <T extends Parcelable> T getParcelable(String key) {
   1165         unparcel();
   1166         Object o = mMap.get(key);
   1167         if (o == null) {
   1168             return null;
   1169         }
   1170         try {
   1171             return (T) o;
   1172         } catch (ClassCastException e) {
   1173             typeWarning(key, o, "Parcelable", e);
   1174             return null;
   1175         }
   1176     }
   1177 
   1178     /**
   1179      * Returns the value associated with the given key, or null if
   1180      * no mapping of the desired type exists for the given key or a null
   1181      * value is explicitly associated with the key.
   1182      *
   1183      * @param key a String, or null
   1184      * @return a Parcelable[] value, or null
   1185      */
   1186     public Parcelable[] getParcelableArray(String key) {
   1187         unparcel();
   1188         Object o = mMap.get(key);
   1189         if (o == null) {
   1190             return null;
   1191         }
   1192         try {
   1193             return (Parcelable[]) o;
   1194         } catch (ClassCastException e) {
   1195             typeWarning(key, o, "Parcelable[]", e);
   1196             return null;
   1197         }
   1198     }
   1199 
   1200     /**
   1201      * Returns the value associated with the given key, or null if
   1202      * no mapping of the desired type exists for the given key or a null
   1203      * value is explicitly associated with the key.
   1204      *
   1205      * @param key a String, or null
   1206      * @return an ArrayList<T> value, or null
   1207      */
   1208     public <T extends Parcelable> ArrayList<T> getParcelableArrayList(String key) {
   1209         unparcel();
   1210         Object o = mMap.get(key);
   1211         if (o == null) {
   1212             return null;
   1213         }
   1214         try {
   1215             return (ArrayList<T>) o;
   1216         } catch (ClassCastException e) {
   1217             typeWarning(key, o, "ArrayList", e);
   1218             return null;
   1219         }
   1220     }
   1221 
   1222     /**
   1223      * Returns the value associated with the given key, or null if
   1224      * no mapping of the desired type exists for the given key or a null
   1225      * value is explicitly associated with the key.
   1226      *
   1227      * @param key a String, or null
   1228      *
   1229      * @return a SparseArray of T values, or null
   1230      */
   1231     public <T extends Parcelable> SparseArray<T> getSparseParcelableArray(String key) {
   1232         unparcel();
   1233         Object o = mMap.get(key);
   1234         if (o == null) {
   1235             return null;
   1236         }
   1237         try {
   1238             return (SparseArray<T>) o;
   1239         } catch (ClassCastException e) {
   1240             typeWarning(key, o, "SparseArray", e);
   1241             return null;
   1242         }
   1243     }
   1244 
   1245     /**
   1246      * Returns the value associated with the given key, or null if
   1247      * no mapping of the desired type exists for the given key or a null
   1248      * value is explicitly associated with the key.
   1249      *
   1250      * @param key a String, or null
   1251      * @return a Serializable value, or null
   1252      */
   1253     public Serializable getSerializable(String key) {
   1254         unparcel();
   1255         Object o = mMap.get(key);
   1256         if (o == null) {
   1257             return null;
   1258         }
   1259         try {
   1260             return (Serializable) o;
   1261         } catch (ClassCastException e) {
   1262             typeWarning(key, o, "Serializable", e);
   1263             return null;
   1264         }
   1265     }
   1266 
   1267     /**
   1268      * Returns the value associated with the given key, or null if
   1269      * no mapping of the desired type exists for the given key or a null
   1270      * value is explicitly associated with the key.
   1271      *
   1272      * @param key a String, or null
   1273      * @return an ArrayList<String> value, or null
   1274      */
   1275     public ArrayList<Integer> getIntegerArrayList(String key) {
   1276         unparcel();
   1277         Object o = mMap.get(key);
   1278         if (o == null) {
   1279             return null;
   1280         }
   1281         try {
   1282             return (ArrayList<Integer>) o;
   1283         } catch (ClassCastException e) {
   1284             typeWarning(key, o, "ArrayList<Integer>", e);
   1285             return null;
   1286         }
   1287     }
   1288 
   1289     /**
   1290      * Returns the value associated with the given key, or null if
   1291      * no mapping of the desired type exists for the given key or a null
   1292      * value is explicitly associated with the key.
   1293      *
   1294      * @param key a String, or null
   1295      * @return an ArrayList<String> value, or null
   1296      */
   1297     public ArrayList<String> getStringArrayList(String key) {
   1298         unparcel();
   1299         Object o = mMap.get(key);
   1300         if (o == null) {
   1301             return null;
   1302         }
   1303         try {
   1304             return (ArrayList<String>) o;
   1305         } catch (ClassCastException e) {
   1306             typeWarning(key, o, "ArrayList<String>", e);
   1307             return null;
   1308         }
   1309     }
   1310 
   1311     /**
   1312      * Returns the value associated with the given key, or null if
   1313      * no mapping of the desired type exists for the given key or a null
   1314      * value is explicitly associated with the key.
   1315      *
   1316      * @param key a String, or null
   1317      * @return an ArrayList<CharSequence> value, or null
   1318      */
   1319     public ArrayList<CharSequence> getCharSequenceArrayList(String key) {
   1320         unparcel();
   1321         Object o = mMap.get(key);
   1322         if (o == null) {
   1323             return null;
   1324         }
   1325         try {
   1326             return (ArrayList<CharSequence>) o;
   1327         } catch (ClassCastException e) {
   1328             typeWarning(key, o, "ArrayList<CharSequence>", e);
   1329             return null;
   1330         }
   1331     }
   1332 
   1333     /**
   1334      * Returns the value associated with the given key, or null if
   1335      * no mapping of the desired type exists for the given key or a null
   1336      * value is explicitly associated with the key.
   1337      *
   1338      * @param key a String, or null
   1339      * @return a boolean[] value, or null
   1340      */
   1341     public boolean[] getBooleanArray(String key) {
   1342         unparcel();
   1343         Object o = mMap.get(key);
   1344         if (o == null) {
   1345             return null;
   1346         }
   1347         try {
   1348             return (boolean[]) o;
   1349         } catch (ClassCastException e) {
   1350             typeWarning(key, o, "byte[]", e);
   1351             return null;
   1352         }
   1353     }
   1354 
   1355     /**
   1356      * Returns the value associated with the given key, or null if
   1357      * no mapping of the desired type exists for the given key or a null
   1358      * value is explicitly associated with the key.
   1359      *
   1360      * @param key a String, or null
   1361      * @return a byte[] value, or null
   1362      */
   1363     public byte[] getByteArray(String key) {
   1364         unparcel();
   1365         Object o = mMap.get(key);
   1366         if (o == null) {
   1367             return null;
   1368         }
   1369         try {
   1370             return (byte[]) o;
   1371         } catch (ClassCastException e) {
   1372             typeWarning(key, o, "byte[]", e);
   1373             return null;
   1374         }
   1375     }
   1376 
   1377     /**
   1378      * Returns the value associated with the given key, or null if
   1379      * no mapping of the desired type exists for the given key or a null
   1380      * value is explicitly associated with the key.
   1381      *
   1382      * @param key a String, or null
   1383      * @return a short[] value, or null
   1384      */
   1385     public short[] getShortArray(String key) {
   1386         unparcel();
   1387         Object o = mMap.get(key);
   1388         if (o == null) {
   1389             return null;
   1390         }
   1391         try {
   1392             return (short[]) o;
   1393         } catch (ClassCastException e) {
   1394             typeWarning(key, o, "short[]", e);
   1395             return null;
   1396         }
   1397     }
   1398 
   1399     /**
   1400      * Returns the value associated with the given key, or null if
   1401      * no mapping of the desired type exists for the given key or a null
   1402      * value is explicitly associated with the key.
   1403      *
   1404      * @param key a String, or null
   1405      * @return a char[] value, or null
   1406      */
   1407     public char[] getCharArray(String key) {
   1408         unparcel();
   1409         Object o = mMap.get(key);
   1410         if (o == null) {
   1411             return null;
   1412         }
   1413         try {
   1414             return (char[]) o;
   1415         } catch (ClassCastException e) {
   1416             typeWarning(key, o, "char[]", e);
   1417             return null;
   1418         }
   1419     }
   1420 
   1421     /**
   1422      * Returns the value associated with the given key, or null if
   1423      * no mapping of the desired type exists for the given key or a null
   1424      * value is explicitly associated with the key.
   1425      *
   1426      * @param key a String, or null
   1427      * @return an int[] value, or null
   1428      */
   1429     public int[] getIntArray(String key) {
   1430         unparcel();
   1431         Object o = mMap.get(key);
   1432         if (o == null) {
   1433             return null;
   1434         }
   1435         try {
   1436             return (int[]) o;
   1437         } catch (ClassCastException e) {
   1438             typeWarning(key, o, "int[]", e);
   1439             return null;
   1440         }
   1441     }
   1442 
   1443     /**
   1444      * Returns the value associated with the given key, or null if
   1445      * no mapping of the desired type exists for the given key or a null
   1446      * value is explicitly associated with the key.
   1447      *
   1448      * @param key a String, or null
   1449      * @return a long[] value, or null
   1450      */
   1451     public long[] getLongArray(String key) {
   1452         unparcel();
   1453         Object o = mMap.get(key);
   1454         if (o == null) {
   1455             return null;
   1456         }
   1457         try {
   1458             return (long[]) o;
   1459         } catch (ClassCastException e) {
   1460             typeWarning(key, o, "long[]", e);
   1461             return null;
   1462         }
   1463     }
   1464 
   1465     /**
   1466      * Returns the value associated with the given key, or null if
   1467      * no mapping of the desired type exists for the given key or a null
   1468      * value is explicitly associated with the key.
   1469      *
   1470      * @param key a String, or null
   1471      * @return a float[] value, or null
   1472      */
   1473     public float[] getFloatArray(String key) {
   1474         unparcel();
   1475         Object o = mMap.get(key);
   1476         if (o == null) {
   1477             return null;
   1478         }
   1479         try {
   1480             return (float[]) o;
   1481         } catch (ClassCastException e) {
   1482             typeWarning(key, o, "float[]", e);
   1483             return null;
   1484         }
   1485     }
   1486 
   1487     /**
   1488      * Returns the value associated with the given key, or null if
   1489      * no mapping of the desired type exists for the given key or a null
   1490      * value is explicitly associated with the key.
   1491      *
   1492      * @param key a String, or null
   1493      * @return a double[] value, or null
   1494      */
   1495     public double[] getDoubleArray(String key) {
   1496         unparcel();
   1497         Object o = mMap.get(key);
   1498         if (o == null) {
   1499             return null;
   1500         }
   1501         try {
   1502             return (double[]) o;
   1503         } catch (ClassCastException e) {
   1504             typeWarning(key, o, "double[]", e);
   1505             return null;
   1506         }
   1507     }
   1508 
   1509     /**
   1510      * Returns the value associated with the given key, or null if
   1511      * no mapping of the desired type exists for the given key or a null
   1512      * value is explicitly associated with the key.
   1513      *
   1514      * @param key a String, or null
   1515      * @return a String[] value, or null
   1516      */
   1517     public String[] getStringArray(String key) {
   1518         unparcel();
   1519         Object o = mMap.get(key);
   1520         if (o == null) {
   1521             return null;
   1522         }
   1523         try {
   1524             return (String[]) o;
   1525         } catch (ClassCastException e) {
   1526             typeWarning(key, o, "String[]", e);
   1527             return null;
   1528         }
   1529     }
   1530 
   1531     /**
   1532      * Returns the value associated with the given key, or null if
   1533      * no mapping of the desired type exists for the given key or a null
   1534      * value is explicitly associated with the key.
   1535      *
   1536      * @param key a String, or null
   1537      * @return a CharSequence[] value, or null
   1538      */
   1539     public CharSequence[] getCharSequenceArray(String key) {
   1540         unparcel();
   1541         Object o = mMap.get(key);
   1542         if (o == null) {
   1543             return null;
   1544         }
   1545         try {
   1546             return (CharSequence[]) o;
   1547         } catch (ClassCastException e) {
   1548             typeWarning(key, o, "CharSequence[]", e);
   1549             return null;
   1550         }
   1551     }
   1552 
   1553     /**
   1554      * Returns the value associated with the given key, or null if
   1555      * no mapping of the desired type exists for the given key or a null
   1556      * value is explicitly associated with the key.
   1557      *
   1558      * @param key a String, or null
   1559      * @return an IBinder value, or null
   1560      *
   1561      * @deprecated
   1562      * @hide
   1563      */
   1564     @Deprecated
   1565     public IBinder getIBinder(String key) {
   1566         unparcel();
   1567         Object o = mMap.get(key);
   1568         if (o == null) {
   1569             return null;
   1570         }
   1571         try {
   1572             return (IBinder) o;
   1573         } catch (ClassCastException e) {
   1574             typeWarning(key, o, "IBinder", e);
   1575             return null;
   1576         }
   1577     }
   1578 
   1579     public static final Parcelable.Creator<Bundle> CREATOR =
   1580         new Parcelable.Creator<Bundle>() {
   1581         public Bundle createFromParcel(Parcel in) {
   1582             return in.readBundle();
   1583         }
   1584 
   1585         public Bundle[] newArray(int size) {
   1586             return new Bundle[size];
   1587         }
   1588     };
   1589 
   1590     /**
   1591      * Report the nature of this Parcelable's contents
   1592      */
   1593     public int describeContents() {
   1594         int mask = 0;
   1595         if (hasFileDescriptors()) {
   1596             mask |= Parcelable.CONTENTS_FILE_DESCRIPTOR;
   1597         }
   1598         return mask;
   1599     }
   1600 
   1601     /**
   1602      * Writes the Bundle contents to a Parcel, typically in order for
   1603      * it to be passed through an IBinder connection.
   1604      * @param parcel The parcel to copy this bundle to.
   1605      */
   1606     public void writeToParcel(Parcel parcel, int flags) {
   1607         final boolean oldAllowFds = parcel.pushAllowFds(mAllowFds);
   1608         try {
   1609             if (mParcelledData != null) {
   1610                 int length = mParcelledData.dataSize();
   1611                 parcel.writeInt(length);
   1612                 parcel.writeInt(0x4C444E42); // 'B' 'N' 'D' 'L'
   1613                 parcel.appendFrom(mParcelledData, 0, length);
   1614             } else {
   1615                 parcel.writeInt(-1); // dummy, will hold length
   1616                 parcel.writeInt(0x4C444E42); // 'B' 'N' 'D' 'L'
   1617 
   1618                 int oldPos = parcel.dataPosition();
   1619                 parcel.writeMapInternal(mMap);
   1620                 int newPos = parcel.dataPosition();
   1621 
   1622                 // Backpatch length
   1623                 parcel.setDataPosition(oldPos - 8);
   1624                 int length = newPos - oldPos;
   1625                 parcel.writeInt(length);
   1626                 parcel.setDataPosition(newPos);
   1627             }
   1628         } finally {
   1629             parcel.restoreAllowFds(oldAllowFds);
   1630         }
   1631     }
   1632 
   1633     /**
   1634      * Reads the Parcel contents into this Bundle, typically in order for
   1635      * it to be passed through an IBinder connection.
   1636      * @param parcel The parcel to overwrite this bundle from.
   1637      */
   1638     public void readFromParcel(Parcel parcel) {
   1639         int length = parcel.readInt();
   1640         if (length < 0) {
   1641             throw new RuntimeException("Bad length in parcel: " + length);
   1642         }
   1643         readFromParcelInner(parcel, length);
   1644     }
   1645 
   1646     void readFromParcelInner(Parcel parcel, int length) {
   1647         int magic = parcel.readInt();
   1648         if (magic != 0x4C444E42) {
   1649             //noinspection ThrowableInstanceNeverThrown
   1650             String st = Log.getStackTraceString(new RuntimeException());
   1651             Log.e("Bundle", "readBundle: bad magic number");
   1652             Log.e("Bundle", "readBundle: trace = " + st);
   1653         }
   1654 
   1655         // Advance within this Parcel
   1656         int offset = parcel.dataPosition();
   1657         parcel.setDataPosition(offset + length);
   1658 
   1659         Parcel p = Parcel.obtain();
   1660         p.setDataPosition(0);
   1661         p.appendFrom(parcel, offset, length);
   1662         p.setDataPosition(0);
   1663 
   1664         mParcelledData = p;
   1665         mHasFds = p.hasFileDescriptors();
   1666         mFdsKnown = true;
   1667     }
   1668 
   1669     @Override
   1670     public synchronized String toString() {
   1671         if (mParcelledData != null) {
   1672             return "Bundle[mParcelledData.dataSize=" +
   1673                     mParcelledData.dataSize() + "]";
   1674         }
   1675         return "Bundle[" + mMap.toString() + "]";
   1676     }
   1677 }
   1678