private static String getPackageName(Config config) {
   try {
     final String packageName = config.packageName();
     if (packageName != null && !packageName.isEmpty()) {
       return packageName;
     } else {
       return ReflectionHelpers.getStaticField(config.constants(), "APPLICATION_ID");
     }
   } catch (Throwable e) {
     return null;
   }
 }
 private AndroidManifest createDummyManifest() {
   return new AndroidManifest(
       null,
       null,
       null,
       !config.packageName().isEmpty() ? config.packageName() : "org.robolectric.default") {
     @Override
     public int getTargetSdkVersion() {
       return SdkConfig.FALLBACK_SDK_VERSION;
     }
   };
 }
 private static String getFlavor(Config config) {
   try {
     return ReflectionHelpers.getStaticField(config.constants(), "FLAVOR");
   } catch (Throwable e) {
     return null;
   }
 }
 private static String getType(Config config) {
   try {
     return ReflectionHelpers.getStaticField(config.constants(), "BUILD_TYPE");
   } catch (Throwable e) {
     return null;
   }
 }
 private String stringify(Config config) {
   int emulateSdk = config.emulateSdk();
   String manifest = config.manifest();
   String qualifiers = config.qualifiers();
   String resourceDir = config.resourceDir();
   int reportSdk = config.reportSdk();
   Class<?>[] shadows = config.shadows();
   return stringify(emulateSdk, manifest, qualifiers, resourceDir, reportSdk, shadows);
 }
  @Override
  protected AndroidManifest getAppManifest(Config config) {
    if (config.constants() == Void.class) {
      Logger.error("Field 'constants' not specified in @Config annotation");
      Logger.error("This is required when using RobolectricGradleTestRunner!");
      throw new RuntimeException("No 'constants' field in @Config annotation!");
    }

    final String type = getType(config);
    final String flavor = getFlavor(config);
    final String packageName = getPackageName(config);

    final FileFsFile res;
    final FileFsFile assets;
    final FileFsFile manifest;

    if (FileFsFile.from(BUILD_OUTPUT, "data-binding-layout-out").exists()) {
      // Android gradle plugin 1.5.0+ puts the merged layouts in data-binding-layout-out.
      // https://github.com/robolectric/robolectric/issues/2143
      res = FileFsFile.from(BUILD_OUTPUT, "data-binding-layout-out", flavor, type);
    } else if (FileFsFile.from(BUILD_OUTPUT, "res", "merged").exists()) {
      // res/merged added in Android Gradle plugin 1.3-beta1
      res = FileFsFile.from(BUILD_OUTPUT, "res", "merged", flavor, type);
    } else if (FileFsFile.from(BUILD_OUTPUT, "res").exists()) {
      res = FileFsFile.from(BUILD_OUTPUT, "res", flavor, type);
    } else {
      res = FileFsFile.from(BUILD_OUTPUT, "bundles", flavor, type, "res");
    }

    if (FileFsFile.from(BUILD_OUTPUT, "assets").exists()) {
      assets = FileFsFile.from(BUILD_OUTPUT, "assets", flavor, type);
    } else {
      assets = FileFsFile.from(BUILD_OUTPUT, "bundles", flavor, type, "assets");
    }

    if (FileFsFile.from(BUILD_OUTPUT, "manifests").exists()) {
      manifest =
          FileFsFile.from(BUILD_OUTPUT, "manifests", "full", flavor, type, "AndroidManifest.xml");
    } else {
      manifest = FileFsFile.from(BUILD_OUTPUT, "bundles", flavor, type, "AndroidManifest.xml");
    }

    Logger.debug("Robolectric assets directory: " + assets.getPath());
    Logger.debug("   Robolectric res directory: " + res.getPath());
    Logger.debug("   Robolectric manifest path: " + manifest.getPath());
    Logger.debug("    Robolectric package name: " + packageName);
    return new AndroidManifest(manifest, res, assets, packageName);
  }
  @Override
  public AndroidManifest create() {
    if (config.manifest().equals(Config.NONE)) {
      return createDummyManifest();
    }

    FsFile manifestFile =
        getBaseDir()
            .join(
                config.manifest().equals(Config.DEFAULT_MANIFEST)
                    ? DEFAULT_MANIFEST_NAME
                    : config.manifest().replaceAll("^(\\./)+", ""));
    FsFile baseDir = manifestFile.getParent();
    FsFile resDir = baseDir.join(config.resourceDir());
    FsFile assetDir = baseDir.join(config.assetDir());

    List<FsFile> libraryDirs = null;
    if (config.libraries().length > 0) {
      libraryDirs = new ArrayList<>();
      for (String libraryDirName : config.libraries()) {
        libraryDirs.add(baseDir.join(libraryDirName));
      }
    }

    ManifestIdentifier identifier =
        new ManifestIdentifier(manifestFile, resDir, assetDir, config.packageName(), libraryDirs);
    synchronized (appManifestsByFile) {
      AndroidManifest appManifest;
      appManifest = appManifestsByFile.get(identifier);
      if (appManifest == null) {
        appManifest = createAppManifest(manifestFile, resDir, assetDir, config.packageName());
        appManifestsByFile.put(identifier, appManifest);
      }
      // The AppManifest may STILL be null if no file was found.
      if (appManifest != null) {
        appManifest.setLibraryManifests(createLibraryManifests(appManifest, libraryDirs));
      }
      return appManifest;
    }
  }