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