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