blob: d7dae9b364a3852ba606f9d289783dbb7387c553 [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.M;
import static android.os.Build.VERSION_CODES.N_MR1;
import static android.os.Build.VERSION_CODES.O;
import static android.os.Build.VERSION_CODES.P;
import static android.os.Build.VERSION_CODES.Q;
import static android.os.Build.VERSION_CODES.R;
import android.accounts.IAccountManager;
import android.app.IAlarmManager;
import android.app.INotificationManager;
import android.app.ISearchManager;
import android.app.admin.IDevicePolicyManager;
import android.app.job.IJobScheduler;
import android.app.role.IRoleManager;
import android.app.slice.ISliceManager;
import android.app.trust.ITrustManager;
import android.app.usage.IUsageStatsManager;
import android.content.Context;
import android.content.IClipboard;
import android.content.IRestrictionsManager;
import android.content.pm.ICrossProfileApps;
import android.content.pm.IShortcutService;
import android.hardware.display.IColorDisplayManager;
import android.hardware.fingerprint.IFingerprintService;
import android.hardware.input.IInputManager;
import android.hardware.usb.IUsbManager;
import android.location.ICountryDetector;
import android.location.ILocationManager;
import android.media.IAudioService;
import android.media.IMediaRouterService;
import android.media.session.ISessionManager;
import android.net.IConnectivityManager;
import android.net.INetworkScoreService;
import android.net.ITetheringConnector;
import android.net.nsd.INsdManager;
import android.net.wifi.IWifiManager;
import android.net.wifi.p2p.IWifiP2pManager;
import android.os.BatteryStats;
import android.os.Binder;
import android.os.IBatteryPropertiesRegistrar;
import android.os.IBinder;
import android.os.IInterface;
import android.os.IPowerManager;
import android.os.IThermalService;
import android.os.IUserManager;
import android.os.RemoteException;
import android.os.ServiceManager;
import android.os.storage.IStorageManager;
import android.service.persistentdata.IPersistentDataBlockService;
import com.android.internal.app.IAppOpsService;
import com.android.internal.app.IBatteryStats;
import com.android.internal.appwidget.IAppWidgetService;
import com.android.internal.os.IDropBoxManagerService;
import com.android.internal.view.IInputMethodManager;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import org.robolectric.RuntimeEnvironment;
import org.robolectric.annotation.Implementation;
import org.robolectric.annotation.Implements;
import org.robolectric.annotation.Resetter;
import org.robolectric.util.ReflectionHelpers;
@SuppressWarnings("NewApi")
@Implements(value = ServiceManager.class, isInAndroidSdk = false)
public class ShadowServiceManager {
private static final Map<String, IBinder> SERVICES;
private static final Set<String> unavailableServices = new HashSet<>();
static {
Map<String, IBinder> map = new HashMap<>();
map.put(
Context.CLIPBOARD_SERVICE, createBinder(IClipboard.class, "android.content.IClipboard"));
map.put(
Context.WIFI_P2P_SERVICE,
createBinder(IWifiP2pManager.class, "android.net.wifi.p2p.IWifiP2pManager"));
map.put(
Context.ACCOUNT_SERVICE,
createBinder(IAccountManager.class, "android.accounts.IAccountManager"));
map.put(
Context.USB_SERVICE, createBinder(IUsbManager.class, "android.hardware.usb.IUsbManager"));
map.put(
Context.LOCATION_SERVICE,
createBinder(ILocationManager.class, "android.location.ILocationManager"));
map.put(
Context.INPUT_METHOD_SERVICE,
createBinder(IInputMethodManager.class, "com.android.internal.view.IInputMethodManager"));
map.put(Context.ALARM_SERVICE, createBinder(IAlarmManager.class, "android.app.IAlarmManager"));
map.put(Context.POWER_SERVICE, createBinder(IPowerManager.class, "android.os.IPowerManager"));
map.put(
BatteryStats.SERVICE_NAME,
createBinder(IBatteryStats.class, "com.android.internal.app.IBatteryStats"));
map.put(
Context.DROPBOX_SERVICE,
createBinder(
IDropBoxManagerService.class, "com.android.internal.os.IDropBoxManagerService"));
map.put(
Context.DEVICE_POLICY_SERVICE,
createBinder(IDevicePolicyManager.class, "android.app.admin.IDevicePolicyManager"));
map.put(
Context.CONNECTIVITY_SERVICE,
createBinder(IConnectivityManager.class, "android.net.IConnectivityManager"));
map.put(
Context.WIFI_SERVICE, createBinder(IWifiManager.class, "android.net.wifi.IWifiManager"));
map.put(
Context.SEARCH_SERVICE, createBinder(ISearchManager.class, "android.app.ISearchManager"));
map.put(
Context.UI_MODE_SERVICE, createBinder(ISearchManager.class, "android.app.IUiModeManager"));
map.put(
Context.NETWORK_POLICY_SERVICE,
createBinder(ISearchManager.class, "android.net.INetworkPolicyManager"));
map.put(Context.INPUT_SERVICE, createBinder(IInputManager.class, "android.net.IInputManager"));
map.put(
Context.COUNTRY_DETECTOR,
createBinder(ICountryDetector.class, "android.location.ICountryDetector"));
map.put(
Context.NSD_SERVICE, createBinder(INsdManager.class, "android.net.nsd.INsdManagerandroi"));
map.put(
Context.AUDIO_SERVICE, createBinder(IAudioService.class, "android.media.IAudioService"));
map.put(
Context.APPWIDGET_SERVICE,
createBinder(IAppWidgetService.class, "com.android.internal.appwidget.IAppWidgetService"));
if (RuntimeEnvironment.getApiLevel() >= JELLY_BEAN_MR1) {
map.put(Context.USER_SERVICE, createBinder(IUserManager.class, "android.os.IUserManager"));
}
if (RuntimeEnvironment.getApiLevel() >= JELLY_BEAN_MR2) {
map.put(
Context.APP_OPS_SERVICE,
createBinder(IAppOpsService.class, "com.android.internal.app.IAppOpsService"));
}
if (RuntimeEnvironment.getApiLevel() >= KITKAT) {
map.put(
"batteryproperties",
createBinder(
IBatteryPropertiesRegistrar.class, "android.os.IBatteryPropertiesRegistrar"));
}
if (RuntimeEnvironment.getApiLevel() >= LOLLIPOP) {
map.put(
Context.RESTRICTIONS_SERVICE,
createBinder(IRestrictionsManager.class, "android.content.IRestrictionsManager"));
map.put(
Context.TRUST_SERVICE,
createBinder(ITrustManager.class, "android.app.trust.ITrustManager"));
map.put(
Context.JOB_SCHEDULER_SERVICE,
createBinder(IJobScheduler.class, "android.app.job.IJobScheduler"));
map.put(
Context.NETWORK_SCORE_SERVICE,
createBinder(INetworkScoreService.class, "android.net.INetworkScoreService"));
map.put(
Context.USAGE_STATS_SERVICE,
createBinder(IUsageStatsManager.class, "android.app.usage.IUsageStatsManager"));
map.put(
Context.MEDIA_ROUTER_SERVICE,
createBinder(IMediaRouterService.class, "android.media.IMediaRouterService"));
map.put(
Context.MEDIA_SESSION_SERVICE,
createDeepBinder(ISessionManager.class, "android.media.session.ISessionManager"));
map.put(
Context.PERSISTENT_DATA_BLOCK_SERVICE,
createBinder(IPersistentDataBlockService.class,
"android.service.persistentdata.IPersistentDataBlockService"));
}
if (RuntimeEnvironment.getApiLevel() >= M) {
map.put(
Context.FINGERPRINT_SERVICE,
createBinder(
IFingerprintService.class, "android.hardware.fingerprint.IFingerprintService"));
}
if (RuntimeEnvironment.getApiLevel() >= N_MR1) {
map.put(
Context.SHORTCUT_SERVICE,
createBinder(IShortcutService.class, "android.content.pm.IShortcutService"));
}
if (RuntimeEnvironment.getApiLevel() >= O) {
map.put("mount", createBinder(IStorageManager.class, "android.os.storage.IStorageManager"));
} else {
map.put(
"mount",
createBinder("android.os.storage.IMountService", "android.os.storage.IMountService"));
}
if (RuntimeEnvironment.getApiLevel() >= P) {
map.put(
Context.SLICE_SERVICE,
createBinder(ISliceManager.class, "android.app.slice.SliceManager"));
map.put(
Context.CROSS_PROFILE_APPS_SERVICE,
createBinder(ICrossProfileApps.class, "android.content.pm.ICrossProfileApps"));
}
// BEGIN-INTERNAL
if (RuntimeEnvironment.getApiLevel() >= Q) {
map.put(Context.NOTIFICATION_SERVICE,
createBinder(INotificationManager.class, "android.app.INotificationManager"));
map.put(Context.COLOR_DISPLAY_SERVICE, createBinder(IColorDisplayManager.class,
"android.hardware.display.ColorDisplayManager"));
map.put(Context.ROLE_SERVICE,
createBinder(IRoleManager.class, "android.app.role.IRoleManager"));
}
if (RuntimeEnvironment.getApiLevel() >= R) {
map.put(Context.TETHERING_SERVICE,
createBinder(ITetheringConnector.class, "android.net.ITetheringConnector"));
map.put(Context.THERMAL_SERVICE,
createBinder(IThermalService.class, "android.os.IThermalService"));
}
// END-INTERNAL
SERVICES = Collections.unmodifiableMap(map);
}
/**
* Returns the binder associated with the given system service. If the given service is set to
* unavailable in {@link #setServiceAvailability}, {@code null} will be returned.
*/
@Implementation
protected static IBinder getService(String name) {
if (unavailableServices.contains(name)) {
return null;
}
return SERVICES.get(name);
}
private static Binder createBinder(String className, String descriptor) {
Class<IInterface> clazz;
try {
clazz = (Class<IInterface>) Class.forName(className);
} catch (ClassNotFoundException e) {
throw new RuntimeException(e);
}
Binder binder = new Binder();
binder.attachInterface(ReflectionHelpers.createNullProxy(clazz), descriptor);
return binder;
}
private static Binder createBinder(Class<? extends IInterface> clazz, String descriptor) {
Binder binder = new Binder();
binder.attachInterface(ReflectionHelpers.createNullProxy(clazz), descriptor);
return binder;
}
private static Binder createDeepBinder(Class<? extends IInterface> clazz, String descriptor) {
Binder binder = new Binder();
binder.attachInterface(ReflectionHelpers.createDeepProxy(clazz), descriptor);
return binder;
}
@Implementation
protected static void addService(String name, IBinder service) {}
@Implementation
protected static IBinder checkService(String name) {
return null;
}
@Implementation
protected static String[] listServices() throws RemoteException {
return null;
}
@Implementation
protected static void initServiceCache(Map<String, IBinder> cache) {}
/**
* Sets the availability of the given system service. If the service is set as unavailable,
* subsequent calls to {@link Context#getSystemService} for that service will return {@code null}.
*/
public static void setServiceAvailability(String service, boolean available) {
if (available) {
unavailableServices.remove(service);
} else {
unavailableServices.add(service);
}
}
@Resetter
public static void reset() {
unavailableServices.clear();
}
}