blob: b6c919e272770d266f6489fd860fd76c92e00a3c [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
Scott Kennedyc6a65dff2015-03-01 17:10:10 -080019import android.annotation.Nullable;
Craig Mautner719e6b12014-04-04 20:29:41 -070020import android.util.ArrayMap;
21import android.util.Log;
Adam Lesinski1619ed42015-09-22 13:02:09 -070022import android.util.MathUtils;
Amith Yamasani23879322016-03-30 16:51:26 -070023import android.util.Slog;
Craig Mautner719e6b12014-04-04 20:29:41 -070024
25import java.io.Serializable;
26import java.util.ArrayList;
Craig Mautner719e6b12014-04-04 20:29:41 -070027import java.util.Set;
28
29/**
Jeff Sharkeyd136e512016-03-09 22:30:56 -070030 * A mapping from String keys to values of various types. In most cases, you
31 * should work directly with either the {@link Bundle} or
32 * {@link PersistableBundle} subclass.
Craig Mautner719e6b12014-04-04 20:29:41 -070033 */
Craig Mautner0a8e160e2014-05-29 10:27:32 -070034public class BaseBundle {
Craig Mautner719e6b12014-04-04 20:29:41 -070035 private static final String TAG = "Bundle";
36 static final boolean DEBUG = false;
37
Samuel Tan3cefe6a2015-12-14 13:29:17 -080038 // Keep in sync with frameworks/native/libs/binder/PersistableBundle.cpp.
Craig Mautner719e6b12014-04-04 20:29:41 -070039 static final int BUNDLE_MAGIC = 0x4C444E42; // 'B' 'N' 'D' 'L'
Samuel Tan3cefe6a2015-12-14 13:29:17 -080040
Jeff Sharkeyd136e512016-03-09 22:30:56 -070041 /**
42 * Flag indicating that this Bundle is okay to "defuse." That is, it's okay
43 * for system processes to ignore any {@link BadParcelableException}
44 * encountered when unparceling it, leaving an empty bundle in its place.
45 * <p>
46 * This should <em>only</em> be set when the Bundle reaches its final
47 * destination, otherwise a system process may clobber contents that were
48 * destined for an app that could have unparceled them.
49 */
50 static final int FLAG_DEFUSABLE = 1 << 0;
51
52 private static volatile boolean sShouldDefuse = false;
53
54 /**
55 * Set global variable indicating that any Bundles parsed in this process
56 * should be "defused." That is, any {@link BadParcelableException}
57 * encountered will be suppressed and logged, leaving an empty Bundle
58 * instead of crashing.
59 *
60 * @hide
61 */
62 public static void setShouldDefuse(boolean shouldDefuse) {
63 sShouldDefuse = shouldDefuse;
64 }
65
66 /** {@hide} */
Craig Mautner719e6b12014-04-04 20:29:41 -070067 static final Parcel EMPTY_PARCEL;
68
69 static {
70 EMPTY_PARCEL = Parcel.obtain();
71 }
72
73 // Invariant - exactly one of mMap / mParcelledData will be null
74 // (except inside a call to unparcel)
75
76 ArrayMap<String, Object> mMap = null;
77
78 /*
79 * If mParcelledData is non-null, then mMap will be null and the
80 * data are stored as a Parcel containing a Bundle. When the data
81 * are unparcelled, mParcelledData willbe set to null.
82 */
83 Parcel mParcelledData = null;
84
85 /**
86 * The ClassLoader used when unparcelling data from mParcelledData.
87 */
88 private ClassLoader mClassLoader;
89
Jeff Sharkeyd136e512016-03-09 22:30:56 -070090 /** {@hide} */
91 int mFlags;
92
Craig Mautner719e6b12014-04-04 20:29:41 -070093 /**
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 * @param capacity Initial size of the ArrayMap.
100 */
Scott Kennedyc6a65dff2015-03-01 17:10:10 -0800101 BaseBundle(@Nullable ClassLoader loader, int capacity) {
Craig Mautner719e6b12014-04-04 20:29:41 -0700102 mMap = capacity > 0 ?
103 new ArrayMap<String, Object>(capacity) : new ArrayMap<String, Object>();
104 mClassLoader = loader == null ? getClass().getClassLoader() : loader;
105 }
106
107 /**
108 * Constructs a new, empty Bundle.
109 */
Craig Mautner0a8e160e2014-05-29 10:27:32 -0700110 BaseBundle() {
Craig Mautner719e6b12014-04-04 20:29:41 -0700111 this((ClassLoader) null, 0);
112 }
113
114 /**
115 * Constructs a Bundle whose data is stored as a Parcel. The data
116 * will be unparcelled on first contact, using the assigned ClassLoader.
117 *
118 * @param parcelledData a Parcel containing a Bundle
119 */
Craig Mautner0a8e160e2014-05-29 10:27:32 -0700120 BaseBundle(Parcel parcelledData) {
Craig Mautner719e6b12014-04-04 20:29:41 -0700121 readFromParcelInner(parcelledData);
122 }
123
Craig Mautner0a8e160e2014-05-29 10:27:32 -0700124 BaseBundle(Parcel parcelledData, int length) {
Craig Mautner719e6b12014-04-04 20:29:41 -0700125 readFromParcelInner(parcelledData, length);
126 }
127
128 /**
129 * Constructs a new, empty Bundle that uses a specific ClassLoader for
130 * instantiating Parcelable and Serializable objects.
131 *
132 * @param loader An explicit ClassLoader to use when instantiating objects
133 * inside of the Bundle.
134 */
Craig Mautner0a8e160e2014-05-29 10:27:32 -0700135 BaseBundle(ClassLoader loader) {
Craig Mautner719e6b12014-04-04 20:29:41 -0700136 this(loader, 0);
137 }
138
139 /**
140 * Constructs a new, empty Bundle sized to hold the given number of
141 * elements. The Bundle will grow as needed.
142 *
143 * @param capacity the initial capacity of the Bundle
144 */
Craig Mautner0a8e160e2014-05-29 10:27:32 -0700145 BaseBundle(int capacity) {
Craig Mautner719e6b12014-04-04 20:29:41 -0700146 this((ClassLoader) null, capacity);
147 }
148
149 /**
150 * Constructs a Bundle containing a copy of the mappings from the given
151 * Bundle.
152 *
153 * @param b a Bundle to be copied.
154 */
Craig Mautner0a8e160e2014-05-29 10:27:32 -0700155 BaseBundle(BaseBundle b) {
Craig Mautner719e6b12014-04-04 20:29:41 -0700156 if (b.mParcelledData != null) {
157 if (b.mParcelledData == EMPTY_PARCEL) {
158 mParcelledData = EMPTY_PARCEL;
159 } else {
160 mParcelledData = Parcel.obtain();
161 mParcelledData.appendFrom(b.mParcelledData, 0, b.mParcelledData.dataSize());
162 mParcelledData.setDataPosition(0);
163 }
164 } else {
165 mParcelledData = null;
166 }
167
168 if (b.mMap != null) {
169 mMap = new ArrayMap<String, Object>(b.mMap);
170 } else {
171 mMap = null;
172 }
173
174 mClassLoader = b.mClassLoader;
175 }
176
177 /**
178 * TODO: optimize this later (getting just the value part of a Bundle
179 * with a single pair) once Bundle.forPair() above is implemented
180 * with a special single-value Map implementation/serialization.
181 *
182 * Note: value in single-pair Bundle may be null.
183 *
184 * @hide
185 */
Craig Mautner0a8e160e2014-05-29 10:27:32 -0700186 public String getPairValue() {
Craig Mautner719e6b12014-04-04 20:29:41 -0700187 unparcel();
188 int size = mMap.size();
189 if (size > 1) {
190 Log.w(TAG, "getPairValue() used on Bundle with multiple pairs.");
191 }
192 if (size == 0) {
193 return null;
194 }
195 Object o = mMap.valueAt(0);
196 try {
197 return (String) o;
198 } catch (ClassCastException e) {
199 typeWarning("getPairValue()", o, "String", e);
200 return null;
201 }
202 }
203
204 /**
205 * Changes the ClassLoader this Bundle uses when instantiating objects.
206 *
207 * @param loader An explicit ClassLoader to use when instantiating objects
208 * inside of the Bundle.
209 */
210 void setClassLoader(ClassLoader loader) {
211 mClassLoader = loader;
212 }
213
214 /**
215 * Return the ClassLoader currently associated with this Bundle.
216 */
217 ClassLoader getClassLoader() {
218 return mClassLoader;
219 }
220
221 /**
222 * If the underlying data are stored as a Parcel, unparcel them
223 * using the currently assigned class loader.
224 */
225 /* package */ synchronized void unparcel() {
226 if (mParcelledData == null) {
227 if (DEBUG) Log.d(TAG, "unparcel " + Integer.toHexString(System.identityHashCode(this))
228 + ": no parcelled data");
229 return;
230 }
231
Jeff Sharkeyd136e512016-03-09 22:30:56 -0700232 if (sShouldDefuse && (mFlags & FLAG_DEFUSABLE) == 0) {
Amith Yamasani23879322016-03-30 16:51:26 -0700233 Slog.wtf(TAG, "Attempting to unparcel a Bundle while in transit; this may "
Jeff Sharkeyd136e512016-03-09 22:30:56 -0700234 + "clobber all data inside!", new Throwable());
235 }
236
Craig Mautner719e6b12014-04-04 20:29:41 -0700237 if (mParcelledData == EMPTY_PARCEL) {
238 if (DEBUG) Log.d(TAG, "unparcel " + Integer.toHexString(System.identityHashCode(this))
239 + ": empty");
240 if (mMap == null) {
241 mMap = new ArrayMap<String, Object>(1);
242 } else {
243 mMap.erase();
244 }
245 mParcelledData = null;
246 return;
247 }
248
249 int N = mParcelledData.readInt();
250 if (DEBUG) Log.d(TAG, "unparcel " + Integer.toHexString(System.identityHashCode(this))
251 + ": reading " + N + " maps");
252 if (N < 0) {
253 return;
254 }
255 if (mMap == null) {
256 mMap = new ArrayMap<String, Object>(N);
257 } else {
258 mMap.erase();
259 mMap.ensureCapacity(N);
260 }
Jeff Sharkeyd136e512016-03-09 22:30:56 -0700261 try {
262 mParcelledData.readArrayMapInternal(mMap, N, mClassLoader);
263 } catch (BadParcelableException e) {
264 if (sShouldDefuse) {
265 Log.w(TAG, "Failed to parse Bundle, but defusing quietly", e);
266 mMap.erase();
267 } else {
268 throw e;
269 }
270 } finally {
271 mParcelledData.recycle();
272 mParcelledData = null;
273 }
Craig Mautner719e6b12014-04-04 20:29:41 -0700274 if (DEBUG) Log.d(TAG, "unparcel " + Integer.toHexString(System.identityHashCode(this))
275 + " final map: " + mMap);
276 }
277
278 /**
279 * @hide
280 */
Craig Mautner0a8e160e2014-05-29 10:27:32 -0700281 public boolean isParcelled() {
Craig Mautner719e6b12014-04-04 20:29:41 -0700282 return mParcelledData != null;
283 }
284
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800285 /** @hide */
286 ArrayMap<String, Object> getMap() {
287 unparcel();
288 return mMap;
289 }
290
Craig Mautner719e6b12014-04-04 20:29:41 -0700291 /**
292 * Returns the number of mappings contained in this Bundle.
293 *
294 * @return the number of mappings as an int.
295 */
Craig Mautner0a8e160e2014-05-29 10:27:32 -0700296 public int size() {
Craig Mautner719e6b12014-04-04 20:29:41 -0700297 unparcel();
298 return mMap.size();
299 }
300
301 /**
302 * Returns true if the mapping of this Bundle is empty, false otherwise.
303 */
Craig Mautner0a8e160e2014-05-29 10:27:32 -0700304 public boolean isEmpty() {
Craig Mautner719e6b12014-04-04 20:29:41 -0700305 unparcel();
306 return mMap.isEmpty();
307 }
308
309 /**
310 * Removes all elements from the mapping of this Bundle.
311 */
Craig Mautner0a8e160e2014-05-29 10:27:32 -0700312 public void clear() {
Craig Mautner719e6b12014-04-04 20:29:41 -0700313 unparcel();
314 mMap.clear();
315 }
316
317 /**
318 * Returns true if the given key is contained in the mapping
319 * of this Bundle.
320 *
321 * @param key a String key
322 * @return true if the key is part of the mapping, false otherwise
323 */
Craig Mautner0a8e160e2014-05-29 10:27:32 -0700324 public boolean containsKey(String key) {
Craig Mautner719e6b12014-04-04 20:29:41 -0700325 unparcel();
326 return mMap.containsKey(key);
327 }
328
329 /**
330 * Returns the entry with the given key as an object.
331 *
332 * @param key a String key
333 * @return an Object, or null
334 */
Scott Kennedyc6a65dff2015-03-01 17:10:10 -0800335 @Nullable
Craig Mautner0a8e160e2014-05-29 10:27:32 -0700336 public Object get(String key) {
Craig Mautner719e6b12014-04-04 20:29:41 -0700337 unparcel();
338 return mMap.get(key);
339 }
340
341 /**
342 * Removes any entry with the given key from the mapping of this Bundle.
343 *
344 * @param key a String key
345 */
Craig Mautner0a8e160e2014-05-29 10:27:32 -0700346 public void remove(String key) {
Craig Mautner719e6b12014-04-04 20:29:41 -0700347 unparcel();
348 mMap.remove(key);
349 }
350
351 /**
Craig Mautner0a8e160e2014-05-29 10:27:32 -0700352 * Inserts all mappings from the given PersistableBundle into this BaseBundle.
Craig Mautner719e6b12014-04-04 20:29:41 -0700353 *
354 * @param bundle a PersistableBundle
355 */
Craig Mautner0a8e160e2014-05-29 10:27:32 -0700356 public void putAll(PersistableBundle bundle) {
Craig Mautner719e6b12014-04-04 20:29:41 -0700357 unparcel();
358 bundle.unparcel();
359 mMap.putAll(bundle.mMap);
360 }
361
362 /**
Craig Mautner0a8e160e2014-05-29 10:27:32 -0700363 * Inserts all mappings from the given Map into this BaseBundle.
Craig Mautner21d24a22014-04-23 11:45:37 -0700364 *
365 * @param map a Map
366 */
Dianne Hackborna83ce1d2015-03-11 15:16:13 -0700367 void putAll(ArrayMap map) {
Craig Mautner21d24a22014-04-23 11:45:37 -0700368 unparcel();
369 mMap.putAll(map);
370 }
371
372 /**
Craig Mautner719e6b12014-04-04 20:29:41 -0700373 * Returns a Set containing the Strings used as keys in this Bundle.
374 *
375 * @return a Set of String keys
376 */
Craig Mautner0a8e160e2014-05-29 10:27:32 -0700377 public Set<String> keySet() {
Craig Mautner719e6b12014-04-04 20:29:41 -0700378 unparcel();
379 return mMap.keySet();
380 }
381
382 /**
383 * Inserts a Boolean value into the mapping of this Bundle, replacing
384 * any existing value for the given key. Either key or value may be null.
385 *
386 * @param key a String, or null
Scott Kennedyc6a65dff2015-03-01 17:10:10 -0800387 * @param value a boolean
Craig Mautner719e6b12014-04-04 20:29:41 -0700388 */
Scott Kennedyc6a65dff2015-03-01 17:10:10 -0800389 public void putBoolean(@Nullable String key, boolean value) {
Craig Mautner719e6b12014-04-04 20:29:41 -0700390 unparcel();
391 mMap.put(key, value);
392 }
393
394 /**
395 * Inserts a byte value into the mapping of this Bundle, replacing
396 * any existing value for the given key.
397 *
398 * @param key a String, or null
399 * @param value a byte
400 */
Scott Kennedyc6a65dff2015-03-01 17:10:10 -0800401 void putByte(@Nullable String key, byte value) {
Craig Mautner719e6b12014-04-04 20:29:41 -0700402 unparcel();
403 mMap.put(key, value);
404 }
405
406 /**
407 * Inserts a char value into the mapping of this Bundle, replacing
408 * any existing value for the given key.
409 *
410 * @param key a String, or null
Scott Kennedyc6a65dff2015-03-01 17:10:10 -0800411 * @param value a char
Craig Mautner719e6b12014-04-04 20:29:41 -0700412 */
Scott Kennedyc6a65dff2015-03-01 17:10:10 -0800413 void putChar(@Nullable String key, char value) {
Craig Mautner719e6b12014-04-04 20:29:41 -0700414 unparcel();
415 mMap.put(key, value);
416 }
417
418 /**
419 * Inserts a short value into the mapping of this Bundle, replacing
420 * any existing value for the given key.
421 *
422 * @param key a String, or null
423 * @param value a short
424 */
Scott Kennedyc6a65dff2015-03-01 17:10:10 -0800425 void putShort(@Nullable String key, short value) {
Craig Mautner719e6b12014-04-04 20:29:41 -0700426 unparcel();
427 mMap.put(key, value);
428 }
429
430 /**
431 * Inserts an int value into the mapping of this Bundle, replacing
432 * any existing value for the given key.
433 *
434 * @param key a String, or null
Scott Kennedyc6a65dff2015-03-01 17:10:10 -0800435 * @param value an int
Craig Mautner719e6b12014-04-04 20:29:41 -0700436 */
Scott Kennedyc6a65dff2015-03-01 17:10:10 -0800437 public void putInt(@Nullable String key, int value) {
Craig Mautner719e6b12014-04-04 20:29:41 -0700438 unparcel();
439 mMap.put(key, value);
440 }
441
442 /**
443 * Inserts a long value into the mapping of this Bundle, replacing
444 * any existing value for the given key.
445 *
446 * @param key a String, or null
447 * @param value a long
448 */
Scott Kennedyc6a65dff2015-03-01 17:10:10 -0800449 public void putLong(@Nullable String key, long value) {
Craig Mautner719e6b12014-04-04 20:29:41 -0700450 unparcel();
451 mMap.put(key, value);
452 }
453
454 /**
455 * Inserts a float value into the mapping of this Bundle, replacing
456 * any existing value for the given key.
457 *
458 * @param key a String, or null
459 * @param value a float
460 */
Scott Kennedyc6a65dff2015-03-01 17:10:10 -0800461 void putFloat(@Nullable String key, float value) {
Craig Mautner719e6b12014-04-04 20:29:41 -0700462 unparcel();
463 mMap.put(key, value);
464 }
465
466 /**
467 * Inserts a double value into the mapping of this Bundle, replacing
468 * any existing value for the given key.
469 *
470 * @param key a String, or null
471 * @param value a double
472 */
Scott Kennedyc6a65dff2015-03-01 17:10:10 -0800473 public void putDouble(@Nullable String key, double value) {
Craig Mautner719e6b12014-04-04 20:29:41 -0700474 unparcel();
475 mMap.put(key, value);
476 }
477
478 /**
479 * Inserts a String value into the mapping of this Bundle, replacing
480 * any existing value for the given key. Either key or value may be null.
481 *
482 * @param key a String, or null
483 * @param value a String, or null
484 */
Scott Kennedyc6a65dff2015-03-01 17:10:10 -0800485 public void putString(@Nullable String key, @Nullable String value) {
Craig Mautner719e6b12014-04-04 20:29:41 -0700486 unparcel();
487 mMap.put(key, value);
488 }
489
490 /**
491 * Inserts a CharSequence value into the mapping of this Bundle, replacing
492 * any existing value for the given key. Either key or value may be null.
493 *
494 * @param key a String, or null
495 * @param value a CharSequence, or null
496 */
Scott Kennedyc6a65dff2015-03-01 17:10:10 -0800497 void putCharSequence(@Nullable String key, @Nullable CharSequence value) {
Craig Mautner719e6b12014-04-04 20:29:41 -0700498 unparcel();
499 mMap.put(key, value);
500 }
501
502 /**
503 * Inserts an ArrayList<Integer> value into the mapping of this Bundle, replacing
504 * any existing value for the given key. Either key or value may be null.
505 *
506 * @param key a String, or null
507 * @param value an ArrayList<Integer> object, or null
508 */
Scott Kennedyc6a65dff2015-03-01 17:10:10 -0800509 void putIntegerArrayList(@Nullable String key, @Nullable ArrayList<Integer> value) {
Craig Mautner719e6b12014-04-04 20:29:41 -0700510 unparcel();
511 mMap.put(key, value);
512 }
513
514 /**
515 * Inserts an ArrayList<String> value into the mapping of this Bundle, replacing
516 * any existing value for the given key. Either key or value may be null.
517 *
518 * @param key a String, or null
519 * @param value an ArrayList<String> object, or null
520 */
Scott Kennedyc6a65dff2015-03-01 17:10:10 -0800521 void putStringArrayList(@Nullable String key, @Nullable ArrayList<String> value) {
Craig Mautner719e6b12014-04-04 20:29:41 -0700522 unparcel();
523 mMap.put(key, value);
524 }
525
526 /**
527 * Inserts an ArrayList<CharSequence> value into the mapping of this Bundle, replacing
528 * any existing value for the given key. Either key or value may be null.
529 *
530 * @param key a String, or null
531 * @param value an ArrayList<CharSequence> object, or null
532 */
Scott Kennedyc6a65dff2015-03-01 17:10:10 -0800533 void putCharSequenceArrayList(@Nullable String key, @Nullable ArrayList<CharSequence> value) {
Craig Mautner719e6b12014-04-04 20:29:41 -0700534 unparcel();
535 mMap.put(key, value);
536 }
537
538 /**
539 * Inserts a Serializable value into the mapping of this Bundle, replacing
540 * any existing value for the given key. Either key or value may be null.
541 *
542 * @param key a String, or null
543 * @param value a Serializable object, or null
544 */
Scott Kennedyc6a65dff2015-03-01 17:10:10 -0800545 void putSerializable(@Nullable String key, @Nullable Serializable value) {
Craig Mautner719e6b12014-04-04 20:29:41 -0700546 unparcel();
547 mMap.put(key, value);
548 }
549
550 /**
551 * Inserts a boolean array value into the mapping of this Bundle, replacing
552 * any existing value for the given key. Either key or value may be null.
553 *
554 * @param key a String, or null
555 * @param value a boolean array object, or null
556 */
Scott Kennedyc6a65dff2015-03-01 17:10:10 -0800557 public void putBooleanArray(@Nullable String key, @Nullable boolean[] value) {
Craig Mautner719e6b12014-04-04 20:29:41 -0700558 unparcel();
559 mMap.put(key, value);
560 }
561
562 /**
563 * Inserts a byte array value into the mapping of this Bundle, replacing
564 * any existing value for the given key. Either key or value may be null.
565 *
566 * @param key a String, or null
567 * @param value a byte array object, or null
568 */
Scott Kennedyc6a65dff2015-03-01 17:10:10 -0800569 void putByteArray(@Nullable String key, @Nullable byte[] value) {
Craig Mautner719e6b12014-04-04 20:29:41 -0700570 unparcel();
571 mMap.put(key, value);
572 }
573
574 /**
575 * Inserts a short array value into the mapping of this Bundle, replacing
576 * any existing value for the given key. Either key or value may be null.
577 *
578 * @param key a String, or null
579 * @param value a short array object, or null
580 */
Scott Kennedyc6a65dff2015-03-01 17:10:10 -0800581 void putShortArray(@Nullable String key, @Nullable short[] value) {
Craig Mautner719e6b12014-04-04 20:29:41 -0700582 unparcel();
583 mMap.put(key, value);
584 }
585
586 /**
587 * Inserts a char array value into the mapping of this Bundle, replacing
588 * any existing value for the given key. Either key or value may be null.
589 *
590 * @param key a String, or null
591 * @param value a char array object, or null
592 */
Scott Kennedyc6a65dff2015-03-01 17:10:10 -0800593 void putCharArray(@Nullable String key, @Nullable char[] value) {
Craig Mautner719e6b12014-04-04 20:29:41 -0700594 unparcel();
595 mMap.put(key, value);
596 }
597
598 /**
599 * Inserts an int array value into the mapping of this Bundle, replacing
600 * any existing value for the given key. Either key or value may be null.
601 *
602 * @param key a String, or null
603 * @param value an int array object, or null
604 */
Scott Kennedyc6a65dff2015-03-01 17:10:10 -0800605 public void putIntArray(@Nullable String key, @Nullable int[] value) {
Craig Mautner719e6b12014-04-04 20:29:41 -0700606 unparcel();
607 mMap.put(key, value);
608 }
609
610 /**
611 * Inserts a long array value into the mapping of this Bundle, replacing
612 * any existing value for the given key. Either key or value may be null.
613 *
614 * @param key a String, or null
615 * @param value a long array object, or null
616 */
Scott Kennedyc6a65dff2015-03-01 17:10:10 -0800617 public void putLongArray(@Nullable String key, @Nullable long[] value) {
Craig Mautner719e6b12014-04-04 20:29:41 -0700618 unparcel();
619 mMap.put(key, value);
620 }
621
622 /**
623 * Inserts a float array value into the mapping of this Bundle, replacing
624 * any existing value for the given key. Either key or value may be null.
625 *
626 * @param key a String, or null
627 * @param value a float array object, or null
628 */
Scott Kennedyc6a65dff2015-03-01 17:10:10 -0800629 void putFloatArray(@Nullable String key, @Nullable float[] value) {
Craig Mautner719e6b12014-04-04 20:29:41 -0700630 unparcel();
631 mMap.put(key, value);
632 }
633
634 /**
635 * Inserts a double array value into the mapping of this Bundle, replacing
636 * any existing value for the given key. Either key or value may be null.
637 *
638 * @param key a String, or null
639 * @param value a double array object, or null
640 */
Scott Kennedyc6a65dff2015-03-01 17:10:10 -0800641 public void putDoubleArray(@Nullable String key, @Nullable double[] value) {
Craig Mautner719e6b12014-04-04 20:29:41 -0700642 unparcel();
643 mMap.put(key, value);
644 }
645
646 /**
647 * Inserts a String array value into the mapping of this Bundle, replacing
648 * any existing value for the given key. Either key or value may be null.
649 *
650 * @param key a String, or null
651 * @param value a String array object, or null
652 */
Scott Kennedyc6a65dff2015-03-01 17:10:10 -0800653 public void putStringArray(@Nullable String key, @Nullable String[] value) {
Craig Mautner719e6b12014-04-04 20:29:41 -0700654 unparcel();
655 mMap.put(key, value);
656 }
657
658 /**
659 * Inserts a CharSequence array value into the mapping of this Bundle, replacing
660 * any existing value for the given key. Either key or value may be null.
661 *
662 * @param key a String, or null
663 * @param value a CharSequence array object, or null
664 */
Scott Kennedyc6a65dff2015-03-01 17:10:10 -0800665 void putCharSequenceArray(@Nullable String key, @Nullable CharSequence[] value) {
Craig Mautner719e6b12014-04-04 20:29:41 -0700666 unparcel();
667 mMap.put(key, value);
668 }
669
670 /**
Craig Mautner719e6b12014-04-04 20:29:41 -0700671 * Returns the value associated with the given key, or false if
672 * no mapping of the desired type exists for the given key.
673 *
674 * @param key a String
675 * @return a boolean value
676 */
Craig Mautner73bdf972014-12-09 18:10:20 -0800677 public boolean getBoolean(String key) {
Craig Mautner719e6b12014-04-04 20:29:41 -0700678 unparcel();
679 if (DEBUG) Log.d(TAG, "Getting boolean in "
680 + Integer.toHexString(System.identityHashCode(this)));
681 return getBoolean(key, false);
682 }
683
684 // Log a message if the value was non-null but not of the expected type
685 void typeWarning(String key, Object value, String className,
686 Object defaultValue, ClassCastException e) {
687 StringBuilder sb = new StringBuilder();
688 sb.append("Key ");
689 sb.append(key);
690 sb.append(" expected ");
691 sb.append(className);
692 sb.append(" but value was a ");
693 sb.append(value.getClass().getName());
694 sb.append(". The default value ");
695 sb.append(defaultValue);
696 sb.append(" was returned.");
697 Log.w(TAG, sb.toString());
698 Log.w(TAG, "Attempt to cast generated internal exception:", e);
699 }
700
701 void typeWarning(String key, Object value, String className,
702 ClassCastException e) {
703 typeWarning(key, value, className, "<null>", e);
704 }
705
706 /**
707 * Returns the value associated with the given key, or defaultValue if
708 * no mapping of the desired type exists for the given key.
709 *
710 * @param key a String
711 * @param defaultValue Value to return if key does not exist
712 * @return a boolean value
713 */
Craig Mautner73bdf972014-12-09 18:10:20 -0800714 public boolean getBoolean(String key, boolean defaultValue) {
Craig Mautner719e6b12014-04-04 20:29:41 -0700715 unparcel();
716 Object o = mMap.get(key);
717 if (o == null) {
718 return defaultValue;
719 }
720 try {
721 return (Boolean) o;
722 } catch (ClassCastException e) {
723 typeWarning(key, o, "Boolean", defaultValue, e);
724 return defaultValue;
725 }
726 }
727
728 /**
729 * Returns the value associated with the given key, or (byte) 0 if
730 * no mapping of the desired type exists for the given key.
731 *
732 * @param key a String
733 * @return a byte value
734 */
735 byte getByte(String key) {
736 unparcel();
737 return getByte(key, (byte) 0);
738 }
739
740 /**
741 * Returns the value associated with the given key, or defaultValue if
742 * no mapping of the desired type exists for the given key.
743 *
744 * @param key a String
745 * @param defaultValue Value to return if key does not exist
746 * @return a byte value
747 */
748 Byte getByte(String key, byte defaultValue) {
749 unparcel();
750 Object o = mMap.get(key);
751 if (o == null) {
752 return defaultValue;
753 }
754 try {
755 return (Byte) o;
756 } catch (ClassCastException e) {
757 typeWarning(key, o, "Byte", defaultValue, e);
758 return defaultValue;
759 }
760 }
761
762 /**
763 * Returns the value associated with the given key, or (char) 0 if
764 * no mapping of the desired type exists for the given key.
765 *
766 * @param key a String
767 * @return a char value
768 */
769 char getChar(String key) {
770 unparcel();
771 return getChar(key, (char) 0);
772 }
773
774 /**
775 * Returns the value associated with the given key, or defaultValue if
776 * no mapping of the desired type exists for the given key.
777 *
778 * @param key a String
779 * @param defaultValue Value to return if key does not exist
780 * @return a char value
781 */
782 char getChar(String key, char defaultValue) {
783 unparcel();
784 Object o = mMap.get(key);
785 if (o == null) {
786 return defaultValue;
787 }
788 try {
789 return (Character) o;
790 } catch (ClassCastException e) {
791 typeWarning(key, o, "Character", defaultValue, e);
792 return defaultValue;
793 }
794 }
795
796 /**
797 * Returns the value associated with the given key, or (short) 0 if
798 * no mapping of the desired type exists for the given key.
799 *
800 * @param key a String
801 * @return a short value
802 */
803 short getShort(String key) {
804 unparcel();
805 return getShort(key, (short) 0);
806 }
807
808 /**
809 * Returns the value associated with the given key, or defaultValue if
810 * no mapping of the desired type exists for the given key.
811 *
812 * @param key a String
813 * @param defaultValue Value to return if key does not exist
814 * @return a short value
815 */
816 short getShort(String key, short defaultValue) {
817 unparcel();
818 Object o = mMap.get(key);
819 if (o == null) {
820 return defaultValue;
821 }
822 try {
823 return (Short) o;
824 } catch (ClassCastException e) {
825 typeWarning(key, o, "Short", defaultValue, e);
826 return defaultValue;
827 }
828 }
829
830 /**
831 * Returns the value associated with the given key, or 0 if
832 * no mapping of the desired type exists for the given key.
833 *
834 * @param key a String
835 * @return an int value
836 */
Craig Mautner0a8e160e2014-05-29 10:27:32 -0700837 public int getInt(String key) {
Craig Mautner719e6b12014-04-04 20:29:41 -0700838 unparcel();
839 return getInt(key, 0);
840 }
841
842 /**
843 * Returns the value associated with the given key, or defaultValue if
844 * no mapping of the desired type exists for the given key.
845 *
846 * @param key a String
847 * @param defaultValue Value to return if key does not exist
848 * @return an int value
849 */
Craig Mautner0a8e160e2014-05-29 10:27:32 -0700850 public int getInt(String key, int defaultValue) {
Craig Mautner719e6b12014-04-04 20:29:41 -0700851 unparcel();
852 Object o = mMap.get(key);
853 if (o == null) {
854 return defaultValue;
855 }
856 try {
857 return (Integer) o;
858 } catch (ClassCastException e) {
859 typeWarning(key, o, "Integer", defaultValue, e);
860 return defaultValue;
861 }
862 }
863
864 /**
865 * Returns the value associated with the given key, or 0L if
866 * no mapping of the desired type exists for the given key.
867 *
868 * @param key a String
869 * @return a long value
870 */
Craig Mautner0a8e160e2014-05-29 10:27:32 -0700871 public long getLong(String key) {
Craig Mautner719e6b12014-04-04 20:29:41 -0700872 unparcel();
873 return getLong(key, 0L);
874 }
875
876 /**
877 * Returns the value associated with the given key, or defaultValue if
878 * no mapping of the desired type exists for the given key.
879 *
880 * @param key a String
881 * @param defaultValue Value to return if key does not exist
882 * @return a long value
883 */
Craig Mautner0a8e160e2014-05-29 10:27:32 -0700884 public long getLong(String key, long defaultValue) {
Craig Mautner719e6b12014-04-04 20:29:41 -0700885 unparcel();
886 Object o = mMap.get(key);
887 if (o == null) {
888 return defaultValue;
889 }
890 try {
891 return (Long) o;
892 } catch (ClassCastException e) {
893 typeWarning(key, o, "Long", defaultValue, e);
894 return defaultValue;
895 }
896 }
897
898 /**
899 * Returns the value associated with the given key, or 0.0f if
900 * no mapping of the desired type exists for the given key.
901 *
902 * @param key a String
903 * @return a float value
904 */
905 float getFloat(String key) {
906 unparcel();
907 return getFloat(key, 0.0f);
908 }
909
910 /**
911 * Returns the value associated with the given key, or defaultValue if
912 * no mapping of the desired type exists for the given key.
913 *
914 * @param key a String
915 * @param defaultValue Value to return if key does not exist
916 * @return a float value
917 */
918 float getFloat(String key, float defaultValue) {
919 unparcel();
920 Object o = mMap.get(key);
921 if (o == null) {
922 return defaultValue;
923 }
924 try {
925 return (Float) o;
926 } catch (ClassCastException e) {
927 typeWarning(key, o, "Float", defaultValue, e);
928 return defaultValue;
929 }
930 }
931
932 /**
933 * Returns the value associated with the given key, or 0.0 if
934 * no mapping of the desired type exists for the given key.
935 *
936 * @param key a String
937 * @return a double value
938 */
Craig Mautner0a8e160e2014-05-29 10:27:32 -0700939 public double getDouble(String key) {
Craig Mautner719e6b12014-04-04 20:29:41 -0700940 unparcel();
941 return getDouble(key, 0.0);
942 }
943
944 /**
945 * Returns the value associated with the given key, or defaultValue if
946 * no mapping of the desired type exists for the given key.
947 *
948 * @param key a String
949 * @param defaultValue Value to return if key does not exist
950 * @return a double value
951 */
Craig Mautner0a8e160e2014-05-29 10:27:32 -0700952 public double getDouble(String key, double defaultValue) {
Craig Mautner719e6b12014-04-04 20:29:41 -0700953 unparcel();
954 Object o = mMap.get(key);
955 if (o == null) {
956 return defaultValue;
957 }
958 try {
959 return (Double) o;
960 } catch (ClassCastException e) {
961 typeWarning(key, o, "Double", defaultValue, e);
962 return defaultValue;
963 }
964 }
965
966 /**
967 * Returns the value associated with the given key, or null if
968 * no mapping of the desired type exists for the given key or a null
969 * value is explicitly associated with the key.
970 *
971 * @param key a String, or null
972 * @return a String value, or null
973 */
Scott Kennedyc6a65dff2015-03-01 17:10:10 -0800974 @Nullable
975 public String getString(@Nullable String key) {
Craig Mautner719e6b12014-04-04 20:29:41 -0700976 unparcel();
977 final Object o = mMap.get(key);
978 try {
979 return (String) o;
980 } catch (ClassCastException e) {
981 typeWarning(key, o, "String", e);
982 return null;
983 }
984 }
985
986 /**
987 * Returns the value associated with the given key, or defaultValue if
Narayan Kamathaeaf87f2014-06-26 18:10:51 +0100988 * no mapping of the desired type exists for the given key or if a null
989 * value is explicitly associated with the given key.
Craig Mautner719e6b12014-04-04 20:29:41 -0700990 *
991 * @param key a String, or null
Narayan Kamathaeaf87f2014-06-26 18:10:51 +0100992 * @param defaultValue Value to return if key does not exist or if a null
993 * value is associated with the given key.
Craig Mautner719e6b12014-04-04 20:29:41 -0700994 * @return the String value associated with the given key, or defaultValue
995 * if no valid String object is currently mapped to that key.
996 */
Scott Kennedyc6a65dff2015-03-01 17:10:10 -0800997 public String getString(@Nullable String key, String defaultValue) {
Craig Mautner719e6b12014-04-04 20:29:41 -0700998 final String s = getString(key);
999 return (s == null) ? defaultValue : s;
1000 }
1001
1002 /**
1003 * Returns the value associated with the given key, or null if
1004 * no mapping of the desired type exists for the given key or a null
1005 * value is explicitly associated with the key.
1006 *
1007 * @param key a String, or null
1008 * @return a CharSequence value, or null
1009 */
Scott Kennedyc6a65dff2015-03-01 17:10:10 -08001010 @Nullable
1011 CharSequence getCharSequence(@Nullable String key) {
Craig Mautner719e6b12014-04-04 20:29:41 -07001012 unparcel();
1013 final Object o = mMap.get(key);
1014 try {
1015 return (CharSequence) o;
1016 } catch (ClassCastException e) {
1017 typeWarning(key, o, "CharSequence", e);
1018 return null;
1019 }
1020 }
1021
1022 /**
1023 * Returns the value associated with the given key, or defaultValue if
Narayan Kamathaeaf87f2014-06-26 18:10:51 +01001024 * no mapping of the desired type exists for the given key or if a null
1025 * value is explicitly associated with the given key.
Craig Mautner719e6b12014-04-04 20:29:41 -07001026 *
1027 * @param key a String, or null
Narayan Kamathaeaf87f2014-06-26 18:10:51 +01001028 * @param defaultValue Value to return if key does not exist or if a null
1029 * value is associated with the given key.
Craig Mautner719e6b12014-04-04 20:29:41 -07001030 * @return the CharSequence value associated with the given key, or defaultValue
1031 * if no valid CharSequence object is currently mapped to that key.
1032 */
Scott Kennedyc6a65dff2015-03-01 17:10:10 -08001033 CharSequence getCharSequence(@Nullable String key, CharSequence defaultValue) {
Craig Mautner719e6b12014-04-04 20:29:41 -07001034 final CharSequence cs = getCharSequence(key);
1035 return (cs == null) ? defaultValue : cs;
1036 }
1037
1038 /**
1039 * Returns the value associated with the given key, or null if
1040 * no mapping of the desired type exists for the given key or a null
1041 * value is explicitly associated with the key.
1042 *
1043 * @param key a String, or null
Craig Mautner719e6b12014-04-04 20:29:41 -07001044 * @return a Serializable value, or null
1045 */
Scott Kennedyc6a65dff2015-03-01 17:10:10 -08001046 @Nullable
1047 Serializable getSerializable(@Nullable String key) {
Craig Mautner719e6b12014-04-04 20:29:41 -07001048 unparcel();
1049 Object o = mMap.get(key);
1050 if (o == null) {
1051 return null;
1052 }
1053 try {
1054 return (Serializable) o;
1055 } catch (ClassCastException e) {
1056 typeWarning(key, o, "Serializable", e);
1057 return null;
1058 }
1059 }
1060
1061 /**
1062 * Returns the value associated with the given key, or null if
1063 * no mapping of the desired type exists for the given key or a null
1064 * value is explicitly associated with the key.
1065 *
1066 * @param key a String, or null
1067 * @return an ArrayList<String> value, or null
1068 */
Scott Kennedyc6a65dff2015-03-01 17:10:10 -08001069 @Nullable
1070 ArrayList<Integer> getIntegerArrayList(@Nullable String key) {
Craig Mautner719e6b12014-04-04 20:29:41 -07001071 unparcel();
1072 Object o = mMap.get(key);
1073 if (o == null) {
1074 return null;
1075 }
1076 try {
1077 return (ArrayList<Integer>) o;
1078 } catch (ClassCastException e) {
1079 typeWarning(key, o, "ArrayList<Integer>", e);
1080 return null;
1081 }
1082 }
1083
1084 /**
1085 * Returns the value associated with the given key, or null if
1086 * no mapping of the desired type exists for the given key or a null
1087 * value is explicitly associated with the key.
1088 *
1089 * @param key a String, or null
1090 * @return an ArrayList<String> value, or null
1091 */
Scott Kennedyc6a65dff2015-03-01 17:10:10 -08001092 @Nullable
1093 ArrayList<String> getStringArrayList(@Nullable String key) {
Craig Mautner719e6b12014-04-04 20:29:41 -07001094 unparcel();
1095 Object o = mMap.get(key);
1096 if (o == null) {
1097 return null;
1098 }
1099 try {
1100 return (ArrayList<String>) o;
1101 } catch (ClassCastException e) {
1102 typeWarning(key, o, "ArrayList<String>", e);
1103 return null;
1104 }
1105 }
1106
1107 /**
1108 * Returns the value associated with the given key, or null if
1109 * no mapping of the desired type exists for the given key or a null
1110 * value is explicitly associated with the key.
1111 *
1112 * @param key a String, or null
1113 * @return an ArrayList<CharSequence> value, or null
1114 */
Scott Kennedyc6a65dff2015-03-01 17:10:10 -08001115 @Nullable
1116 ArrayList<CharSequence> getCharSequenceArrayList(@Nullable String key) {
Craig Mautner719e6b12014-04-04 20:29:41 -07001117 unparcel();
1118 Object o = mMap.get(key);
1119 if (o == null) {
1120 return null;
1121 }
1122 try {
1123 return (ArrayList<CharSequence>) o;
1124 } catch (ClassCastException e) {
1125 typeWarning(key, o, "ArrayList<CharSequence>", e);
1126 return null;
1127 }
1128 }
1129
1130 /**
1131 * Returns the value associated with the given key, or null if
1132 * no mapping of the desired type exists for the given key or a null
1133 * value is explicitly associated with the key.
1134 *
1135 * @param key a String, or null
1136 * @return a boolean[] value, or null
1137 */
Scott Kennedyc6a65dff2015-03-01 17:10:10 -08001138 @Nullable
1139 public boolean[] getBooleanArray(@Nullable String key) {
Craig Mautner719e6b12014-04-04 20:29:41 -07001140 unparcel();
1141 Object o = mMap.get(key);
1142 if (o == null) {
1143 return null;
1144 }
1145 try {
1146 return (boolean[]) o;
1147 } catch (ClassCastException e) {
1148 typeWarning(key, o, "byte[]", e);
1149 return null;
1150 }
1151 }
1152
1153 /**
1154 * Returns the value associated with the given key, or null if
1155 * no mapping of the desired type exists for the given key or a null
1156 * value is explicitly associated with the key.
1157 *
1158 * @param key a String, or null
1159 * @return a byte[] value, or null
1160 */
Scott Kennedyc6a65dff2015-03-01 17:10:10 -08001161 @Nullable
1162 byte[] getByteArray(@Nullable String key) {
Craig Mautner719e6b12014-04-04 20:29:41 -07001163 unparcel();
1164 Object o = mMap.get(key);
1165 if (o == null) {
1166 return null;
1167 }
1168 try {
1169 return (byte[]) o;
1170 } catch (ClassCastException e) {
1171 typeWarning(key, o, "byte[]", 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 a short[] value, or null
1183 */
Scott Kennedyc6a65dff2015-03-01 17:10:10 -08001184 @Nullable
1185 short[] getShortArray(@Nullable String key) {
Craig Mautner719e6b12014-04-04 20:29:41 -07001186 unparcel();
1187 Object o = mMap.get(key);
1188 if (o == null) {
1189 return null;
1190 }
1191 try {
1192 return (short[]) o;
1193 } catch (ClassCastException e) {
1194 typeWarning(key, o, "short[]", 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 char[] value, or null
1206 */
Scott Kennedyc6a65dff2015-03-01 17:10:10 -08001207 @Nullable
1208 char[] getCharArray(@Nullable String key) {
Craig Mautner719e6b12014-04-04 20:29:41 -07001209 unparcel();
1210 Object o = mMap.get(key);
1211 if (o == null) {
1212 return null;
1213 }
1214 try {
1215 return (char[]) o;
1216 } catch (ClassCastException e) {
1217 typeWarning(key, o, "char[]", e);
1218 return null;
1219 }
1220 }
1221
1222 /**
1223 * Returns the value associated with the given key, or null if
1224 * no mapping of the desired type exists for the given key or a null
1225 * value is explicitly associated with the key.
1226 *
1227 * @param key a String, or null
1228 * @return an int[] value, or null
1229 */
Scott Kennedyc6a65dff2015-03-01 17:10:10 -08001230 @Nullable
1231 public int[] getIntArray(@Nullable String key) {
Craig Mautner719e6b12014-04-04 20:29:41 -07001232 unparcel();
1233 Object o = mMap.get(key);
1234 if (o == null) {
1235 return null;
1236 }
1237 try {
1238 return (int[]) o;
1239 } catch (ClassCastException e) {
1240 typeWarning(key, o, "int[]", e);
1241 return null;
1242 }
1243 }
1244
1245 /**
1246 * Returns the value associated with the given key, or null if
1247 * no mapping of the desired type exists for the given key or a null
1248 * value is explicitly associated with the key.
1249 *
1250 * @param key a String, or null
1251 * @return a long[] value, or null
1252 */
Scott Kennedyc6a65dff2015-03-01 17:10:10 -08001253 @Nullable
1254 public long[] getLongArray(@Nullable String key) {
Craig Mautner719e6b12014-04-04 20:29:41 -07001255 unparcel();
1256 Object o = mMap.get(key);
1257 if (o == null) {
1258 return null;
1259 }
1260 try {
1261 return (long[]) o;
1262 } catch (ClassCastException e) {
1263 typeWarning(key, o, "long[]", e);
1264 return null;
1265 }
1266 }
1267
1268 /**
1269 * Returns the value associated with the given key, or null if
1270 * no mapping of the desired type exists for the given key or a null
1271 * value is explicitly associated with the key.
1272 *
1273 * @param key a String, or null
1274 * @return a float[] value, or null
1275 */
Scott Kennedyc6a65dff2015-03-01 17:10:10 -08001276 @Nullable
1277 float[] getFloatArray(@Nullable String key) {
Craig Mautner719e6b12014-04-04 20:29:41 -07001278 unparcel();
1279 Object o = mMap.get(key);
1280 if (o == null) {
1281 return null;
1282 }
1283 try {
1284 return (float[]) o;
1285 } catch (ClassCastException e) {
1286 typeWarning(key, o, "float[]", e);
1287 return null;
1288 }
1289 }
1290
1291 /**
1292 * Returns the value associated with the given key, or null if
1293 * no mapping of the desired type exists for the given key or a null
1294 * value is explicitly associated with the key.
1295 *
1296 * @param key a String, or null
1297 * @return a double[] value, or null
1298 */
Scott Kennedyc6a65dff2015-03-01 17:10:10 -08001299 @Nullable
1300 public double[] getDoubleArray(@Nullable String key) {
Craig Mautner719e6b12014-04-04 20:29:41 -07001301 unparcel();
1302 Object o = mMap.get(key);
1303 if (o == null) {
1304 return null;
1305 }
1306 try {
1307 return (double[]) o;
1308 } catch (ClassCastException e) {
1309 typeWarning(key, o, "double[]", e);
1310 return null;
1311 }
1312 }
1313
1314 /**
1315 * Returns the value associated with the given key, or null if
1316 * no mapping of the desired type exists for the given key or a null
1317 * value is explicitly associated with the key.
1318 *
1319 * @param key a String, or null
1320 * @return a String[] value, or null
1321 */
Scott Kennedyc6a65dff2015-03-01 17:10:10 -08001322 @Nullable
1323 public String[] getStringArray(@Nullable String key) {
Craig Mautner719e6b12014-04-04 20:29:41 -07001324 unparcel();
1325 Object o = mMap.get(key);
1326 if (o == null) {
1327 return null;
1328 }
1329 try {
1330 return (String[]) o;
1331 } catch (ClassCastException e) {
1332 typeWarning(key, o, "String[]", e);
1333 return null;
1334 }
1335 }
1336
1337 /**
1338 * Returns the value associated with the given key, or null if
1339 * no mapping of the desired type exists for the given key or a null
1340 * value is explicitly associated with the key.
1341 *
1342 * @param key a String, or null
1343 * @return a CharSequence[] value, or null
1344 */
Scott Kennedyc6a65dff2015-03-01 17:10:10 -08001345 @Nullable
1346 CharSequence[] getCharSequenceArray(@Nullable String key) {
Craig Mautner719e6b12014-04-04 20:29:41 -07001347 unparcel();
1348 Object o = mMap.get(key);
1349 if (o == null) {
1350 return null;
1351 }
1352 try {
1353 return (CharSequence[]) o;
1354 } catch (ClassCastException e) {
1355 typeWarning(key, o, "CharSequence[]", e);
1356 return null;
1357 }
1358 }
1359
1360 /**
1361 * Writes the Bundle contents to a Parcel, typically in order for
1362 * it to be passed through an IBinder connection.
1363 * @param parcel The parcel to copy this bundle to.
1364 */
1365 void writeToParcelInner(Parcel parcel, int flags) {
Samuel Tan3cefe6a2015-12-14 13:29:17 -08001366 // Keep implementation in sync with writeToParcel() in
1367 // frameworks/native/libs/binder/PersistableBundle.cpp.
Craig Mautner719e6b12014-04-04 20:29:41 -07001368 if (mParcelledData != null) {
1369 if (mParcelledData == EMPTY_PARCEL) {
1370 parcel.writeInt(0);
1371 } else {
1372 int length = mParcelledData.dataSize();
1373 parcel.writeInt(length);
1374 parcel.writeInt(BUNDLE_MAGIC);
1375 parcel.appendFrom(mParcelledData, 0, length);
1376 }
1377 } else {
1378 // Special case for empty bundles.
1379 if (mMap == null || mMap.size() <= 0) {
1380 parcel.writeInt(0);
1381 return;
1382 }
1383 int lengthPos = parcel.dataPosition();
1384 parcel.writeInt(-1); // dummy, will hold length
1385 parcel.writeInt(BUNDLE_MAGIC);
1386
1387 int startPos = parcel.dataPosition();
1388 parcel.writeArrayMapInternal(mMap);
1389 int endPos = parcel.dataPosition();
1390
1391 // Backpatch length
1392 parcel.setDataPosition(lengthPos);
1393 int length = endPos - startPos;
1394 parcel.writeInt(length);
1395 parcel.setDataPosition(endPos);
1396 }
1397 }
1398
1399 /**
1400 * Reads the Parcel contents into this Bundle, typically in order for
1401 * it to be passed through an IBinder connection.
1402 * @param parcel The parcel to overwrite this bundle from.
1403 */
1404 void readFromParcelInner(Parcel parcel) {
Samuel Tan3cefe6a2015-12-14 13:29:17 -08001405 // Keep implementation in sync with readFromParcel() in
1406 // frameworks/native/libs/binder/PersistableBundle.cpp.
Craig Mautner719e6b12014-04-04 20:29:41 -07001407 int length = parcel.readInt();
Craig Mautner719e6b12014-04-04 20:29:41 -07001408 readFromParcelInner(parcel, length);
1409 }
1410
1411 private void readFromParcelInner(Parcel parcel, int length) {
Adam Lesinski1619ed42015-09-22 13:02:09 -07001412 if (length < 0) {
1413 throw new RuntimeException("Bad length in parcel: " + length);
1414
1415 } else if (length == 0) {
Craig Mautner719e6b12014-04-04 20:29:41 -07001416 // Empty Bundle or end of data.
1417 mParcelledData = EMPTY_PARCEL;
1418 return;
1419 }
Adam Lesinski1619ed42015-09-22 13:02:09 -07001420
Jeff Sharkeyd136e512016-03-09 22:30:56 -07001421 final int magic = parcel.readInt();
Craig Mautner719e6b12014-04-04 20:29:41 -07001422 if (magic != BUNDLE_MAGIC) {
Craig Mautner719e6b12014-04-04 20:29:41 -07001423 throw new IllegalStateException("Bad magic number for Bundle: 0x"
1424 + Integer.toHexString(magic));
1425 }
1426
1427 // Advance within this Parcel
1428 int offset = parcel.dataPosition();
Adam Lesinski1619ed42015-09-22 13:02:09 -07001429 parcel.setDataPosition(MathUtils.addOrThrow(offset, length));
Craig Mautner719e6b12014-04-04 20:29:41 -07001430
1431 Parcel p = Parcel.obtain();
1432 p.setDataPosition(0);
1433 p.appendFrom(parcel, offset, length);
1434 if (DEBUG) Log.d(TAG, "Retrieving " + Integer.toHexString(System.identityHashCode(this))
1435 + ": " + length + " bundle bytes starting at " + offset);
1436 p.setDataPosition(0);
1437
1438 mParcelledData = p;
1439 }
1440}