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