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