1/* 2 * Copyright (C) 2007 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17package android.os; 18 19import android.util.Log; 20import android.util.SparseArray; 21 22import java.io.Serializable; 23import java.util.ArrayList; 24import java.util.Collections; 25import java.util.HashMap; 26import java.util.Iterator; 27import java.util.Map; 28import java.util.Set; 29 30/** 31 * A mapping from String values to various Parcelable types. 32 * 33 */ 34public final class Bundle implements Parcelable, Cloneable { 35 private static final String LOG_TAG = "Bundle"; 36 public static final Bundle EMPTY; 37 38 static { 39 EMPTY = new Bundle(); 40 EMPTY.mMap = Collections.unmodifiableMap(new HashMap<String, Object>()); 41 } 42 43 // Invariant - exactly one of mMap / mParcelledData will be null 44 // (except inside a call to unparcel) 45 46 /* package */ Map<String, Object> mMap = null; 47 48 /* 49 * If mParcelledData is non-null, then mMap will be null and the 50 * data are stored as a Parcel containing a Bundle. When the data 51 * are unparcelled, mParcelledData willbe set to null. 52 */ 53 /* package */ Parcel mParcelledData = null; 54 55 private boolean mHasFds = false; 56 private boolean mFdsKnown = true; 57 private boolean mAllowFds = true; 58 59 /** 60 * The ClassLoader used when unparcelling data from mParcelledData. 61 */ 62 private ClassLoader mClassLoader; 63 64 /** 65 * Constructs a new, empty Bundle. 66 */ 67 public Bundle() { 68 mMap = new HashMap<String, Object>(); 69 mClassLoader = getClass().getClassLoader(); 70 } 71 72 /** 73 * Constructs a Bundle whose data is stored as a Parcel. The data 74 * will be unparcelled on first contact, using the assigned ClassLoader. 75 * 76 * @param parcelledData a Parcel containing a Bundle 77 */ 78 Bundle(Parcel parcelledData) { 79 readFromParcel(parcelledData); 80 } 81 82 /* package */ Bundle(Parcel parcelledData, int length) { 83 readFromParcelInner(parcelledData, length); 84 } 85 86 /** 87 * Constructs a new, empty Bundle that uses a specific ClassLoader for 88 * instantiating Parcelable and Serializable objects. 89 * 90 * @param loader An explicit ClassLoader to use when instantiating objects 91 * inside of the Bundle. 92 */ 93 public Bundle(ClassLoader loader) { 94 mMap = new HashMap<String, Object>(); 95 mClassLoader = loader; 96 } 97 98 /** 99 * Constructs a new, empty Bundle sized to hold the given number of 100 * elements. The Bundle will grow as needed. 101 * 102 * @param capacity the initial capacity of the Bundle 103 */ 104 public Bundle(int capacity) { 105 mMap = new HashMap<String, Object>(capacity); 106 mClassLoader = getClass().getClassLoader(); 107 } 108 109 /** 110 * Constructs a Bundle containing a copy of the mappings from the given 111 * Bundle. 112 * 113 * @param b a Bundle to be copied. 114 */ 115 public Bundle(Bundle b) { 116 if (b.mParcelledData != null) { 117 mParcelledData = Parcel.obtain(); 118 mParcelledData.appendFrom(b.mParcelledData, 0, b.mParcelledData.dataSize()); 119 mParcelledData.setDataPosition(0); 120 } else { 121 mParcelledData = null; 122 } 123 124 if (b.mMap != null) { 125 mMap = new HashMap<String, Object>(b.mMap); 126 } else { 127 mMap = null; 128 } 129 130 mHasFds = b.mHasFds; 131 mFdsKnown = b.mFdsKnown; 132 mClassLoader = b.mClassLoader; 133 } 134 135 /** 136 * Make a Bundle for a single key/value pair. 137 * 138 * @hide 139 */ 140 public static Bundle forPair(String key, String value) { 141 // TODO: optimize this case. 142 Bundle b = new Bundle(1); 143 b.putString(key, value); 144 return b; 145 } 146 147 /** 148 * TODO: optimize this later (getting just the value part of a Bundle 149 * with a single pair) once Bundle.forPair() above is implemented 150 * with a special single-value Map implementation/serialization. 151 * 152 * Note: value in single-pair Bundle may be null. 153 * 154 * @hide 155 */ 156 public String getPairValue() { 157 unparcel(); 158 int size = mMap.size(); 159 if (size > 1) { 160 Log.w(LOG_TAG, "getPairValue() used on Bundle with multiple pairs."); 161 } 162 if (size == 0) { 163 return null; 164 } 165 Object o = mMap.values().iterator().next(); 166 try { 167 return (String) o; 168 } catch (ClassCastException e) { 169 typeWarning("getPairValue()", o, "String", e); 170 return null; 171 } 172 } 173 174 /** 175 * Changes the ClassLoader this Bundle uses when instantiating objects. 176 * 177 * @param loader An explicit ClassLoader to use when instantiating objects 178 * inside of the Bundle. 179 */ 180 public void setClassLoader(ClassLoader loader) { 181 mClassLoader = loader; 182 } 183 184 /** 185 * Return the ClassLoader currently associated with this Bundle. 186 */ 187 public ClassLoader getClassLoader() { 188 return mClassLoader; 189 } 190 191 /** @hide */ 192 public boolean setAllowFds(boolean allowFds) { 193 boolean orig = mAllowFds; 194 mAllowFds = allowFds; 195 return orig; 196 } 197 198 /** 199 * Clones the current Bundle. The internal map is cloned, but the keys and 200 * values to which it refers are copied by reference. 201 */ 202 @Override 203 public Object clone() { 204 return new Bundle(this); 205 } 206 207 /** 208 * If the underlying data are stored as a Parcel, unparcel them 209 * using the currently assigned class loader. 210 */ 211 /* package */ synchronized void unparcel() { 212 if (mParcelledData == null) { 213 return; 214 } 215 216 int N = mParcelledData.readInt(); 217 if (N < 0) { 218 return; 219 } 220 if (mMap == null) { 221 mMap = new HashMap<String, Object>(); 222 } 223 mParcelledData.readMapInternal(mMap, N, mClassLoader); 224 mParcelledData.recycle(); 225 mParcelledData = null; 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 mHasFds = false; 260 mFdsKnown = true; 261 } 262 263 /** 264 * Returns true if the given key is contained in the mapping 265 * of this Bundle. 266 * 267 * @param key a String key 268 * @return true if the key is part of the mapping, false otherwise 269 */ 270 public boolean containsKey(String key) { 271 unparcel(); 272 return mMap.containsKey(key); 273 } 274 275 /** 276 * Returns the entry with the given key as an object. 277 * 278 * @param key a String key 279 * @return an Object, or null 280 */ 281 public Object get(String key) { 282 unparcel(); 283 return mMap.get(key); 284 } 285 286 /** 287 * Removes any entry with the given key from the mapping of this Bundle. 288 * 289 * @param key a String key 290 */ 291 public void remove(String key) { 292 unparcel(); 293 mMap.remove(key); 294 } 295 296 /** 297 * Inserts all mappings from the given Bundle into this Bundle. 298 * 299 * @param map a Bundle 300 */ 301 public void putAll(Bundle map) { 302 unparcel(); 303 map.unparcel(); 304 mMap.putAll(map.mMap); 305 306 // fd state is now known if and only if both bundles already knew 307 mHasFds |= map.mHasFds; 308 mFdsKnown = mFdsKnown && map.mFdsKnown; 309 } 310 311 /** 312 * Returns a Set containing the Strings used as keys in this Bundle. 313 * 314 * @return a Set of String keys 315 */ 316 public Set<String> keySet() { 317 unparcel(); 318 return mMap.keySet(); 319 } 320 321 /** 322 * Reports whether the bundle contains any parcelled file descriptors. 323 */ 324 public boolean hasFileDescriptors() { 325 if (!mFdsKnown) { 326 boolean fdFound = false; // keep going until we find one or run out of data 327 328 if (mParcelledData != null) { 329 if (mParcelledData.hasFileDescriptors()) { 330 fdFound = true; 331 } 332 } else { 333 // It's been unparcelled, so we need to walk the map 334 Iterator<Map.Entry<String, Object>> iter = mMap.entrySet().iterator(); 335 while (!fdFound && iter.hasNext()) { 336 Object obj = iter.next().getValue(); 337 if (obj instanceof Parcelable) { 338 if ((((Parcelable)obj).describeContents() 339 & Parcelable.CONTENTS_FILE_DESCRIPTOR) != 0) { 340 fdFound = true; 341 break; 342 } 343 } else if (obj instanceof Parcelable[]) { 344 Parcelable[] array = (Parcelable[]) obj; 345 for (int n = array.length - 1; n >= 0; n--) { 346 if ((array[n].describeContents() 347 & Parcelable.CONTENTS_FILE_DESCRIPTOR) != 0) { 348 fdFound = true; 349 break; 350 } 351 } 352 } else if (obj instanceof SparseArray) { 353 SparseArray<? extends Parcelable> array = 354 (SparseArray<? extends Parcelable>) obj; 355 for (int n = array.size() - 1; n >= 0; n--) { 356 if ((array.get(n).describeContents() 357 & Parcelable.CONTENTS_FILE_DESCRIPTOR) != 0) { 358 fdFound = true; 359 break; 360 } 361 } 362 } else if (obj instanceof ArrayList) { 363 ArrayList array = (ArrayList) obj; 364 // an ArrayList here might contain either Strings or 365 // Parcelables; only look inside for Parcelables 366 if ((array.size() > 0) 367 && (array.get(0) instanceof Parcelable)) { 368 for (int n = array.size() - 1; n >= 0; n--) { 369 Parcelable p = (Parcelable) array.get(n); 370 if (p != null && ((p.describeContents() 371 & Parcelable.CONTENTS_FILE_DESCRIPTOR) != 0)) { 372 fdFound = true; 373 break; 374 } 375 } 376 } 377 } 378 } 379 } 380 381 mHasFds = fdFound; 382 mFdsKnown = true; 383 } 384 return mHasFds; 385 } 386 387 /** 388 * Inserts a Boolean value into the mapping of this Bundle, replacing 389 * any existing value for the given key. Either key or value may be null. 390 * 391 * @param key a String, or null 392 * @param value a Boolean, or null 393 */ 394 public void putBoolean(String key, boolean value) { 395 unparcel(); 396 mMap.put(key, value); 397 } 398 399 /** 400 * Inserts a byte value into the mapping of this Bundle, replacing 401 * any existing value for the given key. 402 * 403 * @param key a String, or null 404 * @param value a byte 405 */ 406 public void putByte(String key, byte value) { 407 unparcel(); 408 mMap.put(key, value); 409 } 410 411 /** 412 * Inserts a char value into the mapping of this Bundle, replacing 413 * any existing value for the given key. 414 * 415 * @param key a String, or null 416 * @param value a char, or null 417 */ 418 public void putChar(String key, char value) { 419 unparcel(); 420 mMap.put(key, value); 421 } 422 423 /** 424 * Inserts a short value into the mapping of this Bundle, replacing 425 * any existing value for the given key. 426 * 427 * @param key a String, or null 428 * @param value a short 429 */ 430 public void putShort(String key, short value) { 431 unparcel(); 432 mMap.put(key, value); 433 } 434 435 /** 436 * Inserts an int value into the mapping of this Bundle, replacing 437 * any existing value for the given key. 438 * 439 * @param key a String, or null 440 * @param value an int, or null 441 */ 442 public void putInt(String key, int value) { 443 unparcel(); 444 mMap.put(key, value); 445 } 446 447 /** 448 * Inserts a long value into the mapping of this Bundle, replacing 449 * any existing value for the given key. 450 * 451 * @param key a String, or null 452 * @param value a long 453 */ 454 public void putLong(String key, long value) { 455 unparcel(); 456 mMap.put(key, value); 457 } 458 459 /** 460 * Inserts a float value into the mapping of this Bundle, replacing 461 * any existing value for the given key. 462 * 463 * @param key a String, or null 464 * @param value a float 465 */ 466 public void putFloat(String key, float value) { 467 unparcel(); 468 mMap.put(key, value); 469 } 470 471 /** 472 * Inserts a double value into the mapping of this Bundle, replacing 473 * any existing value for the given key. 474 * 475 * @param key a String, or null 476 * @param value a double 477 */ 478 public void putDouble(String key, double value) { 479 unparcel(); 480 mMap.put(key, value); 481 } 482 483 /** 484 * Inserts a String value into the mapping of this Bundle, replacing 485 * any existing value for the given key. Either key or value may be null. 486 * 487 * @param key a String, or null 488 * @param value a String, or null 489 */ 490 public void putString(String key, String value) { 491 unparcel(); 492 mMap.put(key, value); 493 } 494 495 /** 496 * Inserts a CharSequence value into the mapping of this Bundle, replacing 497 * any existing value for the given key. Either key or value may be null. 498 * 499 * @param key a String, or null 500 * @param value a CharSequence, or null 501 */ 502 public void putCharSequence(String key, CharSequence value) { 503 unparcel(); 504 mMap.put(key, value); 505 } 506 507 /** 508 * Inserts a Parcelable value into the mapping of this Bundle, replacing 509 * any existing value for the given key. Either key or value may be null. 510 * 511 * @param key a String, or null 512 * @param value a Parcelable object, or null 513 */ 514 public void putParcelable(String key, Parcelable value) { 515 unparcel(); 516 mMap.put(key, value); 517 mFdsKnown = false; 518 } 519 520 /** 521 * Inserts an array of Parcelable values into the mapping of this Bundle, 522 * replacing any existing value for the given key. Either key or value may 523 * be null. 524 * 525 * @param key a String, or null 526 * @param value an array of Parcelable objects, or null 527 */ 528 public void putParcelableArray(String key, Parcelable[] value) { 529 unparcel(); 530 mMap.put(key, value); 531 mFdsKnown = false; 532 } 533 534 /** 535 * Inserts a List of Parcelable values into the mapping of this Bundle, 536 * replacing any existing value for the given key. Either key or value may 537 * be null. 538 * 539 * @param key a String, or null 540 * @param value an ArrayList of Parcelable objects, or null 541 */ 542 public void putParcelableArrayList(String key, 543 ArrayList<? extends Parcelable> value) { 544 unparcel(); 545 mMap.put(key, value); 546 mFdsKnown = false; 547 } 548 549 /** 550 * Inserts a SparceArray of Parcelable values into the mapping of this 551 * Bundle, replacing any existing value for the given key. Either key 552 * or value may be null. 553 * 554 * @param key a String, or null 555 * @param value a SparseArray of Parcelable objects, or null 556 */ 557 public void putSparseParcelableArray(String key, 558 SparseArray<? extends Parcelable> value) { 559 unparcel(); 560 mMap.put(key, value); 561 mFdsKnown = false; 562 } 563 564 /** 565 * Inserts an ArrayList<Integer> value into the mapping of this Bundle, replacing 566 * any existing value for the given key. Either key or value may be null. 567 * 568 * @param key a String, or null 569 * @param value an ArrayList<Integer> object, or null 570 */ 571 public void putIntegerArrayList(String key, ArrayList<Integer> value) { 572 unparcel(); 573 mMap.put(key, value); 574 } 575 576 /** 577 * Inserts an ArrayList<String> value into the mapping of this Bundle, replacing 578 * any existing value for the given key. Either key or value may be null. 579 * 580 * @param key a String, or null 581 * @param value an ArrayList<String> object, or null 582 */ 583 public void putStringArrayList(String key, ArrayList<String> value) { 584 unparcel(); 585 mMap.put(key, value); 586 } 587 588 /** 589 * Inserts an ArrayList<CharSequence> value into the mapping of this Bundle, replacing 590 * any existing value for the given key. Either key or value may be null. 591 * 592 * @param key a String, or null 593 * @param value an ArrayList<CharSequence> object, or null 594 */ 595 public void putCharSequenceArrayList(String key, ArrayList<CharSequence> value) { 596 unparcel(); 597 mMap.put(key, value); 598 } 599 600 /** 601 * Inserts a Serializable value into the mapping of this Bundle, replacing 602 * any existing value for the given key. Either key or value may be null. 603 * 604 * @param key a String, or null 605 * @param value a Serializable object, or null 606 */ 607 public void putSerializable(String key, Serializable value) { 608 unparcel(); 609 mMap.put(key, value); 610 } 611 612 /** 613 * Inserts a boolean array value into the mapping of this Bundle, replacing 614 * any existing value for the given key. Either key or value may be null. 615 * 616 * @param key a String, or null 617 * @param value a boolean array object, or null 618 */ 619 public void putBooleanArray(String key, boolean[] value) { 620 unparcel(); 621 mMap.put(key, value); 622 } 623 624 /** 625 * Inserts a byte array value into the mapping of this Bundle, replacing 626 * any existing value for the given key. Either key or value may be null. 627 * 628 * @param key a String, or null 629 * @param value a byte array object, or null 630 */ 631 public void putByteArray(String key, byte[] value) { 632 unparcel(); 633 mMap.put(key, value); 634 } 635 636 /** 637 * Inserts a short array value into the mapping of this Bundle, replacing 638 * any existing value for the given key. Either key or value may be null. 639 * 640 * @param key a String, or null 641 * @param value a short array object, or null 642 */ 643 public void putShortArray(String key, short[] value) { 644 unparcel(); 645 mMap.put(key, value); 646 } 647 648 /** 649 * Inserts a char array value into the mapping of this Bundle, replacing 650 * any existing value for the given key. Either key or value may be null. 651 * 652 * @param key a String, or null 653 * @param value a char array object, or null 654 */ 655 public void putCharArray(String key, char[] value) { 656 unparcel(); 657 mMap.put(key, value); 658 } 659 660 /** 661 * Inserts an int array value into the mapping of this Bundle, replacing 662 * any existing value for the given key. Either key or value may be null. 663 * 664 * @param key a String, or null 665 * @param value an int array object, or null 666 */ 667 public void putIntArray(String key, int[] value) { 668 unparcel(); 669 mMap.put(key, value); 670 } 671 672 /** 673 * Inserts a long array value into the mapping of this Bundle, replacing 674 * any existing value for the given key. Either key or value may be null. 675 * 676 * @param key a String, or null 677 * @param value a long array object, or null 678 */ 679 public void putLongArray(String key, long[] value) { 680 unparcel(); 681 mMap.put(key, value); 682 } 683 684 /** 685 * Inserts a float array value into the mapping of this Bundle, replacing 686 * any existing value for the given key. Either key or value may be null. 687 * 688 * @param key a String, or null 689 * @param value a float array object, or null 690 */ 691 public void putFloatArray(String key, float[] value) { 692 unparcel(); 693 mMap.put(key, value); 694 } 695 696 /** 697 * Inserts a double array value into the mapping of this Bundle, replacing 698 * any existing value for the given key. Either key or value may be null. 699 * 700 * @param key a String, or null 701 * @param value a double array object, or null 702 */ 703 public void putDoubleArray(String key, double[] value) { 704 unparcel(); 705 mMap.put(key, value); 706 } 707 708 /** 709 * Inserts a String array value into the mapping of this Bundle, replacing 710 * any existing value for the given key. Either key or value may be null. 711 * 712 * @param key a String, or null 713 * @param value a String array object, or null 714 */ 715 public void putStringArray(String key, String[] value) { 716 unparcel(); 717 mMap.put(key, value); 718 } 719 720 /** 721 * Inserts a CharSequence array value into the mapping of this Bundle, replacing 722 * any existing value for the given key. Either key or value may be null. 723 * 724 * @param key a String, or null 725 * @param value a CharSequence array object, or null 726 */ 727 public void putCharSequenceArray(String key, CharSequence[] value) { 728 unparcel(); 729 mMap.put(key, value); 730 } 731 732 /** 733 * Inserts a Bundle value into the mapping of this Bundle, replacing 734 * any existing value for the given key. Either key or value may be null. 735 * 736 * @param key a String, or null 737 * @param value a Bundle object, or null 738 */ 739 public void putBundle(String key, Bundle value) { 740 unparcel(); 741 mMap.put(key, value); 742 } 743 744 /** 745 * Inserts an IBinder value into the mapping of this Bundle, replacing 746 * any existing value for the given key. Either key or value may be null. 747 * 748 * @param key a String, or null 749 * @param value an IBinder object, or null 750 * 751 * @deprecated 752 * @hide 753 */ 754 @Deprecated 755 public void putIBinder(String key, IBinder value) { 756 unparcel(); 757 mMap.put(key, value); 758 } 759 760 /** 761 * Returns the value associated with the given key, or false if 762 * no mapping of the desired type exists for the given key. 763 * 764 * @param key a String 765 * @return a boolean value 766 */ 767 public boolean getBoolean(String key) { 768 unparcel(); 769 return getBoolean(key, false); 770 } 771 772 // Log a message if the value was non-null but not of the expected type 773 private void typeWarning(String key, Object value, String className, 774 Object defaultValue, ClassCastException e) { 775 StringBuilder sb = new StringBuilder(); 776 sb.append("Key "); 777 sb.append(key); 778 sb.append(" expected "); 779 sb.append(className); 780 sb.append(" but value was a "); 781 sb.append(value.getClass().getName()); 782 sb.append(". The default value "); 783 sb.append(defaultValue); 784 sb.append(" was returned."); 785 Log.w(LOG_TAG, sb.toString()); 786 Log.w(LOG_TAG, "Attempt to cast generated internal exception:", e); 787 } 788 789 private void typeWarning(String key, Object value, String className, 790 ClassCastException e) { 791 typeWarning(key, value, className, "<null>", e); 792 } 793 794 /** 795 * Returns the value associated with the given key, or defaultValue if 796 * no mapping of the desired type exists for the given key. 797 * 798 * @param key a String 799 * @param defaultValue Value to return if key does not exist 800 * @return a boolean value 801 */ 802 public boolean getBoolean(String key, boolean defaultValue) { 803 unparcel(); 804 Object o = mMap.get(key); 805 if (o == null) { 806 return defaultValue; 807 } 808 try { 809 return (Boolean) o; 810 } catch (ClassCastException e) { 811 typeWarning(key, o, "Boolean", defaultValue, e); 812 return defaultValue; 813 } 814 } 815 816 /** 817 * Returns the value associated with the given key, or (byte) 0 if 818 * no mapping of the desired type exists for the given key. 819 * 820 * @param key a String 821 * @return a byte value 822 */ 823 public byte getByte(String key) { 824 unparcel(); 825 return getByte(key, (byte) 0); 826 } 827 828 /** 829 * Returns the value associated with the given key, or defaultValue if 830 * no mapping of the desired type exists for the given key. 831 * 832 * @param key a String 833 * @param defaultValue Value to return if key does not exist 834 * @return a byte value 835 */ 836 public Byte getByte(String key, byte defaultValue) { 837 unparcel(); 838 Object o = mMap.get(key); 839 if (o == null) { 840 return defaultValue; 841 } 842 try { 843 return (Byte) o; 844 } catch (ClassCastException e) { 845 typeWarning(key, o, "Byte", defaultValue, e); 846 return defaultValue; 847 } 848 } 849 850 /** 851 * Returns the value associated with the given key, or (char) 0 if 852 * no mapping of the desired type exists for the given key. 853 * 854 * @param key a String 855 * @return a char value 856 */ 857 public char getChar(String key) { 858 unparcel(); 859 return getChar(key, (char) 0); 860 } 861 862 /** 863 * Returns the value associated with the given key, or defaultValue if 864 * no mapping of the desired type exists for the given key. 865 * 866 * @param key a String 867 * @param defaultValue Value to return if key does not exist 868 * @return a char value 869 */ 870 public char getChar(String key, char defaultValue) { 871 unparcel(); 872 Object o = mMap.get(key); 873 if (o == null) { 874 return defaultValue; 875 } 876 try { 877 return (Character) o; 878 } catch (ClassCastException e) { 879 typeWarning(key, o, "Character", defaultValue, e); 880 return defaultValue; 881 } 882 } 883 884 /** 885 * Returns the value associated with the given key, or (short) 0 if 886 * no mapping of the desired type exists for the given key. 887 * 888 * @param key a String 889 * @return a short value 890 */ 891 public short getShort(String key) { 892 unparcel(); 893 return getShort(key, (short) 0); 894 } 895 896 /** 897 * Returns the value associated with the given key, or defaultValue if 898 * no mapping of the desired type exists for the given key. 899 * 900 * @param key a String 901 * @param defaultValue Value to return if key does not exist 902 * @return a short value 903 */ 904 public short getShort(String key, short defaultValue) { 905 unparcel(); 906 Object o = mMap.get(key); 907 if (o == null) { 908 return defaultValue; 909 } 910 try { 911 return (Short) o; 912 } catch (ClassCastException e) { 913 typeWarning(key, o, "Short", defaultValue, e); 914 return defaultValue; 915 } 916 } 917 918 /** 919 * Returns the value associated with the given key, or 0 if 920 * no mapping of the desired type exists for the given key. 921 * 922 * @param key a String 923 * @return an int value 924 */ 925 public int getInt(String key) { 926 unparcel(); 927 return getInt(key, 0); 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. 933 * 934 * @param key a String 935 * @param defaultValue Value to return if key does not exist 936 * @return an int value 937 */ 938 public int getInt(String key, int defaultValue) { 939 unparcel(); 940 Object o = mMap.get(key); 941 if (o == null) { 942 return defaultValue; 943 } 944 try { 945 return (Integer) o; 946 } catch (ClassCastException e) { 947 typeWarning(key, o, "Integer", defaultValue, e); 948 return defaultValue; 949 } 950 } 951 952 /** 953 * Returns the value associated with the given key, or 0L if 954 * no mapping of the desired type exists for the given key. 955 * 956 * @param key a String 957 * @return a long value 958 */ 959 public long getLong(String key) { 960 unparcel(); 961 return getLong(key, 0L); 962 } 963 964 /** 965 * Returns the value associated with the given key, or defaultValue if 966 * no mapping of the desired type exists for the given key. 967 * 968 * @param key a String 969 * @param defaultValue Value to return if key does not exist 970 * @return a long value 971 */ 972 public long getLong(String key, long defaultValue) { 973 unparcel(); 974 Object o = mMap.get(key); 975 if (o == null) { 976 return defaultValue; 977 } 978 try { 979 return (Long) o; 980 } catch (ClassCastException e) { 981 typeWarning(key, o, "Long", defaultValue, e); 982 return defaultValue; 983 } 984 } 985 986 /** 987 * Returns the value associated with the given key, or 0.0f if 988 * no mapping of the desired type exists for the given key. 989 * 990 * @param key a String 991 * @return a float value 992 */ 993 public float getFloat(String key) { 994 unparcel(); 995 return getFloat(key, 0.0f); 996 } 997 998 /** 999 * Returns the value associated with the given key, or defaultValue if 1000 * no mapping of the desired type exists for the given key. 1001 * 1002 * @param key a String 1003 * @param defaultValue Value to return if key does not exist 1004 * @return a float value 1005 */ 1006 public float getFloat(String key, float defaultValue) { 1007 unparcel(); 1008 Object o = mMap.get(key); 1009 if (o == null) { 1010 return defaultValue; 1011 } 1012 try { 1013 return (Float) o; 1014 } catch (ClassCastException e) { 1015 typeWarning(key, o, "Float", defaultValue, e); 1016 return defaultValue; 1017 } 1018 } 1019 1020 /** 1021 * Returns the value associated with the given key, or 0.0 if 1022 * no mapping of the desired type exists for the given key. 1023 * 1024 * @param key a String 1025 * @return a double value 1026 */ 1027 public double getDouble(String key) { 1028 unparcel(); 1029 return getDouble(key, 0.0); 1030 } 1031 1032 /** 1033 * Returns the value associated with the given key, or defaultValue if 1034 * no mapping of the desired type exists for the given key. 1035 * 1036 * @param key a String 1037 * @param defaultValue Value to return if key does not exist 1038 * @return a double value 1039 */ 1040 public double getDouble(String key, double defaultValue) { 1041 unparcel(); 1042 Object o = mMap.get(key); 1043 if (o == null) { 1044 return defaultValue; 1045 } 1046 try { 1047 return (Double) o; 1048 } catch (ClassCastException e) { 1049 typeWarning(key, o, "Double", defaultValue, e); 1050 return defaultValue; 1051 } 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 String value, or null 1061 */ 1062 public String getString(String key) { 1063 unparcel(); 1064 Object o = mMap.get(key); 1065 if (o == null) { 1066 return null; 1067 } 1068 try { 1069 return (String) o; 1070 } catch (ClassCastException e) { 1071 typeWarning(key, o, "String", e); 1072 return null; 1073 } 1074 } 1075 1076 /** 1077 * Returns the value associated with the given key, or defaultValue if 1078 * no mapping of the desired type exists for the given key. 1079 * 1080 * @param key a String, or null 1081 * @param defaultValue Value to return if key does not exist 1082 * @return a String value, or null 1083 */ 1084 public String getString(String key, String defaultValue) { 1085 unparcel(); 1086 Object o = mMap.get(key); 1087 if (o == null) { 1088 return defaultValue; 1089 } 1090 try { 1091 return (String) o; 1092 } catch (ClassCastException e) { 1093 typeWarning(key, o, "String", e); 1094 return defaultValue; 1095 } 1096 } 1097 1098 /** 1099 * Returns the value associated with the given key, or null if 1100 * no mapping of the desired type exists for the given key or a null 1101 * value is explicitly associated with the key. 1102 * 1103 * @param key a String, or null 1104 * @return a CharSequence value, or null 1105 */ 1106 public CharSequence getCharSequence(String key) { 1107 unparcel(); 1108 Object o = mMap.get(key); 1109 if (o == null) { 1110 return null; 1111 } 1112 try { 1113 return (CharSequence) o; 1114 } catch (ClassCastException e) { 1115 typeWarning(key, o, "CharSequence", e); 1116 return null; 1117 } 1118 } 1119 1120 /** 1121 * Returns the value associated with the given key, or defaultValue if 1122 * no mapping of the desired type exists for the given key. 1123 * 1124 * @param key a String, or null 1125 * @param defaultValue Value to return if key does not exist 1126 * @return a CharSequence value, or null 1127 */ 1128 public CharSequence getCharSequence(String key, CharSequence defaultValue) { 1129 unparcel(); 1130 Object o = mMap.get(key); 1131 if (o == null) { 1132 return defaultValue; 1133 } 1134 try { 1135 return (CharSequence) o; 1136 } catch (ClassCastException e) { 1137 typeWarning(key, o, "CharSequence", e); 1138 return defaultValue; 1139 } 1140 } 1141 1142 /** 1143 * Returns the value associated with the given key, or null if 1144 * no mapping of the desired type exists for the given key or a null 1145 * value is explicitly associated with the key. 1146 * 1147 * @param key a String, or null 1148 * @return a Bundle value, or null 1149 */ 1150 public Bundle getBundle(String key) { 1151 unparcel(); 1152 Object o = mMap.get(key); 1153 if (o == null) { 1154 return null; 1155 } 1156 try { 1157 return (Bundle) o; 1158 } catch (ClassCastException e) { 1159 typeWarning(key, o, "Bundle", e); 1160 return null; 1161 } 1162 } 1163 1164 /** 1165 * Returns the value associated with the given key, or null if 1166 * no mapping of the desired type exists for the given key or a null 1167 * value is explicitly associated with the key. 1168 * 1169 * @param key a String, or null 1170 * @return a Parcelable value, or null 1171 */ 1172 public <T extends Parcelable> T getParcelable(String key) { 1173 unparcel(); 1174 Object o = mMap.get(key); 1175 if (o == null) { 1176 return null; 1177 } 1178 try { 1179 return (T) o; 1180 } catch (ClassCastException e) { 1181 typeWarning(key, o, "Parcelable", e); 1182 return null; 1183 } 1184 } 1185 1186 /** 1187 * Returns the value associated with the given key, or null if 1188 * no mapping of the desired type exists for the given key or a null 1189 * value is explicitly associated with the key. 1190 * 1191 * @param key a String, or null 1192 * @return a Parcelable[] value, or null 1193 */ 1194 public Parcelable[] getParcelableArray(String key) { 1195 unparcel(); 1196 Object o = mMap.get(key); 1197 if (o == null) { 1198 return null; 1199 } 1200 try { 1201 return (Parcelable[]) o; 1202 } catch (ClassCastException e) { 1203 typeWarning(key, o, "Parcelable[]", e); 1204 return null; 1205 } 1206 } 1207 1208 /** 1209 * Returns the value associated with the given key, or null if 1210 * no mapping of the desired type exists for the given key or a null 1211 * value is explicitly associated with the key. 1212 * 1213 * @param key a String, or null 1214 * @return an ArrayList<T> value, or null 1215 */ 1216 public <T extends Parcelable> ArrayList<T> getParcelableArrayList(String key) { 1217 unparcel(); 1218 Object o = mMap.get(key); 1219 if (o == null) { 1220 return null; 1221 } 1222 try { 1223 return (ArrayList<T>) o; 1224 } catch (ClassCastException e) { 1225 typeWarning(key, o, "ArrayList", e); 1226 return null; 1227 } 1228 } 1229 1230 /** 1231 * Returns the value associated with the given key, or null if 1232 * no mapping of the desired type exists for the given key or a null 1233 * value is explicitly associated with the key. 1234 * 1235 * @param key a String, or null 1236 * 1237 * @return a SparseArray of T values, or null 1238 */ 1239 public <T extends Parcelable> SparseArray<T> getSparseParcelableArray(String key) { 1240 unparcel(); 1241 Object o = mMap.get(key); 1242 if (o == null) { 1243 return null; 1244 } 1245 try { 1246 return (SparseArray<T>) o; 1247 } catch (ClassCastException e) { 1248 typeWarning(key, o, "SparseArray", e); 1249 return null; 1250 } 1251 } 1252 1253 /** 1254 * Returns the value associated with the given key, or null if 1255 * no mapping of the desired type exists for the given key or a null 1256 * value is explicitly associated with the key. 1257 * 1258 * @param key a String, or null 1259 * @return a Serializable value, or null 1260 */ 1261 public Serializable getSerializable(String key) { 1262 unparcel(); 1263 Object o = mMap.get(key); 1264 if (o == null) { 1265 return null; 1266 } 1267 try { 1268 return (Serializable) o; 1269 } catch (ClassCastException e) { 1270 typeWarning(key, o, "Serializable", e); 1271 return null; 1272 } 1273 } 1274 1275 /** 1276 * Returns the value associated with the given key, or null if 1277 * no mapping of the desired type exists for the given key or a null 1278 * value is explicitly associated with the key. 1279 * 1280 * @param key a String, or null 1281 * @return an ArrayList<String> value, or null 1282 */ 1283 public ArrayList<Integer> getIntegerArrayList(String key) { 1284 unparcel(); 1285 Object o = mMap.get(key); 1286 if (o == null) { 1287 return null; 1288 } 1289 try { 1290 return (ArrayList<Integer>) o; 1291 } catch (ClassCastException e) { 1292 typeWarning(key, o, "ArrayList<Integer>", e); 1293 return null; 1294 } 1295 } 1296 1297 /** 1298 * Returns the value associated with the given key, or null if 1299 * no mapping of the desired type exists for the given key or a null 1300 * value is explicitly associated with the key. 1301 * 1302 * @param key a String, or null 1303 * @return an ArrayList<String> value, or null 1304 */ 1305 public ArrayList<String> getStringArrayList(String key) { 1306 unparcel(); 1307 Object o = mMap.get(key); 1308 if (o == null) { 1309 return null; 1310 } 1311 try { 1312 return (ArrayList<String>) o; 1313 } catch (ClassCastException e) { 1314 typeWarning(key, o, "ArrayList<String>", e); 1315 return null; 1316 } 1317 } 1318 1319 /** 1320 * Returns the value associated with the given key, or null if 1321 * no mapping of the desired type exists for the given key or a null 1322 * value is explicitly associated with the key. 1323 * 1324 * @param key a String, or null 1325 * @return an ArrayList<CharSequence> value, or null 1326 */ 1327 public ArrayList<CharSequence> getCharSequenceArrayList(String key) { 1328 unparcel(); 1329 Object o = mMap.get(key); 1330 if (o == null) { 1331 return null; 1332 } 1333 try { 1334 return (ArrayList<CharSequence>) o; 1335 } catch (ClassCastException e) { 1336 typeWarning(key, o, "ArrayList<CharSequence>", e); 1337 return null; 1338 } 1339 } 1340 1341 /** 1342 * Returns the value associated with the given key, or null if 1343 * no mapping of the desired type exists for the given key or a null 1344 * value is explicitly associated with the key. 1345 * 1346 * @param key a String, or null 1347 * @return a boolean[] value, or null 1348 */ 1349 public boolean[] getBooleanArray(String key) { 1350 unparcel(); 1351 Object o = mMap.get(key); 1352 if (o == null) { 1353 return null; 1354 } 1355 try { 1356 return (boolean[]) o; 1357 } catch (ClassCastException e) { 1358 typeWarning(key, o, "byte[]", e); 1359 return null; 1360 } 1361 } 1362 1363 /** 1364 * Returns the value associated with the given key, or null if 1365 * no mapping of the desired type exists for the given key or a null 1366 * value is explicitly associated with the key. 1367 * 1368 * @param key a String, or null 1369 * @return a byte[] value, or null 1370 */ 1371 public byte[] getByteArray(String key) { 1372 unparcel(); 1373 Object o = mMap.get(key); 1374 if (o == null) { 1375 return null; 1376 } 1377 try { 1378 return (byte[]) o; 1379 } catch (ClassCastException e) { 1380 typeWarning(key, o, "byte[]", e); 1381 return null; 1382 } 1383 } 1384 1385 /** 1386 * Returns the value associated with the given key, or null if 1387 * no mapping of the desired type exists for the given key or a null 1388 * value is explicitly associated with the key. 1389 * 1390 * @param key a String, or null 1391 * @return a short[] value, or null 1392 */ 1393 public short[] getShortArray(String key) { 1394 unparcel(); 1395 Object o = mMap.get(key); 1396 if (o == null) { 1397 return null; 1398 } 1399 try { 1400 return (short[]) o; 1401 } catch (ClassCastException e) { 1402 typeWarning(key, o, "short[]", e); 1403 return null; 1404 } 1405 } 1406 1407 /** 1408 * Returns the value associated with the given key, or null if 1409 * no mapping of the desired type exists for the given key or a null 1410 * value is explicitly associated with the key. 1411 * 1412 * @param key a String, or null 1413 * @return a char[] value, or null 1414 */ 1415 public char[] getCharArray(String key) { 1416 unparcel(); 1417 Object o = mMap.get(key); 1418 if (o == null) { 1419 return null; 1420 } 1421 try { 1422 return (char[]) o; 1423 } catch (ClassCastException e) { 1424 typeWarning(key, o, "char[]", e); 1425 return null; 1426 } 1427 } 1428 1429 /** 1430 * Returns the value associated with the given key, or null if 1431 * no mapping of the desired type exists for the given key or a null 1432 * value is explicitly associated with the key. 1433 * 1434 * @param key a String, or null 1435 * @return an int[] value, or null 1436 */ 1437 public int[] getIntArray(String key) { 1438 unparcel(); 1439 Object o = mMap.get(key); 1440 if (o == null) { 1441 return null; 1442 } 1443 try { 1444 return (int[]) o; 1445 } catch (ClassCastException e) { 1446 typeWarning(key, o, "int[]", e); 1447 return null; 1448 } 1449 } 1450 1451 /** 1452 * Returns the value associated with the given key, or null if 1453 * no mapping of the desired type exists for the given key or a null 1454 * value is explicitly associated with the key. 1455 * 1456 * @param key a String, or null 1457 * @return a long[] value, or null 1458 */ 1459 public long[] getLongArray(String key) { 1460 unparcel(); 1461 Object o = mMap.get(key); 1462 if (o == null) { 1463 return null; 1464 } 1465 try { 1466 return (long[]) o; 1467 } catch (ClassCastException e) { 1468 typeWarning(key, o, "long[]", e); 1469 return null; 1470 } 1471 } 1472 1473 /** 1474 * Returns the value associated with the given key, or null if 1475 * no mapping of the desired type exists for the given key or a null 1476 * value is explicitly associated with the key. 1477 * 1478 * @param key a String, or null 1479 * @return a float[] value, or null 1480 */ 1481 public float[] getFloatArray(String key) { 1482 unparcel(); 1483 Object o = mMap.get(key); 1484 if (o == null) { 1485 return null; 1486 } 1487 try { 1488 return (float[]) o; 1489 } catch (ClassCastException e) { 1490 typeWarning(key, o, "float[]", e); 1491 return null; 1492 } 1493 } 1494 1495 /** 1496 * Returns the value associated with the given key, or null if 1497 * no mapping of the desired type exists for the given key or a null 1498 * value is explicitly associated with the key. 1499 * 1500 * @param key a String, or null 1501 * @return a double[] value, or null 1502 */ 1503 public double[] getDoubleArray(String key) { 1504 unparcel(); 1505 Object o = mMap.get(key); 1506 if (o == null) { 1507 return null; 1508 } 1509 try { 1510 return (double[]) o; 1511 } catch (ClassCastException e) { 1512 typeWarning(key, o, "double[]", e); 1513 return null; 1514 } 1515 } 1516 1517 /** 1518 * Returns the value associated with the given key, or null if 1519 * no mapping of the desired type exists for the given key or a null 1520 * value is explicitly associated with the key. 1521 * 1522 * @param key a String, or null 1523 * @return a String[] value, or null 1524 */ 1525 public String[] getStringArray(String key) { 1526 unparcel(); 1527 Object o = mMap.get(key); 1528 if (o == null) { 1529 return null; 1530 } 1531 try { 1532 return (String[]) o; 1533 } catch (ClassCastException e) { 1534 typeWarning(key, o, "String[]", e); 1535 return null; 1536 } 1537 } 1538 1539 /** 1540 * Returns the value associated with the given key, or null if 1541 * no mapping of the desired type exists for the given key or a null 1542 * value is explicitly associated with the key. 1543 * 1544 * @param key a String, or null 1545 * @return a CharSequence[] value, or null 1546 */ 1547 public CharSequence[] getCharSequenceArray(String key) { 1548 unparcel(); 1549 Object o = mMap.get(key); 1550 if (o == null) { 1551 return null; 1552 } 1553 try { 1554 return (CharSequence[]) o; 1555 } catch (ClassCastException e) { 1556 typeWarning(key, o, "CharSequence[]", e); 1557 return null; 1558 } 1559 } 1560 1561 /** 1562 * Returns the value associated with the given key, or null if 1563 * no mapping of the desired type exists for the given key or a null 1564 * value is explicitly associated with the key. 1565 * 1566 * @param key a String, or null 1567 * @return an IBinder value, or null 1568 * 1569 * @deprecated 1570 * @hide 1571 */ 1572 @Deprecated 1573 public IBinder getIBinder(String key) { 1574 unparcel(); 1575 Object o = mMap.get(key); 1576 if (o == null) { 1577 return null; 1578 } 1579 try { 1580 return (IBinder) o; 1581 } catch (ClassCastException e) { 1582 typeWarning(key, o, "IBinder", e); 1583 return null; 1584 } 1585 } 1586 1587 public static final Parcelable.Creator<Bundle> CREATOR = 1588 new Parcelable.Creator<Bundle>() { 1589 public Bundle createFromParcel(Parcel in) { 1590 return in.readBundle(); 1591 } 1592 1593 public Bundle[] newArray(int size) { 1594 return new Bundle[size]; 1595 } 1596 }; 1597 1598 /** 1599 * Report the nature of this Parcelable's contents 1600 */ 1601 public int describeContents() { 1602 int mask = 0; 1603 if (hasFileDescriptors()) { 1604 mask |= Parcelable.CONTENTS_FILE_DESCRIPTOR; 1605 } 1606 return mask; 1607 } 1608 1609 /** 1610 * Writes the Bundle contents to a Parcel, typically in order for 1611 * it to be passed through an IBinder connection. 1612 * @param parcel The parcel to copy this bundle to. 1613 */ 1614 public void writeToParcel(Parcel parcel, int flags) { 1615 final boolean oldAllowFds = parcel.pushAllowFds(mAllowFds); 1616 try { 1617 if (mParcelledData != null) { 1618 int length = mParcelledData.dataSize(); 1619 parcel.writeInt(length); 1620 parcel.writeInt(0x4C444E42); // 'B' 'N' 'D' 'L' 1621 parcel.appendFrom(mParcelledData, 0, length); 1622 } else { 1623 parcel.writeInt(-1); // dummy, will hold length 1624 parcel.writeInt(0x4C444E42); // 'B' 'N' 'D' 'L' 1625 1626 int oldPos = parcel.dataPosition(); 1627 parcel.writeMapInternal(mMap); 1628 int newPos = parcel.dataPosition(); 1629 1630 // Backpatch length 1631 parcel.setDataPosition(oldPos - 8); 1632 int length = newPos - oldPos; 1633 parcel.writeInt(length); 1634 parcel.setDataPosition(newPos); 1635 } 1636 } finally { 1637 parcel.restoreAllowFds(oldAllowFds); 1638 } 1639 } 1640 1641 /** 1642 * Reads the Parcel contents into this Bundle, typically in order for 1643 * it to be passed through an IBinder connection. 1644 * @param parcel The parcel to overwrite this bundle from. 1645 */ 1646 public void readFromParcel(Parcel parcel) { 1647 int length = parcel.readInt(); 1648 if (length < 0) { 1649 throw new RuntimeException("Bad length in parcel: " + length); 1650 } 1651 readFromParcelInner(parcel, length); 1652 } 1653 1654 void readFromParcelInner(Parcel parcel, int length) { 1655 int magic = parcel.readInt(); 1656 if (magic != 0x4C444E42) { 1657 //noinspection ThrowableInstanceNeverThrown 1658 String st = Log.getStackTraceString(new RuntimeException()); 1659 Log.e("Bundle", "readBundle: bad magic number"); 1660 Log.e("Bundle", "readBundle: trace = " + st); 1661 } 1662 1663 // Advance within this Parcel 1664 int offset = parcel.dataPosition(); 1665 parcel.setDataPosition(offset + length); 1666 1667 Parcel p = Parcel.obtain(); 1668 p.setDataPosition(0); 1669 p.appendFrom(parcel, offset, length); 1670 p.setDataPosition(0); 1671 1672 mParcelledData = p; 1673 mHasFds = p.hasFileDescriptors(); 1674 mFdsKnown = true; 1675 } 1676 1677 @Override 1678 public synchronized String toString() { 1679 if (mParcelledData != null) { 1680 return "Bundle[mParcelledData.dataSize=" + 1681 mParcelledData.dataSize() + "]"; 1682 } 1683 return "Bundle[" + mMap.toString() + "]"; 1684 } 1685} 1686