package org.robolectric.shadows; import android.accounts.IAccountManager; import android.app.admin.IDevicePolicyManager; import android.content.BroadcastReceiver; import android.content.ComponentName; import android.content.ContentResolver; import android.content.Context; import android.content.IContentProvider; import android.content.Intent; import android.content.IntentFilter; import android.content.IntentSender; import android.content.ServiceConnection; import android.hardware.SystemSensorManager; import android.net.wifi.p2p.IWifiP2pManager; import android.net.wifi.p2p.WifiP2pManager; import android.os.Bundle; import android.os.Environment; import android.os.Handler; import android.os.Looper; import android.os.UserHandle; import android.view.Display; import android.view.accessibility.AccessibilityManager; import org.robolectric.RuntimeEnvironment; import org.robolectric.annotation.Implementation; import org.robolectric.annotation.Implements; import org.robolectric.annotation.RealObject; import org.robolectric.annotation.Resetter; import org.robolectric.util.ReflectionHelpers; import org.robolectric.util.ReflectionHelpers.ClassParameter; import java.io.File; import java.util.HashMap; import java.util.Map; import static android.os.Build.VERSION_CODES.*; import static org.robolectric.RuntimeEnvironment.getApiLevel; import static org.robolectric.shadow.api.Shadow.newInstanceOf; @Implements(className = ShadowContextImpl.CLASS_NAME) public class ShadowContextImpl { public static final String CLASS_NAME = "android.app.ContextImpl"; private static final Map<String, String> SYSTEM_SERVICE_MAP = new HashMap<>(); private ContentResolver contentResolver; @RealObject private Context realObject; static { // note that these are different! // They specify concrete classes within Robolectric for interfaces or abstract classes defined by Android SYSTEM_SERVICE_MAP.put(Context.WINDOW_SERVICE, "android.view.WindowManagerImpl"); SYSTEM_SERVICE_MAP.put(Context.CLIPBOARD_SERVICE, "android.content.ClipboardManager"); SYSTEM_SERVICE_MAP.put(Context.SENSOR_SERVICE, "android.hardware.SystemSensorManager"); SYSTEM_SERVICE_MAP.put(Context.VIBRATOR_SERVICE, "org.robolectric.fakes.RoboVibrator"); // the rest are as mapped in docs... SYSTEM_SERVICE_MAP.put(Context.LAYOUT_INFLATER_SERVICE, "android.view.LayoutInflater"); SYSTEM_SERVICE_MAP.put(Context.ACTIVITY_SERVICE, "android.app.ActivityManager"); SYSTEM_SERVICE_MAP.put(Context.POWER_SERVICE, "android.os.PowerManager"); SYSTEM_SERVICE_MAP.put(Context.ALARM_SERVICE, "android.app.AlarmManager"); SYSTEM_SERVICE_MAP.put(Context.NOTIFICATION_SERVICE, "android.app.NotificationManager"); SYSTEM_SERVICE_MAP.put(Context.KEYGUARD_SERVICE, "android.app.KeyguardManager"); SYSTEM_SERVICE_MAP.put(Context.LOCATION_SERVICE, "android.location.LocationManager"); SYSTEM_SERVICE_MAP.put(Context.SEARCH_SERVICE, "android.app.SearchManager"); SYSTEM_SERVICE_MAP.put(Context.STORAGE_SERVICE, "android.os.storage.StorageManager"); SYSTEM_SERVICE_MAP.put(Context.CONNECTIVITY_SERVICE, "android.net.ConnectivityManager"); SYSTEM_SERVICE_MAP.put(Context.WIFI_SERVICE, "android.net.wifi.WifiManager"); SYSTEM_SERVICE_MAP.put(Context.AUDIO_SERVICE, "android.media.AudioManager"); SYSTEM_SERVICE_MAP.put(Context.TELEPHONY_SERVICE, "android.telephony.TelephonyManager"); SYSTEM_SERVICE_MAP.put(Context.INPUT_METHOD_SERVICE, "android.view.inputmethod.InputMethodManager"); SYSTEM_SERVICE_MAP.put(Context.UI_MODE_SERVICE, "android.app.UiModeManager"); SYSTEM_SERVICE_MAP.put(Context.DOWNLOAD_SERVICE, "android.app.DownloadManager"); SYSTEM_SERVICE_MAP.put(Context.TEXT_SERVICES_MANAGER_SERVICE, "android.view.textservice.TextServicesManager"); SYSTEM_SERVICE_MAP.put(Context.DEVICE_POLICY_SERVICE, "android.app.admin.DevicePolicyManager"); SYSTEM_SERVICE_MAP.put(Context.DROPBOX_SERVICE, "android.os.DropBoxManager"); SYSTEM_SERVICE_MAP.put(Context.MEDIA_ROUTER_SERVICE, "android.media.MediaRouter"); SYSTEM_SERVICE_MAP.put(Context.ACCESSIBILITY_SERVICE, "android.view.accessibility.AccessibilityManager"); SYSTEM_SERVICE_MAP.put(Context.ACCOUNT_SERVICE, "android.accounts.AccountManager"); SYSTEM_SERVICE_MAP.put(Context.NFC_SERVICE, "android.nfc.NfcManager"); SYSTEM_SERVICE_MAP.put(Context.WALLPAPER_SERVICE, "android.app.WallpaperManager"); SYSTEM_SERVICE_MAP.put(Context.WIFI_P2P_SERVICE, "android.net.wifi.p2p.WifiP2pManager"); if (getApiLevel() >= JELLY_BEAN_MR1) { SYSTEM_SERVICE_MAP.put(Context.DISPLAY_SERVICE, "android.hardware.display.DisplayManager"); SYSTEM_SERVICE_MAP.put(Context.USER_SERVICE, "android.os.UserManager"); } if (getApiLevel() >= JELLY_BEAN_MR2) { SYSTEM_SERVICE_MAP.put(Context.BLUETOOTH_SERVICE, "android.bluetooth.BluetoothManager"); } if (getApiLevel() >= KITKAT) { SYSTEM_SERVICE_MAP.put(Context.PRINT_SERVICE, "android.print.PrintManager"); } if (getApiLevel() >= LOLLIPOP) { SYSTEM_SERVICE_MAP.put(Context.JOB_SCHEDULER_SERVICE, "android.app.JobSchedulerImpl"); SYSTEM_SERVICE_MAP.put(Context.TELECOM_SERVICE, "android.telecom.TelecomManager"); SYSTEM_SERVICE_MAP.put(Context.MEDIA_SESSION_SERVICE, "android.media.session.MediaSessionManager"); SYSTEM_SERVICE_MAP.put(Context.BATTERY_SERVICE, "android.os.BatteryManager"); } if (getApiLevel() >= LOLLIPOP_MR1) { SYSTEM_SERVICE_MAP.put(Context.TELEPHONY_SUBSCRIPTION_SERVICE, "android.telephony.SubscriptionManager"); } } private Map<String, Object> systemServices = new HashMap<String, Object>(); @Implementation public Object getSystemService(String name) { if (name.equals(Context.LAYOUT_INFLATER_SERVICE)) { return new RoboLayoutInflater(RuntimeEnvironment.application); } Object service = systemServices.get(name); if (service == null) { String serviceClassName = SYSTEM_SERVICE_MAP.get(name); if (serviceClassName == null) { System.err.println("WARNING: unknown service " + name); return null; } try { Class<?> clazz = Class.forName(serviceClassName); if (serviceClassName.equals("android.app.admin.DevicePolicyManager")) { if (getApiLevel() >= N) { service = ReflectionHelpers.callConstructor(clazz, ClassParameter.from(Context.class, RuntimeEnvironment.application), ClassParameter.from(IDevicePolicyManager.class, null), ClassParameter.from(boolean.class, false)); } else { service = ReflectionHelpers.callConstructor(clazz, ClassParameter.from(Context.class, RuntimeEnvironment.application), ClassParameter.from(Handler.class, null)); } } else if (serviceClassName.equals("android.app.SearchManager") || serviceClassName.equals("android.app.ActivityManager") || serviceClassName.equals("android.app.WallpaperManager")) { service = ReflectionHelpers.callConstructor(clazz, ClassParameter.from(Context.class, RuntimeEnvironment.application), ClassParameter.from(Handler.class, null)); } else if (serviceClassName.equals("android.os.storage.StorageManager")) { service = ReflectionHelpers.callConstructor(clazz); } else if (serviceClassName.equals("android.nfc.NfcManager") || serviceClassName.equals("android.telecom.TelecomManager")) { service = ReflectionHelpers.callConstructor(clazz, ClassParameter.from(Context.class, RuntimeEnvironment.application)); } else if (serviceClassName.equals("android.hardware.display.DisplayManager") || serviceClassName.equals("android.telephony.SubscriptionManager")) { service = ReflectionHelpers.callConstructor(clazz, ClassParameter.from(Context.class, RuntimeEnvironment.application)); } else if (serviceClassName.equals("android.view.accessibility.AccessibilityManager")) { service = AccessibilityManager.getInstance(realObject); } else if (getApiLevel() >= JELLY_BEAN_MR1 && serviceClassName.equals("android.view.WindowManagerImpl")) { Class<?> windowMgrImplClass = Class.forName("android.view.WindowManagerImpl"); if (getApiLevel() >= N) { service = ReflectionHelpers.callConstructor(windowMgrImplClass, ClassParameter.from(Context.class, realObject)); } else { Display display = newInstanceOf(Display.class); service = ReflectionHelpers.callConstructor(windowMgrImplClass, ClassParameter.from(Display.class, display)); } } else if (serviceClassName.equals("android.accounts.AccountManager")) { service = ReflectionHelpers.callConstructor(Class.forName("android.accounts.AccountManager"), ClassParameter.from(Context.class, RuntimeEnvironment.application), ClassParameter.from(IAccountManager.class , null)); } else if (serviceClassName.equals("android.net.wifi.p2p.WifiP2pManager")) { service = new WifiP2pManager(ReflectionHelpers.createNullProxy(IWifiP2pManager.class)); } else if (getApiLevel() >= KITKAT && serviceClassName.equals("android.print.PrintManager")) { service = ReflectionHelpers.callConstructor(Class.forName("android.print.PrintManager"), ClassParameter.from(Context.class, RuntimeEnvironment.application), ClassParameter.from(android.print.IPrintManager.class, null), ClassParameter.from(int.class, -1), ClassParameter.from(int.class, -1)); } else if (serviceClassName.equals("android.hardware.SystemSensorManager")) { if (RuntimeEnvironment.getApiLevel() >= JELLY_BEAN_MR2) { service = new SystemSensorManager(RuntimeEnvironment.application, Looper.getMainLooper()); } else { service = ReflectionHelpers.callConstructor( Class.forName(serviceClassName), ClassParameter.from(Looper.class, Looper.getMainLooper())); } } else { service = newInstanceOf(clazz); } } catch (ClassNotFoundException e) { throw new RuntimeException(e); } systemServices.put(name, service); } return service; } public void setSystemService(String key, Object service) { systemServices.put(key, service); } @Implementation public void startIntentSender(IntentSender intent, Intent fillInIntent, int flagsMask, int flagsValues, int extraFlags, Bundle options) throws IntentSender.SendIntentException { intent.sendIntent(realObject, 0, fillInIntent, null, null, null); } @Implementation public ComponentName startService(Intent service) { return ShadowApplication.getInstance().startService(service); } @Implementation public void startActivity(Intent intent) { ShadowApplication.getInstance().startActivity(intent); } @Implementation public void sendBroadcast(Intent intent) { ShadowApplication.getInstance().sendBroadcast(intent); } @Implementation public ClassLoader getClassLoader() { return this.getClass().getClassLoader(); } @Implementation public boolean bindService(Intent intent, final ServiceConnection serviceConnection, int i) { return ShadowApplication.getInstance().bindService(intent, serviceConnection, i); } @Implementation public void unbindService(final ServiceConnection serviceConnection) { ShadowApplication.getInstance().unbindService(serviceConnection); } @Implementation public int checkCallingPermission(String permission) { return checkPermission(permission, -1, -1); } @Implementation public int checkCallingOrSelfPermission(String permission) { return checkPermission(permission, -1, -1); } @Implementation public ContentResolver getContentResolver() { if (contentResolver == null) { contentResolver = new ContentResolver(realObject) { @Override protected IContentProvider acquireProvider(Context c, String name) { return null; } @Override public boolean releaseProvider(IContentProvider icp) { return false; } @Override protected IContentProvider acquireUnstableProvider(Context c, String name) { return null; } @Override public boolean releaseUnstableProvider(IContentProvider icp) { return false; } @Override public void unstableProviderDied(IContentProvider icp) { } }; } return contentResolver; } @Implementation public void sendBroadcast(Intent intent, String receiverPermission) { ShadowApplication.getInstance().sendBroadcast(intent, receiverPermission); } @Implementation public void sendOrderedBroadcast(Intent intent, String receiverPermission) { ShadowApplication.getInstance().sendOrderedBroadcast(intent, receiverPermission); } @Implementation public void sendOrderedBroadcast(Intent intent, String receiverPermission, BroadcastReceiver resultReceiver, Handler scheduler, int initialCode, String initialData, Bundle initialExtras) { ShadowApplication.getInstance().sendOrderedBroadcast(intent, receiverPermission, resultReceiver, scheduler, initialCode, initialData, initialExtras); } @Implementation public void sendStickyBroadcast(Intent intent) { ShadowApplication.getInstance().sendStickyBroadcast(intent); } @Implementation public int checkPermission(String permission, int pid, int uid) { return ShadowApplication.getInstance().checkPermission(permission, pid, uid); } @Implementation public Intent registerReceiver(BroadcastReceiver receiver, IntentFilter filter) { return ShadowApplication.getInstance().registerReceiverWithContext(receiver, filter, null, null, realObject); } @Implementation public Intent registerReceiver(BroadcastReceiver receiver, IntentFilter filter, String broadcastPermission, Handler scheduler) { return ShadowApplication.getInstance().registerReceiverWithContext(receiver, filter, broadcastPermission, scheduler, realObject); } @Implementation public Intent registerReceiverAsUser(BroadcastReceiver receiver, UserHandle user, IntentFilter filter, String broadcastPermission, Handler scheduler) { return ShadowApplication.getInstance().registerReceiverWithContext(receiver, filter, broadcastPermission, scheduler, realObject); } @Implementation public void unregisterReceiver(BroadcastReceiver broadcastReceiver) { ShadowApplication.getInstance().unregisterReceiver(broadcastReceiver); } @Implementation public boolean stopService(Intent name) { return ShadowApplication.getInstance().stopService(name); } @Implementation public void startActivity(Intent intent, Bundle options) { ShadowApplication.getInstance().startActivity(intent, options); } @Implementation public void startActivities(Intent[] intents) { for (int i = intents.length - 1; i >= 0; i--) { startActivity(intents[i]); } } @Implementation public void startActivities(Intent[] intents, Bundle options) { for (int i = intents.length - 1; i >= 0; i--) { startActivity(intents[i], options); } } @Implementation public int getUserId() { return 0; } @Implementation public File getExternalCacheDir() { return Environment.getExternalStorageDirectory(); } @Implementation(maxSdk = JELLY_BEAN_MR2) public File getExternalFilesDir(String type) { return Environment.getExternalStoragePublicDirectory(type); } @Implementation(minSdk = KITKAT) public File[] getExternalFilesDirs(String type) { return new File[] { Environment.getExternalStoragePublicDirectory(type) }; } @Resetter public static void reset() { String prefsCacheFieldName = RuntimeEnvironment.getApiLevel() >= N ? "sSharedPrefsCache" : "sSharedPrefs"; Object prefsDefaultValue = RuntimeEnvironment.getApiLevel() >= KITKAT ? null : new HashMap<>(); Class<?> contextImplClass = ReflectionHelpers.loadClass(ShadowContextImpl.class.getClassLoader(), "android.app.ContextImpl"); ReflectionHelpers.setStaticField(contextImplClass, prefsCacheFieldName, prefsDefaultValue); } }