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