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