1 package com.xtremelabs.robolectric.shadows; 2 3 import android.content.ComponentName; 4 import android.content.Context; 5 import android.content.Intent; 6 import android.net.Uri; 7 import android.os.Bundle; 8 import android.os.Parcel; 9 import android.os.Parcelable; 10 import android.os.Parcelable.Creator; 11 12 import com.xtremelabs.robolectric.Robolectric; 13 import com.xtremelabs.robolectric.internal.Implementation; 14 import com.xtremelabs.robolectric.internal.Implements; 15 import com.xtremelabs.robolectric.internal.RealObject; 16 import com.xtremelabs.robolectric.util.Join; 17 18 import java.io.*; 19 import java.util.*; 20 21 import static android.content.Intent.*; 22 import static com.xtremelabs.robolectric.Robolectric.shadowOf; 23 24 @SuppressWarnings({"UnusedDeclaration"}) 25 @Implements(Intent.class) 26 public class ShadowIntent { 27 @RealObject private Intent realIntent; 28 29 private final Bundle extras = new Bundle(); 30 private String action; 31 private ComponentName componentName; 32 private String type; 33 private Uri data; 34 private int flags; 35 private Class<?> intentClass; 36 private String packageName; 37 private final Set<String> categories = new HashSet<String>(); 38 39 public void __constructor__(Context packageContext, Class cls) { 40 componentName = new ComponentName(packageContext, cls); 41 intentClass = cls; 42 } 43 44 public void __constructor__(String action, Uri uri) { 45 this.action = action; 46 data = uri; 47 } 48 49 public void __constructor__(String action) { 50 __constructor__(action, null); 51 } 52 53 public void __constructor__(Intent intent) { 54 ShadowIntent other = shadowOf(intent); 55 extras.putAll(other.extras); 56 action = other.action; 57 componentName = other.componentName; 58 type = other.type; 59 data = other.data; 60 flags = other.flags; 61 intentClass = other.intentClass; 62 packageName = other.packageName; 63 categories.addAll(other.categories); 64 } 65 66 @Implementation 67 public static Intent createChooser(Intent target, CharSequence title) { 68 Intent intent = new Intent(Intent.ACTION_CHOOSER); 69 intent.putExtra(Intent.EXTRA_INTENT, target); 70 if (title != null) { 71 intent.putExtra(Intent.EXTRA_TITLE, title); 72 } 73 return intent; 74 } 75 76 @Implementation 77 public Intent setAction(String action) { 78 this.action = action; 79 return realIntent; 80 } 81 82 @Implementation 83 public String getAction() { 84 return action; 85 } 86 87 @Implementation 88 public Intent setType(String type) { 89 this.type = type; 90 this.data = null; 91 return realIntent; 92 } 93 94 @Implementation 95 public Intent setDataAndType(Uri data, String type) { 96 this.data = data; 97 this.type = type; 98 return realIntent; 99 } 100 101 @Implementation 102 public String getType() { 103 return type; 104 } 105 106 @Implementation 107 public Intent addCategory(String category) { 108 categories.add(category); 109 return realIntent; 110 } 111 112 @Implementation 113 public void removeCategory(String category) { 114 categories.remove(category); 115 } 116 117 @Implementation 118 public boolean hasCategory(String category) { 119 return categories.contains(category); 120 } 121 122 @Implementation 123 public Set<String> getCategories() { 124 return categories; 125 } 126 127 @Implementation 128 public Intent setPackage(String packageName) { 129 this.packageName = packageName; 130 return realIntent; 131 } 132 133 @Implementation 134 public String getPackage() { 135 return packageName; 136 } 137 138 @Implementation 139 public Uri getData() { 140 return data; 141 } 142 143 @Implementation 144 public Intent setClass(Context packageContext, Class<?> cls) { 145 this.intentClass = cls; 146 return realIntent; 147 } 148 149 @Implementation 150 public Intent setClassName(String packageName, String className) { 151 componentName = new ComponentName(packageName, className); 152 try { 153 this.intentClass = Class.forName(className); 154 } catch (ClassNotFoundException e) { 155 // ignore 156 } 157 return realIntent; 158 } 159 160 @Implementation 161 public Intent setClassName(Context packageContext, String className) { 162 componentName = new ComponentName(packageContext.getPackageName(), className); 163 return realIntent; 164 } 165 166 @Implementation 167 public Intent setData(Uri data) { 168 this.data = data; 169 this.type = null; 170 return realIntent; 171 } 172 173 @Implementation 174 public int getFlags() { 175 return flags; 176 } 177 178 @Implementation 179 public Intent setFlags(int flags) { 180 this.flags = flags; 181 return realIntent; 182 } 183 184 @Implementation 185 public Intent addFlags(int flags) { 186 this.flags |= flags; 187 return realIntent; 188 } 189 190 @Implementation 191 public Intent putExtras(Bundle src) { 192 extras.putAll(src); 193 return realIntent; 194 } 195 196 @Implementation 197 public Intent putExtras(Intent src) { 198 ShadowIntent srcShadowIntent = shadowOf(src); 199 extras.putAll(srcShadowIntent.extras); 200 return realIntent; 201 } 202 203 @Implementation 204 public Bundle getExtras() { 205 return extras != null ? new Bundle(extras) : null; 206 } 207 208 @Implementation 209 public Intent putExtra(String key, int value) { 210 extras.putInt(key, value); 211 return realIntent; 212 } 213 214 @Implementation 215 public Intent putExtra(String key, double value) { 216 extras.putDouble(key, value); 217 return realIntent; 218 } 219 220 @Implementation 221 public Intent putExtra(String key, float value) { 222 extras.putFloat(key, value); 223 return realIntent; 224 } 225 226 @Implementation 227 public Intent putExtra(String key, long value) { 228 extras.putLong(key, value); 229 return realIntent; 230 } 231 232 @Implementation 233 public Intent putExtra(String key, Serializable value) { 234 extras.putSerializable(key, serializeCycle(value)); 235 return realIntent; 236 } 237 238 @Implementation 239 public Intent putExtra(String key, Parcelable value) { 240 extras.putParcelable(key, value); 241 return realIntent; 242 } 243 244 @Implementation 245 public Intent putExtra(String key, Parcelable[] value) { 246 extras.putParcelableArray(key, value); 247 return realIntent; 248 } 249 250 @Implementation 251 public Intent putExtra(String key, String value) { 252 extras.putString(key, value); 253 return realIntent; 254 } 255 256 @Implementation 257 public Intent putExtra(String key, String[] value) { 258 extras.putStringArray(key, value); 259 return realIntent; 260 } 261 262 @Implementation 263 public Intent putExtra(String key, Bundle value) { 264 extras.putBundle(key, value); 265 return realIntent; 266 } 267 268 @Implementation 269 public Intent putExtra(String key, boolean value) { 270 extras.putBoolean(key, value); 271 return realIntent; 272 } 273 274 @Implementation 275 public Intent putExtra(String key, int[] value) { 276 extras.putIntArray(key, value); 277 return realIntent; 278 } 279 280 @Implementation 281 public Intent putExtra(String key, long[] value) { 282 extras.putLongArray(key, value); 283 return realIntent; 284 } 285 286 @Implementation 287 public int[] getIntArrayExtra(String name) { 288 return extras.getIntArray(name); 289 } 290 291 @Implementation 292 public long[] getLongArrayExtra(String name) { 293 return extras.getLongArray(name); 294 } 295 296 @Implementation 297 public boolean getBooleanExtra(String name, boolean defaultValue) { 298 return extras.getBoolean(name, defaultValue); 299 } 300 301 @Implementation 302 public String[] getStringArrayExtra(String name) { 303 return extras.getStringArray(name); 304 } 305 306 @Implementation 307 public Intent putExtra(String key, CharSequence value) { 308 extras.putCharSequence(key, value); 309 return realIntent; 310 } 311 312 @Implementation 313 public CharSequence getCharSequenceExtra(String name) { 314 return extras.getCharSequence(name); 315 } 316 317 @Implementation 318 public void putExtra(String key, byte[] value) { 319 extras.putByteArray(key, value); 320 } 321 322 @Implementation 323 public Intent putStringArrayListExtra(String key, ArrayList<String> value) { 324 extras.putStringArrayList(key, value); 325 return realIntent; 326 } 327 328 @Implementation 329 public ArrayList<String> getStringArrayListExtra(String name) { 330 return extras.getStringArrayList(name); 331 } 332 333 @Implementation 334 public Intent putIntegerArrayListExtra(String key, ArrayList<Integer> value) { 335 extras.putIntegerArrayList(key, value); 336 return realIntent; 337 } 338 339 @Implementation 340 public ArrayList<Integer> getIntegerArrayListExtra(String name) { 341 return extras.getIntegerArrayList(name); 342 } 343 344 @Implementation 345 public Intent putParcelableArrayListExtra(String key, ArrayList<Parcelable> value) { 346 extras.putParcelableArrayList(key, value); 347 return realIntent; 348 } 349 350 @Implementation 351 public ArrayList<Parcelable> getParcelableArrayListExtra(String key) { 352 return extras.getParcelableArrayList(key); 353 } 354 355 @Implementation 356 public boolean hasExtra(String name) { 357 return extras.containsKey(name); 358 } 359 360 @Implementation 361 public String getStringExtra(String name) { 362 return extras.getString(name); 363 } 364 365 @Implementation 366 public Parcelable getParcelableExtra(String name) { 367 return extras.getParcelable(name); 368 } 369 370 @Implementation 371 public Parcelable[] getParcelableArrayExtra(String name) { 372 return extras.getParcelableArray(name); 373 } 374 375 @Implementation 376 public int getIntExtra(String name, int defaultValue) { 377 return extras.getInt(name, defaultValue); 378 } 379 380 @Implementation 381 public long getLongExtra(String name, long defaultValue) { 382 return extras.getLong(name, defaultValue); 383 } 384 385 @Implementation 386 public double getDoubleExtra(String name, double defaultValue) { 387 return extras.getDouble(name, defaultValue); 388 } 389 390 @Implementation 391 public Bundle getBundleExtra(String name) { 392 return extras.getBundle(name); 393 } 394 395 @Implementation 396 public float getFloatExtra(String name, float defaultValue) { 397 return extras.getFloat(name, defaultValue); 398 } 399 400 @Implementation 401 public byte[] getByteArrayExtra(String name) { 402 return extras.getByteArray(name); 403 } 404 405 @Implementation 406 public Serializable getSerializableExtra(String name) { 407 return extras.getSerializable(name); 408 } 409 410 @Implementation 411 public void removeExtra(String name) { 412 extras.remove(name); 413 } 414 415 @Implementation 416 public Intent setComponent(ComponentName componentName) { 417 this.componentName = componentName; 418 return realIntent; 419 } 420 421 @Implementation 422 public ComponentName getComponent() { 423 return componentName; 424 } 425 426 @Implementation 427 public int fillIn(Intent otherIntent, int flags) { 428 int changes = 0; 429 ShadowIntent other = shadowOf(otherIntent); 430 431 if (other.action != null && (action == null || (flags & FILL_IN_ACTION) != 0)) { 432 action = other.action; 433 changes |= FILL_IN_ACTION; 434 } 435 if ((other.data != null || other.type != null) 436 && ((data == null && type == null) || (flags & FILL_IN_DATA) != 0)) { 437 data = other.data; 438 type = other.type; 439 changes |= FILL_IN_DATA; 440 } 441 if (!other.categories.isEmpty() 442 && (categories.isEmpty() || (flags & FILL_IN_CATEGORIES) != 0)) { 443 categories.addAll(other.categories); 444 changes |= FILL_IN_CATEGORIES; 445 } 446 if (other.packageName != null 447 && (packageName == null || (flags & FILL_IN_PACKAGE) != 0)) { 448 packageName = other.packageName; 449 changes |= FILL_IN_PACKAGE; 450 } 451 if (other.componentName != null && (flags & FILL_IN_COMPONENT) != 0) { 452 componentName = other.componentName; 453 changes |= FILL_IN_COMPONENT; 454 } 455 456 extras.putAll(other.extras); 457 return changes; 458 } 459 460 @Implementation 461 // cribbed from Android source 462 public boolean filterEquals(Intent other) { 463 if (other == null) { 464 return false; 465 } 466 if (getAction() != other.getAction()) { 467 if (getAction() != null) { 468 if (!getAction().equals(other.getAction())) { 469 return false; 470 } 471 } else { 472 if (!other.getAction().equals(getAction())) { 473 return false; 474 } 475 } 476 } 477 if (getData() != other.getData()) { 478 if (getData() != null) { 479 if (!getData().equals(other.getData())) { 480 return false; 481 } 482 } else { 483 if (!other.getData().equals(getData())) { 484 return false; 485 } 486 } 487 } 488 if (getType() != other.getType()) { 489 if (getType() != null) { 490 if (!getType().equals(other.getType())) { 491 return false; 492 } 493 } else { 494 if (!other.getType().equals(getType())) { 495 return false; 496 } 497 } 498 } 499 if (getPackage() != other.getPackage()) { 500 if (getPackage() != null) { 501 if (!getPackage().equals(other.getPackage())) { 502 return false; 503 } 504 } else { 505 if (!other.getPackage().equals(getPackage())) { 506 return false; 507 } 508 } 509 } 510 if (getComponent() != other.getComponent()) { 511 if (getComponent() != null) { 512 if (!getComponent().equals(other.getComponent())) { 513 return false; 514 } 515 } else { 516 if (!other.getComponent().equals(getComponent())) { 517 return false; 518 } 519 } 520 } 521 if (getCategories() != other.getCategories()) { 522 if (getCategories() != null) { 523 if (!getCategories().equals(other.getCategories())) { 524 return false; 525 } 526 } else { 527 if (!other.getCategories().equals(getCategories())) { 528 return false; 529 } 530 } 531 } 532 533 return true; 534 } 535 536 /** 537 * Compares an {@code Intent} with a {@code ShadowIntent} (obtained via a call to 538 * {@link Robolectric#shadowOf(android.content.Intent)}) 539 * 540 * @param o a {@code ShadowIntent} 541 * @return whether they are equivalent 542 */ 543 @Deprecated 544 public boolean realIntentEquals(ShadowIntent o) { 545 if (this == o) return true; 546 if (o == null || getClass() != o.getClass()) return false; 547 548 if (action != null ? !action.equals(o.action) : o.action != null) return false; 549 if (componentName != null ? !componentName.equals(o.componentName) : o.componentName != null) 550 return false; 551 if (data != null ? !data.equals(o.data) : o.data != null) return false; 552 if (extras != null ? !extras.equals(o.extras) : o.extras != null) return false; 553 if (type != null ? !type.equals(o.type) : o.type != null) return false; 554 if (categories != null ? !categories.equals(o.categories) : o.categories != null) return false; 555 556 return true; 557 } 558 559 @Override 560 @Implementation 561 public int hashCode() { 562 int result = extras != null ? extras.hashCode() : 0; 563 result = 31 * result + (action != null ? action.hashCode() : 0); 564 result = 31 * result + (componentName != null ? componentName.hashCode() : 0); 565 result = 31 * result + (data != null ? data.hashCode() : 0); 566 result = 31 * result + (type != null ? type.hashCode() : 0); 567 result = 31 * result + flags; 568 return result; 569 } 570 571 @Override 572 @Implementation 573 public boolean equals(Object o) { 574 if (!(o instanceof Intent)) return false; 575 return realIntentEquals(shadowOf((Intent) o)); 576 } 577 578 /** 579 * Non-Android accessor that returns the {@code Class} object set by 580 * {@link #setClass(android.content.Context, Class)} 581 * 582 * @return the {@code Class} object set by 583 * {@link #setClass(android.content.Context, Class)} 584 */ 585 public Class<?> getIntentClass() { 586 return intentClass; 587 } 588 589 @Override 590 @Implementation 591 public String toString() { 592 return "Intent{" + 593 Join.join( 594 ", ", 595 ifWeHave(componentName, "componentName"), 596 ifWeHave(action, "action"), 597 ifWeHave(extras, "extras"), 598 ifWeHave(data, "data"), 599 ifWeHave(type, "type") 600 ) + 601 '}'; 602 } 603 604 @Implementation 605 public void writeToParcel(Parcel out, int flags) { 606 out.writeString(action); 607 if (data != null) { 608 out.writeInt(1); 609 Uri.writeToParcel(out, data); 610 } else { 611 out.writeInt(-1); 612 } 613 out.writeString(type); 614 out.writeInt(flags); 615 out.writeString(packageName); 616 ComponentName.writeToParcel(componentName, out); 617 out.writeInt(categories.size()); 618 619 for (String category : categories) { 620 out.writeString(category); 621 } 622 out.writeBundle(extras); 623 } 624 625 @Implementation 626 public void readFromParcel(Parcel in) { 627 setAction(in.readString()); 628 if (in.readInt() == 1) { 629 data = Uri.CREATOR.createFromParcel(in); 630 } 631 type = in.readString(); 632 flags = in.readInt(); 633 packageName = in.readString(); 634 componentName = ComponentName.readFromParcel(in); 635 int N = in.readInt(); 636 for (int i = 0; i < N; i++) { 637 categories.add(in.readString().intern()); 638 } 639 extras.putAll(in.readBundle()); 640 } 641 642 private Serializable serializeCycle(Serializable serializable) { 643 try { 644 ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(); 645 ObjectOutputStream output = new ObjectOutputStream(byteArrayOutputStream); 646 output.writeObject(serializable); 647 output.close(); 648 649 byte[] bytes = byteArrayOutputStream.toByteArray(); 650 ObjectInputStream input = new ObjectInputStream(new ByteArrayInputStream(bytes)); 651 return (Serializable) input.readObject(); 652 } catch (IOException e) { 653 throw new RuntimeException(e); 654 } catch (ClassNotFoundException e) { 655 throw new RuntimeException(e); 656 } 657 } 658 659 private String ifWeHave(Object o, String name) { 660 if (o == null) return null; 661 if (o instanceof Map && ((Map) o).isEmpty()) return null; 662 return name + "=" + o; 663 } 664 665 public static final Creator<Intent> CREATOR = 666 new Creator<Intent>() { 667 @Override 668 public Intent createFromParcel(Parcel source) { 669 Intent intent = new Intent(); 670 intent.readFromParcel(source); 671 return intent; 672 } 673 674 @Override 675 public Intent[] newArray(int size) { 676 return new Intent[size]; 677 } 678 }; 679 680 public static void reset() { 681 Robolectric.Reflection.setFinalStaticField(Intent.class, "CREATOR", CREATOR); 682 } 683 } 684