Bundle.java revision c04db7e06737c5b9bae276ac462858d44002672e
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
17package android.os;
18
19import android.util.Log;
20import android.util.SparseArray;
21
22import java.io.Serializable;
23import java.util.ArrayList;
24import java.util.Collections;
25import java.util.HashMap;
26import java.util.Iterator;
27import java.util.Map;
28import java.util.Set;
29
30/**
31 * A mapping from String values to various Parcelable types.
32 *
33 */
34public 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