blob: 9c0b2301b715b9173d4d341975b3743bb83772da [file] [log] [blame]
package org.robolectric.android.internal;
import android.app.Application;
import android.app.LoadedApk;
import android.content.Context;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.content.res.Configuration;
import android.content.res.Resources;
import android.os.Looper;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.robolectric.Robolectric;
import org.robolectric.RuntimeEnvironment;
import org.robolectric.ShadowsAdapter;
import org.robolectric.TestLifecycle;
import org.robolectric.android.ApplicationTestUtil;
import org.robolectric.annotation.Config;
import org.robolectric.internal.ParallelUniverseInterface;
import org.robolectric.internal.SdkConfig;
import org.robolectric.android.fakes.RoboInstrumentation;
import org.robolectric.manifest.AndroidManifest;
import org.robolectric.manifest.RoboNotFoundException;
import org.robolectric.res.*;
import org.robolectric.res.builder.DefaultPackageManager;
import org.robolectric.shadows.ShadowLooper;
import org.robolectric.util.ReflectionHelpers;
import org.robolectric.util.Scheduler;
import java.lang.reflect.Method;
import java.security.Security;
import static org.robolectric.util.ReflectionHelpers.ClassParameter;
public class ParallelUniverse implements ParallelUniverseInterface {
private final ShadowsAdapter shadowsAdapter = Robolectric.getShadowsAdapter();
private boolean loggingInitialized = false;
private SdkConfig sdkConfig;
@Override
public void resetStaticState(Config config) {
RuntimeEnvironment.setMainThread(Thread.currentThread());
Robolectric.reset();
if (!loggingInitialized) {
shadowsAdapter.setupLogging();
loggingInitialized = true;
}
}
@Override
public void setUpApplicationState(Method method, TestLifecycle testLifecycle, AndroidManifest appManifest,
Config config, ResourceTable compileTimeResourceTable,
ResourceTable appResourceTable,
ResourceTable systemResourceTable) {
ReflectionHelpers.setStaticField(RuntimeEnvironment.class, "apiLevel", sdkConfig.getApiLevel());
RuntimeEnvironment.application = null;
RuntimeEnvironment.setMasterScheduler(new Scheduler());
RuntimeEnvironment.setMainThread(Thread.currentThread());
DefaultPackageManager packageManager = new DefaultPackageManager();
RuntimeEnvironment.setRobolectricPackageManager(packageManager);
RuntimeEnvironment.setCompileTimeResourceTable(compileTimeResourceTable);
RuntimeEnvironment.setAppResourceTable(appResourceTable);
RuntimeEnvironment.setSystemResourceTable(systemResourceTable);
initializeAppManifest(appManifest, appResourceTable, packageManager);
packageManager.setDependencies(appManifest, appResourceTable);
if (Security.getProvider(BouncyCastleProvider.PROVIDER_NAME) == null) {
Security.insertProviderAt(new BouncyCastleProvider(), 1);
}
String qualifiers = Qualifiers.addPlatformVersion(config.qualifiers(), sdkConfig.getApiLevel());
qualifiers = Qualifiers.addSmallestScreenWidth(qualifiers, 320);
qualifiers = Qualifiers.addScreenWidth(qualifiers, 320);
Resources systemResources = Resources.getSystem();
Configuration configuration = systemResources.getConfiguration();
configuration.smallestScreenWidthDp = Qualifiers.getSmallestScreenWidth(qualifiers);
configuration.screenWidthDp = Qualifiers.getScreenWidth(qualifiers);
String orientation = Qualifiers.getOrientation(qualifiers);
if ("land".equals(orientation)) {
configuration.orientation = Configuration.ORIENTATION_LANDSCAPE;
} else if ("port".equals(orientation)) {
configuration.orientation = Configuration.ORIENTATION_PORTRAIT;
} else {
configuration.orientation = Configuration.ORIENTATION_UNDEFINED;
}
systemResources.updateConfiguration(configuration, systemResources.getDisplayMetrics());
RuntimeEnvironment.setQualifiers(qualifiers);
Class<?> contextImplClass = ReflectionHelpers.loadClass(getClass().getClassLoader(), shadowsAdapter.getShadowContextImplClassName());
Class<?> activityThreadClass = ReflectionHelpers.loadClass(getClass().getClassLoader(), shadowsAdapter.getShadowActivityThreadClassName());
// Looper needs to be prepared before the activity thread is created
if (Looper.myLooper() == null) {
Looper.prepareMainLooper();
}
ShadowLooper.getShadowMainLooper().resetScheduler();
Object activityThread = ReflectionHelpers.newInstance(activityThreadClass);
RuntimeEnvironment.setActivityThread(activityThread);
ReflectionHelpers.setField(activityThread, "mInstrumentation", new RoboInstrumentation());
ReflectionHelpers.setField(activityThread, "mCompatConfiguration", configuration);
Context systemContextImpl = ReflectionHelpers.callStaticMethod(contextImplClass, "createSystemContext", ClassParameter.from(activityThreadClass, activityThread));
final Application application = (Application) testLifecycle.createApplication(method, appManifest, config);
RuntimeEnvironment.application = application;
if (application != null) {
shadowsAdapter.bind(application, appManifest);
ApplicationInfo applicationInfo;
try {
applicationInfo = packageManager.getApplicationInfo(appManifest.getPackageName(), 0);
} catch (PackageManager.NameNotFoundException e) {
throw new RuntimeException(e);
}
Class<?> compatibilityInfoClass = ReflectionHelpers.loadClass(getClass().getClassLoader(), "android.content.res.CompatibilityInfo");
LoadedApk loadedApk = ReflectionHelpers.callInstanceMethod(activityThread, "getPackageInfo",
ClassParameter.from(ApplicationInfo.class, applicationInfo),
ClassParameter.from(compatibilityInfoClass, null),
ClassParameter.from(int.class, Context.CONTEXT_INCLUDE_CODE));
try {
Context contextImpl = systemContextImpl.createPackageContext(applicationInfo.packageName, Context.CONTEXT_INCLUDE_CODE);
ReflectionHelpers.setField(activityThreadClass, activityThread, "mInitialApplication", application);
ApplicationTestUtil.attach(application, contextImpl);
} catch (PackageManager.NameNotFoundException e) {
throw new RuntimeException(e);
}
Resources appResources = application.getResources();
ReflectionHelpers.setField(loadedApk, "mResources", appResources);
ReflectionHelpers.setField(loadedApk, "mApplication", application);
appResources.updateConfiguration(configuration, appResources.getDisplayMetrics());
application.onCreate();
}
}
private void initializeAppManifest(AndroidManifest appManifest, ResourceTable appResourceTable, DefaultPackageManager packageManager) {
try {
appManifest.initMetaData(appResourceTable);
} catch (RoboNotFoundException e) {
throw new Resources.NotFoundException(e.getMessage(), e);
}
int labelRes = 0;
if (appManifest.getLabelRef() != null) {
String fullyQualifiedName = ResName.qualifyResName(appManifest.getLabelRef(), appManifest.getPackageName());
Integer id = fullyQualifiedName == null ? null : appResourceTable.getResourceId(new ResName(fullyQualifiedName));
labelRes = id != null ? id : 0;
}
packageManager.addManifest(appManifest, labelRes);
}
@Override
public Thread getMainThread() {
return RuntimeEnvironment.getMainThread();
}
@Override
public void setMainThread(Thread newMainThread) {
RuntimeEnvironment.setMainThread(newMainThread);
}
@Override
public void tearDownApplication() {
if (RuntimeEnvironment.application != null) {
RuntimeEnvironment.application.onTerminate();
}
}
@Override
public Object getCurrentApplication() {
return RuntimeEnvironment.application;
}
@Override
public void setSdkConfig(SdkConfig sdkConfig) {
this.sdkConfig = sdkConfig;
ReflectionHelpers.setStaticField(RuntimeEnvironment.class, "apiLevel", sdkConfig.getApiLevel());
}
}