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