1 /*
2  * Copyright (C) 2014 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.annotation.Nullable;
20 import android.util.ArrayMap;
21 import android.util.Log;
22 
23 import java.io.Serializable;
24 import java.util.ArrayList;
25 import java.util.Set;
26 
27 /**
28  * A mapping from String values to various types.
29  */
30 public class BaseBundle {
31     private static final String TAG = "Bundle";
32     static final boolean DEBUG = false;
33 
34     static final int BUNDLE_MAGIC = 0x4C444E42; // 'B' 'N' 'D' 'L'
35     static final Parcel EMPTY_PARCEL;
36 
37     static {
38         EMPTY_PARCEL = Parcel.obtain();
39     }
40 
41     // Invariant - exactly one of mMap / mParcelledData will be null
42     // (except inside a call to unparcel)
43 
44     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     Parcel mParcelledData = null;
52 
53     /**
54      * The ClassLoader used when unparcelling data from mParcelledData.
55      */
56     private ClassLoader mClassLoader;
57 
58     /**
59      * Constructs a new, empty Bundle that uses a specific ClassLoader for
60      * instantiating Parcelable and Serializable objects.
61      *
62      * @param loader An explicit ClassLoader to use when instantiating objects
63      * inside of the Bundle.
64      * @param capacity Initial size of the ArrayMap.
65      */
BaseBundle(@ullable ClassLoader loader, int capacity)66     BaseBundle(@Nullable ClassLoader loader, int capacity) {
67         mMap = capacity > 0 ?
68                 new ArrayMap<String, Object>(capacity) : new ArrayMap<String, Object>();
69         mClassLoader = loader == null ? getClass().getClassLoader() : loader;
70     }
71 
72     /**
73      * Constructs a new, empty Bundle.
74      */
BaseBundle()75     BaseBundle() {
76         this((ClassLoader) null, 0);
77     }
78 
79     /**
80      * Constructs a Bundle whose data is stored as a Parcel.  The data
81      * will be unparcelled on first contact, using the assigned ClassLoader.
82      *
83      * @param parcelledData a Parcel containing a Bundle
84      */
BaseBundle(Parcel parcelledData)85     BaseBundle(Parcel parcelledData) {
86         readFromParcelInner(parcelledData);
87     }
88 
BaseBundle(Parcel parcelledData, int length)89     BaseBundle(Parcel parcelledData, int length) {
90         readFromParcelInner(parcelledData, length);
91     }
92 
93     /**
94      * Constructs a new, empty Bundle that uses a specific ClassLoader for
95      * instantiating Parcelable and Serializable objects.
96      *
97      * @param loader An explicit ClassLoader to use when instantiating objects
98      * inside of the Bundle.
99      */
BaseBundle(ClassLoader loader)100     BaseBundle(ClassLoader loader) {
101         this(loader, 0);
102     }
103 
104     /**
105      * Constructs a new, empty Bundle sized to hold the given number of
106      * elements. The Bundle will grow as needed.
107      *
108      * @param capacity the initial capacity of the Bundle
109      */
BaseBundle(int capacity)110     BaseBundle(int capacity) {
111         this((ClassLoader) null, capacity);
112     }
113 
114     /**
115      * Constructs a Bundle containing a copy of the mappings from the given
116      * Bundle.
117      *
118      * @param b a Bundle to be copied.
119      */
BaseBundle(BaseBundle b)120     BaseBundle(BaseBundle b) {
121         if (b.mParcelledData != null) {
122             if (b.mParcelledData == EMPTY_PARCEL) {
123                 mParcelledData = EMPTY_PARCEL;
124             } else {
125                 mParcelledData = Parcel.obtain();
126                 mParcelledData.appendFrom(b.mParcelledData, 0, b.mParcelledData.dataSize());
127                 mParcelledData.setDataPosition(0);
128             }
129         } else {
130             mParcelledData = null;
131         }
132 
133         if (b.mMap != null) {
134             mMap = new ArrayMap<String, Object>(b.mMap);
135         } else {
136             mMap = null;
137         }
138 
139         mClassLoader = b.mClassLoader;
140     }
141 
142     /**
143      * TODO: optimize this later (getting just the value part of a Bundle
144      * with a single pair) once Bundle.forPair() above is implemented
145      * with a special single-value Map implementation/serialization.
146      *
147      * Note: value in single-pair Bundle may be null.
148      *
149      * @hide
150      */
getPairValue()151     public String getPairValue() {
152         unparcel();
153         int size = mMap.size();
154         if (size > 1) {
155             Log.w(TAG, "getPairValue() used on Bundle with multiple pairs.");
156         }
157         if (size == 0) {
158             return null;
159         }
160         Object o = mMap.valueAt(0);
161         try {
162             return (String) o;
163         } catch (ClassCastException e) {
164             typeWarning("getPairValue()", o, "String", e);
165             return null;
166         }
167     }
168 
169     /**
170      * Changes the ClassLoader this Bundle uses when instantiating objects.
171      *
172      * @param loader An explicit ClassLoader to use when instantiating objects
173      * inside of the Bundle.
174      */
setClassLoader(ClassLoader loader)175     void setClassLoader(ClassLoader loader) {
176         mClassLoader = loader;
177     }
178 
179     /**
180      * Return the ClassLoader currently associated with this Bundle.
181      */
getClassLoader()182     ClassLoader getClassLoader() {
183         return mClassLoader;
184     }
185 
186     /**
187      * If the underlying data are stored as a Parcel, unparcel them
188      * using the currently assigned class loader.
189      */
unparcel()190     /* package */ synchronized void unparcel() {
191         if (mParcelledData == null) {
192             if (DEBUG) Log.d(TAG, "unparcel " + Integer.toHexString(System.identityHashCode(this))
193                     + ": no parcelled data");
194             return;
195         }
196 
197         if (mParcelledData == EMPTY_PARCEL) {
198             if (DEBUG) Log.d(TAG, "unparcel " + Integer.toHexString(System.identityHashCode(this))
199                     + ": empty");
200             if (mMap == null) {
201                 mMap = new ArrayMap<String, Object>(1);
202             } else {
203                 mMap.erase();
204             }
205             mParcelledData = null;
206             return;
207         }
208 
209         int N = mParcelledData.readInt();
210         if (DEBUG) Log.d(TAG, "unparcel " + Integer.toHexString(System.identityHashCode(this))
211                 + ": reading " + N + " maps");
212         if (N < 0) {
213             return;
214         }
215         if (mMap == null) {
216             mMap = new ArrayMap<String, Object>(N);
217         } else {
218             mMap.erase();
219             mMap.ensureCapacity(N);
220         }
221         mParcelledData.readArrayMapInternal(mMap, N, mClassLoader);
222         mParcelledData.recycle();
223         mParcelledData = null;
224         if (DEBUG) Log.d(TAG, "unparcel " + Integer.toHexString(System.identityHashCode(this))
225                 + " final map: " + mMap);
226     }
227 
228     /**
229      * @hide
230      */
isParcelled()231     public boolean isParcelled() {
232         return mParcelledData != null;
233     }
234 
235     /**
236      * Returns the number of mappings contained in this Bundle.
237      *
238      * @return the number of mappings as an int.
239      */
size()240     public int size() {
241         unparcel();
242         return mMap.size();
243     }
244 
245     /**
246      * Returns true if the mapping of this Bundle is empty, false otherwise.
247      */
isEmpty()248     public boolean isEmpty() {
249         unparcel();
250         return mMap.isEmpty();
251     }
252 
253     /**
254      * Removes all elements from the mapping of this Bundle.
255      */
clear()256     public void clear() {
257         unparcel();
258         mMap.clear();
259     }
260 
261     /**
262      * Returns true if the given key is contained in the mapping
263      * of this Bundle.
264      *
265      * @param key a String key
266      * @return true if the key is part of the mapping, false otherwise
267      */
containsKey(String key)268     public boolean containsKey(String key) {
269         unparcel();
270         return mMap.containsKey(key);
271     }
272 
273     /**
274      * Returns the entry with the given key as an object.
275      *
276      * @param key a String key
277      * @return an Object, or null
278      */
279     @Nullable
get(String key)280     public Object get(String key) {
281         unparcel();
282         return mMap.get(key);
283     }
284 
285     /**
286      * Removes any entry with the given key from the mapping of this Bundle.
287      *
288      * @param key a String key
289      */
remove(String key)290     public void remove(String key) {
291         unparcel();
292         mMap.remove(key);
293     }
294 
295     /**
296      * Inserts all mappings from the given PersistableBundle into this BaseBundle.
297      *
298      * @param bundle a PersistableBundle
299      */
putAll(PersistableBundle bundle)300     public void putAll(PersistableBundle bundle) {
301         unparcel();
302         bundle.unparcel();
303         mMap.putAll(bundle.mMap);
304     }
305 
306     /**
307      * Inserts all mappings from the given Map into this BaseBundle.
308      *
309      * @param map a Map
310      */
putAll(ArrayMap map)311     void putAll(ArrayMap map) {
312         unparcel();
313         mMap.putAll(map);
314     }
315 
316     /**
317      * Returns a Set containing the Strings used as keys in this Bundle.
318      *
319      * @return a Set of String keys
320      */
keySet()321     public Set<String> keySet() {
322         unparcel();
323         return mMap.keySet();
324     }
325 
326     /**
327      * Inserts a Boolean value into the mapping of this Bundle, replacing
328      * any existing value for the given key.  Either key or value may be null.
329      *
330      * @param key a String, or null
331      * @param value a boolean
332      */
putBoolean(@ullable String key, boolean value)333     public void putBoolean(@Nullable String key, boolean value) {
334         unparcel();
335         mMap.put(key, value);
336     }
337 
338     /**
339      * Inserts a byte value into the mapping of this Bundle, replacing
340      * any existing value for the given key.
341      *
342      * @param key a String, or null
343      * @param value a byte
344      */
putByte(@ullable String key, byte value)345     void putByte(@Nullable String key, byte value) {
346         unparcel();
347         mMap.put(key, value);
348     }
349 
350     /**
351      * Inserts a char value into the mapping of this Bundle, replacing
352      * any existing value for the given key.
353      *
354      * @param key a String, or null
355      * @param value a char
356      */
putChar(@ullable String key, char value)357     void putChar(@Nullable String key, char value) {
358         unparcel();
359         mMap.put(key, value);
360     }
361 
362     /**
363      * Inserts a short value into the mapping of this Bundle, replacing
364      * any existing value for the given key.
365      *
366      * @param key a String, or null
367      * @param value a short
368      */
putShort(@ullable String key, short value)369     void putShort(@Nullable String key, short value) {
370         unparcel();
371         mMap.put(key, value);
372     }
373 
374     /**
375      * Inserts an int value into the mapping of this Bundle, replacing
376      * any existing value for the given key.
377      *
378      * @param key a String, or null
379      * @param value an int
380      */
putInt(@ullable String key, int value)381     public void putInt(@Nullable String key, int value) {
382         unparcel();
383         mMap.put(key, value);
384     }
385 
386     /**
387      * Inserts a long value into the mapping of this Bundle, replacing
388      * any existing value for the given key.
389      *
390      * @param key a String, or null
391      * @param value a long
392      */
putLong(@ullable String key, long value)393     public void putLong(@Nullable String key, long value) {
394         unparcel();
395         mMap.put(key, value);
396     }
397 
398     /**
399      * Inserts a float value into the mapping of this Bundle, replacing
400      * any existing value for the given key.
401      *
402      * @param key a String, or null
403      * @param value a float
404      */
putFloat(@ullable String key, float value)405     void putFloat(@Nullable String key, float value) {
406         unparcel();
407         mMap.put(key, value);
408     }
409 
410     /**
411      * Inserts a double value into the mapping of this Bundle, replacing
412      * any existing value for the given key.
413      *
414      * @param key a String, or null
415      * @param value a double
416      */
putDouble(@ullable String key, double value)417     public void putDouble(@Nullable String key, double value) {
418         unparcel();
419         mMap.put(key, value);
420     }
421 
422     /**
423      * Inserts a String value into the mapping of this Bundle, replacing
424      * any existing value for the given key.  Either key or value may be null.
425      *
426      * @param key a String, or null
427      * @param value a String, or null
428      */
putString(@ullable String key, @Nullable String value)429     public void putString(@Nullable String key, @Nullable String value) {
430         unparcel();
431         mMap.put(key, value);
432     }
433 
434     /**
435      * Inserts a CharSequence value into the mapping of this Bundle, replacing
436      * any existing value for the given key.  Either key or value may be null.
437      *
438      * @param key a String, or null
439      * @param value a CharSequence, or null
440      */
putCharSequence(@ullable String key, @Nullable CharSequence value)441     void putCharSequence(@Nullable String key, @Nullable CharSequence value) {
442         unparcel();
443         mMap.put(key, value);
444     }
445 
446     /**
447      * Inserts an ArrayList<Integer> value into the mapping of this Bundle, replacing
448      * any existing value for the given key.  Either key or value may be null.
449      *
450      * @param key a String, or null
451      * @param value an ArrayList<Integer> object, or null
452      */
putIntegerArrayList(@ullable String key, @Nullable ArrayList<Integer> value)453     void putIntegerArrayList(@Nullable String key, @Nullable ArrayList<Integer> value) {
454         unparcel();
455         mMap.put(key, value);
456     }
457 
458     /**
459      * Inserts an ArrayList<String> value into the mapping of this Bundle, replacing
460      * any existing value for the given key.  Either key or value may be null.
461      *
462      * @param key a String, or null
463      * @param value an ArrayList<String> object, or null
464      */
putStringArrayList(@ullable String key, @Nullable ArrayList<String> value)465     void putStringArrayList(@Nullable String key, @Nullable ArrayList<String> value) {
466         unparcel();
467         mMap.put(key, value);
468     }
469 
470     /**
471      * Inserts an ArrayList<CharSequence> value into the mapping of this Bundle, replacing
472      * any existing value for the given key.  Either key or value may be null.
473      *
474      * @param key a String, or null
475      * @param value an ArrayList<CharSequence> object, or null
476      */
putCharSequenceArrayList(@ullable String key, @Nullable ArrayList<CharSequence> value)477     void putCharSequenceArrayList(@Nullable String key, @Nullable ArrayList<CharSequence> value) {
478         unparcel();
479         mMap.put(key, value);
480     }
481 
482     /**
483      * Inserts a Serializable value into the mapping of this Bundle, replacing
484      * any existing value for the given key.  Either key or value may be null.
485      *
486      * @param key a String, or null
487      * @param value a Serializable object, or null
488      */
putSerializable(@ullable String key, @Nullable Serializable value)489     void putSerializable(@Nullable String key, @Nullable Serializable value) {
490         unparcel();
491         mMap.put(key, value);
492     }
493 
494     /**
495      * Inserts a boolean array value into the mapping of this Bundle, replacing
496      * any existing value for the given key.  Either key or value may be null.
497      *
498      * @param key a String, or null
499      * @param value a boolean array object, or null
500      */
putBooleanArray(@ullable String key, @Nullable boolean[] value)501     public void putBooleanArray(@Nullable String key, @Nullable boolean[] value) {
502         unparcel();
503         mMap.put(key, value);
504     }
505 
506     /**
507      * Inserts a byte array value into the mapping of this Bundle, replacing
508      * any existing value for the given key.  Either key or value may be null.
509      *
510      * @param key a String, or null
511      * @param value a byte array object, or null
512      */
putByteArray(@ullable String key, @Nullable byte[] value)513     void putByteArray(@Nullable String key, @Nullable byte[] value) {
514         unparcel();
515         mMap.put(key, value);
516     }
517 
518     /**
519      * Inserts a short array value into the mapping of this Bundle, replacing
520      * any existing value for the given key.  Either key or value may be null.
521      *
522      * @param key a String, or null
523      * @param value a short array object, or null
524      */
putShortArray(@ullable String key, @Nullable short[] value)525     void putShortArray(@Nullable String key, @Nullable short[] value) {
526         unparcel();
527         mMap.put(key, value);
528     }
529 
530     /**
531      * Inserts a char array value into the mapping of this Bundle, replacing
532      * any existing value for the given key.  Either key or value may be null.
533      *
534      * @param key a String, or null
535      * @param value a char array object, or null
536      */
putCharArray(@ullable String key, @Nullable char[] value)537     void putCharArray(@Nullable String key, @Nullable char[] value) {
538         unparcel();
539         mMap.put(key, value);
540     }
541 
542     /**
543      * Inserts an int array value into the mapping of this Bundle, replacing
544      * any existing value for the given key.  Either key or value may be null.
545      *
546      * @param key a String, or null
547      * @param value an int array object, or null
548      */
putIntArray(@ullable String key, @Nullable int[] value)549     public void putIntArray(@Nullable String key, @Nullable int[] value) {
550         unparcel();
551         mMap.put(key, value);
552     }
553 
554     /**
555      * Inserts a long array value into the mapping of this Bundle, replacing
556      * any existing value for the given key.  Either key or value may be null.
557      *
558      * @param key a String, or null
559      * @param value a long array object, or null
560      */
putLongArray(@ullable String key, @Nullable long[] value)561     public void putLongArray(@Nullable String key, @Nullable long[] value) {
562         unparcel();
563         mMap.put(key, value);
564     }
565 
566     /**
567      * Inserts a float array value into the mapping of this Bundle, replacing
568      * any existing value for the given key.  Either key or value may be null.
569      *
570      * @param key a String, or null
571      * @param value a float array object, or null
572      */
putFloatArray(@ullable String key, @Nullable float[] value)573     void putFloatArray(@Nullable String key, @Nullable float[] value) {
574         unparcel();
575         mMap.put(key, value);
576     }
577 
578     /**
579      * Inserts a double array value into the mapping of this Bundle, replacing
580      * any existing value for the given key.  Either key or value may be null.
581      *
582      * @param key a String, or null
583      * @param value a double array object, or null
584      */
putDoubleArray(@ullable String key, @Nullable double[] value)585     public void putDoubleArray(@Nullable String key, @Nullable double[] value) {
586         unparcel();
587         mMap.put(key, value);
588     }
589 
590     /**
591      * Inserts a String array value into the mapping of this Bundle, replacing
592      * any existing value for the given key.  Either key or value may be null.
593      *
594      * @param key a String, or null
595      * @param value a String array object, or null
596      */
putStringArray(@ullable String key, @Nullable String[] value)597     public void putStringArray(@Nullable String key, @Nullable String[] value) {
598         unparcel();
599         mMap.put(key, value);
600     }
601 
602     /**
603      * Inserts a CharSequence array value into the mapping of this Bundle, replacing
604      * any existing value for the given key.  Either key or value may be null.
605      *
606      * @param key a String, or null
607      * @param value a CharSequence array object, or null
608      */
putCharSequenceArray(@ullable String key, @Nullable CharSequence[] value)609     void putCharSequenceArray(@Nullable String key, @Nullable CharSequence[] value) {
610         unparcel();
611         mMap.put(key, value);
612     }
613 
614     /**
615      * Returns the value associated with the given key, or false if
616      * no mapping of the desired type exists for the given key.
617      *
618      * @param key a String
619      * @return a boolean value
620      */
getBoolean(String key)621     public boolean getBoolean(String key) {
622         unparcel();
623         if (DEBUG) Log.d(TAG, "Getting boolean in "
624                 + Integer.toHexString(System.identityHashCode(this)));
625         return getBoolean(key, false);
626     }
627 
628     // 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)629     void typeWarning(String key, Object value, String className,
630             Object defaultValue, ClassCastException e) {
631         StringBuilder sb = new StringBuilder();
632         sb.append("Key ");
633         sb.append(key);
634         sb.append(" expected ");
635         sb.append(className);
636         sb.append(" but value was a ");
637         sb.append(value.getClass().getName());
638         sb.append(".  The default value ");
639         sb.append(defaultValue);
640         sb.append(" was returned.");
641         Log.w(TAG, sb.toString());
642         Log.w(TAG, "Attempt to cast generated internal exception:", e);
643     }
644 
typeWarning(String key, Object value, String className, ClassCastException e)645     void typeWarning(String key, Object value, String className,
646             ClassCastException e) {
647         typeWarning(key, value, className, "<null>", e);
648     }
649 
650     /**
651      * Returns the value associated with the given key, or defaultValue if
652      * no mapping of the desired type exists for the given key.
653      *
654      * @param key a String
655      * @param defaultValue Value to return if key does not exist
656      * @return a boolean value
657      */
getBoolean(String key, boolean defaultValue)658     public boolean getBoolean(String key, boolean defaultValue) {
659         unparcel();
660         Object o = mMap.get(key);
661         if (o == null) {
662             return defaultValue;
663         }
664         try {
665             return (Boolean) o;
666         } catch (ClassCastException e) {
667             typeWarning(key, o, "Boolean", defaultValue, e);
668             return defaultValue;
669         }
670     }
671 
672     /**
673      * Returns the value associated with the given key, or (byte) 0 if
674      * no mapping of the desired type exists for the given key.
675      *
676      * @param key a String
677      * @return a byte value
678      */
getByte(String key)679     byte getByte(String key) {
680         unparcel();
681         return getByte(key, (byte) 0);
682     }
683 
684     /**
685      * Returns the value associated with the given key, or defaultValue if
686      * no mapping of the desired type exists for the given key.
687      *
688      * @param key a String
689      * @param defaultValue Value to return if key does not exist
690      * @return a byte value
691      */
getByte(String key, byte defaultValue)692     Byte getByte(String key, byte defaultValue) {
693         unparcel();
694         Object o = mMap.get(key);
695         if (o == null) {
696             return defaultValue;
697         }
698         try {
699             return (Byte) o;
700         } catch (ClassCastException e) {
701             typeWarning(key, o, "Byte", defaultValue, e);
702             return defaultValue;
703         }
704     }
705 
706     /**
707      * Returns the value associated with the given key, or (char) 0 if
708      * no mapping of the desired type exists for the given key.
709      *
710      * @param key a String
711      * @return a char value
712      */
getChar(String key)713     char getChar(String key) {
714         unparcel();
715         return getChar(key, (char) 0);
716     }
717 
718     /**
719      * Returns the value associated with the given key, or defaultValue if
720      * no mapping of the desired type exists for the given key.
721      *
722      * @param key a String
723      * @param defaultValue Value to return if key does not exist
724      * @return a char value
725      */
getChar(String key, char defaultValue)726     char getChar(String key, char defaultValue) {
727         unparcel();
728         Object o = mMap.get(key);
729         if (o == null) {
730             return defaultValue;
731         }
732         try {
733             return (Character) o;
734         } catch (ClassCastException e) {
735             typeWarning(key, o, "Character", defaultValue, e);
736             return defaultValue;
737         }
738     }
739 
740     /**
741      * Returns the value associated with the given key, or (short) 0 if
742      * no mapping of the desired type exists for the given key.
743      *
744      * @param key a String
745      * @return a short value
746      */
getShort(String key)747     short getShort(String key) {
748         unparcel();
749         return getShort(key, (short) 0);
750     }
751 
752     /**
753      * Returns the value associated with the given key, or defaultValue if
754      * no mapping of the desired type exists for the given key.
755      *
756      * @param key a String
757      * @param defaultValue Value to return if key does not exist
758      * @return a short value
759      */
getShort(String key, short defaultValue)760     short getShort(String key, short defaultValue) {
761         unparcel();
762         Object o = mMap.get(key);
763         if (o == null) {
764             return defaultValue;
765         }
766         try {
767             return (Short) o;
768         } catch (ClassCastException e) {
769             typeWarning(key, o, "Short", defaultValue, e);
770             return defaultValue;
771         }
772     }
773 
774     /**
775      * Returns the value associated with the given key, or 0 if
776      * no mapping of the desired type exists for the given key.
777      *
778      * @param key a String
779      * @return an int value
780      */
getInt(String key)781     public int getInt(String key) {
782         unparcel();
783         return getInt(key, 0);
784     }
785 
786     /**
787      * Returns the value associated with the given key, or defaultValue if
788      * no mapping of the desired type exists for the given key.
789      *
790      * @param key a String
791      * @param defaultValue Value to return if key does not exist
792      * @return an int value
793      */
getInt(String key, int defaultValue)794    public int getInt(String key, int defaultValue) {
795         unparcel();
796         Object o = mMap.get(key);
797         if (o == null) {
798             return defaultValue;
799         }
800         try {
801             return (Integer) o;
802         } catch (ClassCastException e) {
803             typeWarning(key, o, "Integer", defaultValue, e);
804             return defaultValue;
805         }
806     }
807 
808     /**
809      * Returns the value associated with the given key, or 0L if
810      * no mapping of the desired type exists for the given key.
811      *
812      * @param key a String
813      * @return a long value
814      */
getLong(String key)815     public long getLong(String key) {
816         unparcel();
817         return getLong(key, 0L);
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 long value
827      */
getLong(String key, long defaultValue)828     public long getLong(String key, long defaultValue) {
829         unparcel();
830         Object o = mMap.get(key);
831         if (o == null) {
832             return defaultValue;
833         }
834         try {
835             return (Long) o;
836         } catch (ClassCastException e) {
837             typeWarning(key, o, "Long", defaultValue, e);
838             return defaultValue;
839         }
840     }
841 
842     /**
843      * Returns the value associated with the given key, or 0.0f if
844      * no mapping of the desired type exists for the given key.
845      *
846      * @param key a String
847      * @return a float value
848      */
getFloat(String key)849     float getFloat(String key) {
850         unparcel();
851         return getFloat(key, 0.0f);
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 float value
861      */
getFloat(String key, float defaultValue)862     float getFloat(String key, float defaultValue) {
863         unparcel();
864         Object o = mMap.get(key);
865         if (o == null) {
866             return defaultValue;
867         }
868         try {
869             return (Float) o;
870         } catch (ClassCastException e) {
871             typeWarning(key, o, "Float", defaultValue, e);
872             return defaultValue;
873         }
874     }
875 
876     /**
877      * Returns the value associated with the given key, or 0.0 if
878      * no mapping of the desired type exists for the given key.
879      *
880      * @param key a String
881      * @return a double value
882      */
getDouble(String key)883     public double getDouble(String key) {
884         unparcel();
885         return getDouble(key, 0.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 double value
895      */
getDouble(String key, double defaultValue)896     public double getDouble(String key, double defaultValue) {
897         unparcel();
898         Object o = mMap.get(key);
899         if (o == null) {
900             return defaultValue;
901         }
902         try {
903             return (Double) o;
904         } catch (ClassCastException e) {
905             typeWarning(key, o, "Double", defaultValue, e);
906             return defaultValue;
907         }
908     }
909 
910     /**
911      * Returns the value associated with the given key, or null if
912      * no mapping of the desired type exists for the given key or a null
913      * value is explicitly associated with the key.
914      *
915      * @param key a String, or null
916      * @return a String value, or null
917      */
918     @Nullable
getString(@ullable String key)919     public String getString(@Nullable String key) {
920         unparcel();
921         final Object o = mMap.get(key);
922         try {
923             return (String) o;
924         } catch (ClassCastException e) {
925             typeWarning(key, o, "String", e);
926             return null;
927         }
928     }
929 
930     /**
931      * Returns the value associated with the given key, or defaultValue if
932      * no mapping of the desired type exists for the given key or if a null
933      * value is explicitly associated with the given key.
934      *
935      * @param key a String, or null
936      * @param defaultValue Value to return if key does not exist or if a null
937      *     value is associated with the given key.
938      * @return the String value associated with the given key, or defaultValue
939      *     if no valid String object is currently mapped to that key.
940      */
getString(@ullable String key, String defaultValue)941     public String getString(@Nullable String key, String defaultValue) {
942         final String s = getString(key);
943         return (s == null) ? defaultValue : s;
944     }
945 
946     /**
947      * Returns the value associated with the given key, or null if
948      * no mapping of the desired type exists for the given key or a null
949      * value is explicitly associated with the key.
950      *
951      * @param key a String, or null
952      * @return a CharSequence value, or null
953      */
954     @Nullable
getCharSequence(@ullable String key)955     CharSequence getCharSequence(@Nullable String key) {
956         unparcel();
957         final Object o = mMap.get(key);
958         try {
959             return (CharSequence) o;
960         } catch (ClassCastException e) {
961             typeWarning(key, o, "CharSequence", e);
962             return null;
963         }
964     }
965 
966     /**
967      * Returns the value associated with the given key, or defaultValue if
968      * no mapping of the desired type exists for the given key or if a null
969      * value is explicitly associated with the given key.
970      *
971      * @param key a String, or null
972      * @param defaultValue Value to return if key does not exist or if a null
973      *     value is associated with the given key.
974      * @return the CharSequence value associated with the given key, or defaultValue
975      *     if no valid CharSequence object is currently mapped to that key.
976      */
getCharSequence(@ullable String key, CharSequence defaultValue)977     CharSequence getCharSequence(@Nullable String key, CharSequence defaultValue) {
978         final CharSequence cs = getCharSequence(key);
979         return (cs == null) ? defaultValue : cs;
980     }
981 
982     /**
983      * Returns the value associated with the given key, or null if
984      * no mapping of the desired type exists for the given key or a null
985      * value is explicitly associated with the key.
986      *
987      * @param key a String, or null
988      * @return a Serializable value, or null
989      */
990     @Nullable
getSerializable(@ullable String key)991     Serializable getSerializable(@Nullable String key) {
992         unparcel();
993         Object o = mMap.get(key);
994         if (o == null) {
995             return null;
996         }
997         try {
998             return (Serializable) o;
999         } catch (ClassCastException e) {
1000             typeWarning(key, o, "Serializable", e);
1001             return null;
1002         }
1003     }
1004 
1005     /**
1006      * Returns the value associated with the given key, or null if
1007      * no mapping of the desired type exists for the given key or a null
1008      * value is explicitly associated with the key.
1009      *
1010      * @param key a String, or null
1011      * @return an ArrayList<String> value, or null
1012      */
1013     @Nullable
getIntegerArrayList(@ullable String key)1014     ArrayList<Integer> getIntegerArrayList(@Nullable String key) {
1015         unparcel();
1016         Object o = mMap.get(key);
1017         if (o == null) {
1018             return null;
1019         }
1020         try {
1021             return (ArrayList<Integer>) o;
1022         } catch (ClassCastException e) {
1023             typeWarning(key, o, "ArrayList<Integer>", e);
1024             return null;
1025         }
1026     }
1027 
1028     /**
1029      * Returns the value associated with the given key, or null if
1030      * no mapping of the desired type exists for the given key or a null
1031      * value is explicitly associated with the key.
1032      *
1033      * @param key a String, or null
1034      * @return an ArrayList<String> value, or null
1035      */
1036     @Nullable
getStringArrayList(@ullable String key)1037     ArrayList<String> getStringArrayList(@Nullable String key) {
1038         unparcel();
1039         Object o = mMap.get(key);
1040         if (o == null) {
1041             return null;
1042         }
1043         try {
1044             return (ArrayList<String>) o;
1045         } catch (ClassCastException e) {
1046             typeWarning(key, o, "ArrayList<String>", e);
1047             return null;
1048         }
1049     }
1050 
1051     /**
1052      * Returns the value associated with the given key, or null if
1053      * no mapping of the desired type exists for the given key or a null
1054      * value is explicitly associated with the key.
1055      *
1056      * @param key a String, or null
1057      * @return an ArrayList<CharSequence> value, or null
1058      */
1059     @Nullable
getCharSequenceArrayList(@ullable String key)1060     ArrayList<CharSequence> getCharSequenceArrayList(@Nullable String key) {
1061         unparcel();
1062         Object o = mMap.get(key);
1063         if (o == null) {
1064             return null;
1065         }
1066         try {
1067             return (ArrayList<CharSequence>) o;
1068         } catch (ClassCastException e) {
1069             typeWarning(key, o, "ArrayList<CharSequence>", e);
1070             return null;
1071         }
1072     }
1073 
1074     /**
1075      * Returns the value associated with the given key, or null if
1076      * no mapping of the desired type exists for the given key or a null
1077      * value is explicitly associated with the key.
1078      *
1079      * @param key a String, or null
1080      * @return a boolean[] value, or null
1081      */
1082     @Nullable
getBooleanArray(@ullable String key)1083     public boolean[] getBooleanArray(@Nullable String key) {
1084         unparcel();
1085         Object o = mMap.get(key);
1086         if (o == null) {
1087             return null;
1088         }
1089         try {
1090             return (boolean[]) o;
1091         } catch (ClassCastException e) {
1092             typeWarning(key, o, "byte[]", e);
1093             return null;
1094         }
1095     }
1096 
1097     /**
1098      * Returns the value associated with the given key, or null if
1099      * no mapping of the desired type exists for the given key or a null
1100      * value is explicitly associated with the key.
1101      *
1102      * @param key a String, or null
1103      * @return a byte[] value, or null
1104      */
1105     @Nullable
getByteArray(@ullable String key)1106     byte[] getByteArray(@Nullable String key) {
1107         unparcel();
1108         Object o = mMap.get(key);
1109         if (o == null) {
1110             return null;
1111         }
1112         try {
1113             return (byte[]) o;
1114         } catch (ClassCastException e) {
1115             typeWarning(key, o, "byte[]", e);
1116             return null;
1117         }
1118     }
1119 
1120     /**
1121      * Returns the value associated with the given key, or null if
1122      * no mapping of the desired type exists for the given key or a null
1123      * value is explicitly associated with the key.
1124      *
1125      * @param key a String, or null
1126      * @return a short[] value, or null
1127      */
1128     @Nullable
getShortArray(@ullable String key)1129     short[] getShortArray(@Nullable String key) {
1130         unparcel();
1131         Object o = mMap.get(key);
1132         if (o == null) {
1133             return null;
1134         }
1135         try {
1136             return (short[]) o;
1137         } catch (ClassCastException e) {
1138             typeWarning(key, o, "short[]", e);
1139             return null;
1140         }
1141     }
1142 
1143     /**
1144      * Returns the value associated with the given key, or null if
1145      * no mapping of the desired type exists for the given key or a null
1146      * value is explicitly associated with the key.
1147      *
1148      * @param key a String, or null
1149      * @return a char[] value, or null
1150      */
1151     @Nullable
getCharArray(@ullable String key)1152     char[] getCharArray(@Nullable String key) {
1153         unparcel();
1154         Object o = mMap.get(key);
1155         if (o == null) {
1156             return null;
1157         }
1158         try {
1159             return (char[]) o;
1160         } catch (ClassCastException e) {
1161             typeWarning(key, o, "char[]", e);
1162             return null;
1163         }
1164     }
1165 
1166     /**
1167      * Returns the value associated with the given key, or null if
1168      * no mapping of the desired type exists for the given key or a null
1169      * value is explicitly associated with the key.
1170      *
1171      * @param key a String, or null
1172      * @return an int[] value, or null
1173      */
1174     @Nullable
getIntArray(@ullable String key)1175     public int[] getIntArray(@Nullable String key) {
1176         unparcel();
1177         Object o = mMap.get(key);
1178         if (o == null) {
1179             return null;
1180         }
1181         try {
1182             return (int[]) o;
1183         } catch (ClassCastException e) {
1184             typeWarning(key, o, "int[]", e);
1185             return null;
1186         }
1187     }
1188 
1189     /**
1190      * Returns the value associated with the given key, or null if
1191      * no mapping of the desired type exists for the given key or a null
1192      * value is explicitly associated with the key.
1193      *
1194      * @param key a String, or null
1195      * @return a long[] value, or null
1196      */
1197     @Nullable
getLongArray(@ullable String key)1198     public long[] getLongArray(@Nullable String key) {
1199         unparcel();
1200         Object o = mMap.get(key);
1201         if (o == null) {
1202             return null;
1203         }
1204         try {
1205             return (long[]) o;
1206         } catch (ClassCastException e) {
1207             typeWarning(key, o, "long[]", 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 a float[] value, or null
1219      */
1220     @Nullable
getFloatArray(@ullable String key)1221     float[] getFloatArray(@Nullable String key) {
1222         unparcel();
1223         Object o = mMap.get(key);
1224         if (o == null) {
1225             return null;
1226         }
1227         try {
1228             return (float[]) o;
1229         } catch (ClassCastException e) {
1230             typeWarning(key, o, "float[]", e);
1231             return null;
1232         }
1233     }
1234 
1235     /**
1236      * Returns the value associated with the given key, or null if
1237      * no mapping of the desired type exists for the given key or a null
1238      * value is explicitly associated with the key.
1239      *
1240      * @param key a String, or null
1241      * @return a double[] value, or null
1242      */
1243     @Nullable
getDoubleArray(@ullable String key)1244     public double[] getDoubleArray(@Nullable String key) {
1245         unparcel();
1246         Object o = mMap.get(key);
1247         if (o == null) {
1248             return null;
1249         }
1250         try {
1251             return (double[]) o;
1252         } catch (ClassCastException e) {
1253             typeWarning(key, o, "double[]", e);
1254             return null;
1255         }
1256     }
1257 
1258     /**
1259      * Returns the value associated with the given key, or null if
1260      * no mapping of the desired type exists for the given key or a null
1261      * value is explicitly associated with the key.
1262      *
1263      * @param key a String, or null
1264      * @return a String[] value, or null
1265      */
1266     @Nullable
getStringArray(@ullable String key)1267     public String[] getStringArray(@Nullable String key) {
1268         unparcel();
1269         Object o = mMap.get(key);
1270         if (o == null) {
1271             return null;
1272         }
1273         try {
1274             return (String[]) o;
1275         } catch (ClassCastException e) {
1276             typeWarning(key, o, "String[]", e);
1277             return null;
1278         }
1279     }
1280 
1281     /**
1282      * Returns the value associated with the given key, or null if
1283      * no mapping of the desired type exists for the given key or a null
1284      * value is explicitly associated with the key.
1285      *
1286      * @param key a String, or null
1287      * @return a CharSequence[] value, or null
1288      */
1289     @Nullable
getCharSequenceArray(@ullable String key)1290     CharSequence[] getCharSequenceArray(@Nullable String key) {
1291         unparcel();
1292         Object o = mMap.get(key);
1293         if (o == null) {
1294             return null;
1295         }
1296         try {
1297             return (CharSequence[]) o;
1298         } catch (ClassCastException e) {
1299             typeWarning(key, o, "CharSequence[]", e);
1300             return null;
1301         }
1302     }
1303 
1304     /**
1305      * Writes the Bundle contents to a Parcel, typically in order for
1306      * it to be passed through an IBinder connection.
1307      * @param parcel The parcel to copy this bundle to.
1308      */
writeToParcelInner(Parcel parcel, int flags)1309     void writeToParcelInner(Parcel parcel, int flags) {
1310         if (mParcelledData != null) {
1311             if (mParcelledData == EMPTY_PARCEL) {
1312                 parcel.writeInt(0);
1313             } else {
1314                 int length = mParcelledData.dataSize();
1315                 parcel.writeInt(length);
1316                 parcel.writeInt(BUNDLE_MAGIC);
1317                 parcel.appendFrom(mParcelledData, 0, length);
1318             }
1319         } else {
1320             // Special case for empty bundles.
1321             if (mMap == null || mMap.size() <= 0) {
1322                 parcel.writeInt(0);
1323                 return;
1324             }
1325             int lengthPos = parcel.dataPosition();
1326             parcel.writeInt(-1); // dummy, will hold length
1327             parcel.writeInt(BUNDLE_MAGIC);
1328 
1329             int startPos = parcel.dataPosition();
1330             parcel.writeArrayMapInternal(mMap);
1331             int endPos = parcel.dataPosition();
1332 
1333             // Backpatch length
1334             parcel.setDataPosition(lengthPos);
1335             int length = endPos - startPos;
1336             parcel.writeInt(length);
1337             parcel.setDataPosition(endPos);
1338         }
1339     }
1340 
1341     /**
1342      * Reads the Parcel contents into this Bundle, typically in order for
1343      * it to be passed through an IBinder connection.
1344      * @param parcel The parcel to overwrite this bundle from.
1345      */
readFromParcelInner(Parcel parcel)1346     void readFromParcelInner(Parcel parcel) {
1347         int length = parcel.readInt();
1348         if (length < 0) {
1349             throw new RuntimeException("Bad length in parcel: " + length);
1350         }
1351         readFromParcelInner(parcel, length);
1352     }
1353 
readFromParcelInner(Parcel parcel, int length)1354     private void readFromParcelInner(Parcel parcel, int length) {
1355         if (length == 0) {
1356             // Empty Bundle or end of data.
1357             mParcelledData = EMPTY_PARCEL;
1358             return;
1359         }
1360         int magic = parcel.readInt();
1361         if (magic != BUNDLE_MAGIC) {
1362             //noinspection ThrowableInstanceNeverThrown
1363             throw new IllegalStateException("Bad magic number for Bundle: 0x"
1364                     + Integer.toHexString(magic));
1365         }
1366 
1367         // Advance within this Parcel
1368         int offset = parcel.dataPosition();
1369         parcel.setDataPosition(offset + length);
1370 
1371         Parcel p = Parcel.obtain();
1372         p.setDataPosition(0);
1373         p.appendFrom(parcel, offset, length);
1374         if (DEBUG) Log.d(TAG, "Retrieving "  + Integer.toHexString(System.identityHashCode(this))
1375                 + ": " + length + " bundle bytes starting at " + offset);
1376         p.setDataPosition(0);
1377 
1378         mParcelledData = p;
1379     }
1380 }
1381