• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 package org.robolectric.shadows;
2 
3 import static android.app.PendingIntent.FLAG_CANCEL_CURRENT;
4 import static android.app.PendingIntent.FLAG_IMMUTABLE;
5 import static android.app.PendingIntent.FLAG_NO_CREATE;
6 import static android.app.PendingIntent.FLAG_ONE_SHOT;
7 import static android.app.PendingIntent.FLAG_UPDATE_CURRENT;
8 import static android.os.Build.VERSION_CODES.M;
9 import static android.os.Build.VERSION_CODES.N;
10 import static android.os.Build.VERSION_CODES.O;
11 import static android.os.Build.VERSION_CODES.S;
12 import static org.robolectric.util.reflector.Reflector.reflector;
13 
14 import android.annotation.NonNull;
15 import android.annotation.SuppressLint;
16 import android.app.Activity;
17 import android.app.ActivityThread;
18 import android.app.PendingIntent;
19 import android.app.PendingIntent.CanceledException;
20 import android.app.PendingIntent.OnMarshaledListener;
21 import android.content.Context;
22 import android.content.IIntentSender;
23 import android.content.Intent;
24 import android.content.IntentSender;
25 import android.os.Bundle;
26 import android.os.Handler;
27 import android.os.IBinder;
28 import android.os.Parcel;
29 import android.os.Parcelable.Creator;
30 import java.util.ArrayList;
31 import java.util.Arrays;
32 import java.util.Iterator;
33 import java.util.List;
34 import java.util.Objects;
35 import javax.annotation.Nullable;
36 import javax.annotation.concurrent.GuardedBy;
37 import org.robolectric.RuntimeEnvironment;
38 import org.robolectric.annotation.Implementation;
39 import org.robolectric.annotation.Implements;
40 import org.robolectric.annotation.RealObject;
41 import org.robolectric.annotation.Resetter;
42 import org.robolectric.fakes.RoboIntentSender;
43 import org.robolectric.shadow.api.Shadow;
44 import org.robolectric.util.ReflectionHelpers;
45 import org.robolectric.util.reflector.Accessor;
46 import org.robolectric.util.reflector.ForType;
47 
48 @Implements(PendingIntent.class)
49 @SuppressLint("NewApi")
50 public class ShadowPendingIntent {
51 
52   private enum Type {
53     ACTIVITY,
54     BROADCAST,
55     SERVICE,
56     FOREGROUND_SERVICE
57   }
58 
59   private static final int NULL_PENDING_INTENT_VALUE = -1;
60 
61   @GuardedBy("lock")
62   private static final List<PendingIntent> createdIntents = new ArrayList<>();
63 
64   private static final Object lock = new Object();
65 
66   private static final List<PendingIntent> parceledPendingIntents = new ArrayList<>();
67 
68   @RealObject private PendingIntent realPendingIntent;
69 
70   @NonNull private Intent[] savedIntents;
71   private Context savedContext;
72   private Type type;
73   private int requestCode;
74   private int flags;
75   @Nullable private Bundle options;
76   private String creatorPackage;
77   private int creatorUid;
78   private boolean canceled;
79   @Nullable private PendingIntent.OnFinished lastOnFinished;
80 
81   @Implementation
__staticInitializer__()82   protected static void __staticInitializer__() {
83     Shadow.directInitialize(PendingIntent.class);
84     ReflectionHelpers.setStaticField(PendingIntent.class, "CREATOR", ShadowPendingIntent.CREATOR);
85   }
86 
87   @Implementation
getActivity( Context context, int requestCode, @NonNull Intent intent, int flags)88   protected static PendingIntent getActivity(
89       Context context, int requestCode, @NonNull Intent intent, int flags) {
90     return create(context, new Intent[] {intent}, Type.ACTIVITY, requestCode, flags, null);
91   }
92 
93   @Implementation
getActivity( Context context, int requestCode, @NonNull Intent intent, int flags, Bundle options)94   protected static PendingIntent getActivity(
95       Context context, int requestCode, @NonNull Intent intent, int flags, Bundle options) {
96     return create(context, new Intent[] {intent}, Type.ACTIVITY, requestCode, flags, options);
97   }
98 
99   @Implementation
getActivities( Context context, int requestCode, @NonNull Intent[] intents, int flags)100   protected static PendingIntent getActivities(
101       Context context, int requestCode, @NonNull Intent[] intents, int flags) {
102     return create(context, intents, Type.ACTIVITY, requestCode, flags, null);
103   }
104 
105   @Implementation
getActivities( Context context, int requestCode, @NonNull Intent[] intents, int flags, Bundle options)106   protected static PendingIntent getActivities(
107       Context context, int requestCode, @NonNull Intent[] intents, int flags, Bundle options) {
108     return create(context, intents, Type.ACTIVITY, requestCode, flags, options);
109   }
110 
111   @Implementation
getBroadcast( Context context, int requestCode, @NonNull Intent intent, int flags)112   protected static PendingIntent getBroadcast(
113       Context context, int requestCode, @NonNull Intent intent, int flags) {
114     return create(context, new Intent[] {intent}, Type.BROADCAST, requestCode, flags, null);
115   }
116 
117   @Implementation
getService( Context context, int requestCode, @NonNull Intent intent, int flags)118   protected static PendingIntent getService(
119       Context context, int requestCode, @NonNull Intent intent, int flags) {
120     return create(context, new Intent[] {intent}, Type.SERVICE, requestCode, flags, null);
121   }
122 
123   @Implementation(minSdk = O)
getForegroundService( Context context, int requestCode, @NonNull Intent intent, int flags)124   protected static PendingIntent getForegroundService(
125       Context context, int requestCode, @NonNull Intent intent, int flags) {
126     return create(
127         context, new Intent[] {intent}, Type.FOREGROUND_SERVICE, requestCode, flags, null);
128   }
129 
130   @Implementation
131   @SuppressWarnings("ReferenceEquality")
cancel()132   protected void cancel() {
133     synchronized (lock) {
134       for (Iterator<PendingIntent> i = createdIntents.iterator(); i.hasNext(); ) {
135         PendingIntent pendingIntent = i.next();
136         if (pendingIntent == realPendingIntent) {
137           canceled = true;
138           i.remove();
139           break;
140         }
141       }
142     }
143   }
144 
145   @Implementation
send()146   protected void send() throws CanceledException {
147     send(savedContext, 0, null);
148   }
149 
150   @Implementation
send(int code)151   protected void send(int code) throws CanceledException {
152     send(savedContext, code, null);
153   }
154 
155   @Implementation
send(int code, PendingIntent.OnFinished onFinished, Handler handler)156   protected void send(int code, PendingIntent.OnFinished onFinished, Handler handler)
157       throws CanceledException {
158     send(savedContext, code, null, onFinished, handler);
159   }
160 
161   @Implementation
send(Context context, int code, Intent intent)162   protected void send(Context context, int code, Intent intent) throws CanceledException {
163     send(context, code, intent, null, null);
164   }
165 
166   @Implementation
send( Context context, int code, Intent intent, PendingIntent.OnFinished onFinished, Handler handler)167   protected void send(
168       Context context,
169       int code,
170       Intent intent,
171       PendingIntent.OnFinished onFinished,
172       Handler handler)
173       throws CanceledException {
174     send(context, code, intent, onFinished, handler, null);
175   }
176 
177   @Implementation
send( Context context, int code, Intent intent, PendingIntent.OnFinished onFinished, Handler handler, String requiredPermission)178   protected void send(
179       Context context,
180       int code,
181       Intent intent,
182       PendingIntent.OnFinished onFinished,
183       Handler handler,
184       String requiredPermission)
185       throws CanceledException {
186     // Manually propagating to keep only one implementation regardless of SDK
187     send(context, code, intent, onFinished, handler, requiredPermission, null);
188   }
189 
190   @Implementation(minSdk = M)
send( Context context, int code, Intent intent, PendingIntent.OnFinished onFinished, Handler handler, String requiredPermission, Bundle options)191   protected void send(
192       Context context,
193       int code,
194       Intent intent,
195       PendingIntent.OnFinished onFinished,
196       Handler handler,
197       String requiredPermission,
198       Bundle options)
199       throws CanceledException {
200     send(context, code, intent, onFinished, handler, requiredPermission, options, 0);
201   }
202 
send( Context context, int code, Intent intent, PendingIntent.OnFinished onFinished, Handler handler, String requiredPermission, Bundle options, int requestCode)203   void send(
204       Context context,
205       int code,
206       Intent intent,
207       PendingIntent.OnFinished onFinished,
208       Handler handler,
209       String requiredPermission,
210       Bundle options,
211       int requestCode)
212       throws CanceledException {
213     this.lastOnFinished =
214         handler == null
215             ? onFinished
216             : (pendingIntent, intent1, resultCode, resultData, resultExtras) ->
217                 handler.post(
218                     () ->
219                         onFinished.onSendFinished(
220                             pendingIntent, intent1, resultCode, resultData, resultExtras));
221 
222     if (canceled) {
223       throw new CanceledException();
224     }
225 
226     // Fill in the last Intent, if it is mutable, with information now available at send-time.
227     Intent[] intentsToSend;
228     if (intent != null && isMutable(flags)) {
229       // Copy the last intent before filling it in to avoid modifying this PendingIntent.
230       intentsToSend = Arrays.copyOf(savedIntents, savedIntents.length);
231       Intent lastIntentCopy = new Intent(intentsToSend[intentsToSend.length - 1]);
232       lastIntentCopy.fillIn(intent, flags);
233       intentsToSend[intentsToSend.length - 1] = lastIntentCopy;
234     } else {
235       intentsToSend = savedIntents;
236     }
237 
238     ActivityThread activityThread = (ActivityThread) RuntimeEnvironment.getActivityThread();
239     ShadowInstrumentation shadowInstrumentation =
240         Shadow.extract(activityThread.getInstrumentation());
241     if (isActivity()) {
242       for (Intent intentToSend : intentsToSend) {
243         shadowInstrumentation.execStartActivity(
244             context,
245             (IBinder) null,
246             (IBinder) null,
247             (Activity) null,
248             intentToSend,
249             requestCode,
250             (Bundle) null);
251       }
252     } else if (isBroadcast()) {
253       for (Intent intentToSend : intentsToSend) {
254         shadowInstrumentation.sendBroadcastWithPermission(
255             intentToSend, requiredPermission, context, options, code);
256       }
257     } else if (isService()) {
258       for (Intent intentToSend : intentsToSend) {
259         context.startService(intentToSend);
260       }
261     } else if (isForegroundService()) {
262       for (Intent intentToSend : intentsToSend) {
263         context.startForegroundService(intentToSend);
264       }
265     }
266 
267     if (isOneShot(flags)) {
268       cancel();
269     }
270   }
271 
272   @Implementation
getIntentSender()273   protected IntentSender getIntentSender() {
274     return new RoboIntentSender(realPendingIntent);
275   }
276 
277   /**
278    * Returns {@code true} if this {@code PendingIntent} was created with {@link #getActivity} or
279    * {@link #getActivities}.
280    *
281    * <p>This method is intentionally left {@code public} rather than {@code protected} because it
282    * serves a secondary purpose as a utility shadow method for API levels < 31.
283    */
284   @Implementation(minSdk = S)
isActivity()285   public boolean isActivity() {
286     return type == Type.ACTIVITY;
287   }
288 
289   /**
290    * Returns {@code true} if this {@code PendingIntent} was created with {@link #getBroadcast}.
291    *
292    * <p>This method is intentionally left {@code public} rather than {@code protected} because it
293    * serves a secondary purpose as a utility shadow method for API levels < 31.
294    */
295   @Implementation(minSdk = S)
isBroadcast()296   public boolean isBroadcast() {
297     return type == Type.BROADCAST;
298   }
299 
300   /**
301    * Returns {@code true} if this {@code PendingIntent} was created with {@link
302    * #getForegroundService}.
303    *
304    * <p>This method is intentionally left {@code public} rather than {@code protected} because it
305    * serves a secondary purpose as a utility shadow method for API levels < 31.
306    */
307   @Implementation(minSdk = S)
isForegroundService()308   public boolean isForegroundService() {
309     return type == Type.FOREGROUND_SERVICE;
310   }
311 
312   /**
313    * Returns {@code true} if this {@code PendingIntent} was created with {@link #getService}.
314    *
315    * <p>This method is intentionally left {@code public} rather than {@code protected} because it
316    * serves a secondary purpose as a utility shadow method for API levels < 31.
317    */
318   @Implementation(minSdk = S)
isService()319   public boolean isService() {
320     return type == Type.SERVICE;
321   }
322 
323   /**
324    * Returns {@code true} if this {@code PendingIntent} is marked with {@link
325    * PendingIntent#FLAG_IMMUTABLE}.
326    *
327    * <p>This method is intentionally left {@code public} rather than {@code protected} because it
328    * serves a secondary purpose as a utility shadow method for API levels < 31.
329    */
330   @Implementation(minSdk = S)
isImmutable()331   public boolean isImmutable() {
332     return (flags & FLAG_IMMUTABLE) > 0;
333   }
334 
335   @Implementation
isTargetedToPackage()336   protected boolean isTargetedToPackage() {
337     // This is weird and we know it. See:
338     // https://googleplex-android.googlesource.com/platform/frameworks/base/+/f24a737c89de326199eb6d9f5912eae24b5514e6/services/core/java/com/android/server/am/ActivityManagerService.java#5377
339     for (Intent intent : savedIntents) {
340       if (intent.getPackage() != null && intent.getComponent() != null) {
341         return false;
342       }
343     }
344     return true;
345   }
346 
347   /**
348    * @return {@code true} iff sending this PendingIntent will start an activity
349    * @deprecated prefer {@link #isActivity} which was added to {@link PendingIntent} in API 31
350    *     (Android S).
351    */
352   @Deprecated
isActivityIntent()353   public boolean isActivityIntent() {
354     return type == Type.ACTIVITY;
355   }
356 
357   /**
358    * @return {@code true} iff sending this PendingIntent will broadcast an Intent
359    * @deprecated prefer {@link #isBroadcast} which was added to {@link PendingIntent} in API 31
360    *     (Android S).
361    */
362   @Deprecated
isBroadcastIntent()363   public boolean isBroadcastIntent() {
364     return type == Type.BROADCAST;
365   }
366 
367   /**
368    * @return {@code true} iff sending this PendingIntent will start a service
369    * @deprecated prefer {@link #isService} which was added to {@link PendingIntent} in API 31
370    *     (Android S).
371    */
372   @Deprecated
isServiceIntent()373   public boolean isServiceIntent() {
374     return type == Type.SERVICE;
375   }
376 
377   /**
378    * @return {@code true} iff sending this PendingIntent will start a foreground service
379    * @deprecated prefer {@link #isForegroundService} which was added to {@link PendingIntent} in API
380    *     31 (Android S).
381    */
382   @Deprecated
isForegroundServiceIntent()383   public boolean isForegroundServiceIntent() {
384     return type == Type.FOREGROUND_SERVICE;
385   }
386 
387   /**
388    * @return the context in which this PendingIntent was created
389    */
getSavedContext()390   public Context getSavedContext() {
391     return savedContext;
392   }
393 
394   /**
395    * This returns the last Intent in the Intent[] to be delivered when the PendingIntent is sent.
396    * This method is particularly useful for PendingIntents created with a single Intent:
397    *
398    * <ul>
399    *   <li>{@link #getActivity(Context, int, Intent, int)}
400    *   <li>{@link #getActivity(Context, int, Intent, int, Bundle)}
401    *   <li>{@link #getBroadcast(Context, int, Intent, int)}
402    *   <li>{@link #getService(Context, int, Intent, int)}
403    * </ul>
404    *
405    * @return the final Intent to be delivered when the PendingIntent is sent
406    */
getSavedIntent()407   public Intent getSavedIntent() {
408     return savedIntents[savedIntents.length - 1];
409   }
410 
411   /**
412    * This method is particularly useful for PendingIntents created with multiple Intents:
413    *
414    * <ul>
415    *   <li>{@link #getActivities(Context, int, Intent[], int)}
416    *   <li>{@link #getActivities(Context, int, Intent[], int, Bundle)}
417    * </ul>
418    *
419    * @return all Intents to be delivered when the PendingIntent is sent
420    */
getSavedIntents()421   public Intent[] getSavedIntents() {
422     return savedIntents;
423   }
424 
425   /**
426    * @return {@true} iff this PendingIntent has been canceled
427    */
isCanceled()428   public boolean isCanceled() {
429     return canceled;
430   }
431 
432   /**
433    * @return the request code with which this PendingIntent was created
434    */
getRequestCode()435   public int getRequestCode() {
436     return requestCode;
437   }
438 
439   /**
440    * @return the flags with which this PendingIntent was created
441    */
getFlags()442   public int getFlags() {
443     return flags;
444   }
445 
446   /**
447    * @return the flags with which this PendingIntent was created
448    */
getOptions()449   public @Nullable Bundle getOptions() {
450     return options;
451   }
452 
453   /**
454    * Calls {@link PendingIntent.OnFinished#onSendFinished} on the last {@link
455    * PendingIntent.OnFinished} passed with {@link #send()}.
456    *
457    * <p>{@link PendingIntent.OnFinished#onSendFinished} is called on the {@link Handler} passed with
458    * {@link #send()} (if any). If no {@link Handler} was provided it's invoked on the calling
459    * thread.
460    *
461    * @return false if no {@link PendingIntent.OnFinished} callback was passed with the last {@link
462    *     #send()} call, true otherwise.
463    */
callLastOnFinished( Intent intent, int resultCode, String resultData, Bundle resultExtras)464   public boolean callLastOnFinished(
465       Intent intent, int resultCode, String resultData, Bundle resultExtras) {
466     if (lastOnFinished == null) {
467       return false;
468     }
469 
470     lastOnFinished.onSendFinished(realPendingIntent, intent, resultCode, resultData, resultExtras);
471     return true;
472   }
473 
474   @Implementation
getTargetPackage()475   protected String getTargetPackage() {
476     return getCreatorPackage();
477   }
478 
479   @Implementation
getCreatorPackage()480   protected String getCreatorPackage() {
481     return (creatorPackage == null)
482         ? RuntimeEnvironment.getApplication().getPackageName()
483         : creatorPackage;
484   }
485 
setCreatorPackage(String creatorPackage)486   public void setCreatorPackage(String creatorPackage) {
487     this.creatorPackage = creatorPackage;
488   }
489 
490   @Implementation
getCreatorUid()491   protected int getCreatorUid() {
492     return creatorUid;
493   }
494 
setCreatorUid(int uid)495   public void setCreatorUid(int uid) {
496     this.creatorUid = uid;
497   }
498 
499   @Override
500   @Implementation
equals(Object o)501   public boolean equals(Object o) {
502     if (this == o) return true;
503     if (o == null || realPendingIntent.getClass() != o.getClass()) return false;
504     ShadowPendingIntent that = Shadow.extract((PendingIntent) o);
505 
506     String packageName = savedContext == null ? null : savedContext.getPackageName();
507     String thatPackageName = that.savedContext == null ? null : that.savedContext.getPackageName();
508     if (!Objects.equals(packageName, thatPackageName)) {
509       return false;
510     }
511 
512     if (this.savedIntents.length != that.savedIntents.length) {
513       return false;
514     }
515 
516     for (int i = 0; i < this.savedIntents.length; i++) {
517       if (!this.savedIntents[i].filterEquals(that.savedIntents[i])) {
518         return false;
519       }
520     }
521 
522     if (this.requestCode != that.requestCode) {
523       return false;
524     }
525     return true;
526   }
527 
528   @Override
529   @Implementation
hashCode()530   public int hashCode() {
531     int result = savedIntents != null ? Arrays.hashCode(savedIntents) : 0;
532     if (savedContext != null) {
533       String packageName = savedContext.getPackageName();
534       result = 31 * result + (packageName != null ? packageName.hashCode() : 0);
535     }
536     result = 31 * result + requestCode;
537     return result;
538   }
539 
540   @Implementation
541   @Nullable
readPendingIntentOrNullFromParcel(@onNull Parcel in)542   public static PendingIntent readPendingIntentOrNullFromParcel(@NonNull Parcel in) {
543     int intentIndex = in.readInt();
544     if (intentIndex == NULL_PENDING_INTENT_VALUE) {
545       return null;
546     }
547     return parceledPendingIntents.get(intentIndex);
548   }
549 
550   @Implementation
writePendingIntentOrNullToParcel( @ullable PendingIntent sender, @NonNull Parcel out)551   public static void writePendingIntentOrNullToParcel(
552       @Nullable PendingIntent sender, @NonNull Parcel out) {
553     if (sender == null) {
554       out.writeInt(NULL_PENDING_INTENT_VALUE);
555       return;
556     }
557 
558     int index = parceledPendingIntents.size();
559     parceledPendingIntents.add(sender);
560     out.writeInt(index);
561 
562     if (RuntimeEnvironment.getApiLevel() >= N) {
563       ThreadLocal<OnMarshaledListener> sOnMarshaledListener =
564           ReflectionHelpers.getStaticField(PendingIntent.class, "sOnMarshaledListener");
565       OnMarshaledListener listener = sOnMarshaledListener.get();
566       if (listener != null) {
567         listener.onMarshaled(sender, out, 0);
568       }
569     }
570   }
571 
572   static final Creator<PendingIntent> CREATOR =
573       new Creator<PendingIntent>() {
574         @Override
575         public PendingIntent createFromParcel(Parcel in) {
576           return readPendingIntentOrNullFromParcel(in);
577         }
578 
579         @Override
580         public PendingIntent[] newArray(int size) {
581           return new PendingIntent[size];
582         }
583       };
584 
585   @Implementation
writeToParcel(Parcel out, int flags)586   protected void writeToParcel(Parcel out, int flags) {
587     writePendingIntentOrNullToParcel(realPendingIntent, out);
588   }
589 
create( Context context, Intent[] intents, Type type, int requestCode, int flags, @Nullable Bundle options)590   private static PendingIntent create(
591       Context context,
592       Intent[] intents,
593       Type type,
594       int requestCode,
595       int flags,
596       @Nullable Bundle options) {
597     synchronized (lock) {
598       Objects.requireNonNull(intents, "intents may not be null");
599 
600       // Search for a matching PendingIntent.
601       PendingIntent pendingIntent = getCreatedIntentFor(type, intents, requestCode, flags);
602       if ((flags & FLAG_NO_CREATE) != 0) {
603         return pendingIntent;
604       }
605 
606       // If requested, update the existing PendingIntent if one exists.
607       if (pendingIntent != null && (flags & FLAG_UPDATE_CURRENT) != 0) {
608         ShadowPendingIntent shadowPendingIntent = Shadow.extract(pendingIntent);
609         Intent intent = shadowPendingIntent.getSavedIntent();
610         Bundle extras = intent.getExtras();
611         if (extras != null) {
612           extras.clear();
613         }
614         intent.putExtras(intents[intents.length - 1]);
615         return pendingIntent;
616       }
617 
618       // If requested, cancel the existing PendingIntent if one exists.
619       if (pendingIntent != null && (flags & FLAG_CANCEL_CURRENT) != 0) {
620         ShadowPendingIntent shadowPendingIntent = Shadow.extract(pendingIntent);
621         shadowPendingIntent.cancel();
622         pendingIntent = null;
623       }
624 
625       // Build the PendingIntent if it does not exist.
626       if (pendingIntent == null) {
627         pendingIntent = ReflectionHelpers.callConstructor(PendingIntent.class);
628         // Some methods (e.g. toString) may NPE if 'mTarget' is null.
629         reflector(PendingIntentReflector.class, pendingIntent)
630             .setTarget(ReflectionHelpers.createNullProxy(IIntentSender.class));
631         ShadowPendingIntent shadowPendingIntent = Shadow.extract(pendingIntent);
632         shadowPendingIntent.savedIntents = intents;
633         shadowPendingIntent.type = type;
634         shadowPendingIntent.savedContext = context;
635         shadowPendingIntent.requestCode = requestCode;
636         shadowPendingIntent.flags = flags;
637         shadowPendingIntent.options = options;
638 
639         createdIntents.add(pendingIntent);
640       }
641 
642       return pendingIntent;
643     }
644   }
645 
getCreatedIntentFor( Type type, Intent[] intents, int requestCode, int flags)646   private static PendingIntent getCreatedIntentFor(
647       Type type, Intent[] intents, int requestCode, int flags) {
648     synchronized (lock) {
649       for (PendingIntent createdIntent : createdIntents) {
650         ShadowPendingIntent shadowPendingIntent = Shadow.extract(createdIntent);
651 
652         if (isOneShot(shadowPendingIntent.flags) != isOneShot(flags)) {
653           continue;
654         }
655 
656         if (isMutable(shadowPendingIntent.flags) != isMutable(flags)) {
657           continue;
658         }
659 
660         if (shadowPendingIntent.type != type) {
661           continue;
662         }
663 
664         if (shadowPendingIntent.requestCode != requestCode) {
665           continue;
666         }
667 
668         // The last Intent in the array acts as the "significant element" for matching as per
669         // {@link #getActivities(Context, int, Intent[], int)}.
670         Intent savedIntent = shadowPendingIntent.getSavedIntent();
671         Intent targetIntent = intents[intents.length - 1];
672 
673         if (savedIntent == null ? targetIntent == null : savedIntent.filterEquals(targetIntent)) {
674           return createdIntent;
675         }
676       }
677       return null;
678     }
679   }
680 
isOneShot(int flags)681   private static boolean isOneShot(int flags) {
682     return (flags & FLAG_ONE_SHOT) != 0;
683   }
684 
isMutable(int flags)685   private static boolean isMutable(int flags) {
686     return (flags & FLAG_IMMUTABLE) == 0;
687   }
688 
689   @Resetter
reset()690   public static void reset() {
691     synchronized (lock) {
692       createdIntents.clear();
693       parceledPendingIntents.clear();
694     }
695 
696   }
697 
698   @ForType(PendingIntent.class)
699   interface PendingIntentReflector {
700     @Accessor("mTarget")
setTarget(IIntentSender target)701     void setTarget(IIntentSender target);
702   }
703 }
704