| 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()); |
| } |
| } |