• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.util.ArrayMap;
20 import android.util.Log;
21 
22 import java.io.Serializable;
23 import java.util.ArrayList;
24 import java.util.Map;
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(ClassLoader loader, int capacity)66     BaseBundle(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      */
get(String key)279     public Object get(String key) {
280         unparcel();
281         return mMap.get(key);
282     }
283 
284     /**
285      * Removes any entry with the given key from the mapping of this Bundle.
286      *
287      * @param key a String key
288      */
remove(String key)289     public void remove(String key) {
290         unparcel();
291         mMap.remove(key);
292     }
293 
294     /**
295      * Inserts all mappings from the given PersistableBundle into this BaseBundle.
296      *
297      * @param bundle a PersistableBundle
298      */
putAll(PersistableBundle bundle)299     public void putAll(PersistableBundle bundle) {
300         unparcel();
301         bundle.unparcel();
302         mMap.putAll(bundle.mMap);
303     }
304 
305     /**
306      * Inserts all mappings from the given Map into this BaseBundle.
307      *
308      * @param map a Map
309      */
putAll(Map map)310     void putAll(Map map) {
311         unparcel();
312         mMap.putAll(map);
313     }
314 
315     /**
316      * Returns a Set containing the Strings used as keys in this Bundle.
317      *
318      * @return a Set of String keys
319      */
keySet()320     public Set<String> keySet() {
321         unparcel();
322         return mMap.keySet();
323     }
324 
325     /**
326      * Inserts a Boolean value into the mapping of this Bundle, replacing
327      * any existing value for the given key.  Either key or value may be null.
328      *
329      * @param key a String, or null
330      * @param value a Boolean, or null
331      */
putBoolean(String key, boolean value)332     void putBoolean(String key, boolean value) {
333         unparcel();
334         mMap.put(key, value);
335     }
336 
337     /**
338      * Inserts a byte value into the mapping of this Bundle, replacing
339      * any existing value for the given key.
340      *
341      * @param key a String, or null
342      * @param value a byte
343      */
putByte(String key, byte value)344     void putByte(String key, byte value) {
345         unparcel();
346         mMap.put(key, value);
347     }
348 
349     /**
350      * Inserts a char value into the mapping of this Bundle, replacing
351      * any existing value for the given key.
352      *
353      * @param key a String, or null
354      * @param value a char, or null
355      */
putChar(String key, char value)356     void putChar(String key, char value) {
357         unparcel();
358         mMap.put(key, value);
359     }
360 
361     /**
362      * Inserts a short value into the mapping of this Bundle, replacing
363      * any existing value for the given key.
364      *
365      * @param key a String, or null
366      * @param value a short
367      */
putShort(String key, short value)368     void putShort(String key, short value) {
369         unparcel();
370         mMap.put(key, value);
371     }
372 
373     /**
374      * Inserts an int value into the mapping of this Bundle, replacing
375      * any existing value for the given key.
376      *
377      * @param key a String, or null
378      * @param value an int, or null
379      */
putInt(String key, int value)380     public void putInt(String key, int value) {
381         unparcel();
382         mMap.put(key, value);
383     }
384 
385     /**
386      * Inserts a long value into the mapping of this Bundle, replacing
387      * any existing value for the given key.
388      *
389      * @param key a String, or null
390      * @param value a long
391      */
putLong(String key, long value)392     public void putLong(String key, long value) {
393         unparcel();
394         mMap.put(key, value);
395     }
396 
397     /**
398      * Inserts a float value into the mapping of this Bundle, replacing
399      * any existing value for the given key.
400      *
401      * @param key a String, or null
402      * @param value a float
403      */
putFloat(String key, float value)404     void putFloat(String key, float value) {
405         unparcel();
406         mMap.put(key, value);
407     }
408 
409     /**
410      * Inserts a double value into the mapping of this Bundle, replacing
411      * any existing value for the given key.
412      *
413      * @param key a String, or null
414      * @param value a double
415      */
putDouble(String key, double value)416     public void putDouble(String key, double value) {
417         unparcel();
418         mMap.put(key, value);
419     }
420 
421     /**
422      * Inserts a String value into the mapping of this Bundle, replacing
423      * any existing value for the given key.  Either key or value may be null.
424      *
425      * @param key a String, or null
426      * @param value a String, or null
427      */
putString(String key, String value)428     public void putString(String key, String value) {
429         unparcel();
430         mMap.put(key, value);
431     }
432 
433     /**
434      * Inserts a CharSequence value into the mapping of this Bundle, replacing
435      * any existing value for the given key.  Either key or value may be null.
436      *
437      * @param key a String, or null
438      * @param value a CharSequence, or null
439      */
putCharSequence(String key, CharSequence value)440     void putCharSequence(String key, CharSequence value) {
441         unparcel();
442         mMap.put(key, value);
443     }
444 
445     /**
446      * Inserts an ArrayList<Integer> value into the mapping of this Bundle, replacing
447      * any existing value for the given key.  Either key or value may be null.
448      *
449      * @param key a String, or null
450      * @param value an ArrayList<Integer> object, or null
451      */
putIntegerArrayList(String key, ArrayList<Integer> value)452     void putIntegerArrayList(String key, ArrayList<Integer> value) {
453         unparcel();
454         mMap.put(key, value);
455     }
456 
457     /**
458      * Inserts an ArrayList<String> value into the mapping of this Bundle, replacing
459      * any existing value for the given key.  Either key or value may be null.
460      *
461      * @param key a String, or null
462      * @param value an ArrayList<String> object, or null
463      */
putStringArrayList(String key, ArrayList<String> value)464     void putStringArrayList(String key, ArrayList<String> value) {
465         unparcel();
466         mMap.put(key, value);
467     }
468 
469     /**
470      * Inserts an ArrayList<CharSequence> value into the mapping of this Bundle, replacing
471      * any existing value for the given key.  Either key or value may be null.
472      *
473      * @param key a String, or null
474      * @param value an ArrayList<CharSequence> object, or null
475      */
putCharSequenceArrayList(String key, ArrayList<CharSequence> value)476     void putCharSequenceArrayList(String key, ArrayList<CharSequence> value) {
477         unparcel();
478         mMap.put(key, value);
479     }
480 
481     /**
482      * Inserts a Serializable value into the mapping of this Bundle, replacing
483      * any existing value for the given key.  Either key or value may be null.
484      *
485      * @param key a String, or null
486      * @param value a Serializable object, or null
487      */
putSerializable(String key, Serializable value)488     void putSerializable(String key, Serializable value) {
489         unparcel();
490         mMap.put(key, value);
491     }
492 
493     /**
494      * Inserts a boolean array value into the mapping of this Bundle, replacing
495      * any existing value for the given key.  Either key or value may be null.
496      *
497      * @param key a String, or null
498      * @param value a boolean array object, or null
499      */
putBooleanArray(String key, boolean[] value)500     void putBooleanArray(String key, boolean[] value) {
501         unparcel();
502         mMap.put(key, value);
503     }
504 
505     /**
506      * Inserts a byte array value into the mapping of this Bundle, replacing
507      * any existing value for the given key.  Either key or value may be null.
508      *
509      * @param key a String, or null
510      * @param value a byte array object, or null
511      */
putByteArray(String key, byte[] value)512     void putByteArray(String key, byte[] value) {
513         unparcel();
514         mMap.put(key, value);
515     }
516 
517     /**
518      * Inserts a short array value into the mapping of this Bundle, replacing
519      * any existing value for the given key.  Either key or value may be null.
520      *
521      * @param key a String, or null
522      * @param value a short array object, or null
523      */
putShortArray(String key, short[] value)524     void putShortArray(String key, short[] value) {
525         unparcel();
526         mMap.put(key, value);
527     }
528 
529     /**
530      * Inserts a char array value into the mapping of this Bundle, replacing
531      * any existing value for the given key.  Either key or value may be null.
532      *
533      * @param key a String, or null
534      * @param value a char array object, or null
535      */
putCharArray(String key, char[] value)536     void putCharArray(String key, char[] value) {
537         unparcel();
538         mMap.put(key, value);
539     }
540 
541     /**
542      * Inserts an int array value into the mapping of this Bundle, replacing
543      * any existing value for the given key.  Either key or value may be null.
544      *
545      * @param key a String, or null
546      * @param value an int array object, or null
547      */
putIntArray(String key, int[] value)548     public void putIntArray(String key, int[] value) {
549         unparcel();
550         mMap.put(key, value);
551     }
552 
553     /**
554      * Inserts a long array value into the mapping of this Bundle, replacing
555      * any existing value for the given key.  Either key or value may be null.
556      *
557      * @param key a String, or null
558      * @param value a long array object, or null
559      */
putLongArray(String key, long[] value)560     public void putLongArray(String key, long[] value) {
561         unparcel();
562         mMap.put(key, value);
563     }
564 
565     /**
566      * Inserts a float array value into the mapping of this Bundle, replacing
567      * any existing value for the given key.  Either key or value may be null.
568      *
569      * @param key a String, or null
570      * @param value a float array object, or null
571      */
putFloatArray(String key, float[] value)572     void putFloatArray(String key, float[] value) {
573         unparcel();
574         mMap.put(key, value);
575     }
576 
577     /**
578      * Inserts a double array value into the mapping of this Bundle, replacing
579      * any existing value for the given key.  Either key or value may be null.
580      *
581      * @param key a String, or null
582      * @param value a double array object, or null
583      */
putDoubleArray(String key, double[] value)584     public void putDoubleArray(String key, double[] value) {
585         unparcel();
586         mMap.put(key, value);
587     }
588 
589     /**
590      * Inserts a String array value into the mapping of this Bundle, replacing
591      * any existing value for the given key.  Either key or value may be null.
592      *
593      * @param key a String, or null
594      * @param value a String array object, or null
595      */
putStringArray(String key, String[] value)596     public void putStringArray(String key, String[] value) {
597         unparcel();
598         mMap.put(key, value);
599     }
600 
601     /**
602      * Inserts a CharSequence array value into the mapping of this Bundle, replacing
603      * any existing value for the given key.  Either key or value may be null.
604      *
605      * @param key a String, or null
606      * @param value a CharSequence array object, or null
607      */
putCharSequenceArray(String key, CharSequence[] value)608     void putCharSequenceArray(String key, CharSequence[] value) {
609         unparcel();
610         mMap.put(key, value);
611     }
612 
613     /**
614      * Returns the value associated with the given key, or false if
615      * no mapping of the desired type exists for the given key.
616      *
617      * @param key a String
618      * @return a boolean value
619      */
getBoolean(String key)620     boolean getBoolean(String key) {
621         unparcel();
622         if (DEBUG) Log.d(TAG, "Getting boolean in "
623                 + Integer.toHexString(System.identityHashCode(this)));
624         return getBoolean(key, false);
625     }
626 
627     // 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)628     void typeWarning(String key, Object value, String className,
629             Object defaultValue, ClassCastException e) {
630         StringBuilder sb = new StringBuilder();
631         sb.append("Key ");
632         sb.append(key);
633         sb.append(" expected ");
634         sb.append(className);
635         sb.append(" but value was a ");
636         sb.append(value.getClass().getName());
637         sb.append(".  The default value ");
638         sb.append(defaultValue);
639         sb.append(" was returned.");
640         Log.w(TAG, sb.toString());
641         Log.w(TAG, "Attempt to cast generated internal exception:", e);
642     }
643 
typeWarning(String key, Object value, String className, ClassCastException e)644     void typeWarning(String key, Object value, String className,
645             ClassCastException e) {
646         typeWarning(key, value, className, "<null>", e);
647     }
648 
649     /**
650      * Returns the value associated with the given key, or defaultValue if
651      * no mapping of the desired type exists for the given key.
652      *
653      * @param key a String
654      * @param defaultValue Value to return if key does not exist
655      * @return a boolean value
656      */
getBoolean(String key, boolean defaultValue)657     boolean getBoolean(String key, boolean defaultValue) {
658         unparcel();
659         Object o = mMap.get(key);
660         if (o == null) {
661             return defaultValue;
662         }
663         try {
664             return (Boolean) o;
665         } catch (ClassCastException e) {
666             typeWarning(key, o, "Boolean", defaultValue, e);
667             return defaultValue;
668         }
669     }
670 
671     /**
672      * Returns the value associated with the given key, or (byte) 0 if
673      * no mapping of the desired type exists for the given key.
674      *
675      * @param key a String
676      * @return a byte value
677      */
getByte(String key)678     byte getByte(String key) {
679         unparcel();
680         return getByte(key, (byte) 0);
681     }
682 
683     /**
684      * Returns the value associated with the given key, or defaultValue if
685      * no mapping of the desired type exists for the given key.
686      *
687      * @param key a String
688      * @param defaultValue Value to return if key does not exist
689      * @return a byte value
690      */
getByte(String key, byte defaultValue)691     Byte getByte(String key, byte defaultValue) {
692         unparcel();
693         Object o = mMap.get(key);
694         if (o == null) {
695             return defaultValue;
696         }
697         try {
698             return (Byte) o;
699         } catch (ClassCastException e) {
700             typeWarning(key, o, "Byte", defaultValue, e);
701             return defaultValue;
702         }
703     }
704 
705     /**
706      * Returns the value associated with the given key, or (char) 0 if
707      * no mapping of the desired type exists for the given key.
708      *
709      * @param key a String
710      * @return a char value
711      */
getChar(String key)712     char getChar(String key) {
713         unparcel();
714         return getChar(key, (char) 0);
715     }
716 
717     /**
718      * Returns the value associated with the given key, or defaultValue if
719      * no mapping of the desired type exists for the given key.
720      *
721      * @param key a String
722      * @param defaultValue Value to return if key does not exist
723      * @return a char value
724      */
getChar(String key, char defaultValue)725     char getChar(String key, char defaultValue) {
726         unparcel();
727         Object o = mMap.get(key);
728         if (o == null) {
729             return defaultValue;
730         }
731         try {
732             return (Character) o;
733         } catch (ClassCastException e) {
734             typeWarning(key, o, "Character", defaultValue, e);
735             return defaultValue;
736         }
737     }
738 
739     /**
740      * Returns the value associated with the given key, or (short) 0 if
741      * no mapping of the desired type exists for the given key.
742      *
743      * @param key a String
744      * @return a short value
745      */
getShort(String key)746     short getShort(String key) {
747         unparcel();
748         return getShort(key, (short) 0);
749     }
750 
751     /**
752      * Returns the value associated with the given key, or defaultValue if
753      * no mapping of the desired type exists for the given key.
754      *
755      * @param key a String
756      * @param defaultValue Value to return if key does not exist
757      * @return a short value
758      */
getShort(String key, short defaultValue)759     short getShort(String key, short defaultValue) {
760         unparcel();
761         Object o = mMap.get(key);
762         if (o == null) {
763             return defaultValue;
764         }
765         try {
766             return (Short) o;
767         } catch (ClassCastException e) {
768             typeWarning(key, o, "Short", defaultValue, e);
769             return defaultValue;
770         }
771     }
772 
773     /**
774      * Returns the value associated with the given key, or 0 if
775      * no mapping of the desired type exists for the given key.
776      *
777      * @param key a String
778      * @return an int value
779      */
getInt(String key)780     public int getInt(String key) {
781         unparcel();
782         return getInt(key, 0);
783     }
784 
785     /**
786      * Returns the value associated with the given key, or defaultValue if
787      * no mapping of the desired type exists for the given key.
788      *
789      * @param key a String
790      * @param defaultValue Value to return if key does not exist
791      * @return an int value
792      */
getInt(String key, int defaultValue)793    public int getInt(String key, int defaultValue) {
794         unparcel();
795         Object o = mMap.get(key);
796         if (o == null) {
797             return defaultValue;
798         }
799         try {
800             return (Integer) o;
801         } catch (ClassCastException e) {
802             typeWarning(key, o, "Integer", defaultValue, e);
803             return defaultValue;
804         }
805     }
806 
807     /**
808      * Returns the value associated with the given key, or 0L if
809      * no mapping of the desired type exists for the given key.
810      *
811      * @param key a String
812      * @return a long value
813      */
getLong(String key)814     public long getLong(String key) {
815         unparcel();
816         return getLong(key, 0L);
817     }
818 
819     /**
820      * Returns the value associated with the given key, or defaultValue if
821      * no mapping of the desired type exists for the given key.
822      *
823      * @param key a String
824      * @param defaultValue Value to return if key does not exist
825      * @return a long value
826      */
getLong(String key, long defaultValue)827     public long getLong(String key, long defaultValue) {
828         unparcel();
829         Object o = mMap.get(key);
830         if (o == null) {
831             return defaultValue;
832         }
833         try {
834             return (Long) o;
835         } catch (ClassCastException e) {
836             typeWarning(key, o, "Long", defaultValue, e);
837             return defaultValue;
838         }
839     }
840 
841     /**
842      * Returns the value associated with the given key, or 0.0f if
843      * no mapping of the desired type exists for the given key.
844      *
845      * @param key a String
846      * @return a float value
847      */
getFloat(String key)848     float getFloat(String key) {
849         unparcel();
850         return getFloat(key, 0.0f);
851     }
852 
853     /**
854      * Returns the value associated with the given key, or defaultValue if
855      * no mapping of the desired type exists for the given key.
856      *
857      * @param key a String
858      * @param defaultValue Value to return if key does not exist
859      * @return a float value
860      */
getFloat(String key, float defaultValue)861     float getFloat(String key, float defaultValue) {
862         unparcel();
863         Object o = mMap.get(key);
864         if (o == null) {
865             return defaultValue;
866         }
867         try {
868             return (Float) o;
869         } catch (ClassCastException e) {
870             typeWarning(key, o, "Float", defaultValue, e);
871             return defaultValue;
872         }
873     }
874 
875     /**
876      * Returns the value associated with the given key, or 0.0 if
877      * no mapping of the desired type exists for the given key.
878      *
879      * @param key a String
880      * @return a double value
881      */
getDouble(String key)882     public double getDouble(String key) {
883         unparcel();
884         return getDouble(key, 0.0);
885     }
886 
887     /**
888      * Returns the value associated with the given key, or defaultValue if
889      * no mapping of the desired type exists for the given key.
890      *
891      * @param key a String
892      * @param defaultValue Value to return if key does not exist
893      * @return a double value
894      */
getDouble(String key, double defaultValue)895     public double getDouble(String key, double defaultValue) {
896         unparcel();
897         Object o = mMap.get(key);
898         if (o == null) {
899             return defaultValue;
900         }
901         try {
902             return (Double) o;
903         } catch (ClassCastException e) {
904             typeWarning(key, o, "Double", defaultValue, e);
905             return defaultValue;
906         }
907     }
908 
909     /**
910      * Returns the value associated with the given key, or null if
911      * no mapping of the desired type exists for the given key or a null
912      * value is explicitly associated with the key.
913      *
914      * @param key a String, or null
915      * @return a String value, or null
916      */
getString(String key)917     public String getString(String key) {
918         unparcel();
919         final Object o = mMap.get(key);
920         try {
921             return (String) o;
922         } catch (ClassCastException e) {
923             typeWarning(key, o, "String", e);
924             return null;
925         }
926     }
927 
928     /**
929      * Returns the value associated with the given key, or defaultValue if
930      * no mapping of the desired type exists for the given key or if a null
931      * value is explicitly associated with the given key.
932      *
933      * @param key a String, or null
934      * @param defaultValue Value to return if key does not exist or if a null
935      *     value is associated with the given key.
936      * @return the String value associated with the given key, or defaultValue
937      *     if no valid String object is currently mapped to that key.
938      */
getString(String key, String defaultValue)939     public String getString(String key, String defaultValue) {
940         final String s = getString(key);
941         return (s == null) ? defaultValue : s;
942     }
943 
944     /**
945      * Returns the value associated with the given key, or null if
946      * no mapping of the desired type exists for the given key or a null
947      * value is explicitly associated with the key.
948      *
949      * @param key a String, or null
950      * @return a CharSequence value, or null
951      */
getCharSequence(String key)952     CharSequence getCharSequence(String key) {
953         unparcel();
954         final Object o = mMap.get(key);
955         try {
956             return (CharSequence) o;
957         } catch (ClassCastException e) {
958             typeWarning(key, o, "CharSequence", e);
959             return null;
960         }
961     }
962 
963     /**
964      * Returns the value associated with the given key, or defaultValue if
965      * no mapping of the desired type exists for the given key or if a null
966      * value is explicitly associated with the given key.
967      *
968      * @param key a String, or null
969      * @param defaultValue Value to return if key does not exist or if a null
970      *     value is associated with the given key.
971      * @return the CharSequence value associated with the given key, or defaultValue
972      *     if no valid CharSequence object is currently mapped to that key.
973      */
getCharSequence(String key, CharSequence defaultValue)974     CharSequence getCharSequence(String key, CharSequence defaultValue) {
975         final CharSequence cs = getCharSequence(key);
976         return (cs == null) ? defaultValue : cs;
977     }
978 
979     /**
980      * Returns the value associated with the given key, or null if
981      * no mapping of the desired type exists for the given key or a null
982      * value is explicitly associated with the key.
983      *
984      * @param key a String, or null
985      * @return a Serializable value, or null
986      */
getSerializable(String key)987     Serializable getSerializable(String key) {
988         unparcel();
989         Object o = mMap.get(key);
990         if (o == null) {
991             return null;
992         }
993         try {
994             return (Serializable) o;
995         } catch (ClassCastException e) {
996             typeWarning(key, o, "Serializable", e);
997             return null;
998         }
999     }
1000 
1001     /**
1002      * Returns the value associated with the given key, or null if
1003      * no mapping of the desired type exists for the given key or a null
1004      * value is explicitly associated with the key.
1005      *
1006      * @param key a String, or null
1007      * @return an ArrayList<String> value, or null
1008      */
getIntegerArrayList(String key)1009     ArrayList<Integer> getIntegerArrayList(String key) {
1010         unparcel();
1011         Object o = mMap.get(key);
1012         if (o == null) {
1013             return null;
1014         }
1015         try {
1016             return (ArrayList<Integer>) o;
1017         } catch (ClassCastException e) {
1018             typeWarning(key, o, "ArrayList<Integer>", e);
1019             return null;
1020         }
1021     }
1022 
1023     /**
1024      * Returns the value associated with the given key, or null if
1025      * no mapping of the desired type exists for the given key or a null
1026      * value is explicitly associated with the key.
1027      *
1028      * @param key a String, or null
1029      * @return an ArrayList<String> value, or null
1030      */
getStringArrayList(String key)1031     ArrayList<String> getStringArrayList(String key) {
1032         unparcel();
1033         Object o = mMap.get(key);
1034         if (o == null) {
1035             return null;
1036         }
1037         try {
1038             return (ArrayList<String>) o;
1039         } catch (ClassCastException e) {
1040             typeWarning(key, o, "ArrayList<String>", e);
1041             return null;
1042         }
1043     }
1044 
1045     /**
1046      * Returns the value associated with the given key, or null if
1047      * no mapping of the desired type exists for the given key or a null
1048      * value is explicitly associated with the key.
1049      *
1050      * @param key a String, or null
1051      * @return an ArrayList<CharSequence> value, or null
1052      */
getCharSequenceArrayList(String key)1053     ArrayList<CharSequence> getCharSequenceArrayList(String key) {
1054         unparcel();
1055         Object o = mMap.get(key);
1056         if (o == null) {
1057             return null;
1058         }
1059         try {
1060             return (ArrayList<CharSequence>) o;
1061         } catch (ClassCastException e) {
1062             typeWarning(key, o, "ArrayList<CharSequence>", e);
1063             return null;
1064         }
1065     }
1066 
1067     /**
1068      * Returns the value associated with the given key, or null if
1069      * no mapping of the desired type exists for the given key or a null
1070      * value is explicitly associated with the key.
1071      *
1072      * @param key a String, or null
1073      * @return a boolean[] value, or null
1074      */
getBooleanArray(String key)1075     boolean[] getBooleanArray(String key) {
1076         unparcel();
1077         Object o = mMap.get(key);
1078         if (o == null) {
1079             return null;
1080         }
1081         try {
1082             return (boolean[]) o;
1083         } catch (ClassCastException e) {
1084             typeWarning(key, o, "byte[]", e);
1085             return null;
1086         }
1087     }
1088 
1089     /**
1090      * Returns the value associated with the given key, or null if
1091      * no mapping of the desired type exists for the given key or a null
1092      * value is explicitly associated with the key.
1093      *
1094      * @param key a String, or null
1095      * @return a byte[] value, or null
1096      */
getByteArray(String key)1097     byte[] getByteArray(String key) {
1098         unparcel();
1099         Object o = mMap.get(key);
1100         if (o == null) {
1101             return null;
1102         }
1103         try {
1104             return (byte[]) o;
1105         } catch (ClassCastException e) {
1106             typeWarning(key, o, "byte[]", e);
1107             return null;
1108         }
1109     }
1110 
1111     /**
1112      * Returns the value associated with the given key, or null if
1113      * no mapping of the desired type exists for the given key or a null
1114      * value is explicitly associated with the key.
1115      *
1116      * @param key a String, or null
1117      * @return a short[] value, or null
1118      */
getShortArray(String key)1119     short[] getShortArray(String key) {
1120         unparcel();
1121         Object o = mMap.get(key);
1122         if (o == null) {
1123             return null;
1124         }
1125         try {
1126             return (short[]) o;
1127         } catch (ClassCastException e) {
1128             typeWarning(key, o, "short[]", e);
1129             return null;
1130         }
1131     }
1132 
1133     /**
1134      * Returns the value associated with the given key, or null if
1135      * no mapping of the desired type exists for the given key or a null
1136      * value is explicitly associated with the key.
1137      *
1138      * @param key a String, or null
1139      * @return a char[] value, or null
1140      */
getCharArray(String key)1141     char[] getCharArray(String key) {
1142         unparcel();
1143         Object o = mMap.get(key);
1144         if (o == null) {
1145             return null;
1146         }
1147         try {
1148             return (char[]) o;
1149         } catch (ClassCastException e) {
1150             typeWarning(key, o, "char[]", e);
1151             return null;
1152         }
1153     }
1154 
1155     /**
1156      * Returns the value associated with the given key, or null if
1157      * no mapping of the desired type exists for the given key or a null
1158      * value is explicitly associated with the key.
1159      *
1160      * @param key a String, or null
1161      * @return an int[] value, or null
1162      */
getIntArray(String key)1163     public int[] getIntArray(String key) {
1164         unparcel();
1165         Object o = mMap.get(key);
1166         if (o == null) {
1167             return null;
1168         }
1169         try {
1170             return (int[]) o;
1171         } catch (ClassCastException e) {
1172             typeWarning(key, o, "int[]", e);
1173             return null;
1174         }
1175     }
1176 
1177     /**
1178      * Returns the value associated with the given key, or null if
1179      * no mapping of the desired type exists for the given key or a null
1180      * value is explicitly associated with the key.
1181      *
1182      * @param key a String, or null
1183      * @return a long[] value, or null
1184      */
getLongArray(String key)1185     public long[] getLongArray(String key) {
1186         unparcel();
1187         Object o = mMap.get(key);
1188         if (o == null) {
1189             return null;
1190         }
1191         try {
1192             return (long[]) o;
1193         } catch (ClassCastException e) {
1194             typeWarning(key, o, "long[]", e);
1195             return null;
1196         }
1197     }
1198 
1199     /**
1200      * Returns the value associated with the given key, or null if
1201      * no mapping of the desired type exists for the given key or a null
1202      * value is explicitly associated with the key.
1203      *
1204      * @param key a String, or null
1205      * @return a float[] value, or null
1206      */
getFloatArray(String key)1207     float[] getFloatArray(String key) {
1208         unparcel();
1209         Object o = mMap.get(key);
1210         if (o == null) {
1211             return null;
1212         }
1213         try {
1214             return (float[]) o;
1215         } catch (ClassCastException e) {
1216             typeWarning(key, o, "float[]", e);
1217             return null;
1218         }
1219     }
1220 
1221     /**
1222      * Returns the value associated with the given key, or null if
1223      * no mapping of the desired type exists for the given key or a null
1224      * value is explicitly associated with the key.
1225      *
1226      * @param key a String, or null
1227      * @return a double[] value, or null
1228      */
getDoubleArray(String key)1229     public double[] getDoubleArray(String key) {
1230         unparcel();
1231         Object o = mMap.get(key);
1232         if (o == null) {
1233             return null;
1234         }
1235         try {
1236             return (double[]) o;
1237         } catch (ClassCastException e) {
1238             typeWarning(key, o, "double[]", e);
1239             return null;
1240         }
1241     }
1242 
1243     /**
1244      * Returns the value associated with the given key, or null if
1245      * no mapping of the desired type exists for the given key or a null
1246      * value is explicitly associated with the key.
1247      *
1248      * @param key a String, or null
1249      * @return a String[] value, or null
1250      */
getStringArray(String key)1251     public String[] getStringArray(String key) {
1252         unparcel();
1253         Object o = mMap.get(key);
1254         if (o == null) {
1255             return null;
1256         }
1257         try {
1258             return (String[]) o;
1259         } catch (ClassCastException e) {
1260             typeWarning(key, o, "String[]", e);
1261             return null;
1262         }
1263     }
1264 
1265     /**
1266      * Returns the value associated with the given key, or null if
1267      * no mapping of the desired type exists for the given key or a null
1268      * value is explicitly associated with the key.
1269      *
1270      * @param key a String, or null
1271      * @return a CharSequence[] value, or null
1272      */
getCharSequenceArray(String key)1273     CharSequence[] getCharSequenceArray(String key) {
1274         unparcel();
1275         Object o = mMap.get(key);
1276         if (o == null) {
1277             return null;
1278         }
1279         try {
1280             return (CharSequence[]) o;
1281         } catch (ClassCastException e) {
1282             typeWarning(key, o, "CharSequence[]", e);
1283             return null;
1284         }
1285     }
1286 
1287     /**
1288      * Writes the Bundle contents to a Parcel, typically in order for
1289      * it to be passed through an IBinder connection.
1290      * @param parcel The parcel to copy this bundle to.
1291      */
writeToParcelInner(Parcel parcel, int flags)1292     void writeToParcelInner(Parcel parcel, int flags) {
1293         if (mParcelledData != null) {
1294             if (mParcelledData == EMPTY_PARCEL) {
1295                 parcel.writeInt(0);
1296             } else {
1297                 int length = mParcelledData.dataSize();
1298                 parcel.writeInt(length);
1299                 parcel.writeInt(BUNDLE_MAGIC);
1300                 parcel.appendFrom(mParcelledData, 0, length);
1301             }
1302         } else {
1303             // Special case for empty bundles.
1304             if (mMap == null || mMap.size() <= 0) {
1305                 parcel.writeInt(0);
1306                 return;
1307             }
1308             int lengthPos = parcel.dataPosition();
1309             parcel.writeInt(-1); // dummy, will hold length
1310             parcel.writeInt(BUNDLE_MAGIC);
1311 
1312             int startPos = parcel.dataPosition();
1313             parcel.writeArrayMapInternal(mMap);
1314             int endPos = parcel.dataPosition();
1315 
1316             // Backpatch length
1317             parcel.setDataPosition(lengthPos);
1318             int length = endPos - startPos;
1319             parcel.writeInt(length);
1320             parcel.setDataPosition(endPos);
1321         }
1322     }
1323 
1324     /**
1325      * Reads the Parcel contents into this Bundle, typically in order for
1326      * it to be passed through an IBinder connection.
1327      * @param parcel The parcel to overwrite this bundle from.
1328      */
readFromParcelInner(Parcel parcel)1329     void readFromParcelInner(Parcel parcel) {
1330         int length = parcel.readInt();
1331         if (length < 0) {
1332             throw new RuntimeException("Bad length in parcel: " + length);
1333         }
1334         readFromParcelInner(parcel, length);
1335     }
1336 
readFromParcelInner(Parcel parcel, int length)1337     private void readFromParcelInner(Parcel parcel, int length) {
1338         if (length == 0) {
1339             // Empty Bundle or end of data.
1340             mParcelledData = EMPTY_PARCEL;
1341             return;
1342         }
1343         int magic = parcel.readInt();
1344         if (magic != BUNDLE_MAGIC) {
1345             //noinspection ThrowableInstanceNeverThrown
1346             throw new IllegalStateException("Bad magic number for Bundle: 0x"
1347                     + Integer.toHexString(magic));
1348         }
1349 
1350         // Advance within this Parcel
1351         int offset = parcel.dataPosition();
1352         parcel.setDataPosition(offset + length);
1353 
1354         Parcel p = Parcel.obtain();
1355         p.setDataPosition(0);
1356         p.appendFrom(parcel, offset, length);
1357         if (DEBUG) Log.d(TAG, "Retrieving "  + Integer.toHexString(System.identityHashCode(this))
1358                 + ": " + length + " bundle bytes starting at " + offset);
1359         p.setDataPosition(0);
1360 
1361         mParcelledData = p;
1362     }
1363 }
1364