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