BaseBundle.java revision 73bdf9761be2abdd85efc5fce165f3fa80fcfa65
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
17package android.os;
18
19import android.util.ArrayMap;
20import android.util.Log;
21
22import java.io.Serializable;
23import java.util.ArrayList;
24import java.util.Map;
25import java.util.Set;
26
27/**
28 * A mapping from String values to various types.
29 */
30public 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     */
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     */
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     */
85    BaseBundle(Parcel parcelledData) {
86        readFromParcelInner(parcelledData);
87    }
88
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     */
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     */
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     */
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     */
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     */
175    void setClassLoader(ClassLoader loader) {
176        mClassLoader = loader;
177    }
178
179    /**
180     * Return the ClassLoader currently associated with this Bundle.
181     */
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     */
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     */
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     */
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     */
248    public boolean isEmpty() {
249        unparcel();
250        return mMap.isEmpty();
251    }
252
253    /**
254     * Removes all elements from the mapping of this Bundle.
255     */
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     */
268    public boolean containsKey(String key) {
269        unparcel();
270        return mMap.containsKey(key);
271    }
272
273    /**
274     * Returns the entry with the given key as an object.
275     *
276     * @param key a String key
277     * @return an Object, or null
278     */
279    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     */
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     */
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     */
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     */
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     */
332    public 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     */
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     */
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     */
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     */
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     */
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     */
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     */
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     */
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     */
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     */
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     */
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     */
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     */
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     */
500    public 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     */
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     */
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     */
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     */
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     */
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     */
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     */
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     */
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     */
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     */
620    public 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
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
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     */
657    public 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     */
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     */
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     */
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     */
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     */
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     */
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     */
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     */
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     */
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     */
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     */
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     */
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     */
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     */
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     */
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     */
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     */
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     */
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     */
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     */
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     */
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     */
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     */
1075    public 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     */
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     */
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     */
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     */
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     */
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     */
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     */
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     */
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     */
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     */
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     */
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
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