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