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