Bundle.java revision e3a7f628c6d9fef42be24999b3137ebe5c6f3525
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     * Returns the value associated with the given key, or null if
1033     * no mapping of the desired type exists for the given key or a null
1034     * value is explicitly associated with the key.
1035     *
1036     * @param key a String, or null
1037     * @return a String value, or null
1038     */
1039    public String getString(String key) {
1040        unparcel();
1041        Object o = mMap.get(key);
1042        if (o == null) {
1043            return null;
1044        }
1045        try {
1046            return (String) o;
1047        } catch (ClassCastException e) {
1048            typeWarning(key, o, "String", e);
1049            return null;
1050        }
1051    }
1052
1053    /**
1054     * Returns the value associated with the given key, or defaultValue if
1055     * no mapping of the desired type exists for the given key.
1056     *
1057     * @param key a String, or null
1058     * @param defaultValue Value to return if key does not exist
1059     * @return a String value, or null
1060     */
1061    public String getString(String key, String defaultValue) {
1062        unparcel();
1063        Object o = mMap.get(key);
1064        if (o == null) {
1065            return defaultValue;
1066        }
1067        try {
1068            return (String) o;
1069        } catch (ClassCastException e) {
1070            typeWarning(key, o, "String", e);
1071            return defaultValue;
1072        }
1073    }
1074
1075    /**
1076     * Returns the value associated with the given key, or null if
1077     * no mapping of the desired type exists for the given key or a null
1078     * value is explicitly associated with the key.
1079     *
1080     * @param key a String, or null
1081     * @return a CharSequence value, or null
1082     */
1083    public CharSequence getCharSequence(String key) {
1084        unparcel();
1085        Object o = mMap.get(key);
1086        if (o == null) {
1087            return null;
1088        }
1089        try {
1090            return (CharSequence) o;
1091        } catch (ClassCastException e) {
1092            typeWarning(key, o, "CharSequence", e);
1093            return null;
1094        }
1095    }
1096
1097    /**
1098     * Returns the value associated with the given key, or defaultValue if
1099     * no mapping of the desired type exists for the given key.
1100     *
1101     * @param key a String, or null
1102     * @param defaultValue Value to return if key does not exist
1103     * @return a CharSequence value, or null
1104     */
1105    public CharSequence getCharSequence(String key, CharSequence defaultValue) {
1106        unparcel();
1107        Object o = mMap.get(key);
1108        if (o == null) {
1109            return defaultValue;
1110        }
1111        try {
1112            return (CharSequence) o;
1113        } catch (ClassCastException e) {
1114            typeWarning(key, o, "CharSequence", e);
1115            return defaultValue;
1116        }
1117    }
1118
1119    /**
1120     * Returns the value associated with the given key, or null if
1121     * no mapping of the desired type exists for the given key or a null
1122     * value is explicitly associated with the key.
1123     *
1124     * @param key a String, or null
1125     * @return a Bundle value, or null
1126     */
1127    public Bundle getBundle(String key) {
1128        unparcel();
1129        Object o = mMap.get(key);
1130        if (o == null) {
1131            return null;
1132        }
1133        try {
1134            return (Bundle) o;
1135        } catch (ClassCastException e) {
1136            typeWarning(key, o, "Bundle", e);
1137            return null;
1138        }
1139    }
1140
1141    /**
1142     * Returns the value associated with the given key, or null if
1143     * no mapping of the desired type exists for the given key or a null
1144     * value is explicitly associated with the key.
1145     *
1146     * @param key a String, or null
1147     * @return a Parcelable value, or null
1148     */
1149    public <T extends Parcelable> T getParcelable(String key) {
1150        unparcel();
1151        Object o = mMap.get(key);
1152        if (o == null) {
1153            return null;
1154        }
1155        try {
1156            return (T) o;
1157        } catch (ClassCastException e) {
1158            typeWarning(key, o, "Parcelable", e);
1159            return null;
1160        }
1161    }
1162
1163    /**
1164     * Returns the value associated with the given key, or null if
1165     * no mapping of the desired type exists for the given key or a null
1166     * value is explicitly associated with the key.
1167     *
1168     * @param key a String, or null
1169     * @return a Parcelable[] value, or null
1170     */
1171    public Parcelable[] getParcelableArray(String key) {
1172        unparcel();
1173        Object o = mMap.get(key);
1174        if (o == null) {
1175            return null;
1176        }
1177        try {
1178            return (Parcelable[]) o;
1179        } catch (ClassCastException e) {
1180            typeWarning(key, o, "Parcelable[]", e);
1181            return null;
1182        }
1183    }
1184
1185    /**
1186     * Returns the value associated with the given key, or null if
1187     * no mapping of the desired type exists for the given key or a null
1188     * value is explicitly associated with the key.
1189     *
1190     * @param key a String, or null
1191     * @return an ArrayList<T> value, or null
1192     */
1193    public <T extends Parcelable> ArrayList<T> getParcelableArrayList(String key) {
1194        unparcel();
1195        Object o = mMap.get(key);
1196        if (o == null) {
1197            return null;
1198        }
1199        try {
1200            return (ArrayList<T>) o;
1201        } catch (ClassCastException e) {
1202            typeWarning(key, o, "ArrayList", e);
1203            return null;
1204        }
1205    }
1206
1207    /**
1208     * Returns the value associated with the given key, or null if
1209     * no mapping of the desired type exists for the given key or a null
1210     * value is explicitly associated with the key.
1211     *
1212     * @param key a String, or null
1213     *
1214     * @return a SparseArray of T values, or null
1215     */
1216    public <T extends Parcelable> SparseArray<T> getSparseParcelableArray(String key) {
1217        unparcel();
1218        Object o = mMap.get(key);
1219        if (o == null) {
1220            return null;
1221        }
1222        try {
1223            return (SparseArray<T>) o;
1224        } catch (ClassCastException e) {
1225            typeWarning(key, o, "SparseArray", e);
1226            return null;
1227        }
1228    }
1229
1230    /**
1231     * Returns the value associated with the given key, or null if
1232     * no mapping of the desired type exists for the given key or a null
1233     * value is explicitly associated with the key.
1234     *
1235     * @param key a String, or null
1236     * @return a Serializable value, or null
1237     */
1238    public Serializable getSerializable(String key) {
1239        unparcel();
1240        Object o = mMap.get(key);
1241        if (o == null) {
1242            return null;
1243        }
1244        try {
1245            return (Serializable) o;
1246        } catch (ClassCastException e) {
1247            typeWarning(key, o, "Serializable", e);
1248            return null;
1249        }
1250    }
1251
1252    /**
1253     * Returns the value associated with the given key, or null if
1254     * no mapping of the desired type exists for the given key or a null
1255     * value is explicitly associated with the key.
1256     *
1257     * @param key a String, or null
1258     * @return an ArrayList<String> value, or null
1259     */
1260    public ArrayList<Integer> getIntegerArrayList(String key) {
1261        unparcel();
1262        Object o = mMap.get(key);
1263        if (o == null) {
1264            return null;
1265        }
1266        try {
1267            return (ArrayList<Integer>) o;
1268        } catch (ClassCastException e) {
1269            typeWarning(key, o, "ArrayList<Integer>", e);
1270            return null;
1271        }
1272    }
1273
1274    /**
1275     * Returns the value associated with the given key, or null if
1276     * no mapping of the desired type exists for the given key or a null
1277     * value is explicitly associated with the key.
1278     *
1279     * @param key a String, or null
1280     * @return an ArrayList<String> value, or null
1281     */
1282    public ArrayList<String> getStringArrayList(String key) {
1283        unparcel();
1284        Object o = mMap.get(key);
1285        if (o == null) {
1286            return null;
1287        }
1288        try {
1289            return (ArrayList<String>) o;
1290        } catch (ClassCastException e) {
1291            typeWarning(key, o, "ArrayList<String>", e);
1292            return null;
1293        }
1294    }
1295
1296    /**
1297     * Returns the value associated with the given key, or null if
1298     * no mapping of the desired type exists for the given key or a null
1299     * value is explicitly associated with the key.
1300     *
1301     * @param key a String, or null
1302     * @return an ArrayList<CharSequence> value, or null
1303     */
1304    public ArrayList<CharSequence> getCharSequenceArrayList(String key) {
1305        unparcel();
1306        Object o = mMap.get(key);
1307        if (o == null) {
1308            return null;
1309        }
1310        try {
1311            return (ArrayList<CharSequence>) o;
1312        } catch (ClassCastException e) {
1313            typeWarning(key, o, "ArrayList<CharSequence>", e);
1314            return null;
1315        }
1316    }
1317
1318    /**
1319     * Returns the value associated with the given key, or null if
1320     * no mapping of the desired type exists for the given key or a null
1321     * value is explicitly associated with the key.
1322     *
1323     * @param key a String, or null
1324     * @return a boolean[] value, or null
1325     */
1326    public boolean[] getBooleanArray(String key) {
1327        unparcel();
1328        Object o = mMap.get(key);
1329        if (o == null) {
1330            return null;
1331        }
1332        try {
1333            return (boolean[]) o;
1334        } catch (ClassCastException e) {
1335            typeWarning(key, o, "byte[]", e);
1336            return null;
1337        }
1338    }
1339
1340    /**
1341     * Returns the value associated with the given key, or null if
1342     * no mapping of the desired type exists for the given key or a null
1343     * value is explicitly associated with the key.
1344     *
1345     * @param key a String, or null
1346     * @return a byte[] value, or null
1347     */
1348    public byte[] getByteArray(String key) {
1349        unparcel();
1350        Object o = mMap.get(key);
1351        if (o == null) {
1352            return null;
1353        }
1354        try {
1355            return (byte[]) o;
1356        } catch (ClassCastException e) {
1357            typeWarning(key, o, "byte[]", e);
1358            return null;
1359        }
1360    }
1361
1362    /**
1363     * Returns the value associated with the given key, or null if
1364     * no mapping of the desired type exists for the given key or a null
1365     * value is explicitly associated with the key.
1366     *
1367     * @param key a String, or null
1368     * @return a short[] value, or null
1369     */
1370    public short[] getShortArray(String key) {
1371        unparcel();
1372        Object o = mMap.get(key);
1373        if (o == null) {
1374            return null;
1375        }
1376        try {
1377            return (short[]) o;
1378        } catch (ClassCastException e) {
1379            typeWarning(key, o, "short[]", e);
1380            return null;
1381        }
1382    }
1383
1384    /**
1385     * Returns the value associated with the given key, or null if
1386     * no mapping of the desired type exists for the given key or a null
1387     * value is explicitly associated with the key.
1388     *
1389     * @param key a String, or null
1390     * @return a char[] value, or null
1391     */
1392    public char[] getCharArray(String key) {
1393        unparcel();
1394        Object o = mMap.get(key);
1395        if (o == null) {
1396            return null;
1397        }
1398        try {
1399            return (char[]) o;
1400        } catch (ClassCastException e) {
1401            typeWarning(key, o, "char[]", e);
1402            return null;
1403        }
1404    }
1405
1406    /**
1407     * Returns the value associated with the given key, or null if
1408     * no mapping of the desired type exists for the given key or a null
1409     * value is explicitly associated with the key.
1410     *
1411     * @param key a String, or null
1412     * @return an int[] value, or null
1413     */
1414    public int[] getIntArray(String key) {
1415        unparcel();
1416        Object o = mMap.get(key);
1417        if (o == null) {
1418            return null;
1419        }
1420        try {
1421            return (int[]) o;
1422        } catch (ClassCastException e) {
1423            typeWarning(key, o, "int[]", e);
1424            return null;
1425        }
1426    }
1427
1428    /**
1429     * Returns the value associated with the given key, or null if
1430     * no mapping of the desired type exists for the given key or a null
1431     * value is explicitly associated with the key.
1432     *
1433     * @param key a String, or null
1434     * @return a long[] value, or null
1435     */
1436    public long[] getLongArray(String key) {
1437        unparcel();
1438        Object o = mMap.get(key);
1439        if (o == null) {
1440            return null;
1441        }
1442        try {
1443            return (long[]) o;
1444        } catch (ClassCastException e) {
1445            typeWarning(key, o, "long[]", e);
1446            return null;
1447        }
1448    }
1449
1450    /**
1451     * Returns the value associated with the given key, or null if
1452     * no mapping of the desired type exists for the given key or a null
1453     * value is explicitly associated with the key.
1454     *
1455     * @param key a String, or null
1456     * @return a float[] value, or null
1457     */
1458    public float[] getFloatArray(String key) {
1459        unparcel();
1460        Object o = mMap.get(key);
1461        if (o == null) {
1462            return null;
1463        }
1464        try {
1465            return (float[]) o;
1466        } catch (ClassCastException e) {
1467            typeWarning(key, o, "float[]", e);
1468            return null;
1469        }
1470    }
1471
1472    /**
1473     * Returns the value associated with the given key, or null if
1474     * no mapping of the desired type exists for the given key or a null
1475     * value is explicitly associated with the key.
1476     *
1477     * @param key a String, or null
1478     * @return a double[] value, or null
1479     */
1480    public double[] getDoubleArray(String key) {
1481        unparcel();
1482        Object o = mMap.get(key);
1483        if (o == null) {
1484            return null;
1485        }
1486        try {
1487            return (double[]) o;
1488        } catch (ClassCastException e) {
1489            typeWarning(key, o, "double[]", e);
1490            return null;
1491        }
1492    }
1493
1494    /**
1495     * Returns the value associated with the given key, or null if
1496     * no mapping of the desired type exists for the given key or a null
1497     * value is explicitly associated with the key.
1498     *
1499     * @param key a String, or null
1500     * @return a String[] value, or null
1501     */
1502    public String[] getStringArray(String key) {
1503        unparcel();
1504        Object o = mMap.get(key);
1505        if (o == null) {
1506            return null;
1507        }
1508        try {
1509            return (String[]) o;
1510        } catch (ClassCastException e) {
1511            typeWarning(key, o, "String[]", e);
1512            return null;
1513        }
1514    }
1515
1516    /**
1517     * Returns the value associated with the given key, or null if
1518     * no mapping of the desired type exists for the given key or a null
1519     * value is explicitly associated with the key.
1520     *
1521     * @param key a String, or null
1522     * @return a CharSequence[] value, or null
1523     */
1524    public CharSequence[] getCharSequenceArray(String key) {
1525        unparcel();
1526        Object o = mMap.get(key);
1527        if (o == null) {
1528            return null;
1529        }
1530        try {
1531            return (CharSequence[]) o;
1532        } catch (ClassCastException e) {
1533            typeWarning(key, o, "CharSequence[]", e);
1534            return null;
1535        }
1536    }
1537
1538    /**
1539     * Returns the value associated with the given key, or null if
1540     * no mapping of the desired type exists for the given key or a null
1541     * value is explicitly associated with the key.
1542     *
1543     * @param key a String, or null
1544     * @return an IBinder value, or null
1545     *
1546     * @deprecated
1547     * @hide
1548     */
1549    @Deprecated
1550    public IBinder getIBinder(String key) {
1551        unparcel();
1552        Object o = mMap.get(key);
1553        if (o == null) {
1554            return null;
1555        }
1556        try {
1557            return (IBinder) o;
1558        } catch (ClassCastException e) {
1559            typeWarning(key, o, "IBinder", e);
1560            return null;
1561        }
1562    }
1563
1564    public static final Parcelable.Creator<Bundle> CREATOR =
1565        new Parcelable.Creator<Bundle>() {
1566        public Bundle createFromParcel(Parcel in) {
1567            return in.readBundle();
1568        }
1569
1570        public Bundle[] newArray(int size) {
1571            return new Bundle[size];
1572        }
1573    };
1574
1575    /**
1576     * Report the nature of this Parcelable's contents
1577     */
1578    public int describeContents() {
1579        int mask = 0;
1580        if (hasFileDescriptors()) {
1581            mask |= Parcelable.CONTENTS_FILE_DESCRIPTOR;
1582        }
1583        return mask;
1584    }
1585
1586    /**
1587     * Writes the Bundle contents to a Parcel, typically in order for
1588     * it to be passed through an IBinder connection.
1589     * @param parcel The parcel to copy this bundle to.
1590     */
1591    public void writeToParcel(Parcel parcel, int flags) {
1592        if (mParcelledData != null) {
1593            int length = mParcelledData.dataSize();
1594            parcel.writeInt(length);
1595            parcel.writeInt(0x4C444E42); // 'B' 'N' 'D' 'L'
1596            parcel.appendFrom(mParcelledData, 0, length);
1597        } else {
1598            parcel.writeInt(-1); // dummy, will hold length
1599            parcel.writeInt(0x4C444E42); // 'B' 'N' 'D' 'L'
1600
1601            int oldPos = parcel.dataPosition();
1602            parcel.writeMapInternal(mMap);
1603            int newPos = parcel.dataPosition();
1604
1605            // Backpatch length
1606            parcel.setDataPosition(oldPos - 8);
1607            int length = newPos - oldPos;
1608            parcel.writeInt(length);
1609            parcel.setDataPosition(newPos);
1610        }
1611    }
1612
1613    /**
1614     * Reads the Parcel contents into this Bundle, typically in order for
1615     * it to be passed through an IBinder connection.
1616     * @param parcel The parcel to overwrite this bundle from.
1617     */
1618    public void readFromParcel(Parcel parcel) {
1619        int length = parcel.readInt();
1620        if (length < 0) {
1621            throw new RuntimeException("Bad length in parcel: " + length);
1622        }
1623        readFromParcelInner(parcel, length);
1624    }
1625
1626    void readFromParcelInner(Parcel parcel, int length) {
1627        int magic = parcel.readInt();
1628        if (magic != 0x4C444E42) {
1629            //noinspection ThrowableInstanceNeverThrown
1630            String st = Log.getStackTraceString(new RuntimeException());
1631            Log.e("Bundle", "readBundle: bad magic number");
1632            Log.e("Bundle", "readBundle: trace = " + st);
1633        }
1634
1635        // Advance within this Parcel
1636        int offset = parcel.dataPosition();
1637        parcel.setDataPosition(offset + length);
1638
1639        Parcel p = Parcel.obtain();
1640        p.setDataPosition(0);
1641        p.appendFrom(parcel, offset, length);
1642        p.setDataPosition(0);
1643
1644        mParcelledData = p;
1645        mHasFds = p.hasFileDescriptors();
1646        mFdsKnown = true;
1647    }
1648
1649    @Override
1650    public synchronized String toString() {
1651        if (mParcelledData != null) {
1652            return "Bundle[mParcelledData.dataSize=" +
1653                    mParcelledData.dataSize() + "]";
1654        }
1655        return "Bundle[" + mMap.toString() + "]";
1656    }
1657}
1658