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