1 /*
2  * Copyright (C) 2011 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.android.internal.util.test;
18 
19 import android.content.BroadcastReceiver;
20 import android.content.Context;
21 import android.content.ContextWrapper;
22 import android.content.Intent;
23 import android.content.IntentFilter;
24 import android.os.Bundle;
25 import android.os.Handler;
26 import android.os.UserHandle;
27 
28 import java.util.ArrayList;
29 import java.util.Iterator;
30 import java.util.List;
31 import java.util.concurrent.ExecutionException;
32 import java.util.concurrent.Future;
33 import java.util.concurrent.FutureTask;
34 import java.util.concurrent.TimeUnit;
35 import java.util.concurrent.TimeoutException;
36 
37 /**
38  * {@link ContextWrapper} that can attach listeners for upcoming
39  * {@link Context#sendBroadcast(Intent)}.
40  */
41 public class BroadcastInterceptingContext extends ContextWrapper {
42     private static final String TAG = "WatchingContext";
43 
44     private final List<BroadcastInterceptor> mInterceptors = new ArrayList<>();
45 
46     public abstract class FutureIntent extends FutureTask<Intent> {
FutureIntent()47         public FutureIntent() {
48             super(
49                 () -> { throw new IllegalStateException("Cannot happen"); }
50             );
51         }
52 
assertNotReceived()53         public void assertNotReceived()
54                 throws InterruptedException, ExecutionException {
55             assertNotReceived(5, TimeUnit.SECONDS);
56         }
57 
assertNotReceived(long timeout, TimeUnit unit)58         public abstract void assertNotReceived(long timeout, TimeUnit unit)
59                 throws InterruptedException, ExecutionException;
60     }
61 
62     public class BroadcastInterceptor extends FutureIntent {
63         private final BroadcastReceiver mReceiver;
64         private final IntentFilter mFilter;
65 
BroadcastInterceptor(BroadcastReceiver receiver, IntentFilter filter)66         public BroadcastInterceptor(BroadcastReceiver receiver, IntentFilter filter) {
67             mReceiver = receiver;
68             mFilter = filter;
69         }
70 
dispatchBroadcast(Intent intent)71         public boolean dispatchBroadcast(Intent intent) {
72             if (mFilter.match(getContentResolver(), intent, false, TAG) > 0) {
73                 if (mReceiver != null) {
74                     final Context context = BroadcastInterceptingContext.this;
75                     mReceiver.onReceive(context, intent);
76                     return false;
77                 } else {
78                     set(intent);
79                     return true;
80                 }
81             } else {
82                 return false;
83             }
84         }
85 
86         @Override
get()87         public Intent get() throws InterruptedException, ExecutionException {
88             try {
89                 return get(5, TimeUnit.SECONDS);
90             } catch (TimeoutException e) {
91                 throw new RuntimeException(e);
92             }
93         }
94 
95         @Override
assertNotReceived()96         public void assertNotReceived()
97             throws InterruptedException, ExecutionException {
98             assertNotReceived(5, TimeUnit.SECONDS);
99         }
100 
assertNotReceived(long timeout, TimeUnit unit)101         public void assertNotReceived(long timeout, TimeUnit unit)
102                 throws InterruptedException, ExecutionException {
103             try {
104                 final Intent intent = get(timeout, unit);
105                 throw new AssertionError("Received intent: " + intent);
106             } catch (TimeoutException e) {
107             }
108         }
109     }
110 
BroadcastInterceptingContext(Context base)111     public BroadcastInterceptingContext(Context base) {
112         super(base);
113     }
114 
nextBroadcastIntent(String action)115     public FutureIntent nextBroadcastIntent(String action) {
116         return nextBroadcastIntent(new IntentFilter(action));
117     }
118 
nextBroadcastIntent(IntentFilter filter)119     public FutureIntent nextBroadcastIntent(IntentFilter filter) {
120         final BroadcastInterceptor interceptor = new BroadcastInterceptor(null, filter);
121         synchronized (mInterceptors) {
122             mInterceptors.add(interceptor);
123         }
124         return interceptor;
125     }
126 
127     @Override
registerReceiver(BroadcastReceiver receiver, IntentFilter filter)128     public Intent registerReceiver(BroadcastReceiver receiver, IntentFilter filter) {
129         synchronized (mInterceptors) {
130             mInterceptors.add(new BroadcastInterceptor(receiver, filter));
131         }
132         return null;
133     }
134 
135     @Override
registerReceiver(BroadcastReceiver receiver, IntentFilter filter, String broadcastPermission, Handler scheduler)136     public Intent registerReceiver(BroadcastReceiver receiver, IntentFilter filter,
137             String broadcastPermission, Handler scheduler) {
138         return registerReceiver(receiver, filter);
139     }
140 
141     @Override
unregisterReceiver(BroadcastReceiver receiver)142     public void unregisterReceiver(BroadcastReceiver receiver) {
143         synchronized (mInterceptors) {
144             final Iterator<BroadcastInterceptor> i = mInterceptors.iterator();
145             while (i.hasNext()) {
146                 final BroadcastInterceptor interceptor = i.next();
147                 if (receiver.equals(interceptor.mReceiver)) {
148                     i.remove();
149                 }
150             }
151         }
152     }
153 
154     @Override
sendBroadcast(Intent intent)155     public void sendBroadcast(Intent intent) {
156         synchronized (mInterceptors) {
157             final Iterator<BroadcastInterceptor> i = mInterceptors.iterator();
158             while (i.hasNext()) {
159                 final BroadcastInterceptor interceptor = i.next();
160                 if (interceptor.dispatchBroadcast(intent)) {
161                     i.remove();
162                 }
163             }
164         }
165     }
166 
167     @Override
sendBroadcast(Intent intent, String receiverPermission)168     public void sendBroadcast(Intent intent, String receiverPermission) {
169         sendBroadcast(intent);
170     }
171 
172     @Override
sendBroadcastMultiplePermissions(Intent intent, String[] receiverPermissions)173     public void sendBroadcastMultiplePermissions(Intent intent, String[] receiverPermissions) {
174         sendBroadcast(intent);
175     }
176 
177     @Override
sendBroadcastAsUserMultiplePermissions(Intent intent, UserHandle user, String[] receiverPermissions)178     public void sendBroadcastAsUserMultiplePermissions(Intent intent, UserHandle user,
179             String[] receiverPermissions) {
180         sendBroadcast(intent);
181     }
182 
183     @Override
sendBroadcastAsUser(Intent intent, UserHandle user)184     public void sendBroadcastAsUser(Intent intent, UserHandle user) {
185         sendBroadcast(intent);
186     }
187 
188     @Override
sendBroadcastAsUser(Intent intent, UserHandle user, String receiverPermission)189     public void sendBroadcastAsUser(Intent intent, UserHandle user,
190             String receiverPermission) {
191         sendBroadcast(intent);
192     }
193 
194     @Override
sendStickyBroadcast(Intent intent)195     public void sendStickyBroadcast(Intent intent) {
196         sendBroadcast(intent);
197     }
198 
199     @Override
sendStickyBroadcastAsUser(Intent intent, UserHandle user)200     public void sendStickyBroadcastAsUser(Intent intent, UserHandle user) {
201         sendBroadcast(intent);
202     }
203 
204     @Override
sendStickyBroadcastAsUser(Intent intent, UserHandle user, Bundle options)205     public void sendStickyBroadcastAsUser(Intent intent, UserHandle user, Bundle options) {
206         sendBroadcast(intent);
207     }
208 
209     @Override
removeStickyBroadcast(Intent intent)210     public void removeStickyBroadcast(Intent intent) {
211         // ignored
212     }
213 }
214