1package org.robolectric.shadows;
2
3import static android.os.Build.VERSION_CODES.JELLY_BEAN_MR1;
4import static android.os.Build.VERSION_CODES.JELLY_BEAN_MR2;
5import static android.os.Build.VERSION_CODES.KITKAT;
6import static android.os.Build.VERSION_CODES.LOLLIPOP;
7import static android.os.Build.VERSION_CODES.LOLLIPOP_MR1;
8import static android.os.Build.VERSION_CODES.M;
9import static android.os.Build.VERSION_CODES.N;
10import static android.os.Build.VERSION_CODES.N_MR1;
11import static android.os.Build.VERSION_CODES.O;
12import static android.os.Build.VERSION_CODES.O_MR1;
13import static org.robolectric.RuntimeEnvironment.getApiLevel;
14import static org.robolectric.shadow.api.Shadow.newInstanceOf;
15
16import android.accounts.IAccountManager;
17import android.app.IWallpaperManager;
18import android.app.admin.IDevicePolicyManager;
19import android.content.BroadcastReceiver;
20import android.content.ComponentName;
21import android.content.ContentResolver;
22import android.content.Context;
23import android.content.IContentProvider;
24import android.content.IRestrictionsManager;
25import android.content.Intent;
26import android.content.IntentFilter;
27import android.content.IntentSender;
28import android.content.ServiceConnection;
29import android.hardware.SystemSensorManager;
30import android.hardware.fingerprint.IFingerprintService;
31import android.net.wifi.p2p.IWifiP2pManager;
32import android.net.wifi.p2p.WifiP2pManager;
33import android.os.Bundle;
34import android.os.Environment;
35import android.os.Handler;
36import android.os.IUserManager;
37import android.os.Looper;
38import android.os.UserHandle;
39import android.view.Display;
40import android.view.accessibility.AccessibilityManager;
41import android.view.autofill.IAutoFillManager;
42import java.io.File;
43import java.util.HashMap;
44import java.util.Map;
45import org.robolectric.RuntimeEnvironment;
46import org.robolectric.annotation.Implementation;
47import org.robolectric.annotation.Implements;
48import org.robolectric.annotation.RealObject;
49import org.robolectric.annotation.Resetter;
50import org.robolectric.util.ReflectionHelpers;
51import org.robolectric.util.ReflectionHelpers.ClassParameter;
52
53@Implements(className = ShadowContextImpl.CLASS_NAME)
54public class ShadowContextImpl {
55
56  public static final String CLASS_NAME = "android.app.ContextImpl";
57  private static final Map<String, String> SYSTEM_SERVICE_MAP = new HashMap<>();
58  private ContentResolver contentResolver;
59
60  @RealObject
61  private Context realObject;
62
63  static {
64    // note that these are different!
65    // They specify concrete classes within Robolectric for interfaces or abstract classes defined by Android
66    SYSTEM_SERVICE_MAP.put(Context.WINDOW_SERVICE, "android.view.WindowManagerImpl");
67    SYSTEM_SERVICE_MAP.put(Context.CLIPBOARD_SERVICE, "android.content.ClipboardManager");
68    SYSTEM_SERVICE_MAP.put(Context.SENSOR_SERVICE, "android.hardware.SystemSensorManager");
69    SYSTEM_SERVICE_MAP.put(Context.VIBRATOR_SERVICE, "org.robolectric.fakes.RoboVibrator");
70
71    // the rest are as mapped in docs...
72    SYSTEM_SERVICE_MAP.put(Context.LAYOUT_INFLATER_SERVICE, "android.view.LayoutInflater");
73    SYSTEM_SERVICE_MAP.put(Context.ACTIVITY_SERVICE, "android.app.ActivityManager");
74    SYSTEM_SERVICE_MAP.put(Context.POWER_SERVICE, "android.os.PowerManager");
75    SYSTEM_SERVICE_MAP.put(Context.ALARM_SERVICE, "android.app.AlarmManager");
76    SYSTEM_SERVICE_MAP.put(Context.NOTIFICATION_SERVICE, "android.app.NotificationManager");
77    SYSTEM_SERVICE_MAP.put(Context.KEYGUARD_SERVICE, "android.app.KeyguardManager");
78    SYSTEM_SERVICE_MAP.put(Context.LOCATION_SERVICE, "android.location.LocationManager");
79    SYSTEM_SERVICE_MAP.put(Context.SEARCH_SERVICE, "android.app.SearchManager");
80    SYSTEM_SERVICE_MAP.put(Context.STORAGE_SERVICE, "android.os.storage.StorageManager");
81    SYSTEM_SERVICE_MAP.put(Context.CONNECTIVITY_SERVICE, "android.net.ConnectivityManager");
82    SYSTEM_SERVICE_MAP.put(Context.WIFI_SERVICE, "android.net.wifi.WifiManager");
83    SYSTEM_SERVICE_MAP.put(Context.AUDIO_SERVICE, "android.media.AudioManager");
84    SYSTEM_SERVICE_MAP.put(Context.TELEPHONY_SERVICE, "android.telephony.TelephonyManager");
85    SYSTEM_SERVICE_MAP.put(Context.INPUT_METHOD_SERVICE, "android.view.inputmethod.InputMethodManager");
86    SYSTEM_SERVICE_MAP.put(Context.UI_MODE_SERVICE, "android.app.UiModeManager");
87    SYSTEM_SERVICE_MAP.put(Context.DOWNLOAD_SERVICE, "android.app.DownloadManager");
88    SYSTEM_SERVICE_MAP.put(Context.TEXT_SERVICES_MANAGER_SERVICE, "android.view.textservice.TextServicesManager");
89    SYSTEM_SERVICE_MAP.put(Context.DEVICE_POLICY_SERVICE, "android.app.admin.DevicePolicyManager");
90    SYSTEM_SERVICE_MAP.put(Context.DROPBOX_SERVICE, "android.os.DropBoxManager");
91    SYSTEM_SERVICE_MAP.put(Context.MEDIA_ROUTER_SERVICE, "android.media.MediaRouter");
92    SYSTEM_SERVICE_MAP.put(Context.ACCESSIBILITY_SERVICE, "android.view.accessibility.AccessibilityManager");
93    SYSTEM_SERVICE_MAP.put(Context.ACCOUNT_SERVICE, "android.accounts.AccountManager");
94    SYSTEM_SERVICE_MAP.put(Context.NFC_SERVICE, "android.nfc.NfcManager");
95    SYSTEM_SERVICE_MAP.put(Context.WALLPAPER_SERVICE, "android.app.WallpaperManager");
96    SYSTEM_SERVICE_MAP.put(Context.WIFI_P2P_SERVICE, "android.net.wifi.p2p.WifiP2pManager");
97    SYSTEM_SERVICE_MAP.put(Context.USB_SERVICE, "android.hardware.usb.UsbManager");
98    SYSTEM_SERVICE_MAP.put(Context.AUTOFILL_MANAGER_SERVICE, "android.view.autofill.AutofillManager");
99    SYSTEM_SERVICE_MAP.put(Context.TEXT_CLASSIFICATION_SERVICE, "android.view.textclassifier.TextClassificationManager");
100
101    if (getApiLevel() >= JELLY_BEAN_MR1) {
102      SYSTEM_SERVICE_MAP.put(Context.DISPLAY_SERVICE, "android.hardware.display.DisplayManager");
103      SYSTEM_SERVICE_MAP.put(Context.USER_SERVICE, "android.os.UserManager");
104    }
105    if (getApiLevel() >= JELLY_BEAN_MR2) {
106      SYSTEM_SERVICE_MAP.put(Context.BLUETOOTH_SERVICE, "android.bluetooth.BluetoothManager");
107    }
108    if (getApiLevel() >= KITKAT) {
109      SYSTEM_SERVICE_MAP.put(Context.PRINT_SERVICE, "android.print.PrintManager");
110      SYSTEM_SERVICE_MAP.put(Context.APP_OPS_SERVICE, "android.app.AppOpsManager");
111      SYSTEM_SERVICE_MAP.put(Context.CAPTIONING_SERVICE, "android.view.accessibility.CaptioningManager");
112    }
113    if (getApiLevel() >= LOLLIPOP) {
114      SYSTEM_SERVICE_MAP.put(Context.JOB_SCHEDULER_SERVICE, "android.app.JobSchedulerImpl");
115      SYSTEM_SERVICE_MAP.put(Context.NETWORK_SCORE_SERVICE, "android.net.NetworkScoreManager");
116      SYSTEM_SERVICE_MAP.put(Context.TELECOM_SERVICE, "android.telecom.TelecomManager");
117      SYSTEM_SERVICE_MAP.put(Context.MEDIA_SESSION_SERVICE, "android.media.session.MediaSessionManager");
118      SYSTEM_SERVICE_MAP.put(Context.BATTERY_SERVICE, "android.os.BatteryManager");
119      SYSTEM_SERVICE_MAP.put(Context.RESTRICTIONS_SERVICE, "android.content.RestrictionsManager");
120    }
121    if (getApiLevel() >= LOLLIPOP_MR1) {
122      SYSTEM_SERVICE_MAP.put(Context.TELEPHONY_SUBSCRIPTION_SERVICE, "android.telephony.SubscriptionManager");
123    }
124    if (getApiLevel() >= M) {
125      SYSTEM_SERVICE_MAP.put(Context.FINGERPRINT_SERVICE, "android.hardware.fingerprint.FingerprintManager");
126    }
127    if (getApiLevel() >= N_MR1) {
128      SYSTEM_SERVICE_MAP.put(Context.SHORTCUT_SERVICE, "android.content.pm.ShortcutManager");
129    }
130
131    if (getApiLevel() >= M) {
132      SYSTEM_SERVICE_MAP.put(Context.LAYOUT_INFLATER_SERVICE, "com.android.internal.policy.PhoneLayoutInflater");
133    } else {
134      SYSTEM_SERVICE_MAP.put(Context.LAYOUT_INFLATER_SERVICE, "com.android.internal.policy.impl.PhoneLayoutInflater");
135    }
136  }
137
138  private Map<String, Object> systemServices = new HashMap<String, Object>();
139
140  @Implementation
141  public Object getSystemService(String name) {
142    if (name.equals(Context.LAYOUT_INFLATER_SERVICE)) {
143      return new RoboLayoutInflater(RuntimeEnvironment.application);
144    }
145
146    Object service = systemServices.get(name);
147    if (service == null) {
148      String serviceClassName = SYSTEM_SERVICE_MAP.get(name);
149      if (serviceClassName == null) {
150        System.err.println("WARNING: unknown service " + name);
151        return null;
152      }
153
154      try {
155        Class<?> clazz = Class.forName(serviceClassName);
156
157        if (serviceClassName.equals("android.content.RestrictionsManager")) {
158          service = ReflectionHelpers.callConstructor(clazz,
159              ClassParameter.from(Context.class, RuntimeEnvironment.application),
160              ClassParameter.from(IRestrictionsManager.class, null));
161        } else if (serviceClassName.equals("android.app.admin.DevicePolicyManager")) {
162          if (getApiLevel() >= N) {
163            service = ReflectionHelpers.callConstructor(clazz,
164                ClassParameter.from(Context.class, RuntimeEnvironment.application),
165                ClassParameter.from(IDevicePolicyManager.class, null),
166                ClassParameter.from(boolean.class, false));
167          } else {
168            service = ReflectionHelpers.callConstructor(clazz,
169                ClassParameter.from(Context.class, RuntimeEnvironment.application),
170                ClassParameter.from(Handler.class, null));
171          }
172        } else if (serviceClassName.equals("android.app.SearchManager")
173            || serviceClassName.equals("android.app.ActivityManager")) {
174
175          service = ReflectionHelpers.callConstructor(clazz,
176              ClassParameter.from(Context.class, RuntimeEnvironment.application),
177              ClassParameter.from(Handler.class, null));
178        } else if (serviceClassName.equals("android.app.WallpaperManager")) {
179          if (getApiLevel() <= O_MR1) {
180            service = ReflectionHelpers.callConstructor(clazz,
181                ClassParameter.from(Context.class, RuntimeEnvironment.application),
182                ClassParameter.from(Handler.class, null));
183          }
184          // BEGIN-INTERNAL
185          else {
186            service = ReflectionHelpers.callConstructor(clazz,
187                ClassParameter.from(IWallpaperManager.class, null),
188                ClassParameter.from(Context.class, RuntimeEnvironment.application),
189                ClassParameter.from(Handler.class, null));
190          }
191          // END-INTERNAL
192        } else if (serviceClassName.equals("android.os.storage.StorageManager")) {
193          service = ReflectionHelpers.callConstructor(clazz);
194        } else if (serviceClassName.equals("android.nfc.NfcManager") || serviceClassName.equals("android.telecom.TelecomManager")) {
195          service = ReflectionHelpers.callConstructor(clazz,
196              ClassParameter.from(Context.class, RuntimeEnvironment.application));
197        } else if (serviceClassName.equals("android.hardware.display.DisplayManager") || serviceClassName.equals("android.telephony.SubscriptionManager")) {
198          service = ReflectionHelpers.callConstructor(clazz, ClassParameter.from(Context.class, RuntimeEnvironment.application));
199        } else if (serviceClassName.equals("android.view.accessibility.AccessibilityManager")) {
200          service = AccessibilityManager.getInstance(realObject);
201        } else if (getApiLevel() >= JELLY_BEAN_MR1 && serviceClassName.equals("android.view.WindowManagerImpl")) {
202          Class<?> windowMgrImplClass = Class.forName("android.view.WindowManagerImpl");
203          if (getApiLevel() >= N) {
204            service = ReflectionHelpers.callConstructor(windowMgrImplClass,
205                ClassParameter.from(Context.class, realObject));
206          } else {
207            Display display = ShadowDisplayManagerGlobal.getInstance().getRealDisplay(Display.DEFAULT_DISPLAY);
208            service = ReflectionHelpers.callConstructor(windowMgrImplClass,
209                ClassParameter.from(Display.class, display));
210          }
211        } else if (serviceClassName.equals("android.accounts.AccountManager")) {
212          service = ReflectionHelpers.callConstructor(Class.forName("android.accounts.AccountManager"),
213                ClassParameter.from(Context.class, RuntimeEnvironment.application),
214                ClassParameter.from(IAccountManager.class , null));
215        } else if (serviceClassName.equals("android.net.wifi.p2p.WifiP2pManager")) {
216          service = new WifiP2pManager(ReflectionHelpers.createNullProxy(IWifiP2pManager.class));
217        } else if (getApiLevel() >= KITKAT && serviceClassName.equals("android.print.PrintManager")) {
218          service = ReflectionHelpers.callConstructor(Class.forName("android.print.PrintManager"),
219            ClassParameter.from(Context.class, RuntimeEnvironment.application),
220            ClassParameter.from(android.print.IPrintManager.class, null),
221            ClassParameter.from(int.class, -1),
222            ClassParameter.from(int.class, -1));
223        } else if (serviceClassName.equals("android.hardware.SystemSensorManager")) {
224          if (RuntimeEnvironment.getApiLevel() >= JELLY_BEAN_MR2) {
225            service = new SystemSensorManager(RuntimeEnvironment.application, Looper.getMainLooper());
226          } else {
227            service = ReflectionHelpers.callConstructor(
228                Class.forName(serviceClassName),
229                ClassParameter.from(Looper.class, Looper.getMainLooper()));
230          }
231        } else if (getApiLevel() >= O && serviceClassName.equals("android.app.KeyguardManager")) {
232          service =
233              ReflectionHelpers.callConstructor(
234                  clazz, ClassParameter.from(Context.class, RuntimeEnvironment.application));
235        } else if (getApiLevel() >= KITKAT && serviceClassName.equals("android.view.accessibility.CaptioningManager")) {
236          service = ReflectionHelpers.callConstructor(clazz,
237              ClassParameter.from(Context.class, RuntimeEnvironment.application));
238        } else if (serviceClassName.equals("android.os.UserManager")) {
239          service = ReflectionHelpers.callConstructor(clazz,
240                ClassParameter.from(Context.class, RuntimeEnvironment.application),
241                ClassParameter.from(IUserManager.class, null));
242        } else if (getApiLevel() >= M && serviceClassName.equals("android.hardware.fingerprint.FingerprintManager")) {
243          service = ReflectionHelpers.callConstructor(clazz,
244              ClassParameter.from(Context.class, RuntimeEnvironment.application),
245              ClassParameter.from(IFingerprintService.class, null));
246        } else if (getApiLevel() >= O && serviceClassName.equals("android.view.autofill.AutofillManager")) {
247          service = ReflectionHelpers.callConstructor(clazz,
248              ClassParameter.from(Context.class, RuntimeEnvironment.application),
249              ClassParameter.from(IAutoFillManager.class, null));
250        } else if (getApiLevel() >= O && serviceClassName.equals("android.view.textclassifier.TextClassificationManager")) {
251          service = ReflectionHelpers.callConstructor(clazz,
252              ClassParameter.from(Context.class, RuntimeEnvironment.application));
253        } else if (serviceClassName.equals("com.android.internal.policy.impl.PhoneLayoutInflater") || serviceClassName.equals("com.android.internal.policy.PhoneLayoutInflater")) {
254          service = ReflectionHelpers.callConstructor(clazz,
255              ClassParameter.from(Context.class, RuntimeEnvironment.application));
256        } else {
257          service = newInstanceOf(clazz);
258        }
259      } catch (ClassNotFoundException e) {
260        throw new RuntimeException(e);
261      }
262
263      systemServices.put(name, service);
264    }
265    return service;
266  }
267
268  public void setSystemService(String key, Object service) {
269    systemServices.put(key, service);
270  }
271
272  @Implementation
273  public void startIntentSender(IntentSender intent, Intent fillInIntent,
274                    int flagsMask, int flagsValues, int extraFlags, Bundle options) throws IntentSender.SendIntentException {
275    intent.sendIntent(realObject, 0, fillInIntent, null, null, null);
276  }
277
278  @Implementation
279  public ComponentName startService(Intent service) {
280    return ShadowApplication.getInstance().startService(service);
281  }
282
283  @Implementation(minSdk = O)
284  public ComponentName startForegroundService(Intent service) {
285    return ShadowApplication.getInstance().startService(service);
286  }
287
288  @Implementation
289  public void startActivity(Intent intent) {
290    ShadowApplication.getInstance().startActivity(intent);
291  }
292
293  @Implementation
294  public void sendBroadcast(Intent intent) {
295    ShadowApplication.getInstance().sendBroadcast(intent);
296  }
297
298  @Implementation
299  public ClassLoader getClassLoader() {
300    return this.getClass().getClassLoader();
301  }
302
303  @Implementation
304  public boolean bindService(Intent intent, final ServiceConnection serviceConnection, int i) {
305    return ShadowApplication.getInstance().bindService(intent, serviceConnection, i);
306  }
307
308  @Implementation
309  public void unbindService(final ServiceConnection serviceConnection) {
310    ShadowApplication.getInstance().unbindService(serviceConnection);
311  }
312
313  @Implementation
314  public int checkCallingPermission(String permission) {
315    return checkPermission(permission, -1, -1);
316  }
317
318  @Implementation
319  public int checkCallingOrSelfPermission(String permission) {
320    return checkPermission(permission, -1, -1);
321  }
322
323  @Implementation
324  public ContentResolver getContentResolver() {
325    if (contentResolver == null) {
326      contentResolver = new ContentResolver(realObject) {
327        @Override
328        protected IContentProvider acquireProvider(Context c, String name) {
329          return null;
330        }
331
332        @Override
333        public boolean releaseProvider(IContentProvider icp) {
334          return false;
335        }
336
337        @Override
338        protected IContentProvider acquireUnstableProvider(Context c, String name) {
339          return null;
340        }
341
342        @Override
343        public boolean releaseUnstableProvider(IContentProvider icp) {
344          return false;
345        }
346
347        @Override
348        public void unstableProviderDied(IContentProvider icp) {
349
350        }
351      };
352    }
353    return contentResolver;
354  }
355
356  @Implementation
357  public void sendBroadcast(Intent intent, String receiverPermission) {
358    ShadowApplication.getInstance().sendBroadcast(intent, receiverPermission);
359  }
360
361  @Implementation
362  public void sendOrderedBroadcast(Intent intent, String receiverPermission) {
363    ShadowApplication.getInstance().sendOrderedBroadcast(intent, receiverPermission);
364  }
365
366  @Implementation
367  public void sendOrderedBroadcast(Intent intent, String receiverPermission, BroadcastReceiver resultReceiver,
368                                   Handler scheduler, int initialCode, String initialData, Bundle initialExtras) {
369    ShadowApplication.getInstance().sendOrderedBroadcast(intent, receiverPermission, resultReceiver, scheduler, initialCode,
370        initialData, initialExtras);
371  }
372
373  @Implementation
374  public void sendStickyBroadcast(Intent intent) {
375    ShadowApplication.getInstance().sendStickyBroadcast(intent);
376  }
377
378  @Implementation
379  public int checkPermission(String permission, int pid, int uid) {
380    return ShadowApplication.getInstance().checkPermission(permission, pid, uid);
381  }
382
383  @Implementation
384  public Intent registerReceiver(BroadcastReceiver receiver, IntentFilter filter) {
385    return ShadowApplication.getInstance().registerReceiverWithContext(receiver, filter, null, null, realObject);
386  }
387
388  @Implementation
389  public Intent registerReceiver(BroadcastReceiver receiver, IntentFilter filter, String broadcastPermission, Handler scheduler) {
390    return ShadowApplication.getInstance().registerReceiverWithContext(receiver, filter, broadcastPermission, scheduler, realObject);
391  }
392
393  @Implementation
394  public Intent registerReceiverAsUser(BroadcastReceiver receiver, UserHandle user,
395      IntentFilter filter, String broadcastPermission, Handler scheduler) {
396    return ShadowApplication.getInstance().registerReceiverWithContext(receiver, filter, broadcastPermission, scheduler, realObject);
397  }
398
399  @Implementation
400  public void unregisterReceiver(BroadcastReceiver broadcastReceiver) {
401    ShadowApplication.getInstance().unregisterReceiver(broadcastReceiver);
402  }
403
404  @Implementation
405  public boolean stopService(Intent name) {
406    return ShadowApplication.getInstance().stopService(name);
407  }
408
409  @Implementation
410  public void startActivity(Intent intent, Bundle options) {
411    ShadowApplication.getInstance().startActivity(intent, options);
412  }
413
414  @Implementation
415  public void startActivities(Intent[] intents) {
416    for (int i = intents.length - 1; i >= 0; i--) {
417      startActivity(intents[i]);
418    }
419  }
420
421  @Implementation
422  public void startActivities(Intent[] intents, Bundle options) {
423    for (int i = intents.length - 1; i >= 0; i--) {
424      startActivity(intents[i], options);
425    }
426  }
427
428  @Implementation
429  public int getUserId() {
430    return 0;
431  }
432
433  @Implementation
434  public File getExternalCacheDir() {
435    return Environment.getExternalStorageDirectory();
436  }
437
438  @Implementation(maxSdk = JELLY_BEAN_MR2)
439  public File getExternalFilesDir(String type) {
440    return Environment.getExternalStoragePublicDirectory(type);
441  }
442
443  @Implementation(minSdk = KITKAT)
444  public File[] getExternalFilesDirs(String type) {
445    return new File[] { Environment.getExternalStoragePublicDirectory(type) };
446  }
447
448  @Resetter
449  public static void reset() {
450    String prefsCacheFieldName = RuntimeEnvironment.getApiLevel() >= N ? "sSharedPrefsCache" : "sSharedPrefs";
451    Object prefsDefaultValue = RuntimeEnvironment.getApiLevel() >= KITKAT ? null : new HashMap<>();
452    Class<?> contextImplClass = ReflectionHelpers.loadClass(ShadowContextImpl.class.getClassLoader(), "android.app.ContextImpl");
453    ReflectionHelpers.setStaticField(contextImplClass, prefsCacheFieldName, prefsDefaultValue);
454  }
455}
456