PersistableBundle.java revision 21d24a21ea4aaadd78e73de54168e8a8a8973e4d
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 17package android.os; 18 19import android.util.ArrayMap; 20import com.android.internal.util.XmlUtils; 21import org.xmlpull.v1.XmlPullParser; 22import org.xmlpull.v1.XmlPullParserException; 23import org.xmlpull.v1.XmlSerializer; 24 25import java.io.IOException; 26import java.util.Iterator; 27import java.util.Map; 28import java.util.Set; 29 30/** 31 * A mapping from String values to various types that can be saved to persistent and later 32 * restored. 33 * 34 */ 35public final class PersistableBundle extends CommonBundle implements XmlUtils.WriteMapCallback { 36 private static final String TAG_PERSISTABLEMAP = "pbundle_as_map"; 37 public static final PersistableBundle EMPTY; 38 static final Parcel EMPTY_PARCEL; 39 40 static { 41 EMPTY = new PersistableBundle(); 42 EMPTY.mMap = ArrayMap.EMPTY; 43 EMPTY_PARCEL = CommonBundle.EMPTY_PARCEL; 44 } 45 46 /** 47 * Constructs a new, empty PersistableBundle. 48 */ 49 public PersistableBundle() { 50 super(); 51 } 52 53 /** 54 * Constructs a PersistableBundle whose data is stored as a Parcel. The data 55 * will be unparcelled on first contact, using the assigned ClassLoader. 56 * 57 * @param parcelledData a Parcel containing a PersistableBundle 58 */ 59 PersistableBundle(Parcel parcelledData) { 60 super(parcelledData); 61 } 62 63 /* package */ PersistableBundle(Parcel parcelledData, int length) { 64 super(parcelledData, length); 65 } 66 67 /** 68 * Constructs a new, empty PersistableBundle that uses a specific ClassLoader for 69 * instantiating Parcelable and Serializable objects. 70 * 71 * @param loader An explicit ClassLoader to use when instantiating objects 72 * inside of the PersistableBundle. 73 */ 74 public PersistableBundle(ClassLoader loader) { 75 super(loader); 76 } 77 78 /** 79 * Constructs a new, empty PersistableBundle sized to hold the given number of 80 * elements. The PersistableBundle will grow as needed. 81 * 82 * @param capacity the initial capacity of the PersistableBundle 83 */ 84 public PersistableBundle(int capacity) { 85 super(capacity); 86 } 87 88 /** 89 * Constructs a PersistableBundle containing a copy of the mappings from the given 90 * PersistableBundle. 91 * 92 * @param b a PersistableBundle to be copied. 93 */ 94 public PersistableBundle(PersistableBundle b) { 95 super(b); 96 } 97 98 /** 99 * Constructs a PersistableBundle containing the mappings passed in. 100 * 101 * @param map a Map containing only those items that can be persisted. 102 * @throws IllegalArgumentException if any element of #map cannot be persisted. 103 */ 104 private PersistableBundle(Map<String, Object> map) { 105 super(); 106 107 // First stuff everything in. 108 putAll(map); 109 110 // Now verify each item throwing an exception if there is a violation. 111 Set<String> keys = map.keySet(); 112 Iterator<String> iterator = keys.iterator(); 113 while (iterator.hasNext()) { 114 String key = iterator.next(); 115 Object value = map.get(key); 116 if (value instanceof Map) { 117 // Fix up any Maps by replacing them with PersistableBundles. 118 putPersistableBundle(key, new PersistableBundle((Map<String, Object>) value)); 119 } else if (!(value instanceof Integer) && !(value instanceof Long) && 120 !(value instanceof Double) && !(value instanceof String) && 121 !(value instanceof int[]) && !(value instanceof long[]) && 122 !(value instanceof double[]) && !(value instanceof String[]) && 123 !(value instanceof PersistableBundle) && (value != null)) { 124 throw new IllegalArgumentException("Bad value in PersistableBundle key=" + key + 125 " value=" + value); 126 } 127 } 128 } 129 130 /** 131 * Make a PersistableBundle for a single key/value pair. 132 * 133 * @hide 134 */ 135 public static PersistableBundle forPair(String key, String value) { 136 PersistableBundle b = new PersistableBundle(1); 137 b.putString(key, value); 138 return b; 139 } 140 141 /** 142 * @hide 143 */ 144 @Override 145 public String getPairValue() { 146 return super.getPairValue(); 147 } 148 149 /** 150 * Changes the ClassLoader this PersistableBundle uses when instantiating objects. 151 * 152 * @param loader An explicit ClassLoader to use when instantiating objects 153 * inside of the PersistableBundle. 154 */ 155 @Override 156 public void setClassLoader(ClassLoader loader) { 157 super.setClassLoader(loader); 158 } 159 160 /** 161 * Return the ClassLoader currently associated with this PersistableBundle. 162 */ 163 @Override 164 public ClassLoader getClassLoader() { 165 return super.getClassLoader(); 166 } 167 168 /** 169 * Clones the current PersistableBundle. The internal map is cloned, but the keys and 170 * values to which it refers are copied by reference. 171 */ 172 @Override 173 public Object clone() { 174 return new PersistableBundle(this); 175 } 176 177 /** 178 * @hide 179 */ 180 @Override 181 public boolean isParcelled() { 182 return super.isParcelled(); 183 } 184 185 /** 186 * Returns the number of mappings contained in this PersistableBundle. 187 * 188 * @return the number of mappings as an int. 189 */ 190 @Override 191 public int size() { 192 return super.size(); 193 } 194 195 /** 196 * Returns true if the mapping of this PersistableBundle is empty, false otherwise. 197 */ 198 @Override 199 public boolean isEmpty() { 200 return super.isEmpty(); 201 } 202 203 /** 204 * Removes all elements from the mapping of this PersistableBundle. 205 */ 206 @Override 207 public void clear() { 208 super.clear(); 209 } 210 211 /** 212 * Returns true if the given key is contained in the mapping 213 * of this PersistableBundle. 214 * 215 * @param key a String key 216 * @return true if the key is part of the mapping, false otherwise 217 */ 218 @Override 219 public boolean containsKey(String key) { 220 return super.containsKey(key); 221 } 222 223 /** 224 * Returns the entry with the given key as an object. 225 * 226 * @param key a String key 227 * @return an Object, or null 228 */ 229 @Override 230 public Object get(String key) { 231 return super.get(key); 232 } 233 234 /** 235 * Removes any entry with the given key from the mapping of this PersistableBundle. 236 * 237 * @param key a String key 238 */ 239 @Override 240 public void remove(String key) { 241 super.remove(key); 242 } 243 244 /** 245 * Inserts all mappings from the given PersistableBundle into this Bundle. 246 * 247 * @param bundle a PersistableBundle 248 */ 249 @Override 250 public void putAll(PersistableBundle bundle) { 251 super.putAll(bundle); 252 } 253 254 /** 255 * Returns a Set containing the Strings used as keys in this PersistableBundle. 256 * 257 * @return a Set of String keys 258 */ 259 @Override 260 public Set<String> keySet() { 261 return super.keySet(); 262 } 263 264 /** 265 * Inserts an int value into the mapping of this PersistableBundle, replacing 266 * any existing value for the given key. 267 * 268 * @param key a String, or null 269 * @param value an int, or null 270 */ 271 @Override 272 public void putInt(String key, int value) { 273 super.putInt(key, value); 274 } 275 276 /** 277 * Inserts a long value into the mapping of this PersistableBundle, replacing 278 * any existing value for the given key. 279 * 280 * @param key a String, or null 281 * @param value a long 282 */ 283 @Override 284 public void putLong(String key, long value) { 285 super.putLong(key, value); 286 } 287 288 /** 289 * Inserts a double value into the mapping of this PersistableBundle, replacing 290 * any existing value for the given key. 291 * 292 * @param key a String, or null 293 * @param value a double 294 */ 295 @Override 296 public void putDouble(String key, double value) { 297 super.putDouble(key, value); 298 } 299 300 /** 301 * Inserts a String value into the mapping of this PersistableBundle, replacing 302 * any existing value for the given key. Either key or value may be null. 303 * 304 * @param key a String, or null 305 * @param value a String, or null 306 */ 307 @Override 308 public void putString(String key, String value) { 309 super.putString(key, value); 310 } 311 312 /** 313 * Inserts an int array value into the mapping of this PersistableBundle, replacing 314 * any existing value for the given key. Either key or value may be null. 315 * 316 * @param key a String, or null 317 * @param value an int array object, or null 318 */ 319 @Override 320 public void putIntArray(String key, int[] value) { 321 super.putIntArray(key, value); 322 } 323 324 /** 325 * Inserts a long array value into the mapping of this PersistableBundle, replacing 326 * any existing value for the given key. Either key or value may be null. 327 * 328 * @param key a String, or null 329 * @param value a long array object, or null 330 */ 331 @Override 332 public void putLongArray(String key, long[] value) { 333 super.putLongArray(key, value); 334 } 335 336 /** 337 * Inserts a double array value into the mapping of this PersistableBundle, replacing 338 * any existing value for the given key. Either key or value may be null. 339 * 340 * @param key a String, or null 341 * @param value a double array object, or null 342 */ 343 @Override 344 public void putDoubleArray(String key, double[] value) { 345 super.putDoubleArray(key, value); 346 } 347 348 /** 349 * Inserts a String array value into the mapping of this PersistableBundle, replacing 350 * any existing value for the given key. Either key or value may be null. 351 * 352 * @param key a String, or null 353 * @param value a String array object, or null 354 */ 355 @Override 356 public void putStringArray(String key, String[] value) { 357 super.putStringArray(key, value); 358 } 359 360 /** 361 * Inserts a PersistableBundle value into the mapping of this Bundle, replacing 362 * any existing value for the given key. Either key or value may be null. 363 * 364 * @param key a String, or null 365 * @param value a Bundle object, or null 366 */ 367 @Override 368 public void putPersistableBundle(String key, PersistableBundle value) { 369 super.putPersistableBundle(key, value); 370 } 371 372 /** 373 * Returns the value associated with the given key, or 0 if 374 * no mapping of the desired type exists for the given key. 375 * 376 * @param key a String 377 * @return an int value 378 */ 379 @Override 380 public int getInt(String key) { 381 return super.getInt(key); 382 } 383 384 /** 385 * Returns the value associated with the given key, or defaultValue if 386 * no mapping of the desired type exists for the given key. 387 * 388 * @param key a String 389 * @param defaultValue Value to return if key does not exist 390 * @return an int value 391 */ 392 @Override 393 public int getInt(String key, int defaultValue) { 394 return super.getInt(key, defaultValue); 395 } 396 397 /** 398 * Returns the value associated with the given key, or 0L if 399 * no mapping of the desired type exists for the given key. 400 * 401 * @param key a String 402 * @return a long value 403 */ 404 @Override 405 public long getLong(String key) { 406 return super.getLong(key); 407 } 408 409 /** 410 * Returns the value associated with the given key, or defaultValue if 411 * no mapping of the desired type exists for the given key. 412 * 413 * @param key a String 414 * @param defaultValue Value to return if key does not exist 415 * @return a long value 416 */ 417 @Override 418 public long getLong(String key, long defaultValue) { 419 return super.getLong(key, defaultValue); 420 } 421 422 /** 423 * Returns the value associated with the given key, or 0.0 if 424 * no mapping of the desired type exists for the given key. 425 * 426 * @param key a String 427 * @return a double value 428 */ 429 @Override 430 public double getDouble(String key) { 431 return super.getDouble(key); 432 } 433 434 /** 435 * Returns the value associated with the given key, or defaultValue if 436 * no mapping of the desired type exists for the given key. 437 * 438 * @param key a String 439 * @param defaultValue Value to return if key does not exist 440 * @return a double value 441 */ 442 @Override 443 public double getDouble(String key, double defaultValue) { 444 return super.getDouble(key, defaultValue); 445 } 446 447 /** 448 * Returns the value associated with the given key, or null if 449 * no mapping of the desired type exists for the given key or a null 450 * value is explicitly associated with the key. 451 * 452 * @param key a String, or null 453 * @return a String value, or null 454 */ 455 @Override 456 public String getString(String key) { 457 return super.getString(key); 458 } 459 460 /** 461 * Returns the value associated with the given key, or defaultValue if 462 * no mapping of the desired type exists for the given key. 463 * 464 * @param key a String, or null 465 * @param defaultValue Value to return if key does not exist 466 * @return the String value associated with the given key, or defaultValue 467 * if no valid String object is currently mapped to that key. 468 */ 469 @Override 470 public String getString(String key, String defaultValue) { 471 return super.getString(key, defaultValue); 472 } 473 474 /** 475 * Returns the value associated with the given key, or null if 476 * no mapping of the desired type exists for the given key or a null 477 * value is explicitly associated with the key. 478 * 479 * @param key a String, or null 480 * @return a Bundle value, or null 481 */ 482 @Override 483 public PersistableBundle getPersistableBundle(String key) { 484 return super.getPersistableBundle(key); 485 } 486 487 /** 488 * Returns the value associated with the given key, or null if 489 * no mapping of the desired type exists for the given key or a null 490 * value is explicitly associated with the key. 491 * 492 * @param key a String, or null 493 * @return an int[] value, or null 494 */ 495 @Override 496 public int[] getIntArray(String key) { 497 return super.getIntArray(key); 498 } 499 500 /** 501 * Returns the value associated with the given key, or null if 502 * no mapping of the desired type exists for the given key or a null 503 * value is explicitly associated with the key. 504 * 505 * @param key a String, or null 506 * @return a long[] value, or null 507 */ 508 @Override 509 public long[] getLongArray(String key) { 510 return super.getLongArray(key); 511 } 512 513 /** 514 * Returns the value associated with the given key, or null if 515 * no mapping of the desired type exists for the given key or a null 516 * value is explicitly associated with the key. 517 * 518 * @param key a String, or null 519 * @return a double[] value, or null 520 */ 521 @Override 522 public double[] getDoubleArray(String key) { 523 return super.getDoubleArray(key); 524 } 525 526 /** 527 * Returns the value associated with the given key, or null if 528 * no mapping of the desired type exists for the given key or a null 529 * value is explicitly associated with the key. 530 * 531 * @param key a String, or null 532 * @return a String[] value, or null 533 */ 534 @Override 535 public String[] getStringArray(String key) { 536 return super.getStringArray(key); 537 } 538 539 public static final Parcelable.Creator<PersistableBundle> CREATOR = 540 new Parcelable.Creator<PersistableBundle>() { 541 @Override 542 public PersistableBundle createFromParcel(Parcel in) { 543 return in.readPersistableBundle(); 544 } 545 546 @Override 547 public PersistableBundle[] newArray(int size) { 548 return new PersistableBundle[size]; 549 } 550 }; 551 552 /** 553 * Report the nature of this Parcelable's contents 554 */ 555 @Override 556 public int describeContents() { 557 return 0; 558 } 559 560 /** 561 * Writes the PersistableBundle contents to a Parcel, typically in order for 562 * it to be passed through an IBinder connection. 563 * @param parcel The parcel to copy this bundle to. 564 */ 565 @Override 566 public void writeToParcel(Parcel parcel, int flags) { 567 final boolean oldAllowFds = parcel.pushAllowFds(false); 568 try { 569 super.writeToParcelInner(parcel, flags); 570 } finally { 571 parcel.restoreAllowFds(oldAllowFds); 572 } 573 } 574 575 /** 576 * Reads the Parcel contents into this PersistableBundle, typically in order for 577 * it to be passed through an IBinder connection. 578 * @param parcel The parcel to overwrite this bundle from. 579 */ 580 public void readFromParcel(Parcel parcel) { 581 super.readFromParcelInner(parcel); 582 } 583 584 /** @hide */ 585 @Override 586 public void writeUnknownObject(Object v, String name, XmlSerializer out) 587 throws XmlPullParserException, IOException { 588 if (v instanceof PersistableBundle) { 589 out.startTag(null, TAG_PERSISTABLEMAP); 590 out.attribute(null, "name", name); 591 ((PersistableBundle) v).saveToXml(out); 592 out.endTag(null, TAG_PERSISTABLEMAP); 593 } else { 594 throw new XmlPullParserException("Unknown Object o=" + v); 595 } 596 } 597 598 /** @hide */ 599 public void saveToXml(XmlSerializer out) throws IOException, XmlPullParserException { 600 unparcel(); 601 XmlUtils.writeMapXml(mMap, out, this); 602 } 603 604 /** @hide */ 605 static class MyReadMapCallback implements XmlUtils.ReadMapCallback { 606 @Override 607 public Object readThisUnknownObjectXml(XmlPullParser in, String tag) 608 throws XmlPullParserException, IOException { 609 if (TAG_PERSISTABLEMAP.equals(tag)) { 610 return restoreFromXml(in); 611 } 612 throw new XmlPullParserException("Unknown tag=" + tag); 613 } 614 } 615 616 /** 617 * @hide 618 */ 619 public static PersistableBundle restoreFromXml(XmlPullParser in) throws IOException, 620 XmlPullParserException { 621 final int outerDepth = in.getDepth(); 622 final String startTag = in.getName(); 623 final String[] tagName = new String[1]; 624 int event; 625 while (((event = in.next()) != XmlPullParser.END_DOCUMENT) && 626 (event != XmlPullParser.END_TAG || in.getDepth() < outerDepth)) { 627 if (event == XmlPullParser.START_TAG) { 628 return new PersistableBundle((Map<String, Object>) 629 XmlUtils.readThisMapXml(in, startTag, tagName, new MyReadMapCallback())); 630 } 631 } 632 return EMPTY; 633 } 634 635 @Override 636 synchronized public String toString() { 637 if (mParcelledData != null) { 638 if (mParcelledData == EMPTY_PARCEL) { 639 return "PersistableBundle[EMPTY_PARCEL]"; 640 } else { 641 return "PersistableBundle[mParcelledData.dataSize=" + 642 mParcelledData.dataSize() + "]"; 643 } 644 } 645 return "PersistableBundle[" + mMap.toString() + "]"; 646 } 647 648} 649