1 package org.robolectric.shadows; 2 3 import static org.robolectric.annotation.LooperMode.Mode.LEGACY; 4 import static org.robolectric.shadows.ShadowLooper.assertLooperMode; 5 6 import android.app.ActivityThread; 7 import android.app.AlertDialog; 8 import android.app.Application; 9 import android.app.Dialog; 10 import android.appwidget.AppWidgetManager; 11 import android.bluetooth.BluetoothAdapter; 12 import android.content.BroadcastReceiver; 13 import android.content.ComponentName; 14 import android.content.Context; 15 import android.content.ContextWrapper; 16 import android.content.Intent; 17 import android.content.IntentFilter; 18 import android.content.ServiceConnection; 19 import android.os.Handler; 20 import android.os.IBinder; 21 import android.os.PowerManager; 22 import android.widget.ListPopupWindow; 23 import android.widget.PopupWindow; 24 import android.widget.Toast; 25 import com.google.common.collect.ImmutableList; 26 import java.util.ArrayList; 27 import java.util.HashMap; 28 import java.util.List; 29 import java.util.Map; 30 import org.robolectric.RuntimeEnvironment; 31 import org.robolectric.annotation.Implements; 32 import org.robolectric.annotation.RealObject; 33 import org.robolectric.shadow.api.Shadow; 34 import org.robolectric.shadows.ShadowActivityThread._ActivityThread_; 35 import org.robolectric.shadows.ShadowActivityThread._AppBindData_; 36 import org.robolectric.shadows.ShadowUserManager.UserManagerState; 37 import org.robolectric.util.ReflectionHelpers; 38 import org.robolectric.util.Scheduler; 39 import org.robolectric.util.reflector.Reflector; 40 41 @Implements(Application.class) 42 public class ShadowApplication extends ShadowContextWrapper { 43 @RealObject private Application realApplication; 44 45 private List<android.widget.Toast> shownToasts = new ArrayList<>(); 46 private ShadowPopupMenu latestPopupMenu; 47 private PopupWindow latestPopupWindow; 48 private ListPopupWindow latestListPopupWindow; 49 private UserManagerState userManagerState; 50 51 /** 52 * @deprecated Use {@code shadowOf({@link ApplicationProvider#getApplicationContext()})} instead. 53 */ 54 @Deprecated getInstance()55 public static ShadowApplication getInstance() { 56 return Shadow.extract(RuntimeEnvironment.getApplication()); 57 } 58 59 /** 60 * Runs any background tasks previously queued by {@link android.os.AsyncTask#execute(Object[])}. 61 * 62 * <p>Note: calling this method does not pause or un-pause the scheduler. 63 */ runBackgroundTasks()64 public static void runBackgroundTasks() { 65 getInstance().getBackgroundThreadScheduler().advanceBy(0); 66 } 67 68 /** Configures the value to be returned by {@link Application#getProcessName()}. */ setProcessName(String processName)69 public static void setProcessName(String processName) { 70 // No need for a @Resetter because the whole ActivityThread is reset before each test. 71 _ActivityThread_ activityThread = 72 Reflector.reflector(_ActivityThread_.class, ShadowActivityThread.currentActivityThread()); 73 Reflector.reflector(_AppBindData_.class, activityThread.getBoundApplication()) 74 .setProcessName(processName); 75 } 76 77 /** 78 * Attaches an application to a base context. 79 * 80 * @param context The context with which to initialize the application, whose base context will be 81 * attached to the application 82 */ callAttach(Context context)83 public void callAttach(Context context) { 84 ReflectionHelpers.callInstanceMethod( 85 Application.class, 86 realApplication, 87 "attach", 88 ReflectionHelpers.ClassParameter.from(Context.class, context)); 89 } 90 getShownToasts()91 public List<Toast> getShownToasts() { 92 return shownToasts; 93 } 94 95 /** 96 * Return the foreground scheduler. 97 * 98 * @return Foreground scheduler. 99 * @deprecated use {@link org.robolectric.Robolectric#getForegroundThreadScheduler()} 100 */ 101 @Deprecated getForegroundThreadScheduler()102 public Scheduler getForegroundThreadScheduler() { 103 return RuntimeEnvironment.getMasterScheduler(); 104 } 105 106 /** 107 * Return the background scheduler. 108 * 109 * @return Background scheduler. 110 * @deprecated use {@link org.robolectric.Robolectric#getBackgroundThreadScheduler()} 111 */ 112 @Deprecated getBackgroundThreadScheduler()113 public Scheduler getBackgroundThreadScheduler() { 114 assertLooperMode(LEGACY); 115 return ShadowLegacyLooper.getBackgroundThreadScheduler(); 116 } 117 118 /** 119 * Sets whether or not calls to unbindService should call onServiceDisconnected(). 120 * 121 * <p>The default for this is currently {@code true} because that is the historical behavior. 122 * However, this does not correctly mirror Android's actual behavior. This value will eventually 123 * default to {@code false} once users have had a chance to migrate, and eventually the option 124 * will be removed altogether. 125 */ setUnbindServiceCallsOnServiceDisconnected(boolean flag)126 public void setUnbindServiceCallsOnServiceDisconnected(boolean flag) { 127 getShadowInstrumentation().setUnbindServiceCallsOnServiceDisconnected(flag); 128 } 129 setComponentNameAndServiceForBindService(ComponentName name, IBinder service)130 public void setComponentNameAndServiceForBindService(ComponentName name, IBinder service) { 131 getShadowInstrumentation().setComponentNameAndServiceForBindService(name, service); 132 } 133 setComponentNameAndServiceForBindServiceForIntent( Intent intent, ComponentName name, IBinder service)134 public void setComponentNameAndServiceForBindServiceForIntent( 135 Intent intent, ComponentName name, IBinder service) { 136 getShadowInstrumentation() 137 .setComponentNameAndServiceForBindServiceForIntent(intent, name, service); 138 } 139 assertNoBroadcastListenersOfActionRegistered(ContextWrapper context, String action)140 public void assertNoBroadcastListenersOfActionRegistered(ContextWrapper context, String action) { 141 getShadowInstrumentation().assertNoBroadcastListenersOfActionRegistered(context, action); 142 } 143 getBoundServiceConnections()144 public List<ServiceConnection> getBoundServiceConnections() { 145 return getShadowInstrumentation().getBoundServiceConnections(); 146 } 147 setUnbindServiceShouldThrowIllegalArgument(boolean flag)148 public void setUnbindServiceShouldThrowIllegalArgument(boolean flag) { 149 getShadowInstrumentation().setUnbindServiceShouldThrowIllegalArgument(flag); 150 } 151 152 /** 153 * Configures the ShadowApplication so that calls to bindService will throw the given 154 * SecurityException. 155 */ setThrowInBindService(SecurityException e)156 public void setThrowInBindService(SecurityException e) { 157 getShadowInstrumentation().setThrowInBindService(e); 158 } 159 160 /** 161 * Configures the ShadowApplication so that calls to bindService will call 162 * ServiceConnection#onServiceConnected before returning. 163 */ setBindServiceCallsOnServiceConnectedDirectly(boolean callDirectly)164 public void setBindServiceCallsOnServiceConnectedDirectly(boolean callDirectly) { 165 getShadowInstrumentation().setBindServiceCallsOnServiceConnectedDirectly(callDirectly); 166 } 167 getUnboundServiceConnections()168 public List<ServiceConnection> getUnboundServiceConnections() { 169 return getShadowInstrumentation().getUnboundServiceConnections(); 170 } 171 172 /** 173 * @deprecated use PackageManager.queryBroadcastReceivers instead 174 */ 175 @Deprecated hasReceiverForIntent(Intent intent)176 public boolean hasReceiverForIntent(Intent intent) { 177 return getShadowInstrumentation().hasReceiverForIntent(intent); 178 } 179 180 /** 181 * @deprecated use PackageManager.queryBroadcastReceivers instead 182 */ 183 @Deprecated getReceiversForIntent(Intent intent)184 public List<BroadcastReceiver> getReceiversForIntent(Intent intent) { 185 return getShadowInstrumentation().getReceiversForIntent(intent); 186 } 187 188 /** 189 * @return list of {@link Wrapper}s for registered receivers 190 */ getRegisteredReceivers()191 public ImmutableList<Wrapper> getRegisteredReceivers() { 192 return getShadowInstrumentation().getRegisteredReceivers(); 193 } 194 195 /** Clears the list of {@link Wrapper}s for registered receivers */ clearRegisteredReceivers()196 public void clearRegisteredReceivers() { 197 getShadowInstrumentation().clearRegisteredReceivers(); 198 } 199 200 /** 201 * @deprecated Please use {@link Context#getSystemService(Context.APPWIDGET_SERVICE)} intstead. 202 */ 203 @Deprecated getAppWidgetManager()204 public AppWidgetManager getAppWidgetManager() { 205 return (AppWidgetManager) realApplication.getSystemService(Context.APPWIDGET_SERVICE); 206 } 207 208 /** 209 * @deprecated Use {@link ShadowAlertDialog#getLatestAlertDialog()} instead. 210 */ 211 @Deprecated getLatestAlertDialog()212 public ShadowAlertDialog getLatestAlertDialog() { 213 AlertDialog dialog = ShadowAlertDialog.getLatestAlertDialog(); 214 return dialog == null ? null : Shadow.extract(dialog); 215 } 216 217 /** 218 * @deprecated Use {@link ShadowDialog#getLatestDialog()} instead. 219 */ 220 @Deprecated getLatestDialog()221 public ShadowDialog getLatestDialog() { 222 Dialog dialog = ShadowDialog.getLatestDialog(); 223 return dialog == null ? null : Shadow.extract(dialog); 224 } 225 226 /** 227 * @deprecated Use {@link BluetoothAdapter#getDefaultAdapter()} ()} instead. 228 */ 229 @Deprecated getBluetoothAdapter()230 public final BluetoothAdapter getBluetoothAdapter() { 231 return BluetoothAdapter.getDefaultAdapter(); 232 } 233 declareActionUnbindable(String action)234 public void declareActionUnbindable(String action) { 235 getShadowInstrumentation().declareActionUnbindable(action); 236 } 237 238 /** 239 * Configures the ShadowApplication so that bindService calls for the given ComponentName return 240 * false and do not call onServiceConnected. 241 */ declareComponentUnbindable(ComponentName component)242 public void declareComponentUnbindable(ComponentName component) { 243 getShadowInstrumentation().declareComponentUnbindable(component); 244 } 245 246 /** 247 * @deprecated use ShadowPowerManager.getLatestWakeLock 248 */ 249 @Deprecated getLatestWakeLock()250 public PowerManager.WakeLock getLatestWakeLock() { 251 return ShadowPowerManager.getLatestWakeLock(); 252 } 253 254 /** 255 * @deprecated use PowerManager APIs instead 256 */ 257 @Deprecated addWakeLock(PowerManager.WakeLock wl)258 public void addWakeLock(PowerManager.WakeLock wl) { 259 ShadowPowerManager.addWakeLock(wl); 260 } 261 262 /** 263 * @deprecated use ShadowPowerManager.clearWakeLocks 264 */ 265 @Deprecated clearWakeLocks()266 public void clearWakeLocks() { 267 ShadowPowerManager.clearWakeLocks(); 268 } 269 270 private final Map<String, Object> singletons = new HashMap<>(); 271 getSingleton(Class<T> clazz, Provider<T> provider)272 public <T> T getSingleton(Class<T> clazz, Provider<T> provider) { 273 synchronized (singletons) { 274 //noinspection unchecked 275 T item = (T) singletons.get(clazz.getName()); 276 if (item == null) { 277 singletons.put(clazz.getName(), item = provider.get()); 278 } 279 return item; 280 } 281 } 282 283 /** 284 * Set to true if you'd like Robolectric to strictly simulate the real Android behavior when 285 * calling {@link Context#startActivity(android.content.Intent)}. Real Android throws a {@link 286 * android.content.ActivityNotFoundException} if given an {@link Intent} that is not known to the 287 * {@link android.content.pm.PackageManager} 288 * 289 * <p>By default, this behavior is off (false). 290 * 291 * @param checkActivities True to validate activities. 292 */ checkActivities(boolean checkActivities)293 public void checkActivities(boolean checkActivities) { 294 ActivityThread activityThread = (ActivityThread) RuntimeEnvironment.getActivityThread(); 295 ShadowInstrumentation shadowInstrumentation = 296 Shadow.extract(activityThread.getInstrumentation()); 297 shadowInstrumentation.checkActivities(checkActivities); 298 } 299 300 /** 301 * @deprecated Use {@link ShadowPopupMenu#getLatestPopupMenu()} instead. 302 */ 303 @Deprecated getLatestPopupMenu()304 public ShadowPopupMenu getLatestPopupMenu() { 305 return latestPopupMenu; 306 } 307 setLatestPopupMenu(ShadowPopupMenu latestPopupMenu)308 protected void setLatestPopupMenu(ShadowPopupMenu latestPopupMenu) { 309 this.latestPopupMenu = latestPopupMenu; 310 } 311 getLatestPopupWindow()312 public PopupWindow getLatestPopupWindow() { 313 return latestPopupWindow; 314 } 315 setLatestPopupWindow(PopupWindow latestPopupWindow)316 protected void setLatestPopupWindow(PopupWindow latestPopupWindow) { 317 this.latestPopupWindow = latestPopupWindow; 318 } 319 getLatestListPopupWindow()320 public ListPopupWindow getLatestListPopupWindow() { 321 return latestListPopupWindow; 322 } 323 setLatestListPopupWindow(ListPopupWindow latestListPopupWindow)324 protected void setLatestListPopupWindow(ListPopupWindow latestListPopupWindow) { 325 this.latestListPopupWindow = latestListPopupWindow; 326 } 327 getUserManagerState()328 UserManagerState getUserManagerState() { 329 if (userManagerState == null) { 330 userManagerState = new UserManagerState(); 331 } 332 333 return userManagerState; 334 } 335 336 public static final class Wrapper { 337 public BroadcastReceiver broadcastReceiver; 338 public IntentFilter intentFilter; 339 public Context context; 340 public Throwable exception; 341 public String broadcastPermission; 342 public Handler scheduler; 343 public int flags; 344 Wrapper( BroadcastReceiver broadcastReceiver, IntentFilter intentFilter, Context context, String broadcastPermission, Handler scheduler, int flags)345 public Wrapper( 346 BroadcastReceiver broadcastReceiver, 347 IntentFilter intentFilter, 348 Context context, 349 String broadcastPermission, 350 Handler scheduler, 351 int flags) { 352 this.broadcastReceiver = broadcastReceiver; 353 this.intentFilter = intentFilter; 354 this.context = context; 355 this.broadcastPermission = broadcastPermission; 356 this.scheduler = scheduler; 357 this.flags = flags; 358 exception = new Throwable(); 359 } 360 getBroadcastReceiver()361 public BroadcastReceiver getBroadcastReceiver() { 362 return broadcastReceiver; 363 } 364 getIntentFilter()365 public IntentFilter getIntentFilter() { 366 return intentFilter; 367 } 368 getContext()369 public Context getContext() { 370 return context; 371 } 372 373 @Override toString()374 public String toString() { 375 return "Wrapper[receiver=[" 376 + broadcastReceiver 377 + "], context=[" 378 + context 379 + "], intentFilter=[" 380 + intentFilter 381 + "]]"; 382 } 383 } 384 385 /** 386 * @deprecated Do not depend on this method to override services as it will be removed in a future 387 * update. The preferered method is use the shadow of the corresponding service. 388 */ 389 @Deprecated setSystemService(String key, Object service)390 public void setSystemService(String key, Object service) { 391 ShadowContextImpl shadowContext = Shadow.extract(realApplication.getBaseContext()); 392 shadowContext.setSystemService(key, service); 393 } 394 } 395