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