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 
__constructor__(Context packageContext, Class cls)39     public void __constructor__(Context packageContext, Class cls) {
40         componentName = new ComponentName(packageContext, cls);
41         intentClass = cls;
42     }
43 
__constructor__(String action, Uri uri)44     public void __constructor__(String action, Uri uri) {
45         this.action = action;
46         data = uri;
47     }
48 
__constructor__(String action)49     public void __constructor__(String action) {
50         __constructor__(action, null);
51     }
52 
__constructor__(Intent intent)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
createChooser(Intent target, CharSequence title)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
setAction(String action)77     public Intent setAction(String action) {
78         this.action = action;
79         return realIntent;
80     }
81 
82     @Implementation
getAction()83     public String getAction() {
84         return action;
85     }
86 
87     @Implementation
setType(String type)88     public Intent setType(String type) {
89         this.type = type;
90         this.data = null;
91         return realIntent;
92     }
93 
94     @Implementation
setDataAndType(Uri data, String type)95     public Intent setDataAndType(Uri data, String type) {
96         this.data = data;
97         this.type = type;
98         return realIntent;
99     }
100 
101     @Implementation
getType()102     public String getType() {
103         return type;
104     }
105 
106     @Implementation
addCategory(String category)107     public Intent addCategory(String category) {
108         categories.add(category);
109         return realIntent;
110     }
111 
112     @Implementation
removeCategory(String category)113     public void removeCategory(String category) {
114         categories.remove(category);
115     }
116 
117     @Implementation
hasCategory(String category)118     public boolean hasCategory(String category) {
119         return categories.contains(category);
120     }
121 
122     @Implementation
getCategories()123     public Set<String> getCategories() {
124         return categories;
125     }
126 
127     @Implementation
setPackage(String packageName)128     public Intent setPackage(String packageName) {
129         this.packageName = packageName;
130         return realIntent;
131     }
132 
133     @Implementation
getPackage()134     public String getPackage() {
135         return packageName;
136     }
137 
138     @Implementation
getData()139     public Uri getData() {
140         return data;
141     }
142 
143     @Implementation
setClass(Context packageContext, Class<?> cls)144     public Intent setClass(Context packageContext, Class<?> cls) {
145         this.intentClass = cls;
146         return realIntent;
147     }
148 
149     @Implementation
setClassName(String packageName, String className)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
setClassName(Context packageContext, String className)161     public Intent setClassName(Context packageContext, String className) {
162         componentName = new ComponentName(packageContext.getPackageName(), className);
163         return realIntent;
164     }
165 
166     @Implementation
setData(Uri data)167     public Intent setData(Uri data) {
168         this.data = data;
169         this.type = null;
170         return realIntent;
171     }
172 
173     @Implementation
getFlags()174     public int getFlags() {
175         return flags;
176     }
177 
178     @Implementation
setFlags(int flags)179     public Intent setFlags(int flags) {
180         this.flags = flags;
181         return realIntent;
182     }
183 
184     @Implementation
addFlags(int flags)185     public Intent addFlags(int flags) {
186         this.flags |= flags;
187         return realIntent;
188     }
189 
190     @Implementation
putExtras(Bundle src)191     public Intent putExtras(Bundle src) {
192         extras.putAll(src);
193         return realIntent;
194     }
195 
196     @Implementation
putExtras(Intent src)197     public Intent putExtras(Intent src) {
198         ShadowIntent srcShadowIntent = shadowOf(src);
199         extras.putAll(srcShadowIntent.extras);
200         return realIntent;
201     }
202 
203     @Implementation
getExtras()204     public Bundle getExtras() {
205         return extras != null ? new Bundle(extras) : null;
206     }
207 
208     @Implementation
putExtra(String key, int value)209     public Intent putExtra(String key, int value) {
210         extras.putInt(key, value);
211         return realIntent;
212     }
213 
214     @Implementation
putExtra(String key, double value)215     public Intent putExtra(String key, double value) {
216         extras.putDouble(key, value);
217         return realIntent;
218     }
219 
220     @Implementation
putExtra(String key, float value)221     public Intent putExtra(String key, float value) {
222         extras.putFloat(key, value);
223         return realIntent;
224     }
225 
226     @Implementation
putExtra(String key, long value)227     public Intent putExtra(String key, long value) {
228         extras.putLong(key, value);
229         return realIntent;
230     }
231 
232     @Implementation
putExtra(String key, Serializable value)233     public Intent putExtra(String key, Serializable value) {
234         extras.putSerializable(key, serializeCycle(value));
235         return realIntent;
236     }
237 
238     @Implementation
putExtra(String key, Parcelable value)239     public Intent putExtra(String key, Parcelable value) {
240         extras.putParcelable(key, value);
241         return realIntent;
242     }
243 
244     @Implementation
putExtra(String key, Parcelable[] value)245     public Intent putExtra(String key, Parcelable[] value) {
246         extras.putParcelableArray(key, value);
247         return realIntent;
248     }
249 
250     @Implementation
putExtra(String key, String value)251     public Intent putExtra(String key, String value) {
252         extras.putString(key, value);
253         return realIntent;
254     }
255 
256     @Implementation
putExtra(String key, String[] value)257     public Intent putExtra(String key, String[] value) {
258         extras.putStringArray(key, value);
259         return realIntent;
260     }
261 
262     @Implementation
putExtra(String key, Bundle value)263     public Intent putExtra(String key, Bundle value) {
264         extras.putBundle(key, value);
265         return realIntent;
266     }
267 
268     @Implementation
putExtra(String key, boolean value)269     public Intent putExtra(String key, boolean value) {
270         extras.putBoolean(key, value);
271         return realIntent;
272     }
273 
274     @Implementation
putExtra(String key, int[] value)275     public Intent putExtra(String key, int[] value) {
276         extras.putIntArray(key, value);
277         return realIntent;
278     }
279 
280     @Implementation
putExtra(String key, long[] value)281     public Intent putExtra(String key, long[] value) {
282         extras.putLongArray(key, value);
283         return realIntent;
284     }
285 
286     @Implementation
getIntArrayExtra(String name)287     public int[] getIntArrayExtra(String name) {
288         return extras.getIntArray(name);
289     }
290 
291     @Implementation
getLongArrayExtra(String name)292     public long[] getLongArrayExtra(String name) {
293         return extras.getLongArray(name);
294     }
295 
296     @Implementation
getBooleanExtra(String name, boolean defaultValue)297     public boolean getBooleanExtra(String name, boolean defaultValue) {
298         return extras.getBoolean(name, defaultValue);
299     }
300 
301     @Implementation
getStringArrayExtra(String name)302     public String[] getStringArrayExtra(String name) {
303         return extras.getStringArray(name);
304     }
305 
306     @Implementation
putExtra(String key, CharSequence value)307     public Intent putExtra(String key, CharSequence value) {
308         extras.putCharSequence(key, value);
309         return realIntent;
310     }
311 
312     @Implementation
getCharSequenceExtra(String name)313     public CharSequence getCharSequenceExtra(String name) {
314         return extras.getCharSequence(name);
315     }
316 
317     @Implementation
putExtra(String key, byte[] value)318     public void putExtra(String key, byte[] value) {
319         extras.putByteArray(key, value);
320     }
321 
322     @Implementation
putStringArrayListExtra(String key, ArrayList<String> value)323     public Intent putStringArrayListExtra(String key, ArrayList<String> value) {
324         extras.putStringArrayList(key, value);
325         return realIntent;
326     }
327 
328     @Implementation
getStringArrayListExtra(String name)329     public ArrayList<String> getStringArrayListExtra(String name) {
330         return extras.getStringArrayList(name);
331     }
332 
333     @Implementation
putIntegerArrayListExtra(String key, ArrayList<Integer> value)334     public Intent putIntegerArrayListExtra(String key, ArrayList<Integer> value) {
335         extras.putIntegerArrayList(key, value);
336         return realIntent;
337     }
338 
339     @Implementation
getIntegerArrayListExtra(String name)340     public ArrayList<Integer> getIntegerArrayListExtra(String name) {
341         return extras.getIntegerArrayList(name);
342     }
343 
344     @Implementation
putParcelableArrayListExtra(String key, ArrayList<Parcelable> value)345     public Intent putParcelableArrayListExtra(String key, ArrayList<Parcelable> value) {
346         extras.putParcelableArrayList(key, value);
347         return realIntent;
348     }
349 
350     @Implementation
getParcelableArrayListExtra(String key)351     public ArrayList<Parcelable> getParcelableArrayListExtra(String key) {
352         return extras.getParcelableArrayList(key);
353     }
354 
355     @Implementation
hasExtra(String name)356     public boolean hasExtra(String name) {
357         return extras.containsKey(name);
358     }
359 
360     @Implementation
getStringExtra(String name)361     public String getStringExtra(String name) {
362         return extras.getString(name);
363     }
364 
365     @Implementation
getParcelableExtra(String name)366     public Parcelable getParcelableExtra(String name) {
367         return extras.getParcelable(name);
368     }
369 
370     @Implementation
getParcelableArrayExtra(String name)371     public Parcelable[] getParcelableArrayExtra(String name) {
372         return extras.getParcelableArray(name);
373     }
374 
375     @Implementation
getIntExtra(String name, int defaultValue)376     public int getIntExtra(String name, int defaultValue) {
377         return extras.getInt(name, defaultValue);
378     }
379 
380     @Implementation
getLongExtra(String name, long defaultValue)381     public long getLongExtra(String name, long defaultValue) {
382         return extras.getLong(name, defaultValue);
383     }
384 
385     @Implementation
getDoubleExtra(String name, double defaultValue)386     public double getDoubleExtra(String name, double defaultValue) {
387         return extras.getDouble(name, defaultValue);
388     }
389 
390     @Implementation
getBundleExtra(String name)391     public Bundle getBundleExtra(String name) {
392         return extras.getBundle(name);
393     }
394 
395     @Implementation
getFloatExtra(String name, float defaultValue)396     public float getFloatExtra(String name, float defaultValue) {
397         return extras.getFloat(name, defaultValue);
398     }
399 
400     @Implementation
getByteArrayExtra(String name)401     public byte[] getByteArrayExtra(String name) {
402         return extras.getByteArray(name);
403     }
404 
405     @Implementation
getSerializableExtra(String name)406     public Serializable getSerializableExtra(String name) {
407         return extras.getSerializable(name);
408     }
409 
410     @Implementation
removeExtra(String name)411     public void removeExtra(String name) {
412         extras.remove(name);
413     }
414 
415     @Implementation
setComponent(ComponentName componentName)416     public Intent setComponent(ComponentName componentName) {
417         this.componentName = componentName;
418         return realIntent;
419     }
420 
421     @Implementation
getComponent()422     public ComponentName getComponent() {
423         return componentName;
424     }
425 
426     @Implementation
fillIn(Intent otherIntent, int flags)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
filterEquals(Intent other)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
realIntentEquals(ShadowIntent o)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
hashCode()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
equals(Object o)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      */
getIntentClass()585     public Class<?> getIntentClass() {
586         return intentClass;
587     }
588 
589     @Override
590     @Implementation
toString()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
writeToParcel(Parcel out, int flags)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
readFromParcel(Parcel in)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 
serializeCycle(Serializable serializable)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 
ifWeHave(Object o, String name)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 
reset()680     public static void reset() {
681         Robolectric.Reflection.setFinalStaticField(Intent.class, "CREATOR", CREATOR);
682     }
683 }
684