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