1 package org.robolectric.shadows;
2 
3 import static org.robolectric.util.reflector.Reflector.reflector;
4 
5 import android.content.BroadcastReceiver;
6 import android.content.BroadcastReceiver.PendingResult;
7 import android.content.Context;
8 import android.content.Intent;
9 import java.util.concurrent.atomic.AtomicBoolean;
10 import org.robolectric.annotation.Implementation;
11 import org.robolectric.annotation.Implements;
12 import org.robolectric.annotation.RealObject;
13 import org.robolectric.util.reflector.Direct;
14 import org.robolectric.util.reflector.ForType;
15 
16 @Implements(BroadcastReceiver.class)
17 public class ShadowBroadcastReceiver {
18   @RealObject BroadcastReceiver receiver;
19 
20   // The abort state of the currently processed broadcast
21   private AtomicBoolean abort = new AtomicBoolean(false);
22   private boolean wentAsync = false;
23   private PendingResult originalPendingResult;
24 
25   @Implementation
abortBroadcast()26   protected void abortBroadcast() {
27     // TODO probably needs a check to prevent calling this method from ordinary Broadcasts
28     abort.set(true);
29   }
30 
31   @Implementation
onReceive(Context context, Intent intent)32   protected void onReceive(Context context, Intent intent) {
33     if (abort == null || !abort.get()) {
34       receiver.onReceive(context, intent);
35     }
36   }
37 
onReceive(Context context, Intent intent, AtomicBoolean abort)38   public void onReceive(Context context, Intent intent, AtomicBoolean abort) {
39     this.abort = abort;
40     onReceive(context, intent);
41     // If the underlying receiver has called goAsync(), we should not finish the pending result yet
42     // - they'll do that
43     // for us.
44     if (receiver.getPendingResult() != null) {
45       receiver.getPendingResult().finish();
46     }
47   }
48 
49   @Implementation
goAsync()50   protected PendingResult goAsync() {
51     // Save the PendingResult before goAsync() clears it.
52     originalPendingResult = receiver.getPendingResult();
53     wentAsync = true;
54     return reflector(BroadcastReceiverReflector.class, receiver).goAsync();
55   }
56 
wentAsync()57   public boolean wentAsync() {
58     return wentAsync;
59   }
60 
getOriginalPendingResult()61   public PendingResult getOriginalPendingResult() {
62     if (wentAsync) {
63       return originalPendingResult;
64     } else {
65       return receiver.getPendingResult();
66     }
67   }
68 
69   @ForType(BroadcastReceiver.class)
70   interface BroadcastReceiverReflector {
71 
72     @Direct
goAsync()73     PendingResult goAsync();
74   }
75 }
76