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