Config.java revision 9cc9bde8928b83e5de9cd1c521e157e1a584b2fd
1cfb3d242306311ce27ec51bf511764377c173a7cKiran Ryali + Christian Williamspackage org.robolectric.annotation; 2dd40f718cf785a56e63c0685feeb73d266c13e3fWenhui Yao 39cc9bde8928b83e5de9cd1c521e157e1a584b2fdJonathan Gerrishimport android.app.Application; 4f6df8a55ac378dee35324bc865fb4d741dcb4824Christian Williamsimport org.jetbrains.annotations.NotNull; 5f6df8a55ac378dee35324bc865fb4d741dcb4824Christian Williams 6f6df8a55ac378dee35324bc865fb4d741dcb4824Christian Williamsimport java.lang.annotation.Annotation; 7f6df8a55ac378dee35324bc865fb4d741dcb4824Christian Williamsimport java.lang.annotation.Documented; 8f6df8a55ac378dee35324bc865fb4d741dcb4824Christian Williamsimport java.lang.annotation.ElementType; 9f6df8a55ac378dee35324bc865fb4d741dcb4824Christian Williamsimport java.lang.annotation.Retention; 10f6df8a55ac378dee35324bc865fb4d741dcb4824Christian Williamsimport java.lang.annotation.RetentionPolicy; 11f6df8a55ac378dee35324bc865fb4d741dcb4824Christian Williamsimport java.lang.annotation.Target; 12f6df8a55ac378dee35324bc865fb4d741dcb4824Christian Williamsimport java.util.Arrays; 13c77f5791f081893a18f9db753bb5022269a7c5a6Simon Arlottimport java.util.HashSet; 1423a26cc3e5b33c0503a99847292ac99817f5af43Christian Williamsimport java.util.Properties; 15c77f5791f081893a18f9db753bb5022269a7c5a6Simon Arlottimport java.util.Set; 16f6df8a55ac378dee35324bc865fb4d741dcb4824Christian Williams 17dd40f718cf785a56e63c0685feeb73d266c13e3fWenhui Yao/** 1880c8a1718d42c7e2165289a7bbfab5e7f3dc0513Christian Williams & Dimitris Couchell * Indicate that robolectric should look for values that is specific by those qualifiers 19dd40f718cf785a56e63c0685feeb73d266c13e3fWenhui Yao */ 20f6df8a55ac378dee35324bc865fb4d741dcb4824Christian Williams@Documented 21f6df8a55ac378dee35324bc865fb4d741dcb4824Christian Williams@Retention(RetentionPolicy.RUNTIME) 22f6df8a55ac378dee35324bc865fb4d741dcb4824Christian Williams@Target({ElementType.TYPE, ElementType.METHOD}) 237be4d2ba0e45483ad70cbd994955ae1b70afafdcKiran Ryali + Christian Williamspublic @interface Config { 2429a8359eaef1ee9f40c967d3c4b5c1117c8c2a43Christian Williams @SuppressWarnings("UnusedDeclaration") 2529a8359eaef1ee9f40c967d3c4b5c1117c8c2a43Christian Williams public static final String NONE = "--none"; 2629a8359eaef1ee9f40c967d3c4b5c1117c8c2a43Christian Williams public static final String DEFAULT = "--default"; 2729a8359eaef1ee9f40c967d3c4b5c1117c8c2a43Christian Williams 2829a8359eaef1ee9f40c967d3c4b5c1117c8c2a43Christian Williams /** 29074a38a2ee8dd8cb1904853aebf2f30146d563a2Mike Grafton * The Android SDK level to emulate. If not specified, Robolectric defaults to API 16. 3029a8359eaef1ee9f40c967d3c4b5c1117c8c2a43Christian Williams */ 31b2a2e594372228d4e4cae61730152d4e1047c8a7Erich Douglass int emulateSdk() default -1; 3229a8359eaef1ee9f40c967d3c4b5c1117c8c2a43Christian Williams 3329a8359eaef1ee9f40c967d3c4b5c1117c8c2a43Christian Williams /** 3429a8359eaef1ee9f40c967d3c4b5c1117c8c2a43Christian Williams * The Android manifest file to load; Robolectric will look relative to the current directory. 3529a8359eaef1ee9f40c967d3c4b5c1117c8c2a43Christian Williams * Resources and assets will be loaded relative to the manifest. 3629a8359eaef1ee9f40c967d3c4b5c1117c8c2a43Christian Williams * 3729a8359eaef1ee9f40c967d3c4b5c1117c8c2a43Christian Williams * If not specified, Robolectric defaults to {@code AndroidManifest.xml}. 3829a8359eaef1ee9f40c967d3c4b5c1117c8c2a43Christian Williams * 3929a8359eaef1ee9f40c967d3c4b5c1117c8c2a43Christian Williams * If your project has no manifest or resources, use {@link Config#NONE}. 4029a8359eaef1ee9f40c967d3c4b5c1117c8c2a43Christian Williams */ 4129a8359eaef1ee9f40c967d3c4b5c1117c8c2a43Christian Williams String manifest() default DEFAULT; 4229a8359eaef1ee9f40c967d3c4b5c1117c8c2a43Christian Williams 4329a8359eaef1ee9f40c967d3c4b5c1117c8c2a43Christian Williams /** 449cc9bde8928b83e5de9cd1c521e157e1a584b2fdJonathan Gerrish * The {@link android.app.Application} class to use in the test, this takes precedence over any application 459cc9bde8928b83e5de9cd1c521e157e1a584b2fdJonathan Gerrish * specified in the AndroidManifest.xml. 469cc9bde8928b83e5de9cd1c521e157e1a584b2fdJonathan Gerrish */ 479cc9bde8928b83e5de9cd1c521e157e1a584b2fdJonathan Gerrish Class<? extends Application> application() default Application.class; 489cc9bde8928b83e5de9cd1c521e157e1a584b2fdJonathan Gerrish 499cc9bde8928b83e5de9cd1c521e157e1a584b2fdJonathan Gerrish /** 5029a8359eaef1ee9f40c967d3c4b5c1117c8c2a43Christian Williams * Qualifiers for the resource resolution, such as "fr-normal-port-hdpi". 5129a8359eaef1ee9f40c967d3c4b5c1117c8c2a43Christian Williams * 5229a8359eaef1ee9f40c967d3c4b5c1117c8c2a43Christian Williams * @see <a href="http://developer.android.com/guide/topics/resources/providing-resources.html">Providing Resources</a> in the Android Developer docs for more information. 5329a8359eaef1ee9f40c967d3c4b5c1117c8c2a43Christian Williams */ 5429a8359eaef1ee9f40c967d3c4b5c1117c8c2a43Christian Williams String qualifiers() default ""; 5529a8359eaef1ee9f40c967d3c4b5c1117c8c2a43Christian Williams 5629a8359eaef1ee9f40c967d3c4b5c1117c8c2a43Christian Williams /** 575277f871bca2be31c657ace35ae305285b2e0c55Ryan Spore and Trevor John * The Directory from which to load resources. This should be relative from the directory containing the AndroidManifest. 585277f871bca2be31c657ace35ae305285b2e0c55Ryan Spore and Trevor John * 595277f871bca2be31c657ace35ae305285b2e0c55Ryan Spore and Trevor John * If not specified, Robolectric defaults to {@code res}. 605277f871bca2be31c657ace35ae305285b2e0c55Ryan Spore and Trevor John */ 615277f871bca2be31c657ace35ae305285b2e0c55Ryan Spore and Trevor John String resourceDir() default "res"; 625277f871bca2be31c657ace35ae305285b2e0c55Ryan Spore and Trevor John 635277f871bca2be31c657ace35ae305285b2e0c55Ryan Spore and Trevor John /** 6429a8359eaef1ee9f40c967d3c4b5c1117c8c2a43Christian Williams * The Android SDK level to report in Build.VERSION.SDK_INT. 6529a8359eaef1ee9f40c967d3c4b5c1117c8c2a43Christian Williams * 6629a8359eaef1ee9f40c967d3c4b5c1117c8c2a43Christian Williams * @see <a href="http://en.wikipedia.org/wiki/Android_version_history">Android Version History</a>. 6729a8359eaef1ee9f40c967d3c4b5c1117c8c2a43Christian Williams */ 6829a8359eaef1ee9f40c967d3c4b5c1117c8c2a43Christian Williams int reportSdk() default -1; 6929a8359eaef1ee9f40c967d3c4b5c1117c8c2a43Christian Williams 7029a8359eaef1ee9f40c967d3c4b5c1117c8c2a43Christian Williams /** 7129a8359eaef1ee9f40c967d3c4b5c1117c8c2a43Christian Williams * A list of shadow classes to enable, in addition to those that are already present. 7229a8359eaef1ee9f40c967d3c4b5c1117c8c2a43Christian Williams */ 7329a8359eaef1ee9f40c967d3c4b5c1117c8c2a43Christian Williams Class<?>[] shadows() default {}; 7429a8359eaef1ee9f40c967d3c4b5c1117c8c2a43Christian Williams 7529a8359eaef1ee9f40c967d3c4b5c1117c8c2a43Christian Williams public class Implementation implements Config { 7629a8359eaef1ee9f40c967d3c4b5c1117c8c2a43Christian Williams private final int emulateSdk; 7729a8359eaef1ee9f40c967d3c4b5c1117c8c2a43Christian Williams private final String manifest; 7829a8359eaef1ee9f40c967d3c4b5c1117c8c2a43Christian Williams private final String qualifiers; 795277f871bca2be31c657ace35ae305285b2e0c55Ryan Spore and Trevor John private final String resourceDir; 8029a8359eaef1ee9f40c967d3c4b5c1117c8c2a43Christian Williams private final int reportSdk; 8129a8359eaef1ee9f40c967d3c4b5c1117c8c2a43Christian Williams private final Class<?>[] shadows; 829cc9bde8928b83e5de9cd1c521e157e1a584b2fdJonathan Gerrish private final Class<? extends Application> application; 8329a8359eaef1ee9f40c967d3c4b5c1117c8c2a43Christian Williams 8429a8359eaef1ee9f40c967d3c4b5c1117c8c2a43Christian Williams public static Config fromProperties(Properties configProperties) { 8529a8359eaef1ee9f40c967d3c4b5c1117c8c2a43Christian Williams if (configProperties == null || configProperties.size() == 0) return null; 8629a8359eaef1ee9f40c967d3c4b5c1117c8c2a43Christian Williams return new Implementation( 8729a8359eaef1ee9f40c967d3c4b5c1117c8c2a43Christian Williams Integer.parseInt(configProperties.getProperty("emulateSdk", "-1")), 8829a8359eaef1ee9f40c967d3c4b5c1117c8c2a43Christian Williams configProperties.getProperty("manifest", DEFAULT), 8929a8359eaef1ee9f40c967d3c4b5c1117c8c2a43Christian Williams configProperties.getProperty("qualifiers", ""), 905277f871bca2be31c657ace35ae305285b2e0c55Ryan Spore and Trevor John configProperties.getProperty("resourceDir", "res"), 9129a8359eaef1ee9f40c967d3c4b5c1117c8c2a43Christian Williams Integer.parseInt(configProperties.getProperty("reportSdk", "-1")), 929cc9bde8928b83e5de9cd1c521e157e1a584b2fdJonathan Gerrish parseClasses(configProperties.getProperty("shadows", "")), 939cc9bde8928b83e5de9cd1c521e157e1a584b2fdJonathan Gerrish parseApplication(configProperties.getProperty("application", "android.app.Application")) 9429a8359eaef1ee9f40c967d3c4b5c1117c8c2a43Christian Williams ); 9529a8359eaef1ee9f40c967d3c4b5c1117c8c2a43Christian Williams } 9623a26cc3e5b33c0503a99847292ac99817f5af43Christian Williams 9729a8359eaef1ee9f40c967d3c4b5c1117c8c2a43Christian Williams private static Class<?>[] parseClasses(String classList) { 9829a8359eaef1ee9f40c967d3c4b5c1117c8c2a43Christian Williams if (classList.length() == 0) return new Class[0]; 9929a8359eaef1ee9f40c967d3c4b5c1117c8c2a43Christian Williams String[] classNames = classList.split("[, ]+"); 10029a8359eaef1ee9f40c967d3c4b5c1117c8c2a43Christian Williams Class[] classes = new Class[classNames.length]; 10129a8359eaef1ee9f40c967d3c4b5c1117c8c2a43Christian Williams for (int i = 0; i < classNames.length; i++) { 10229a8359eaef1ee9f40c967d3c4b5c1117c8c2a43Christian Williams try { 10329a8359eaef1ee9f40c967d3c4b5c1117c8c2a43Christian Williams classes[i] = Implementation.class.getClassLoader().loadClass(classNames[i]); 10429a8359eaef1ee9f40c967d3c4b5c1117c8c2a43Christian Williams } catch (ClassNotFoundException e) { 10529a8359eaef1ee9f40c967d3c4b5c1117c8c2a43Christian Williams throw new RuntimeException(e); 10623a26cc3e5b33c0503a99847292ac99817f5af43Christian Williams } 10729a8359eaef1ee9f40c967d3c4b5c1117c8c2a43Christian Williams } 10829a8359eaef1ee9f40c967d3c4b5c1117c8c2a43Christian Williams return classes; 10929a8359eaef1ee9f40c967d3c4b5c1117c8c2a43Christian Williams } 11023a26cc3e5b33c0503a99847292ac99817f5af43Christian Williams 1119cc9bde8928b83e5de9cd1c521e157e1a584b2fdJonathan Gerrish private static <T extends Application> Class<T> parseApplication(String className) { 1129cc9bde8928b83e5de9cd1c521e157e1a584b2fdJonathan Gerrish try { 1139cc9bde8928b83e5de9cd1c521e157e1a584b2fdJonathan Gerrish Class<T> aClass = (Class<T>) Implementation.class.getClassLoader().loadClass(className); 1149cc9bde8928b83e5de9cd1c521e157e1a584b2fdJonathan Gerrish return aClass; 1159cc9bde8928b83e5de9cd1c521e157e1a584b2fdJonathan Gerrish } catch (ClassNotFoundException e) { 1169cc9bde8928b83e5de9cd1c521e157e1a584b2fdJonathan Gerrish throw new RuntimeException(e); 1179cc9bde8928b83e5de9cd1c521e157e1a584b2fdJonathan Gerrish } 1189cc9bde8928b83e5de9cd1c521e157e1a584b2fdJonathan Gerrish } 1199cc9bde8928b83e5de9cd1c521e157e1a584b2fdJonathan Gerrish 1209cc9bde8928b83e5de9cd1c521e157e1a584b2fdJonathan Gerrish public Implementation(int emulateSdk, String manifest, String qualifiers, String resourceDir, int reportSdk, Class<?>[] shadows, Class<? extends Application> application) { 12129a8359eaef1ee9f40c967d3c4b5c1117c8c2a43Christian Williams this.emulateSdk = emulateSdk; 12229a8359eaef1ee9f40c967d3c4b5c1117c8c2a43Christian Williams this.manifest = manifest; 12329a8359eaef1ee9f40c967d3c4b5c1117c8c2a43Christian Williams this.qualifiers = qualifiers; 1245277f871bca2be31c657ace35ae305285b2e0c55Ryan Spore and Trevor John this.resourceDir = resourceDir; 12529a8359eaef1ee9f40c967d3c4b5c1117c8c2a43Christian Williams this.reportSdk = reportSdk; 12629a8359eaef1ee9f40c967d3c4b5c1117c8c2a43Christian Williams this.shadows = shadows; 1279cc9bde8928b83e5de9cd1c521e157e1a584b2fdJonathan Gerrish this.application = application; 12829a8359eaef1ee9f40c967d3c4b5c1117c8c2a43Christian Williams } 129f6df8a55ac378dee35324bc865fb4d741dcb4824Christian Williams 13029a8359eaef1ee9f40c967d3c4b5c1117c8c2a43Christian Williams public Implementation(Config baseConfig, Config overlayConfig) { 131b2a2e594372228d4e4cae61730152d4e1047c8a7Erich Douglass this.emulateSdk = pick(baseConfig.emulateSdk(), overlayConfig.emulateSdk(), -1); 13229a8359eaef1ee9f40c967d3c4b5c1117c8c2a43Christian Williams this.manifest = pick(baseConfig.manifest(), overlayConfig.manifest(), DEFAULT); 13329a8359eaef1ee9f40c967d3c4b5c1117c8c2a43Christian Williams this.qualifiers = pick(baseConfig.qualifiers(), overlayConfig.qualifiers(), ""); 1345277f871bca2be31c657ace35ae305285b2e0c55Ryan Spore and Trevor John this.resourceDir = pick(baseConfig.resourceDir(), overlayConfig.resourceDir(), "res"); 13529a8359eaef1ee9f40c967d3c4b5c1117c8c2a43Christian Williams this.reportSdk = pick(baseConfig.reportSdk(), overlayConfig.reportSdk(), -1); 136c77f5791f081893a18f9db753bb5022269a7c5a6Simon Arlott Set<Class<?>> shadows = new HashSet<Class<?>>(); 13729a8359eaef1ee9f40c967d3c4b5c1117c8c2a43Christian Williams shadows.addAll(Arrays.asList(baseConfig.shadows())); 13829a8359eaef1ee9f40c967d3c4b5c1117c8c2a43Christian Williams shadows.addAll(Arrays.asList(overlayConfig.shadows())); 13929a8359eaef1ee9f40c967d3c4b5c1117c8c2a43Christian Williams this.shadows = shadows.toArray(new Class[shadows.size()]); 1409cc9bde8928b83e5de9cd1c521e157e1a584b2fdJonathan Gerrish this.application = pick(baseConfig.application(), overlayConfig.application(), null); 14129a8359eaef1ee9f40c967d3c4b5c1117c8c2a43Christian Williams } 142f6df8a55ac378dee35324bc865fb4d741dcb4824Christian Williams 14329a8359eaef1ee9f40c967d3c4b5c1117c8c2a43Christian Williams private <T> T pick(T baseValue, T overlayValue, T nullValue) { 14429a8359eaef1ee9f40c967d3c4b5c1117c8c2a43Christian Williams return overlayValue.equals(nullValue) ? baseValue : overlayValue; 14529a8359eaef1ee9f40c967d3c4b5c1117c8c2a43Christian Williams } 146f6df8a55ac378dee35324bc865fb4d741dcb4824Christian Williams 14729a8359eaef1ee9f40c967d3c4b5c1117c8c2a43Christian Williams @Override public int emulateSdk() { 14829a8359eaef1ee9f40c967d3c4b5c1117c8c2a43Christian Williams return emulateSdk; 14929a8359eaef1ee9f40c967d3c4b5c1117c8c2a43Christian Williams } 150f6df8a55ac378dee35324bc865fb4d741dcb4824Christian Williams 15129a8359eaef1ee9f40c967d3c4b5c1117c8c2a43Christian Williams @Override public String manifest() { 15229a8359eaef1ee9f40c967d3c4b5c1117c8c2a43Christian Williams return manifest; 15329a8359eaef1ee9f40c967d3c4b5c1117c8c2a43Christian Williams } 15448f95f3e0955035946f7c416dec56219a9b19886Christian Williams 1559cc9bde8928b83e5de9cd1c521e157e1a584b2fdJonathan Gerrish @Override 1569cc9bde8928b83e5de9cd1c521e157e1a584b2fdJonathan Gerrish public Class<? extends Application> application() { 1579cc9bde8928b83e5de9cd1c521e157e1a584b2fdJonathan Gerrish return application; 1589cc9bde8928b83e5de9cd1c521e157e1a584b2fdJonathan Gerrish } 1599cc9bde8928b83e5de9cd1c521e157e1a584b2fdJonathan Gerrish 16029a8359eaef1ee9f40c967d3c4b5c1117c8c2a43Christian Williams @Override public String qualifiers() { 16129a8359eaef1ee9f40c967d3c4b5c1117c8c2a43Christian Williams return qualifiers; 16229a8359eaef1ee9f40c967d3c4b5c1117c8c2a43Christian Williams } 163f6df8a55ac378dee35324bc865fb4d741dcb4824Christian Williams 1645277f871bca2be31c657ace35ae305285b2e0c55Ryan Spore and Trevor John @Override 1655277f871bca2be31c657ace35ae305285b2e0c55Ryan Spore and Trevor John public String resourceDir() { 1665277f871bca2be31c657ace35ae305285b2e0c55Ryan Spore and Trevor John return resourceDir; 1675277f871bca2be31c657ace35ae305285b2e0c55Ryan Spore and Trevor John } 1685277f871bca2be31c657ace35ae305285b2e0c55Ryan Spore and Trevor John 16929a8359eaef1ee9f40c967d3c4b5c1117c8c2a43Christian Williams @Override public int reportSdk() { 17029a8359eaef1ee9f40c967d3c4b5c1117c8c2a43Christian Williams return reportSdk; 17129a8359eaef1ee9f40c967d3c4b5c1117c8c2a43Christian Williams } 172f6df8a55ac378dee35324bc865fb4d741dcb4824Christian Williams 17329a8359eaef1ee9f40c967d3c4b5c1117c8c2a43Christian Williams @Override public Class<?>[] shadows() { 17429a8359eaef1ee9f40c967d3c4b5c1117c8c2a43Christian Williams return shadows; 17529a8359eaef1ee9f40c967d3c4b5c1117c8c2a43Christian Williams } 176f6df8a55ac378dee35324bc865fb4d741dcb4824Christian Williams 17729a8359eaef1ee9f40c967d3c4b5c1117c8c2a43Christian Williams @NotNull @Override public Class<? extends Annotation> annotationType() { 17829a8359eaef1ee9f40c967d3c4b5c1117c8c2a43Christian Williams return Config.class; 17929a8359eaef1ee9f40c967d3c4b5c1117c8c2a43Christian Williams } 180f6df8a55ac378dee35324bc865fb4d741dcb4824Christian Williams 18129a8359eaef1ee9f40c967d3c4b5c1117c8c2a43Christian Williams @Override 18229a8359eaef1ee9f40c967d3c4b5c1117c8c2a43Christian Williams public boolean equals(Object o) { 18329a8359eaef1ee9f40c967d3c4b5c1117c8c2a43Christian Williams if (this == o) return true; 18429a8359eaef1ee9f40c967d3c4b5c1117c8c2a43Christian Williams if (o == null || getClass() != o.getClass()) return false; 185f6df8a55ac378dee35324bc865fb4d741dcb4824Christian Williams 18629a8359eaef1ee9f40c967d3c4b5c1117c8c2a43Christian Williams Implementation other = (Implementation) o; 187f6df8a55ac378dee35324bc865fb4d741dcb4824Christian Williams 18829a8359eaef1ee9f40c967d3c4b5c1117c8c2a43Christian Williams if (emulateSdk != other.emulateSdk) return false; 18929a8359eaef1ee9f40c967d3c4b5c1117c8c2a43Christian Williams if (reportSdk != other.reportSdk) return false; 19029a8359eaef1ee9f40c967d3c4b5c1117c8c2a43Christian Williams if (!qualifiers.equals(other.qualifiers)) return false; 19129a8359eaef1ee9f40c967d3c4b5c1117c8c2a43Christian Williams if (!Arrays.equals(shadows, other.shadows)) return false; 1929cc9bde8928b83e5de9cd1c521e157e1a584b2fdJonathan Gerrish if (application != other.application) return false; 193f6df8a55ac378dee35324bc865fb4d741dcb4824Christian Williams 19429a8359eaef1ee9f40c967d3c4b5c1117c8c2a43Christian Williams return true; 19529a8359eaef1ee9f40c967d3c4b5c1117c8c2a43Christian Williams } 196f6df8a55ac378dee35324bc865fb4d741dcb4824Christian Williams 19729a8359eaef1ee9f40c967d3c4b5c1117c8c2a43Christian Williams @Override 19829a8359eaef1ee9f40c967d3c4b5c1117c8c2a43Christian Williams public int hashCode() { 19929a8359eaef1ee9f40c967d3c4b5c1117c8c2a43Christian Williams int result = emulateSdk; 20029a8359eaef1ee9f40c967d3c4b5c1117c8c2a43Christian Williams result = 31 * result + qualifiers.hashCode(); 20129a8359eaef1ee9f40c967d3c4b5c1117c8c2a43Christian Williams result = 31 * result + reportSdk; 20229a8359eaef1ee9f40c967d3c4b5c1117c8c2a43Christian Williams result = 31 * result + Arrays.hashCode(shadows); 2039cc9bde8928b83e5de9cd1c521e157e1a584b2fdJonathan Gerrish result = 31 * result + application.hashCode(); 20429a8359eaef1ee9f40c967d3c4b5c1117c8c2a43Christian Williams return result; 205f6df8a55ac378dee35324bc865fb4d741dcb4824Christian Williams } 20629a8359eaef1ee9f40c967d3c4b5c1117c8c2a43Christian Williams } 207dd40f718cf785a56e63c0685feeb73d266c13e3fWenhui Yao} 208