blob: 02c6fb17cb03d8c8260628959faaf8d1a8028965 [file] [log] [blame]
package org.robolectric.shadows;
import static android.os.Build.VERSION_CODES.JELLY_BEAN_MR1;
import static android.os.Build.VERSION_CODES.JELLY_BEAN_MR2;
import static android.os.Build.VERSION_CODES.KITKAT;
import static android.os.Build.VERSION_CODES.LOLLIPOP;
import static android.os.Build.VERSION_CODES.LOLLIPOP_MR1;
import static android.os.Build.VERSION_CODES.N;
import static android.os.Build.VERSION_CODES.N_MR1;
import static android.os.Build.VERSION_CODES.O;
import static org.robolectric.RuntimeEnvironment.getApiLevel;
import static org.robolectric.shadow.api.Shadow.newInstanceOf;
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 java.io.File;
import java.util.HashMap;
import java.util.Map;
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;
@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");
SYSTEM_SERVICE_MAP.put(Context.USB_SERVICE, "android.hardware.usb.UsbManager");
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");
SYSTEM_SERVICE_MAP.put(Context.APP_OPS_SERVICE, "android.app.AppOpsManager");
SYSTEM_SERVICE_MAP.put(Context.CAPTIONING_SERVICE, "android.view.accessibility.CaptioningManager");
}
if (getApiLevel() >= LOLLIPOP) {
SYSTEM_SERVICE_MAP.put(Context.JOB_SCHEDULER_SERVICE, "android.app.JobSchedulerImpl");
SYSTEM_SERVICE_MAP.put(Context.NETWORK_SCORE_SERVICE, "android.net.NetworkScoreManager");
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");
}
if (getApiLevel() >= N_MR1) {
SYSTEM_SERVICE_MAP.put(Context.SHORTCUT_SERVICE, "android.content.pm.ShortcutManager");
}
}
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 if (getApiLevel() >= O && serviceClassName.equals("android.app.KeyguardManager")) {
service =
ReflectionHelpers.callConstructor(
clazz, ClassParameter.from(Context.class, RuntimeEnvironment.application));
} else if (getApiLevel() >= KITKAT && serviceClassName.equals("android.view.accessibility.CaptioningManager")) {
service = ReflectionHelpers.callConstructor(clazz,
ClassParameter.from(Context.class, RuntimeEnvironment.application));
} 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(minSdk = O)
public ComponentName startForegroundService(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);
}
}