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