OSDN Git Service

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