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