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.annotation.Nullable;
20import android.util.ArrayMap;
21import android.util.Size;
22import android.util.SizeF;
23import android.util.SparseArray;
24
25import java.io.Serializable;
26import java.util.ArrayList;
27import java.util.List;
28
29/**
30 * A mapping from String keys to various {@link Parcelable} values.
31 *
32 * @see PersistableBundle
33 */
34public final class Bundle extends BaseBundle implements Cloneable, Parcelable {
35    private static final int FLAG_HAS_FDS = 1 << 8;
36    private static final int FLAG_HAS_FDS_KNOWN = 1 << 9;
37    private static final int FLAG_ALLOW_FDS = 1 << 10;
38
39    public static final Bundle EMPTY;
40
41    static {
42        EMPTY = new Bundle();
43        EMPTY.mMap = ArrayMap.EMPTY;
44    }
45
46    /**
47     * Constructs a new, empty Bundle.
48     */
49    public Bundle() {
50        super();
51        mFlags = FLAG_HAS_FDS_KNOWN | FLAG_ALLOW_FDS;
52    }
53
54    /**
55     * Constructs a Bundle whose data is stored as a Parcel.  The data
56     * will be unparcelled on first contact, using the assigned ClassLoader.
57     *
58     * @param parcelledData a Parcel containing a Bundle
59     */
60    Bundle(Parcel parcelledData) {
61        super(parcelledData);
62        mFlags = FLAG_HAS_FDS_KNOWN | FLAG_ALLOW_FDS;
63        if (mParcelledData.hasFileDescriptors()) {
64            mFlags |= FLAG_HAS_FDS;
65        }
66    }
67
68    /* package */ Bundle(Parcel parcelledData, int length) {
69        super(parcelledData, length);
70        mFlags = FLAG_HAS_FDS_KNOWN | FLAG_ALLOW_FDS;
71        if (mParcelledData.hasFileDescriptors()) {
72            mFlags |= FLAG_HAS_FDS;
73        }
74    }
75
76    /**
77     * Constructs a new, empty Bundle that uses a specific ClassLoader for
78     * instantiating Parcelable and Serializable objects.
79     *
80     * @param loader An explicit ClassLoader to use when instantiating objects
81     * inside of the Bundle.
82     */
83    public Bundle(ClassLoader loader) {
84        super(loader);
85        mFlags = FLAG_HAS_FDS_KNOWN | FLAG_ALLOW_FDS;
86    }
87
88    /**
89     * Constructs a new, empty Bundle sized to hold the given number of
90     * elements. The Bundle will grow as needed.
91     *
92     * @param capacity the initial capacity of the Bundle
93     */
94    public Bundle(int capacity) {
95        super(capacity);
96        mFlags = FLAG_HAS_FDS_KNOWN | FLAG_ALLOW_FDS;
97    }
98
99    /**
100     * Constructs a Bundle containing a copy of the mappings from the given
101     * Bundle.
102     *
103     * @param b a Bundle to be copied.
104     */
105    public Bundle(Bundle b) {
106        super(b);
107        mFlags = b.mFlags;
108    }
109
110    /**
111     * Constructs a Bundle containing a copy of the mappings from the given
112     * PersistableBundle.
113     *
114     * @param b a Bundle to be copied.
115     */
116    public Bundle(PersistableBundle b) {
117        super(b);
118        mFlags = FLAG_HAS_FDS_KNOWN | FLAG_ALLOW_FDS;
119    }
120
121    /**
122     * Make a Bundle for a single key/value pair.
123     *
124     * @hide
125     */
126    public static Bundle forPair(String key, String value) {
127        Bundle b = new Bundle(1);
128        b.putString(key, value);
129        return b;
130    }
131
132    /**
133     * Changes the ClassLoader this Bundle uses when instantiating objects.
134     *
135     * @param loader An explicit ClassLoader to use when instantiating objects
136     * inside of the Bundle.
137     */
138    @Override
139    public void setClassLoader(ClassLoader loader) {
140        super.setClassLoader(loader);
141    }
142
143    /**
144     * Return the ClassLoader currently associated with this Bundle.
145     */
146    @Override
147    public ClassLoader getClassLoader() {
148        return super.getClassLoader();
149    }
150
151    /** {@hide} */
152    public boolean setAllowFds(boolean allowFds) {
153        final boolean orig = (mFlags & FLAG_ALLOW_FDS) != 0;
154        if (allowFds) {
155            mFlags |= FLAG_ALLOW_FDS;
156        } else {
157            mFlags &= ~FLAG_ALLOW_FDS;
158        }
159        return orig;
160    }
161
162    /**
163     * Mark if this Bundle is okay to "defuse." That is, it's okay for system
164     * processes to ignore any {@link BadParcelableException} encountered when
165     * unparceling it, leaving an empty bundle in its place.
166     * <p>
167     * This should <em>only</em> be set when the Bundle reaches its final
168     * destination, otherwise a system process may clobber contents that were
169     * destined for an app that could have unparceled them.
170     *
171     * @hide
172     */
173    public void setDefusable(boolean defusable) {
174        if (defusable) {
175            mFlags |= FLAG_DEFUSABLE;
176        } else {
177            mFlags &= ~FLAG_DEFUSABLE;
178        }
179    }
180
181    /** {@hide} */
182    public static Bundle setDefusable(Bundle bundle, boolean defusable) {
183        if (bundle != null) {
184            bundle.setDefusable(defusable);
185        }
186        return bundle;
187    }
188
189    /**
190     * Clones the current Bundle. The internal map is cloned, but the keys and
191     * values to which it refers are copied by reference.
192     */
193    @Override
194    public Object clone() {
195        return new Bundle(this);
196    }
197
198    /**
199     * Removes all elements from the mapping of this Bundle.
200     */
201    @Override
202    public void clear() {
203        super.clear();
204        mFlags = FLAG_HAS_FDS_KNOWN | FLAG_ALLOW_FDS;
205    }
206
207    /**
208     * Removes any entry with the given key from the mapping of this Bundle.
209     *
210     * @param key a String key
211     */
212    public void remove(String key) {
213        super.remove(key);
214        if ((mFlags & FLAG_HAS_FDS) != 0) {
215            mFlags &= ~FLAG_HAS_FDS_KNOWN;
216        }
217    }
218
219    /**
220     * Inserts all mappings from the given Bundle into this Bundle.
221     *
222     * @param bundle a Bundle
223     */
224    public void putAll(Bundle bundle) {
225        unparcel();
226        bundle.unparcel();
227        mMap.putAll(bundle.mMap);
228
229        // FD state is now known if and only if both bundles already knew
230        if ((bundle.mFlags & FLAG_HAS_FDS) != 0) {
231            mFlags |= FLAG_HAS_FDS;
232        }
233        if ((bundle.mFlags & FLAG_HAS_FDS_KNOWN) == 0) {
234            mFlags &= ~FLAG_HAS_FDS_KNOWN;
235        }
236    }
237
238    /**
239     * Reports whether the bundle contains any parcelled file descriptors.
240     */
241    public boolean hasFileDescriptors() {
242        if ((mFlags & FLAG_HAS_FDS_KNOWN) == 0) {
243            boolean fdFound = false;    // keep going until we find one or run out of data
244
245            if (mParcelledData != null) {
246                if (mParcelledData.hasFileDescriptors()) {
247                    fdFound = true;
248                }
249            } else {
250                // It's been unparcelled, so we need to walk the map
251                for (int i=mMap.size()-1; i>=0; i--) {
252                    Object obj = mMap.valueAt(i);
253                    if (obj instanceof Parcelable) {
254                        if ((((Parcelable)obj).describeContents()
255                                & Parcelable.CONTENTS_FILE_DESCRIPTOR) != 0) {
256                            fdFound = true;
257                            break;
258                        }
259                    } else if (obj instanceof Parcelable[]) {
260                        Parcelable[] array = (Parcelable[]) obj;
261                        for (int n = array.length - 1; n >= 0; n--) {
262                            Parcelable p = array[n];
263                            if (p != null && ((p.describeContents()
264                                    & Parcelable.CONTENTS_FILE_DESCRIPTOR) != 0)) {
265                                fdFound = true;
266                                break;
267                            }
268                        }
269                    } else if (obj instanceof SparseArray) {
270                        SparseArray<? extends Parcelable> array =
271                                (SparseArray<? extends Parcelable>) obj;
272                        for (int n = array.size() - 1; n >= 0; n--) {
273                            Parcelable p = array.valueAt(n);
274                            if (p != null && (p.describeContents()
275                                    & Parcelable.CONTENTS_FILE_DESCRIPTOR) != 0) {
276                                fdFound = true;
277                                break;
278                            }
279                        }
280                    } else if (obj instanceof ArrayList) {
281                        ArrayList array = (ArrayList) obj;
282                        // an ArrayList here might contain either Strings or
283                        // Parcelables; only look inside for Parcelables
284                        if (!array.isEmpty() && (array.get(0) instanceof Parcelable)) {
285                            for (int n = array.size() - 1; n >= 0; n--) {
286                                Parcelable p = (Parcelable) array.get(n);
287                                if (p != null && ((p.describeContents()
288                                        & Parcelable.CONTENTS_FILE_DESCRIPTOR) != 0)) {
289                                    fdFound = true;
290                                    break;
291                                }
292                            }
293                        }
294                    }
295                }
296            }
297
298            if (fdFound) {
299                mFlags |= FLAG_HAS_FDS;
300            } else {
301                mFlags &= ~FLAG_HAS_FDS;
302            }
303            mFlags |= FLAG_HAS_FDS_KNOWN;
304        }
305        return (mFlags & FLAG_HAS_FDS) != 0;
306    }
307
308    /**
309     * Filter values in Bundle to only basic types.
310     * @hide
311     */
312    public Bundle filterValues() {
313        unparcel();
314        Bundle bundle = this;
315        if (mMap != null) {
316            ArrayMap<String, Object> map = mMap;
317            for (int i = map.size() - 1; i >= 0; i--) {
318                Object value = map.valueAt(i);
319                if (PersistableBundle.isValidType(value)) {
320                    continue;
321                }
322                if (value instanceof Bundle) {
323                    Bundle newBundle = ((Bundle)value).filterValues();
324                    if (newBundle != value) {
325                        if (map == mMap) {
326                            // The filter had to generate a new bundle, but we have not yet
327                            // created a new one here.  Do that now.
328                            bundle = new Bundle(this);
329                            // Note the ArrayMap<> constructor is guaranteed to generate
330                            // a new object with items in the same order as the original.
331                            map = bundle.mMap;
332                        }
333                        // Replace this current entry with the new child bundle.
334                        map.setValueAt(i, newBundle);
335                    }
336                    continue;
337                }
338                if (value.getClass().getName().startsWith("android.")) {
339                    continue;
340                }
341                if (map == mMap) {
342                    // This is the first time we have had to remove something, that means we
343                    // need to switch to a new Bundle.
344                    bundle = new Bundle(this);
345                    // Note the ArrayMap<> constructor is guaranteed to generate
346                    // a new object with items in the same order as the original.
347                    map = bundle.mMap;
348                }
349                map.removeAt(i);
350            }
351        }
352        mFlags |= FLAG_HAS_FDS_KNOWN;
353        mFlags &= ~FLAG_HAS_FDS;
354        return bundle;
355    }
356
357    /**
358     * Inserts a byte value into the mapping of this Bundle, replacing
359     * any existing value for the given key.
360     *
361     * @param key a String, or null
362     * @param value a byte
363     */
364    @Override
365    public void putByte(@Nullable String key, byte value) {
366        super.putByte(key, value);
367    }
368
369    /**
370     * Inserts a char value into the mapping of this Bundle, replacing
371     * any existing value for the given key.
372     *
373     * @param key a String, or null
374     * @param value a char
375     */
376    @Override
377    public void putChar(@Nullable String key, char value) {
378        super.putChar(key, value);
379    }
380
381    /**
382     * Inserts a short value into the mapping of this Bundle, replacing
383     * any existing value for the given key.
384     *
385     * @param key a String, or null
386     * @param value a short
387     */
388    @Override
389    public void putShort(@Nullable String key, short value) {
390        super.putShort(key, value);
391    }
392
393    /**
394     * Inserts a float value into the mapping of this Bundle, replacing
395     * any existing value for the given key.
396     *
397     * @param key a String, or null
398     * @param value a float
399     */
400    @Override
401    public void putFloat(@Nullable String key, float value) {
402        super.putFloat(key, value);
403    }
404
405    /**
406     * Inserts a CharSequence value into the mapping of this Bundle, replacing
407     * any existing value for the given key.  Either key or value may be null.
408     *
409     * @param key a String, or null
410     * @param value a CharSequence, or null
411     */
412    @Override
413    public void putCharSequence(@Nullable String key, @Nullable CharSequence value) {
414        super.putCharSequence(key, value);
415    }
416
417    /**
418     * Inserts a Parcelable value into the mapping of this Bundle, replacing
419     * any existing value for the given key.  Either key or value may be null.
420     *
421     * @param key a String, or null
422     * @param value a Parcelable object, or null
423     */
424    public void putParcelable(@Nullable String key, @Nullable Parcelable value) {
425        unparcel();
426        mMap.put(key, value);
427        mFlags &= ~FLAG_HAS_FDS_KNOWN;
428    }
429
430    /**
431     * Inserts a Size value into the mapping of this Bundle, replacing
432     * any existing value for the given key.  Either key or value may be null.
433     *
434     * @param key a String, or null
435     * @param value a Size object, or null
436     */
437    public void putSize(@Nullable String key, @Nullable Size value) {
438        unparcel();
439        mMap.put(key, value);
440    }
441
442    /**
443     * Inserts a SizeF value into the mapping of this Bundle, replacing
444     * any existing value for the given key.  Either key or value may be null.
445     *
446     * @param key a String, or null
447     * @param value a SizeF object, or null
448     */
449    public void putSizeF(@Nullable String key, @Nullable SizeF value) {
450        unparcel();
451        mMap.put(key, value);
452    }
453
454    /**
455     * Inserts an array of Parcelable values into the mapping of this Bundle,
456     * replacing any existing value for the given key.  Either key or value may
457     * be null.
458     *
459     * @param key a String, or null
460     * @param value an array of Parcelable objects, or null
461     */
462    public void putParcelableArray(@Nullable String key, @Nullable Parcelable[] value) {
463        unparcel();
464        mMap.put(key, value);
465        mFlags &= ~FLAG_HAS_FDS_KNOWN;
466    }
467
468    /**
469     * Inserts a List of Parcelable values into the mapping of this Bundle,
470     * replacing any existing value for the given key.  Either key or value may
471     * be null.
472     *
473     * @param key a String, or null
474     * @param value an ArrayList of Parcelable objects, or null
475     */
476    public void putParcelableArrayList(@Nullable String key,
477            @Nullable ArrayList<? extends Parcelable> value) {
478        unparcel();
479        mMap.put(key, value);
480        mFlags &= ~FLAG_HAS_FDS_KNOWN;
481    }
482
483    /** {@hide} */
484    public void putParcelableList(String key, List<? extends Parcelable> value) {
485        unparcel();
486        mMap.put(key, value);
487        mFlags &= ~FLAG_HAS_FDS_KNOWN;
488    }
489
490    /**
491     * Inserts a SparceArray of Parcelable values into the mapping of this
492     * Bundle, replacing any existing value for the given key.  Either key
493     * or value may be null.
494     *
495     * @param key a String, or null
496     * @param value a SparseArray of Parcelable objects, or null
497     */
498    public void putSparseParcelableArray(@Nullable String key,
499            @Nullable SparseArray<? extends Parcelable> value) {
500        unparcel();
501        mMap.put(key, value);
502        mFlags &= ~FLAG_HAS_FDS_KNOWN;
503    }
504
505    /**
506     * Inserts an ArrayList<Integer> value into the mapping of this Bundle, replacing
507     * any existing value for the given key.  Either key or value may be null.
508     *
509     * @param key a String, or null
510     * @param value an ArrayList<Integer> object, or null
511     */
512    @Override
513    public void putIntegerArrayList(@Nullable String key, @Nullable ArrayList<Integer> value) {
514        super.putIntegerArrayList(key, value);
515    }
516
517    /**
518     * Inserts an ArrayList<String> value into the mapping of this Bundle, replacing
519     * any existing value for the given key.  Either key or value may be null.
520     *
521     * @param key a String, or null
522     * @param value an ArrayList<String> object, or null
523     */
524    @Override
525    public void putStringArrayList(@Nullable String key, @Nullable ArrayList<String> value) {
526        super.putStringArrayList(key, value);
527    }
528
529    /**
530     * Inserts an ArrayList<CharSequence> value into the mapping of this Bundle, replacing
531     * any existing value for the given key.  Either key or value may be null.
532     *
533     * @param key a String, or null
534     * @param value an ArrayList<CharSequence> object, or null
535     */
536    @Override
537    public void putCharSequenceArrayList(@Nullable String key,
538            @Nullable ArrayList<CharSequence> value) {
539        super.putCharSequenceArrayList(key, value);
540    }
541
542    /**
543     * Inserts a Serializable 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 a Serializable object, or null
548     */
549    @Override
550    public void putSerializable(@Nullable String key, @Nullable Serializable value) {
551        super.putSerializable(key, value);
552    }
553
554    /**
555     * Inserts a byte array 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 a byte array object, or null
560     */
561    @Override
562    public void putByteArray(@Nullable String key, @Nullable byte[] value) {
563        super.putByteArray(key, value);
564    }
565
566    /**
567     * Inserts a short array 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 a short array object, or null
572     */
573    @Override
574    public void putShortArray(@Nullable String key, @Nullable short[] value) {
575        super.putShortArray(key, value);
576    }
577
578    /**
579     * Inserts a char array 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 char array object, or null
584     */
585    @Override
586    public void putCharArray(@Nullable String key, @Nullable char[] value) {
587        super.putCharArray(key, value);
588    }
589
590    /**
591     * Inserts a float 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 float array object, or null
596     */
597    @Override
598    public void putFloatArray(@Nullable String key, @Nullable float[] value) {
599        super.putFloatArray(key, value);
600    }
601
602    /**
603     * Inserts a CharSequence 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 CharSequence array object, or null
608     */
609    @Override
610    public void putCharSequenceArray(@Nullable String key, @Nullable CharSequence[] value) {
611        super.putCharSequenceArray(key, value);
612    }
613
614    /**
615     * Inserts a Bundle 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 Bundle object, or null
620     */
621    public void putBundle(@Nullable String key, @Nullable Bundle value) {
622        unparcel();
623        mMap.put(key, value);
624    }
625
626    /**
627     * Inserts an {@link IBinder} 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     * <p class="note">You should be very careful when using this function.  In many
631     * places where Bundles are used (such as inside of Intent objects), the Bundle
632     * can live longer inside of another process than the process that had originally
633     * created it.  In that case, the IBinder you supply here will become invalid
634     * when your process goes away, and no longer usable, even if a new process is
635     * created for you later on.</p>
636     *
637     * @param key a String, or null
638     * @param value an IBinder object, or null
639     */
640    public void putBinder(@Nullable String key, @Nullable IBinder value) {
641        unparcel();
642        mMap.put(key, value);
643    }
644
645    /**
646     * Inserts an IBinder value into the mapping of this Bundle, replacing
647     * any existing value for the given key.  Either key or value may be null.
648     *
649     * @param key a String, or null
650     * @param value an IBinder object, or null
651     *
652     * @deprecated
653     * @hide This is the old name of the function.
654     */
655    @Deprecated
656    public void putIBinder(@Nullable String key, @Nullable IBinder value) {
657        unparcel();
658        mMap.put(key, value);
659    }
660
661    /**
662     * Returns the value associated with the given key, or (byte) 0 if
663     * no mapping of the desired type exists for the given key.
664     *
665     * @param key a String
666     * @return a byte value
667     */
668    @Override
669    public byte getByte(String key) {
670        return super.getByte(key);
671    }
672
673    /**
674     * Returns the value associated with the given key, or defaultValue if
675     * no mapping of the desired type exists for the given key.
676     *
677     * @param key a String
678     * @param defaultValue Value to return if key does not exist
679     * @return a byte value
680     */
681    @Override
682    public Byte getByte(String key, byte defaultValue) {
683        return super.getByte(key, defaultValue);
684    }
685
686    /**
687     * Returns the value associated with the given key, or (char) 0 if
688     * no mapping of the desired type exists for the given key.
689     *
690     * @param key a String
691     * @return a char value
692     */
693    @Override
694    public char getChar(String key) {
695        return super.getChar(key);
696    }
697
698    /**
699     * Returns the value associated with the given key, or defaultValue if
700     * no mapping of the desired type exists for the given key.
701     *
702     * @param key a String
703     * @param defaultValue Value to return if key does not exist
704     * @return a char value
705     */
706    @Override
707    public char getChar(String key, char defaultValue) {
708        return super.getChar(key, defaultValue);
709    }
710
711    /**
712     * Returns the value associated with the given key, or (short) 0 if
713     * no mapping of the desired type exists for the given key.
714     *
715     * @param key a String
716     * @return a short value
717     */
718    @Override
719    public short getShort(String key) {
720        return super.getShort(key);
721    }
722
723    /**
724     * Returns the value associated with the given key, or defaultValue if
725     * no mapping of the desired type exists for the given key.
726     *
727     * @param key a String
728     * @param defaultValue Value to return if key does not exist
729     * @return a short value
730     */
731    @Override
732    public short getShort(String key, short defaultValue) {
733        return super.getShort(key, defaultValue);
734    }
735
736    /**
737     * Returns the value associated with the given key, or 0.0f if
738     * no mapping of the desired type exists for the given key.
739     *
740     * @param key a String
741     * @return a float value
742     */
743    @Override
744    public float getFloat(String key) {
745        return super.getFloat(key);
746    }
747
748    /**
749     * Returns the value associated with the given key, or defaultValue if
750     * no mapping of the desired type exists for the given key.
751     *
752     * @param key a String
753     * @param defaultValue Value to return if key does not exist
754     * @return a float value
755     */
756    @Override
757    public float getFloat(String key, float defaultValue) {
758        return super.getFloat(key, defaultValue);
759    }
760
761    /**
762     * Returns the value associated with the given key, or null if
763     * no mapping of the desired type exists for the given key or a null
764     * value is explicitly associated with the key.
765     *
766     * @param key a String, or null
767     * @return a CharSequence value, or null
768     */
769    @Override
770    @Nullable
771    public CharSequence getCharSequence(@Nullable String key) {
772        return super.getCharSequence(key);
773    }
774
775    /**
776     * Returns the value associated with the given key, or defaultValue if
777     * no mapping of the desired type exists for the given key or if a null
778     * value is explicitly associatd with the given key.
779     *
780     * @param key a String, or null
781     * @param defaultValue Value to return if key does not exist or if a null
782     *     value is associated with the given key.
783     * @return the CharSequence value associated with the given key, or defaultValue
784     *     if no valid CharSequence object is currently mapped to that key.
785     */
786    @Override
787    public CharSequence getCharSequence(@Nullable String key, CharSequence defaultValue) {
788        return super.getCharSequence(key, defaultValue);
789    }
790
791    /**
792     * Returns the value associated with the given key, or null if
793     * no mapping of the desired type exists for the given key or a null
794     * value is explicitly associated with the key.
795     *
796     * @param key a String, or null
797     * @return a Size value, or null
798     */
799    @Nullable
800    public Size getSize(@Nullable String key) {
801        unparcel();
802        final Object o = mMap.get(key);
803        try {
804            return (Size) o;
805        } catch (ClassCastException e) {
806            typeWarning(key, o, "Size", e);
807            return null;
808        }
809    }
810
811    /**
812     * Returns the value associated with the given key, or null if
813     * no mapping of the desired type exists for the given key or a null
814     * value is explicitly associated with the key.
815     *
816     * @param key a String, or null
817     * @return a Size value, or null
818     */
819    @Nullable
820    public SizeF getSizeF(@Nullable String key) {
821        unparcel();
822        final Object o = mMap.get(key);
823        try {
824            return (SizeF) o;
825        } catch (ClassCastException e) {
826            typeWarning(key, o, "SizeF", e);
827            return null;
828        }
829    }
830
831    /**
832     * Returns the value associated with the given key, or null if
833     * no mapping of the desired type exists for the given key or a null
834     * value is explicitly associated with the key.
835     *
836     * @param key a String, or null
837     * @return a Bundle value, or null
838     */
839    @Nullable
840    public Bundle getBundle(@Nullable String key) {
841        unparcel();
842        Object o = mMap.get(key);
843        if (o == null) {
844            return null;
845        }
846        try {
847            return (Bundle) o;
848        } catch (ClassCastException e) {
849            typeWarning(key, o, "Bundle", e);
850            return null;
851        }
852    }
853
854    /**
855     * Returns the value associated with the given key, or null if
856     * no mapping of the desired type exists for the given key or a null
857     * value is explicitly associated with the key.
858     *
859     * @param key a String, or null
860     * @return a Parcelable value, or null
861     */
862    @Nullable
863    public <T extends Parcelable> T getParcelable(@Nullable String key) {
864        unparcel();
865        Object o = mMap.get(key);
866        if (o == null) {
867            return null;
868        }
869        try {
870            return (T) o;
871        } catch (ClassCastException e) {
872            typeWarning(key, o, "Parcelable", e);
873            return null;
874        }
875    }
876
877    /**
878     * Returns the value associated with the given key, or null if
879     * no mapping of the desired type exists for the given key or a null
880     * value is explicitly associated with the key.
881     *
882     * @param key a String, or null
883     * @return a Parcelable[] value, or null
884     */
885    @Nullable
886    public Parcelable[] getParcelableArray(@Nullable String key) {
887        unparcel();
888        Object o = mMap.get(key);
889        if (o == null) {
890            return null;
891        }
892        try {
893            return (Parcelable[]) o;
894        } catch (ClassCastException e) {
895            typeWarning(key, o, "Parcelable[]", e);
896            return null;
897        }
898    }
899
900    /**
901     * Returns the value associated with the given key, or null if
902     * no mapping of the desired type exists for the given key or a null
903     * value is explicitly associated with the key.
904     *
905     * @param key a String, or null
906     * @return an ArrayList<T> value, or null
907     */
908    @Nullable
909    public <T extends Parcelable> ArrayList<T> getParcelableArrayList(@Nullable String key) {
910        unparcel();
911        Object o = mMap.get(key);
912        if (o == null) {
913            return null;
914        }
915        try {
916            return (ArrayList<T>) o;
917        } catch (ClassCastException e) {
918            typeWarning(key, o, "ArrayList", e);
919            return null;
920        }
921    }
922
923    /**
924     * Returns the value associated with the given key, or null if
925     * no mapping of the desired type exists for the given key or a null
926     * value is explicitly associated with the key.
927     *
928     * @param key a String, or null
929     *
930     * @return a SparseArray of T values, or null
931     */
932    @Nullable
933    public <T extends Parcelable> SparseArray<T> getSparseParcelableArray(@Nullable String key) {
934        unparcel();
935        Object o = mMap.get(key);
936        if (o == null) {
937            return null;
938        }
939        try {
940            return (SparseArray<T>) o;
941        } catch (ClassCastException e) {
942            typeWarning(key, o, "SparseArray", e);
943            return null;
944        }
945    }
946
947    /**
948     * Returns the value associated with the given key, or null if
949     * no mapping of the desired type exists for the given key or a null
950     * value is explicitly associated with the key.
951     *
952     * @param key a String, or null
953     * @return a Serializable value, or null
954     */
955    @Override
956    @Nullable
957    public Serializable getSerializable(@Nullable String key) {
958        return super.getSerializable(key);
959    }
960
961    /**
962     * Returns the value associated with the given key, or null if
963     * no mapping of the desired type exists for the given key or a null
964     * value is explicitly associated with the key.
965     *
966     * @param key a String, or null
967     * @return an ArrayList<String> value, or null
968     */
969    @Override
970    @Nullable
971    public ArrayList<Integer> getIntegerArrayList(@Nullable String key) {
972        return super.getIntegerArrayList(key);
973    }
974
975    /**
976     * Returns the value associated with the given key, or null if
977     * no mapping of the desired type exists for the given key or a null
978     * value is explicitly associated with the key.
979     *
980     * @param key a String, or null
981     * @return an ArrayList<String> value, or null
982     */
983    @Override
984    @Nullable
985    public ArrayList<String> getStringArrayList(@Nullable String key) {
986        return super.getStringArrayList(key);
987    }
988
989    /**
990     * Returns the value associated with the given key, or null if
991     * no mapping of the desired type exists for the given key or a null
992     * value is explicitly associated with the key.
993     *
994     * @param key a String, or null
995     * @return an ArrayList<CharSequence> value, or null
996     */
997    @Override
998    @Nullable
999    public ArrayList<CharSequence> getCharSequenceArrayList(@Nullable String key) {
1000        return super.getCharSequenceArrayList(key);
1001    }
1002
1003    /**
1004     * Returns the value associated with the given key, or null if
1005     * no mapping of the desired type exists for the given key or a null
1006     * value is explicitly associated with the key.
1007     *
1008     * @param key a String, or null
1009     * @return a byte[] value, or null
1010     */
1011    @Override
1012    @Nullable
1013    public byte[] getByteArray(@Nullable String key) {
1014        return super.getByteArray(key);
1015    }
1016
1017    /**
1018     * Returns the value associated with the given key, or null if
1019     * no mapping of the desired type exists for the given key or a null
1020     * value is explicitly associated with the key.
1021     *
1022     * @param key a String, or null
1023     * @return a short[] value, or null
1024     */
1025    @Override
1026    @Nullable
1027    public short[] getShortArray(@Nullable String key) {
1028        return super.getShortArray(key);
1029    }
1030
1031    /**
1032     * Returns the value associated with the given key, or null if
1033     * no mapping of the desired type exists for the given key or a null
1034     * value is explicitly associated with the key.
1035     *
1036     * @param key a String, or null
1037     * @return a char[] value, or null
1038     */
1039    @Override
1040    @Nullable
1041    public char[] getCharArray(@Nullable String key) {
1042        return super.getCharArray(key);
1043    }
1044
1045    /**
1046     * Returns the value associated with the given key, or null if
1047     * no mapping of the desired type exists for the given key or a null
1048     * value is explicitly associated with the key.
1049     *
1050     * @param key a String, or null
1051     * @return a float[] value, or null
1052     */
1053    @Override
1054    @Nullable
1055    public float[] getFloatArray(@Nullable String key) {
1056        return super.getFloatArray(key);
1057    }
1058
1059    /**
1060     * Returns the value associated with the given key, or null if
1061     * no mapping of the desired type exists for the given key or a null
1062     * value is explicitly associated with the key.
1063     *
1064     * @param key a String, or null
1065     * @return a CharSequence[] value, or null
1066     */
1067    @Override
1068    @Nullable
1069    public CharSequence[] getCharSequenceArray(@Nullable String key) {
1070        return super.getCharSequenceArray(key);
1071    }
1072
1073    /**
1074     * Returns the value associated with the given key, or null if
1075     * no mapping of the desired type exists for the given key or a null
1076     * value is explicitly associated with the key.
1077     *
1078     * @param key a String, or null
1079     * @return an IBinder value, or null
1080     */
1081    @Nullable
1082    public IBinder getBinder(@Nullable String key) {
1083        unparcel();
1084        Object o = mMap.get(key);
1085        if (o == null) {
1086            return null;
1087        }
1088        try {
1089            return (IBinder) o;
1090        } catch (ClassCastException e) {
1091            typeWarning(key, o, "IBinder", e);
1092            return null;
1093        }
1094    }
1095
1096    /**
1097     * Returns the value associated with the given key, or null if
1098     * no mapping of the desired type exists for the given key or a null
1099     * value is explicitly associated with the key.
1100     *
1101     * @param key a String, or null
1102     * @return an IBinder value, or null
1103     *
1104     * @deprecated
1105     * @hide This is the old name of the function.
1106     */
1107    @Deprecated
1108    @Nullable
1109    public IBinder getIBinder(@Nullable String key) {
1110        unparcel();
1111        Object o = mMap.get(key);
1112        if (o == null) {
1113            return null;
1114        }
1115        try {
1116            return (IBinder) o;
1117        } catch (ClassCastException e) {
1118            typeWarning(key, o, "IBinder", e);
1119            return null;
1120        }
1121    }
1122
1123    public static final Parcelable.Creator<Bundle> CREATOR =
1124        new Parcelable.Creator<Bundle>() {
1125        @Override
1126        public Bundle createFromParcel(Parcel in) {
1127            return in.readBundle();
1128        }
1129
1130        @Override
1131        public Bundle[] newArray(int size) {
1132            return new Bundle[size];
1133        }
1134    };
1135
1136    /**
1137     * Report the nature of this Parcelable's contents
1138     */
1139    @Override
1140    public int describeContents() {
1141        int mask = 0;
1142        if (hasFileDescriptors()) {
1143            mask |= Parcelable.CONTENTS_FILE_DESCRIPTOR;
1144        }
1145        return mask;
1146    }
1147
1148    /**
1149     * Writes the Bundle contents to a Parcel, typically in order for
1150     * it to be passed through an IBinder connection.
1151     * @param parcel The parcel to copy this bundle to.
1152     */
1153    @Override
1154    public void writeToParcel(Parcel parcel, int flags) {
1155        final boolean oldAllowFds = parcel.pushAllowFds((mFlags & FLAG_ALLOW_FDS) != 0);
1156        try {
1157            super.writeToParcelInner(parcel, flags);
1158        } finally {
1159            parcel.restoreAllowFds(oldAllowFds);
1160        }
1161    }
1162
1163    /**
1164     * Reads the Parcel contents into this Bundle, typically in order for
1165     * it to be passed through an IBinder connection.
1166     * @param parcel The parcel to overwrite this bundle from.
1167     */
1168    public void readFromParcel(Parcel parcel) {
1169        super.readFromParcelInner(parcel);
1170        mFlags = FLAG_HAS_FDS_KNOWN | FLAG_ALLOW_FDS;
1171        if (mParcelledData.hasFileDescriptors()) {
1172            mFlags |= FLAG_HAS_FDS;
1173        }
1174    }
1175
1176    @Override
1177    public synchronized String toString() {
1178        if (mParcelledData != null) {
1179            if (isEmptyParcel()) {
1180                return "Bundle[EMPTY_PARCEL]";
1181            } else {
1182                return "Bundle[mParcelledData.dataSize=" +
1183                        mParcelledData.dataSize() + "]";
1184            }
1185        }
1186        return "Bundle[" + mMap.toString() + "]";
1187    }
1188}
1189