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.FutureTask; 33 import java.util.concurrent.TimeUnit; 34 import java.util.concurrent.TimeoutException; 35 36 /** 37 * {@link ContextWrapper} that can attach listeners for upcoming 38 * {@link Context#sendBroadcast(Intent)}. 39 */ 40 public class BroadcastInterceptingContext extends ContextWrapper { 41 private static final String TAG = "WatchingContext"; 42 43 private final List<BroadcastInterceptor> mInterceptors = new ArrayList<>(); 44 45 private boolean mUseRegisteredHandlers; 46 47 public abstract class FutureIntent extends FutureTask<Intent> { FutureIntent()48 public FutureIntent() { 49 super( 50 () -> { throw new IllegalStateException("Cannot happen"); } 51 ); 52 } 53 assertNotReceived()54 public void assertNotReceived() 55 throws InterruptedException, ExecutionException { 56 assertNotReceived(5, TimeUnit.SECONDS); 57 } 58 assertNotReceived(long timeout, TimeUnit unit)59 public abstract void assertNotReceived(long timeout, TimeUnit unit) 60 throws InterruptedException, ExecutionException; 61 } 62 63 public class BroadcastInterceptor extends FutureIntent { 64 private final BroadcastReceiver mReceiver; 65 private final IntentFilter mFilter; 66 private final Handler mHandler; 67 BroadcastInterceptor(BroadcastReceiver receiver, IntentFilter filter, Handler handler)68 public BroadcastInterceptor(BroadcastReceiver receiver, IntentFilter filter, 69 Handler handler) { 70 mReceiver = receiver; 71 mFilter = filter; 72 mHandler = mUseRegisteredHandlers ? handler : null; 73 } 74 dispatchBroadcast(Intent intent)75 public boolean dispatchBroadcast(Intent intent) { 76 if (mFilter.match(getContentResolver(), intent, false, TAG) > 0) { 77 if (mReceiver != null) { 78 final Context context = BroadcastInterceptingContext.this; 79 if (mHandler == null) { 80 mReceiver.onReceive(context, intent); 81 } else { 82 mHandler.post(() -> mReceiver.onReceive(context, intent)); 83 } 84 return false; 85 } else { 86 set(intent); 87 return true; 88 } 89 } else { 90 return false; 91 } 92 } 93 94 @Override get()95 public Intent get() throws InterruptedException, ExecutionException { 96 try { 97 return get(5, TimeUnit.SECONDS); 98 } catch (TimeoutException e) { 99 throw new RuntimeException(e); 100 } 101 } 102 103 @Override assertNotReceived()104 public void assertNotReceived() 105 throws InterruptedException, ExecutionException { 106 assertNotReceived(5, TimeUnit.SECONDS); 107 } 108 assertNotReceived(long timeout, TimeUnit unit)109 public void assertNotReceived(long timeout, TimeUnit unit) 110 throws InterruptedException, ExecutionException { 111 try { 112 final Intent intent = get(timeout, unit); 113 throw new AssertionError("Received intent: " + intent); 114 } catch (TimeoutException e) { 115 } 116 } 117 } 118 BroadcastInterceptingContext(Context base)119 public BroadcastInterceptingContext(Context base) { 120 super(base); 121 } 122 nextBroadcastIntent(String action)123 public FutureIntent nextBroadcastIntent(String action) { 124 return nextBroadcastIntent(new IntentFilter(action)); 125 } 126 nextBroadcastIntent(IntentFilter filter)127 public FutureIntent nextBroadcastIntent(IntentFilter filter) { 128 final BroadcastInterceptor interceptor = new BroadcastInterceptor(null, filter, null); 129 synchronized (mInterceptors) { 130 mInterceptors.add(interceptor); 131 } 132 return interceptor; 133 } 134 135 /** 136 * Whether to send broadcasts to registered handlers. By default, receivers are called 137 * synchronously by sendBroadcast. If this method is called with {@code true}, the receiver is 138 * instead called by a runnable posted to the Handler specified when the receiver was 139 * registered. This method applies only to future registrations, already-registered receivers 140 * are unaffected. 141 */ setUseRegisteredHandlers(boolean use)142 public void setUseRegisteredHandlers(boolean use) { 143 synchronized (mInterceptors) { 144 mUseRegisteredHandlers = use; 145 } 146 } 147 148 @Override registerReceiver(BroadcastReceiver receiver, IntentFilter filter)149 public Intent registerReceiver(BroadcastReceiver receiver, IntentFilter filter) { 150 return registerReceiver(receiver, filter, null, null, 0); 151 } 152 153 /** 154 * Registers the specified {@code receiver} to listen for broadcasts that match the {@code 155 * filter} in the current process. 156 * 157 * <p>Since this method only listens for broadcasts in the current process, the provided {@code 158 * flags} are ignored; this method is primarily intended to allow receivers that register with 159 * flags to register in the current process during tests. 160 */ 161 @Override registerReceiver(BroadcastReceiver receiver, IntentFilter filter, int flags)162 public Intent registerReceiver(BroadcastReceiver receiver, IntentFilter filter, int flags) { 163 return registerReceiver(receiver, filter, null, null, flags); 164 } 165 166 @Override registerReceiver(BroadcastReceiver receiver, IntentFilter filter, String broadcastPermission, Handler scheduler)167 public Intent registerReceiver(BroadcastReceiver receiver, IntentFilter filter, 168 String broadcastPermission, Handler scheduler) { 169 return registerReceiver(receiver, filter, broadcastPermission, scheduler, 0); 170 } 171 172 /** 173 * Registers the specified {@code receiver} to listen for broadcasts that match the {@code 174 * filter} to run in the context of the specified {@code scheduler} in the current process. 175 * 176 * <p>Since this method only listens for broadcasts in the current process, the provided {@code 177 * flags} are ignored; this method is primarily intended to allow receivers that register with 178 * flags to register in the current process during tests. 179 */ 180 @Override registerReceiver(BroadcastReceiver receiver, IntentFilter filter, String broadcastPermission, Handler scheduler, int flags)181 public Intent registerReceiver(BroadcastReceiver receiver, IntentFilter filter, 182 String broadcastPermission, Handler scheduler, int flags) { 183 synchronized (mInterceptors) { 184 mInterceptors.add(new BroadcastInterceptor(receiver, filter, scheduler)); 185 } 186 return null; 187 } 188 189 @Override unregisterReceiver(BroadcastReceiver receiver)190 public void unregisterReceiver(BroadcastReceiver receiver) { 191 synchronized (mInterceptors) { 192 final Iterator<BroadcastInterceptor> i = mInterceptors.iterator(); 193 while (i.hasNext()) { 194 final BroadcastInterceptor interceptor = i.next(); 195 if (receiver.equals(interceptor.mReceiver)) { 196 i.remove(); 197 } 198 } 199 } 200 } 201 202 @Override sendBroadcast(Intent intent)203 public void sendBroadcast(Intent intent) { 204 synchronized (mInterceptors) { 205 final Iterator<BroadcastInterceptor> i = mInterceptors.iterator(); 206 while (i.hasNext()) { 207 final BroadcastInterceptor interceptor = i.next(); 208 if (interceptor.dispatchBroadcast(intent)) { 209 i.remove(); 210 } 211 } 212 } 213 } 214 215 @Override sendBroadcast(Intent intent, String receiverPermission)216 public void sendBroadcast(Intent intent, String receiverPermission) { 217 sendBroadcast(intent); 218 } 219 220 @Override sendBroadcastMultiplePermissions(Intent intent, String[] receiverPermissions)221 public void sendBroadcastMultiplePermissions(Intent intent, String[] receiverPermissions) { 222 sendBroadcast(intent); 223 } 224 225 @Override sendBroadcastMultiplePermissions(Intent intent, String[] receiverPermissions, Bundle options)226 public void sendBroadcastMultiplePermissions(Intent intent, String[] receiverPermissions, 227 Bundle options) { 228 sendBroadcast(intent); 229 } 230 231 @Override sendBroadcastAsUserMultiplePermissions(Intent intent, UserHandle user, String[] receiverPermissions)232 public void sendBroadcastAsUserMultiplePermissions(Intent intent, UserHandle user, 233 String[] receiverPermissions) { 234 sendBroadcast(intent); 235 } 236 237 @Override sendBroadcastAsUser(Intent intent, UserHandle user)238 public void sendBroadcastAsUser(Intent intent, UserHandle user) { 239 sendBroadcast(intent); 240 } 241 242 @Override sendBroadcastAsUser(Intent intent, UserHandle user, String receiverPermission)243 public void sendBroadcastAsUser(Intent intent, UserHandle user, 244 String receiverPermission) { 245 sendBroadcast(intent); 246 } 247 248 @Override sendBroadcastAsUser(Intent intent, UserHandle user, String receiverPermission, Bundle options)249 public void sendBroadcastAsUser(Intent intent, UserHandle user, 250 String receiverPermission, Bundle options) { 251 sendBroadcast(intent); 252 } 253 254 @Override sendStickyBroadcast(Intent intent)255 public void sendStickyBroadcast(Intent intent) { 256 sendBroadcast(intent); 257 } 258 259 @Override sendStickyBroadcast(Intent intent, Bundle options)260 public void sendStickyBroadcast(Intent intent, Bundle options) { 261 sendBroadcast(intent); 262 } 263 264 @Override sendStickyBroadcastAsUser(Intent intent, UserHandle user)265 public void sendStickyBroadcastAsUser(Intent intent, UserHandle user) { 266 sendBroadcast(intent); 267 } 268 269 @Override sendStickyBroadcastAsUser(Intent intent, UserHandle user, Bundle options)270 public void sendStickyBroadcastAsUser(Intent intent, UserHandle user, Bundle options) { 271 sendBroadcast(intent); 272 } 273 274 @Override removeStickyBroadcast(Intent intent)275 public void removeStickyBroadcast(Intent intent) { 276 // ignored 277 } 278 } 279