155b52578fdaca7097ea4b28b3daebac84094dab4Christian Williamspackage org.robolectric.internal; 2b4c08d70a2f549cf344c81bb20c824d3cc31c298Vijay Nayar 3851f2a9519be23c73a9e2929128179b405e2e7a6Christian Williamsimport java.io.File; 4851f2a9519be23c73a9e2929128179b405e2e7a6Christian Williamsimport java.net.URL; 52a324a6cbb9db3b2ccfafc4435760d8e1a04d746Michael Hoisieimport java.nio.file.Files; 62a324a6cbb9db3b2ccfafc4435760d8e1a04d746Michael Hoisieimport java.nio.file.Path; 72a324a6cbb9db3b2ccfafc4435760d8e1a04d746Michael Hoisieimport java.nio.file.Paths; 8b4c08d70a2f549cf344c81bb20c824d3cc31c298Vijay Nayarimport org.robolectric.annotation.Config; 9b4c08d70a2f549cf344c81bb20c824d3cc31c298Vijay Nayarimport org.robolectric.res.FileFsFile; 10b4c08d70a2f549cf344c81bb20c824d3cc31c298Vijay Nayarimport org.robolectric.util.Logger; 11b4c08d70a2f549cf344c81bb20c824d3cc31c298Vijay Nayarimport org.robolectric.util.ReflectionHelpers; 12b4c08d70a2f549cf344c81bb20c824d3cc31c298Vijay Nayar 1355b52578fdaca7097ea4b28b3daebac84094dab4Christian Williamspublic class GradleManifestFactory implements ManifestFactory { 14b4c08d70a2f549cf344c81bb20c824d3cc31c298Vijay Nayar @Override 15eb01f4f02fcd34067b8ff5e53bfeb9575b874e1fChristian Williams public ManifestIdentifier identify(Config config) { 16b4c08d70a2f549cf344c81bb20c824d3cc31c298Vijay Nayar if (config.constants() == Void.class) { 17b4c08d70a2f549cf344c81bb20c824d3cc31c298Vijay Nayar Logger.error("Field 'constants' not specified in @Config annotation"); 1855b52578fdaca7097ea4b28b3daebac84094dab4Christian Williams Logger.error("This is required when using Robolectric with Gradle!"); 19b4c08d70a2f549cf344c81bb20c824d3cc31c298Vijay Nayar throw new RuntimeException("No 'constants' field in @Config annotation!"); 20b4c08d70a2f549cf344c81bb20c824d3cc31c298Vijay Nayar } 21b4c08d70a2f549cf344c81bb20c824d3cc31c298Vijay Nayar 22b4c08d70a2f549cf344c81bb20c824d3cc31c298Vijay Nayar final String buildOutputDir = getBuildOutputDir(config); 23b4c08d70a2f549cf344c81bb20c824d3cc31c298Vijay Nayar final String type = getType(config); 24b4c08d70a2f549cf344c81bb20c824d3cc31c298Vijay Nayar final String flavor = getFlavor(config); 25d7812f81cb863ffc228a6beec03eb365115aa1f3Jonathan Gerrish final String abiSplit = getAbiSplit(config); 2655b52578fdaca7097ea4b28b3daebac84094dab4Christian Williams final String packageName = config.packageName().isEmpty() 2755b52578fdaca7097ea4b28b3daebac84094dab4Christian Williams ? config.constants().getPackage().getName() 2855b52578fdaca7097ea4b28b3daebac84094dab4Christian Williams : config.packageName(); 29b4c08d70a2f549cf344c81bb20c824d3cc31c298Vijay Nayar 30b4c08d70a2f549cf344c81bb20c824d3cc31c298Vijay Nayar final FileFsFile res; 31b4c08d70a2f549cf344c81bb20c824d3cc31c298Vijay Nayar final FileFsFile assets; 32b4c08d70a2f549cf344c81bb20c824d3cc31c298Vijay Nayar final FileFsFile manifest; 33b4c08d70a2f549cf344c81bb20c824d3cc31c298Vijay Nayar 34b4c08d70a2f549cf344c81bb20c824d3cc31c298Vijay Nayar if (FileFsFile.from(buildOutputDir, "data-binding-layout-out").exists()) { 35b4c08d70a2f549cf344c81bb20c824d3cc31c298Vijay Nayar // Android gradle plugin 1.5.0+ puts the merged layouts in data-binding-layout-out. 36b4c08d70a2f549cf344c81bb20c824d3cc31c298Vijay Nayar // https://github.com/robolectric/robolectric/issues/2143 37b4c08d70a2f549cf344c81bb20c824d3cc31c298Vijay Nayar res = FileFsFile.from(buildOutputDir, "data-binding-layout-out", flavor, type); 38b4c08d70a2f549cf344c81bb20c824d3cc31c298Vijay Nayar } else if (FileFsFile.from(buildOutputDir, "res", "merged").exists()) { 39b4c08d70a2f549cf344c81bb20c824d3cc31c298Vijay Nayar // res/merged added in Android Gradle plugin 1.3-beta1 40b4c08d70a2f549cf344c81bb20c824d3cc31c298Vijay Nayar res = FileFsFile.from(buildOutputDir, "res", "merged", flavor, type); 41b4c08d70a2f549cf344c81bb20c824d3cc31c298Vijay Nayar } else if (FileFsFile.from(buildOutputDir, "res").exists()) { 42b4c08d70a2f549cf344c81bb20c824d3cc31c298Vijay Nayar res = FileFsFile.from(buildOutputDir, "res", flavor, type); 43b4c08d70a2f549cf344c81bb20c824d3cc31c298Vijay Nayar } else { 44b4c08d70a2f549cf344c81bb20c824d3cc31c298Vijay Nayar res = FileFsFile.from(buildOutputDir, "bundles", flavor, type, "res"); 45b4c08d70a2f549cf344c81bb20c824d3cc31c298Vijay Nayar } 46b4c08d70a2f549cf344c81bb20c824d3cc31c298Vijay Nayar 474c8cedc6e3cecbee3b30dce84d7746a9b527812cScott Kennedy if (!Config.DEFAULT_ASSET_FOLDER.equals(config.assetDir()) 484c8cedc6e3cecbee3b30dce84d7746a9b527812cScott Kennedy && FileFsFile.from(buildOutputDir, config.assetDir()).exists()) { 494c8cedc6e3cecbee3b30dce84d7746a9b527812cScott Kennedy assets = FileFsFile.from(buildOutputDir, config.assetDir()); 504c8cedc6e3cecbee3b30dce84d7746a9b527812cScott Kennedy } else if (FileFsFile.from(buildOutputDir, "assets").exists()) { 51b4c08d70a2f549cf344c81bb20c824d3cc31c298Vijay Nayar assets = FileFsFile.from(buildOutputDir, "assets", flavor, type); 52b4c08d70a2f549cf344c81bb20c824d3cc31c298Vijay Nayar } else { 53b4c08d70a2f549cf344c81bb20c824d3cc31c298Vijay Nayar assets = FileFsFile.from(buildOutputDir, "bundles", flavor, type, "assets"); 54b4c08d70a2f549cf344c81bb20c824d3cc31c298Vijay Nayar } 55b4c08d70a2f549cf344c81bb20c824d3cc31c298Vijay Nayar 56b4d0e3b1d6313b7f37852f42a2b8b54cc57af17eChristian Williams String manifestName = config.manifest(); 57b4d0e3b1d6313b7f37852f42a2b8b54cc57af17eChristian Williams URL manifestUrl = getClass().getClassLoader().getResource(manifestName); 58b4d0e3b1d6313b7f37852f42a2b8b54cc57af17eChristian Williams if (manifestUrl != null && manifestUrl.getProtocol().equals("file")) { 59b4d0e3b1d6313b7f37852f42a2b8b54cc57af17eChristian Williams manifest = FileFsFile.from(manifestUrl.getPath()); 60b4d0e3b1d6313b7f37852f42a2b8b54cc57af17eChristian Williams } else if (FileFsFile.from(buildOutputDir, "manifests", "full").exists()) { 61b4d0e3b1d6313b7f37852f42a2b8b54cc57af17eChristian Williams manifest = FileFsFile.from(buildOutputDir, "manifests", "full", flavor, abiSplit, type, manifestName); 6224973cd7fa61401b3af1069f01d516e40080221cHilal Alsibai } else if (FileFsFile.from(buildOutputDir, "manifests", "aapt").exists()) { 6324973cd7fa61401b3af1069f01d516e40080221cHilal Alsibai // Android gradle plugin 2.2.0+ can put library manifest files inside of "aapt" instead of "full" 64b4d0e3b1d6313b7f37852f42a2b8b54cc57af17eChristian Williams manifest = FileFsFile.from(buildOutputDir, "manifests", "aapt", flavor, abiSplit, type, manifestName); 65b4c08d70a2f549cf344c81bb20c824d3cc31c298Vijay Nayar } else { 66b4d0e3b1d6313b7f37852f42a2b8b54cc57af17eChristian Williams manifest = FileFsFile.from(buildOutputDir, "bundles", flavor, abiSplit, type, manifestName); 67b4c08d70a2f549cf344c81bb20c824d3cc31c298Vijay Nayar } 68b4c08d70a2f549cf344c81bb20c824d3cc31c298Vijay Nayar 69eb01f4f02fcd34067b8ff5e53bfeb9575b874e1fChristian Williams return new ManifestIdentifier(manifest, res, assets, packageName, null); 70eb01f4f02fcd34067b8ff5e53bfeb9575b874e1fChristian Williams } 71eb01f4f02fcd34067b8ff5e53bfeb9575b874e1fChristian Williams 72b4c08d70a2f549cf344c81bb20c824d3cc31c298Vijay Nayar private static String getBuildOutputDir(Config config) { 732a324a6cbb9db3b2ccfafc4435760d8e1a04d746Michael Hoisie Path buildDir = Paths.get(config.buildDir(), "intermediates"); 742a324a6cbb9db3b2ccfafc4435760d8e1a04d746Michael Hoisie if (!Files.exists(buildDir)) { 752a324a6cbb9db3b2ccfafc4435760d8e1a04d746Michael Hoisie // By default build dir is a relative path. However, the build dir lookup may fail if the 762a324a6cbb9db3b2ccfafc4435760d8e1a04d746Michael Hoisie // working directory of the test configuration in Android Studio is not set to the module 772a324a6cbb9db3b2ccfafc4435760d8e1a04d746Michael Hoisie // root directory (e.g it is set to the entire project root directory). Attempt to locate it 782a324a6cbb9db3b2ccfafc4435760d8e1a04d746Michael Hoisie // relative to the constants class, which is generated in the build output directory. 792a324a6cbb9db3b2ccfafc4435760d8e1a04d746Michael Hoisie String moduleRoot = config.constants().getResource("").toString().replace("file:", ""); 802a324a6cbb9db3b2ccfafc4435760d8e1a04d746Michael Hoisie int idx = moduleRoot.lastIndexOf(File.separator + "intermediates"); 812a324a6cbb9db3b2ccfafc4435760d8e1a04d746Michael Hoisie if (idx > 0) { 822a324a6cbb9db3b2ccfafc4435760d8e1a04d746Michael Hoisie buildDir = Paths.get(moduleRoot.substring(0, idx), "intermediates"); 832a324a6cbb9db3b2ccfafc4435760d8e1a04d746Michael Hoisie } else { 842a324a6cbb9db3b2ccfafc4435760d8e1a04d746Michael Hoisie Logger.error("Failed to locate build dir"); 852a324a6cbb9db3b2ccfafc4435760d8e1a04d746Michael Hoisie } 862a324a6cbb9db3b2ccfafc4435760d8e1a04d746Michael Hoisie } 872a324a6cbb9db3b2ccfafc4435760d8e1a04d746Michael Hoisie return buildDir.toString(); 88b4c08d70a2f549cf344c81bb20c824d3cc31c298Vijay Nayar } 89b4c08d70a2f549cf344c81bb20c824d3cc31c298Vijay Nayar 90b4c08d70a2f549cf344c81bb20c824d3cc31c298Vijay Nayar private static String getType(Config config) { 91b4c08d70a2f549cf344c81bb20c824d3cc31c298Vijay Nayar try { 92b4c08d70a2f549cf344c81bb20c824d3cc31c298Vijay Nayar return ReflectionHelpers.getStaticField(config.constants(), "BUILD_TYPE"); 93b4c08d70a2f549cf344c81bb20c824d3cc31c298Vijay Nayar } catch (Throwable e) { 94b4c08d70a2f549cf344c81bb20c824d3cc31c298Vijay Nayar return null; 95b4c08d70a2f549cf344c81bb20c824d3cc31c298Vijay Nayar } 96b4c08d70a2f549cf344c81bb20c824d3cc31c298Vijay Nayar } 97b4c08d70a2f549cf344c81bb20c824d3cc31c298Vijay Nayar 98b4c08d70a2f549cf344c81bb20c824d3cc31c298Vijay Nayar private static String getFlavor(Config config) { 99b4c08d70a2f549cf344c81bb20c824d3cc31c298Vijay Nayar try { 100b4c08d70a2f549cf344c81bb20c824d3cc31c298Vijay Nayar return ReflectionHelpers.getStaticField(config.constants(), "FLAVOR"); 101b4c08d70a2f549cf344c81bb20c824d3cc31c298Vijay Nayar } catch (Throwable e) { 102b4c08d70a2f549cf344c81bb20c824d3cc31c298Vijay Nayar return null; 103b4c08d70a2f549cf344c81bb20c824d3cc31c298Vijay Nayar } 104b4c08d70a2f549cf344c81bb20c824d3cc31c298Vijay Nayar } 105b4c08d70a2f549cf344c81bb20c824d3cc31c298Vijay Nayar 106d7812f81cb863ffc228a6beec03eb365115aa1f3Jonathan Gerrish private static String getAbiSplit(Config config) { 107d7812f81cb863ffc228a6beec03eb365115aa1f3Jonathan Gerrish try { 108d7812f81cb863ffc228a6beec03eb365115aa1f3Jonathan Gerrish return config.abiSplit(); 109d7812f81cb863ffc228a6beec03eb365115aa1f3Jonathan Gerrish } catch (Throwable e) { 110d7812f81cb863ffc228a6beec03eb365115aa1f3Jonathan Gerrish return null; 111d7812f81cb863ffc228a6beec03eb365115aa1f3Jonathan Gerrish } 112d7812f81cb863ffc228a6beec03eb365115aa1f3Jonathan Gerrish } 113b4c08d70a2f549cf344c81bb20c824d3cc31c298Vijay Nayar} 114