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