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>();
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.get(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 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     * @param key a String, or null
749     * @param value an IBinder object, or null
750     *
751     * @deprecated
752     * @hide
753     */
754    @Deprecated
755    public void putIBinder(String key, IBinder value) {
756        unparcel();
757        mMap.put(key, value);
758    }
759
760    /**
761     * Returns the value associated with the given key, or false if
762     * no mapping of the desired type exists for the given key.
763     *
764     * @param key a String
765     * @return a boolean value
766     */
767    public boolean getBoolean(String key) {
768        unparcel();
769        return getBoolean(key, false);
770    }
771
772    // Log a message if the value was non-null but not of the expected type
773    private void typeWarning(String key, Object value, String className,
774        Object defaultValue, ClassCastException e) {
775        StringBuilder sb = new StringBuilder();
776        sb.append("Key ");
777        sb.append(key);
778        sb.append(" expected ");
779        sb.append(className);
780        sb.append(" but value was a ");
781        sb.append(value.getClass().getName());
782        sb.append(".  The default value ");
783        sb.append(defaultValue);
784        sb.append(" was returned.");
785        Log.w(LOG_TAG, sb.toString());
786        Log.w(LOG_TAG, "Attempt to cast generated internal exception:", e);
787    }
788
789    private void typeWarning(String key, Object value, String className,
790        ClassCastException e) {
791        typeWarning(key, value, className, "<null>", e);
792    }
793
794    /**
795     * Returns the value associated with the given key, or defaultValue if
796     * no mapping of the desired type exists for the given key.
797     *
798     * @param key a String
799     * @param defaultValue Value to return if key does not exist
800     * @return a boolean value
801     */
802    public boolean getBoolean(String key, boolean defaultValue) {
803        unparcel();
804        Object o = mMap.get(key);
805        if (o == null) {
806            return defaultValue;
807        }
808        try {
809            return (Boolean) o;
810        } catch (ClassCastException e) {
811            typeWarning(key, o, "Boolean", defaultValue, e);
812            return defaultValue;
813        }
814    }
815
816    /**
817     * Returns the value associated with the given key, or (byte) 0 if
818     * no mapping of the desired type exists for the given key.
819     *
820     * @param key a String
821     * @return a byte value
822     */
823    public byte getByte(String key) {
824        unparcel();
825        return getByte(key, (byte) 0);
826    }
827
828    /**
829     * Returns the value associated with the given key, or defaultValue if
830     * no mapping of the desired type exists for the given key.
831     *
832     * @param key a String
833     * @param defaultValue Value to return if key does not exist
834     * @return a byte value
835     */
836    public Byte getByte(String key, byte defaultValue) {
837        unparcel();
838        Object o = mMap.get(key);
839        if (o == null) {
840            return defaultValue;
841        }
842        try {
843            return (Byte) o;
844        } catch (ClassCastException e) {
845            typeWarning(key, o, "Byte", defaultValue, e);
846            return defaultValue;
847        }
848    }
849
850    /**
851     * Returns the value associated with the given key, or (char) 0 if
852     * no mapping of the desired type exists for the given key.
853     *
854     * @param key a String
855     * @return a char value
856     */
857    public char getChar(String key) {
858        unparcel();
859        return getChar(key, (char) 0);
860    }
861
862    /**
863     * Returns the value associated with the given key, or defaultValue if
864     * no mapping of the desired type exists for the given key.
865     *
866     * @param key a String
867     * @param defaultValue Value to return if key does not exist
868     * @return a char value
869     */
870    public char getChar(String key, char defaultValue) {
871        unparcel();
872        Object o = mMap.get(key);
873        if (o == null) {
874            return defaultValue;
875        }
876        try {
877            return (Character) o;
878        } catch (ClassCastException e) {
879            typeWarning(key, o, "Character", defaultValue, e);
880            return defaultValue;
881        }
882    }
883
884    /**
885     * Returns the value associated with the given key, or (short) 0 if
886     * no mapping of the desired type exists for the given key.
887     *
888     * @param key a String
889     * @return a short value
890     */
891    public short getShort(String key) {
892        unparcel();
893        return getShort(key, (short) 0);
894    }
895
896    /**
897     * Returns the value associated with the given key, or defaultValue if
898     * no mapping of the desired type exists for the given key.
899     *
900     * @param key a String
901     * @param defaultValue Value to return if key does not exist
902     * @return a short value
903     */
904    public short getShort(String key, short defaultValue) {
905        unparcel();
906        Object o = mMap.get(key);
907        if (o == null) {
908            return defaultValue;
909        }
910        try {
911            return (Short) o;
912        } catch (ClassCastException e) {
913            typeWarning(key, o, "Short", defaultValue, e);
914            return defaultValue;
915        }
916    }
917
918    /**
919     * Returns the value associated with the given key, or 0 if
920     * no mapping of the desired type exists for the given key.
921     *
922     * @param key a String
923     * @return an int value
924     */
925    public int getInt(String key) {
926        unparcel();
927        return getInt(key, 0);
928    }
929
930    /**
931     * Returns the value associated with the given key, or defaultValue if
932     * no mapping of the desired type exists for the given key.
933     *
934     * @param key a String
935     * @param defaultValue Value to return if key does not exist
936     * @return an int value
937     */
938    public int getInt(String key, int defaultValue) {
939        unparcel();
940        Object o = mMap.get(key);
941        if (o == null) {
942            return defaultValue;
943        }
944        try {
945            return (Integer) o;
946        } catch (ClassCastException e) {
947            typeWarning(key, o, "Integer", defaultValue, e);
948            return defaultValue;
949        }
950    }
951
952    /**
953     * Returns the value associated with the given key, or 0L if
954     * no mapping of the desired type exists for the given key.
955     *
956     * @param key a String
957     * @return a long value
958     */
959    public long getLong(String key) {
960        unparcel();
961        return getLong(key, 0L);
962    }
963
964    /**
965     * Returns the value associated with the given key, or defaultValue if
966     * no mapping of the desired type exists for the given key.
967     *
968     * @param key a String
969     * @param defaultValue Value to return if key does not exist
970     * @return a long value
971     */
972    public long getLong(String key, long defaultValue) {
973        unparcel();
974        Object o = mMap.get(key);
975        if (o == null) {
976            return defaultValue;
977        }
978        try {
979            return (Long) o;
980        } catch (ClassCastException e) {
981            typeWarning(key, o, "Long", defaultValue, e);
982            return defaultValue;
983        }
984    }
985
986    /**
987     * Returns the value associated with the given key, or 0.0f if
988     * no mapping of the desired type exists for the given key.
989     *
990     * @param key a String
991     * @return a float value
992     */
993    public float getFloat(String key) {
994        unparcel();
995        return getFloat(key, 0.0f);
996    }
997
998    /**
999     * Returns the value associated with the given key, or defaultValue if
1000     * no mapping of the desired type exists for the given key.
1001     *
1002     * @param key a String
1003     * @param defaultValue Value to return if key does not exist
1004     * @return a float value
1005     */
1006    public float getFloat(String key, float defaultValue) {
1007        unparcel();
1008        Object o = mMap.get(key);
1009        if (o == null) {
1010            return defaultValue;
1011        }
1012        try {
1013            return (Float) o;
1014        } catch (ClassCastException e) {
1015            typeWarning(key, o, "Float", defaultValue, e);
1016            return defaultValue;
1017        }
1018    }
1019
1020    /**
1021     * Returns the value associated with the given key, or 0.0 if
1022     * no mapping of the desired type exists for the given key.
1023     *
1024     * @param key a String
1025     * @return a double value
1026     */
1027    public double getDouble(String key) {
1028        unparcel();
1029        return getDouble(key, 0.0);
1030    }
1031
1032    /**
1033     * Returns the value associated with the given key, or defaultValue if
1034     * no mapping of the desired type exists for the given key.
1035     *
1036     * @param key a String
1037     * @param defaultValue Value to return if key does not exist
1038     * @return a double value
1039     */
1040    public double getDouble(String key, double defaultValue) {
1041        unparcel();
1042        Object o = mMap.get(key);
1043        if (o == null) {
1044            return defaultValue;
1045        }
1046        try {
1047            return (Double) o;
1048        } catch (ClassCastException e) {
1049            typeWarning(key, o, "Double", defaultValue, e);
1050            return defaultValue;
1051        }
1052    }
1053
1054    /**
1055     * Returns the value associated with the given key, or null if
1056     * no mapping of the desired type exists for the given key or a null
1057     * value is explicitly associated with the key.
1058     *
1059     * @param key a String, or null
1060     * @return a String value, or null
1061     */
1062    public String getString(String key) {
1063        unparcel();
1064        Object o = mMap.get(key);
1065        if (o == null) {
1066            return null;
1067        }
1068        try {
1069            return (String) o;
1070        } catch (ClassCastException e) {
1071            typeWarning(key, o, "String", e);
1072            return null;
1073        }
1074    }
1075
1076    /**
1077     * Returns the value associated with the given key, or defaultValue if
1078     * no mapping of the desired type exists for the given key.
1079     *
1080     * @param key a String, or null
1081     * @param defaultValue Value to return if key does not exist
1082     * @return a String value, or null
1083     */
1084    public String getString(String key, String defaultValue) {
1085        unparcel();
1086        Object o = mMap.get(key);
1087        if (o == null) {
1088            return defaultValue;
1089        }
1090        try {
1091            return (String) o;
1092        } catch (ClassCastException e) {
1093            typeWarning(key, o, "String", e);
1094            return defaultValue;
1095        }
1096    }
1097
1098    /**
1099     * Returns the value associated with the given key, or null if
1100     * no mapping of the desired type exists for the given key or a null
1101     * value is explicitly associated with the key.
1102     *
1103     * @param key a String, or null
1104     * @return a CharSequence value, or null
1105     */
1106    public CharSequence getCharSequence(String key) {
1107        unparcel();
1108        Object o = mMap.get(key);
1109        if (o == null) {
1110            return null;
1111        }
1112        try {
1113            return (CharSequence) o;
1114        } catch (ClassCastException e) {
1115            typeWarning(key, o, "CharSequence", e);
1116            return null;
1117        }
1118    }
1119
1120    /**
1121     * Returns the value associated with the given key, or defaultValue if
1122     * no mapping of the desired type exists for the given key.
1123     *
1124     * @param key a String, or null
1125     * @param defaultValue Value to return if key does not exist
1126     * @return a CharSequence value, or null
1127     */
1128    public CharSequence getCharSequence(String key, CharSequence defaultValue) {
1129        unparcel();
1130        Object o = mMap.get(key);
1131        if (o == null) {
1132            return defaultValue;
1133        }
1134        try {
1135            return (CharSequence) o;
1136        } catch (ClassCastException e) {
1137            typeWarning(key, o, "CharSequence", e);
1138            return defaultValue;
1139        }
1140    }
1141
1142    /**
1143     * Returns the value associated with the given key, or null if
1144     * no mapping of the desired type exists for the given key or a null
1145     * value is explicitly associated with the key.
1146     *
1147     * @param key a String, or null
1148     * @return a Bundle value, or null
1149     */
1150    public Bundle getBundle(String key) {
1151        unparcel();
1152        Object o = mMap.get(key);
1153        if (o == null) {
1154            return null;
1155        }
1156        try {
1157            return (Bundle) o;
1158        } catch (ClassCastException e) {
1159            typeWarning(key, o, "Bundle", e);
1160            return null;
1161        }
1162    }
1163
1164    /**
1165     * Returns the value associated with the given key, or null if
1166     * no mapping of the desired type exists for the given key or a null
1167     * value is explicitly associated with the key.
1168     *
1169     * @param key a String, or null
1170     * @return a Parcelable value, or null
1171     */
1172    public <T extends Parcelable> T getParcelable(String key) {
1173        unparcel();
1174        Object o = mMap.get(key);
1175        if (o == null) {
1176            return null;
1177        }
1178        try {
1179            return (T) o;
1180        } catch (ClassCastException e) {
1181            typeWarning(key, o, "Parcelable", e);
1182            return null;
1183        }
1184    }
1185
1186    /**
1187     * Returns the value associated with the given key, or null if
1188     * no mapping of the desired type exists for the given key or a null
1189     * value is explicitly associated with the key.
1190     *
1191     * @param key a String, or null
1192     * @return a Parcelable[] value, or null
1193     */
1194    public Parcelable[] getParcelableArray(String key) {
1195        unparcel();
1196        Object o = mMap.get(key);
1197        if (o == null) {
1198            return null;
1199        }
1200        try {
1201            return (Parcelable[]) o;
1202        } catch (ClassCastException e) {
1203            typeWarning(key, o, "Parcelable[]", e);
1204            return null;
1205        }
1206    }
1207
1208    /**
1209     * Returns the value associated with the given key, or null if
1210     * no mapping of the desired type exists for the given key or a null
1211     * value is explicitly associated with the key.
1212     *
1213     * @param key a String, or null
1214     * @return an ArrayList<T> value, or null
1215     */
1216    public <T extends Parcelable> ArrayList<T> getParcelableArrayList(String key) {
1217        unparcel();
1218        Object o = mMap.get(key);
1219        if (o == null) {
1220            return null;
1221        }
1222        try {
1223            return (ArrayList<T>) o;
1224        } catch (ClassCastException e) {
1225            typeWarning(key, o, "ArrayList", e);
1226            return null;
1227        }
1228    }
1229
1230    /**
1231     * Returns the value associated with the given key, or null if
1232     * no mapping of the desired type exists for the given key or a null
1233     * value is explicitly associated with the key.
1234     *
1235     * @param key a String, or null
1236     *
1237     * @return a SparseArray of T values, or null
1238     */
1239    public <T extends Parcelable> SparseArray<T> getSparseParcelableArray(String key) {
1240        unparcel();
1241        Object o = mMap.get(key);
1242        if (o == null) {
1243            return null;
1244        }
1245        try {
1246            return (SparseArray<T>) o;
1247        } catch (ClassCastException e) {
1248            typeWarning(key, o, "SparseArray", e);
1249            return null;
1250        }
1251    }
1252
1253    /**
1254     * Returns the value associated with the given key, or null if
1255     * no mapping of the desired type exists for the given key or a null
1256     * value is explicitly associated with the key.
1257     *
1258     * @param key a String, or null
1259     * @return a Serializable value, or null
1260     */
1261    public Serializable getSerializable(String key) {
1262        unparcel();
1263        Object o = mMap.get(key);
1264        if (o == null) {
1265            return null;
1266        }
1267        try {
1268            return (Serializable) o;
1269        } catch (ClassCastException e) {
1270            typeWarning(key, o, "Serializable", e);
1271            return null;
1272        }
1273    }
1274
1275    /**
1276     * Returns the value associated with the given key, or null if
1277     * no mapping of the desired type exists for the given key or a null
1278     * value is explicitly associated with the key.
1279     *
1280     * @param key a String, or null
1281     * @return an ArrayList<String> value, or null
1282     */
1283    public ArrayList<Integer> getIntegerArrayList(String key) {
1284        unparcel();
1285        Object o = mMap.get(key);
1286        if (o == null) {
1287            return null;
1288        }
1289        try {
1290            return (ArrayList<Integer>) o;
1291        } catch (ClassCastException e) {
1292            typeWarning(key, o, "ArrayList<Integer>", e);
1293            return null;
1294        }
1295    }
1296
1297    /**
1298     * Returns the value associated with the given key, or null if
1299     * no mapping of the desired type exists for the given key or a null
1300     * value is explicitly associated with the key.
1301     *
1302     * @param key a String, or null
1303     * @return an ArrayList<String> value, or null
1304     */
1305    public ArrayList<String> getStringArrayList(String key) {
1306        unparcel();
1307        Object o = mMap.get(key);
1308        if (o == null) {
1309            return null;
1310        }
1311        try {
1312            return (ArrayList<String>) o;
1313        } catch (ClassCastException e) {
1314            typeWarning(key, o, "ArrayList<String>", e);
1315            return null;
1316        }
1317    }
1318
1319    /**
1320     * Returns the value associated with the given key, or null if
1321     * no mapping of the desired type exists for the given key or a null
1322     * value is explicitly associated with the key.
1323     *
1324     * @param key a String, or null
1325     * @return an ArrayList<CharSequence> value, or null
1326     */
1327    public ArrayList<CharSequence> getCharSequenceArrayList(String key) {
1328        unparcel();
1329        Object o = mMap.get(key);
1330        if (o == null) {
1331            return null;
1332        }
1333        try {
1334            return (ArrayList<CharSequence>) o;
1335        } catch (ClassCastException e) {
1336            typeWarning(key, o, "ArrayList<CharSequence>", e);
1337            return null;
1338        }
1339    }
1340
1341    /**
1342     * Returns the value associated with the given key, or null if
1343     * no mapping of the desired type exists for the given key or a null
1344     * value is explicitly associated with the key.
1345     *
1346     * @param key a String, or null
1347     * @return a boolean[] value, or null
1348     */
1349    public boolean[] getBooleanArray(String key) {
1350        unparcel();
1351        Object o = mMap.get(key);
1352        if (o == null) {
1353            return null;
1354        }
1355        try {
1356            return (boolean[]) o;
1357        } catch (ClassCastException e) {
1358            typeWarning(key, o, "byte[]", e);
1359            return null;
1360        }
1361    }
1362
1363    /**
1364     * Returns the value associated with the given key, or null if
1365     * no mapping of the desired type exists for the given key or a null
1366     * value is explicitly associated with the key.
1367     *
1368     * @param key a String, or null
1369     * @return a byte[] value, or null
1370     */
1371    public byte[] getByteArray(String key) {
1372        unparcel();
1373        Object o = mMap.get(key);
1374        if (o == null) {
1375            return null;
1376        }
1377        try {
1378            return (byte[]) o;
1379        } catch (ClassCastException e) {
1380            typeWarning(key, o, "byte[]", e);
1381            return null;
1382        }
1383    }
1384
1385    /**
1386     * Returns the value associated with the given key, or null if
1387     * no mapping of the desired type exists for the given key or a null
1388     * value is explicitly associated with the key.
1389     *
1390     * @param key a String, or null
1391     * @return a short[] value, or null
1392     */
1393    public short[] getShortArray(String key) {
1394        unparcel();
1395        Object o = mMap.get(key);
1396        if (o == null) {
1397            return null;
1398        }
1399        try {
1400            return (short[]) o;
1401        } catch (ClassCastException e) {
1402            typeWarning(key, o, "short[]", e);
1403            return null;
1404        }
1405    }
1406
1407    /**
1408     * Returns the value associated with the given key, or null if
1409     * no mapping of the desired type exists for the given key or a null
1410     * value is explicitly associated with the key.
1411     *
1412     * @param key a String, or null
1413     * @return a char[] value, or null
1414     */
1415    public char[] getCharArray(String key) {
1416        unparcel();
1417        Object o = mMap.get(key);
1418        if (o == null) {
1419            return null;
1420        }
1421        try {
1422            return (char[]) o;
1423        } catch (ClassCastException e) {
1424            typeWarning(key, o, "char[]", e);
1425            return null;
1426        }
1427    }
1428
1429    /**
1430     * Returns the value associated with the given key, or null if
1431     * no mapping of the desired type exists for the given key or a null
1432     * value is explicitly associated with the key.
1433     *
1434     * @param key a String, or null
1435     * @return an int[] value, or null
1436     */
1437    public int[] getIntArray(String key) {
1438        unparcel();
1439        Object o = mMap.get(key);
1440        if (o == null) {
1441            return null;
1442        }
1443        try {
1444            return (int[]) o;
1445        } catch (ClassCastException e) {
1446            typeWarning(key, o, "int[]", e);
1447            return null;
1448        }
1449    }
1450
1451    /**
1452     * Returns the value associated with the given key, or null if
1453     * no mapping of the desired type exists for the given key or a null
1454     * value is explicitly associated with the key.
1455     *
1456     * @param key a String, or null
1457     * @return a long[] value, or null
1458     */
1459    public long[] getLongArray(String key) {
1460        unparcel();
1461        Object o = mMap.get(key);
1462        if (o == null) {
1463            return null;
1464        }
1465        try {
1466            return (long[]) o;
1467        } catch (ClassCastException e) {
1468            typeWarning(key, o, "long[]", e);
1469            return null;
1470        }
1471    }
1472
1473    /**
1474     * Returns the value associated with the given key, or null if
1475     * no mapping of the desired type exists for the given key or a null
1476     * value is explicitly associated with the key.
1477     *
1478     * @param key a String, or null
1479     * @return a float[] value, or null
1480     */
1481    public float[] getFloatArray(String key) {
1482        unparcel();
1483        Object o = mMap.get(key);
1484        if (o == null) {
1485            return null;
1486        }
1487        try {
1488            return (float[]) o;
1489        } catch (ClassCastException e) {
1490            typeWarning(key, o, "float[]", e);
1491            return null;
1492        }
1493    }
1494
1495    /**
1496     * Returns the value associated with the given key, or null if
1497     * no mapping of the desired type exists for the given key or a null
1498     * value is explicitly associated with the key.
1499     *
1500     * @param key a String, or null
1501     * @return a double[] value, or null
1502     */
1503    public double[] getDoubleArray(String key) {
1504        unparcel();
1505        Object o = mMap.get(key);
1506        if (o == null) {
1507            return null;
1508        }
1509        try {
1510            return (double[]) o;
1511        } catch (ClassCastException e) {
1512            typeWarning(key, o, "double[]", e);
1513            return null;
1514        }
1515    }
1516
1517    /**
1518     * Returns the value associated with the given key, or null if
1519     * no mapping of the desired type exists for the given key or a null
1520     * value is explicitly associated with the key.
1521     *
1522     * @param key a String, or null
1523     * @return a String[] value, or null
1524     */
1525    public String[] getStringArray(String key) {
1526        unparcel();
1527        Object o = mMap.get(key);
1528        if (o == null) {
1529            return null;
1530        }
1531        try {
1532            return (String[]) o;
1533        } catch (ClassCastException e) {
1534            typeWarning(key, o, "String[]", e);
1535            return null;
1536        }
1537    }
1538
1539    /**
1540     * Returns the value associated with the given key, or null if
1541     * no mapping of the desired type exists for the given key or a null
1542     * value is explicitly associated with the key.
1543     *
1544     * @param key a String, or null
1545     * @return a CharSequence[] value, or null
1546     */
1547    public CharSequence[] getCharSequenceArray(String key) {
1548        unparcel();
1549        Object o = mMap.get(key);
1550        if (o == null) {
1551            return null;
1552        }
1553        try {
1554            return (CharSequence[]) o;
1555        } catch (ClassCastException e) {
1556            typeWarning(key, o, "CharSequence[]", e);
1557            return null;
1558        }
1559    }
1560
1561    /**
1562     * Returns the value associated with the given key, or null if
1563     * no mapping of the desired type exists for the given key or a null
1564     * value is explicitly associated with the key.
1565     *
1566     * @param key a String, or null
1567     * @return an IBinder value, or null
1568     *
1569     * @deprecated
1570     * @hide
1571     */
1572    @Deprecated
1573    public IBinder getIBinder(String key) {
1574        unparcel();
1575        Object o = mMap.get(key);
1576        if (o == null) {
1577            return null;
1578        }
1579        try {
1580            return (IBinder) o;
1581        } catch (ClassCastException e) {
1582            typeWarning(key, o, "IBinder", e);
1583            return null;
1584        }
1585    }
1586
1587    public static final Parcelable.Creator<Bundle> CREATOR =
1588        new Parcelable.Creator<Bundle>() {
1589        public Bundle createFromParcel(Parcel in) {
1590            return in.readBundle();
1591        }
1592
1593        public Bundle[] newArray(int size) {
1594            return new Bundle[size];
1595        }
1596    };
1597
1598    /**
1599     * Report the nature of this Parcelable's contents
1600     */
1601    public int describeContents() {
1602        int mask = 0;
1603        if (hasFileDescriptors()) {
1604            mask |= Parcelable.CONTENTS_FILE_DESCRIPTOR;
1605        }
1606        return mask;
1607    }
1608
1609    /**
1610     * Writes the Bundle contents to a Parcel, typically in order for
1611     * it to be passed through an IBinder connection.
1612     * @param parcel The parcel to copy this bundle to.
1613     */
1614    public void writeToParcel(Parcel parcel, int flags) {
1615        final boolean oldAllowFds = parcel.pushAllowFds(mAllowFds);
1616        try {
1617            if (mParcelledData != null) {
1618                int length = mParcelledData.dataSize();
1619                parcel.writeInt(length);
1620                parcel.writeInt(0x4C444E42); // 'B' 'N' 'D' 'L'
1621                parcel.appendFrom(mParcelledData, 0, length);
1622            } else {
1623                parcel.writeInt(-1); // dummy, will hold length
1624                parcel.writeInt(0x4C444E42); // 'B' 'N' 'D' 'L'
1625
1626                int oldPos = parcel.dataPosition();
1627                parcel.writeMapInternal(mMap);
1628                int newPos = parcel.dataPosition();
1629
1630                // Backpatch length
1631                parcel.setDataPosition(oldPos - 8);
1632                int length = newPos - oldPos;
1633                parcel.writeInt(length);
1634                parcel.setDataPosition(newPos);
1635            }
1636        } finally {
1637            parcel.restoreAllowFds(oldAllowFds);
1638        }
1639    }
1640
1641    /**
1642     * Reads the Parcel contents into this Bundle, typically in order for
1643     * it to be passed through an IBinder connection.
1644     * @param parcel The parcel to overwrite this bundle from.
1645     */
1646    public void readFromParcel(Parcel parcel) {
1647        int length = parcel.readInt();
1648        if (length < 0) {
1649            throw new RuntimeException("Bad length in parcel: " + length);
1650        }
1651        readFromParcelInner(parcel, length);
1652    }
1653
1654    void readFromParcelInner(Parcel parcel, int length) {
1655        int magic = parcel.readInt();
1656        if (magic != 0x4C444E42) {
1657            //noinspection ThrowableInstanceNeverThrown
1658            String st = Log.getStackTraceString(new RuntimeException());
1659            Log.e("Bundle", "readBundle: bad magic number");
1660            Log.e("Bundle", "readBundle: trace = " + st);
1661        }
1662
1663        // Advance within this Parcel
1664        int offset = parcel.dataPosition();
1665        parcel.setDataPosition(offset + length);
1666
1667        Parcel p = Parcel.obtain();
1668        p.setDataPosition(0);
1669        p.appendFrom(parcel, offset, length);
1670        p.setDataPosition(0);
1671
1672        mParcelledData = p;
1673        mHasFds = p.hasFileDescriptors();
1674        mFdsKnown = true;
1675    }
1676
1677    @Override
1678    public synchronized String toString() {
1679        if (mParcelledData != null) {
1680            return "Bundle[mParcelledData.dataSize=" +
1681                    mParcelledData.dataSize() + "]";
1682        }
1683        return "Bundle[" + mMap.toString() + "]";
1684    }
1685}
1686