1cfb3d242306311ce27ec51bf511764377c173a7cKiran Ryali + Christian Williamspackage org.robolectric.annotation;
2dd40f718cf785a56e63c0685feeb73d266c13e3fWenhui Yao
39cc9bde8928b83e5de9cd1c521e157e1a584b2fdJonathan Gerrishimport android.app.Application;
4f6df8a55ac378dee35324bc865fb4d741dcb4824Christian Williamsimport java.lang.annotation.Annotation;
5f6df8a55ac378dee35324bc865fb4d741dcb4824Christian Williamsimport java.lang.annotation.Documented;
6f6df8a55ac378dee35324bc865fb4d741dcb4824Christian Williamsimport java.lang.annotation.ElementType;
7f6e6129091939d868f32182a3dbba7ca0188e515ChrisHennickAtGoogleimport java.lang.annotation.Inherited;
8f6df8a55ac378dee35324bc865fb4d741dcb4824Christian Williamsimport java.lang.annotation.Retention;
9f6df8a55ac378dee35324bc865fb4d741dcb4824Christian Williamsimport java.lang.annotation.RetentionPolicy;
10f6df8a55ac378dee35324bc865fb4d741dcb4824Christian Williamsimport java.lang.annotation.Target;
11084d588b645d53c1110ff24b82433b5a331cc6d3James Lemieuximport java.util.ArrayList;
12f6df8a55ac378dee35324bc865fb4d741dcb4824Christian Williamsimport java.util.Arrays;
13c77f5791f081893a18f9db753bb5022269a7c5a6Simon Arlottimport java.util.HashSet;
14084d588b645d53c1110ff24b82433b5a331cc6d3James Lemieuximport java.util.List;
1523a26cc3e5b33c0503a99847292ac99817f5af43Christian Williamsimport java.util.Properties;
16c77f5791f081893a18f9db753bb5022269a7c5a6Simon Arlottimport java.util.Set;
17851f2a9519be23c73a9e2929128179b405e2e7a6Christian Williamsimport javax.annotation.Nonnull;
18f6df8a55ac378dee35324bc865fb4d741dcb4824Christian Williams
19dd40f718cf785a56e63c0685feeb73d266c13e3fWenhui Yao/**
20c7482da584ddaa03f91afa7b785ed17fa084aa47Erich Douglass * Configuration settings that can be used on a per-class or per-test basis.
21dd40f718cf785a56e63c0685feeb73d266c13e3fWenhui Yao */
22f6df8a55ac378dee35324bc865fb4d741dcb4824Christian Williams@Documented
23f6e6129091939d868f32182a3dbba7ca0188e515ChrisHennickAtGoogle@Inherited
24f6df8a55ac378dee35324bc865fb4d741dcb4824Christian Williams@Retention(RetentionPolicy.RUNTIME)
25f6df8a55ac378dee35324bc865fb4d741dcb4824Christian Williams@Target({ElementType.TYPE, ElementType.METHOD})
26084d588b645d53c1110ff24b82433b5a331cc6d3James Lemieux@SuppressWarnings(value = {"BadAnnotationImplementation", "ImmutableAnnotationChecker"})
277be4d2ba0e45483ad70cbd994955ae1b70afafdcKiran Ryali + Christian Williamspublic @interface Config {
28b4c08d70a2f549cf344c81bb20c824d3cc31c298Vijay Nayar  /**
29b4c08d70a2f549cf344c81bb20c824d3cc31c298Vijay Nayar   * TODO(vnayar): Create named constants for default values instead of magic numbers.
30084d588b645d53c1110ff24b82433b5a331cc6d3James Lemieux   * Array named constants must be avoided in order to dodge a JDK 1.7 bug.
3184ec27668a169c2c23f5872da93eb532e7e4ae94Christian Williams   *   error: annotation Config is missing value for the attribute <clinit>
3284ec27668a169c2c23f5872da93eb532e7e4ae94Christian Williams   * See <a href="https://bugs.openjdk.java.net/browse/JDK-8013485">JDK-8013485</a>.
33b4c08d70a2f549cf344c81bb20c824d3cc31c298Vijay Nayar   */
340bbbacc2633146b2725cce97c24dc121ffa0e89bErich Douglass  String NONE = "--none";
35b4d0e3b1d6313b7f37852f42a2b8b54cc57af17eChristian Williams  String DEFAULT_VALUE_STRING = "--default";
36b4d0e3b1d6313b7f37852f42a2b8b54cc57af17eChristian Williams  int DEFAULT_VALUE_INT = -1;
37b4d0e3b1d6313b7f37852f42a2b8b54cc57af17eChristian Williams
38b4d0e3b1d6313b7f37852f42a2b8b54cc57af17eChristian Williams  String DEFAULT_MANIFEST_NAME = "AndroidManifest.xml";
39104b292a58958d310fcb27472fd7e450b3d99946Christian Williams  Class<? extends Application> DEFAULT_APPLICATION = DefaultApplication.class;
40b4c08d70a2f549cf344c81bb20c824d3cc31c298Vijay Nayar  String DEFAULT_PACKAGE_NAME = "";
41b4c08d70a2f549cf344c81bb20c824d3cc31c298Vijay Nayar  String DEFAULT_ABI_SPLIT = "";
42b4c08d70a2f549cf344c81bb20c824d3cc31c298Vijay Nayar  String DEFAULT_QUALIFIERS = "";
430bbbacc2633146b2725cce97c24dc121ffa0e89bErich Douglass  String DEFAULT_RES_FOLDER = "res";
440bbbacc2633146b2725cce97c24dc121ffa0e89bErich Douglass  String DEFAULT_ASSET_FOLDER = "assets";
45ed249b15fa2ff94708d5f079f94284356a96c2a4Sean Kenny  String DEFAULT_BUILD_FOLDER = "build";
4629a8359eaef1ee9f40c967d3c4b5c1117c8c2a43Christian Williams
47104b292a58958d310fcb27472fd7e450b3d99946Christian Williams  int ALL_SDKS = -2;
48104b292a58958d310fcb27472fd7e450b3d99946Christian Williams  int TARGET_SDK = -3;
49104b292a58958d310fcb27472fd7e450b3d99946Christian Williams  int OLDEST_SDK = -4;
50104b292a58958d310fcb27472fd7e450b3d99946Christian Williams  int NEWEST_SDK = -5;
51104b292a58958d310fcb27472fd7e450b3d99946Christian Williams
5229a8359eaef1ee9f40c967d3c4b5c1117c8c2a43Christian Williams  /**
53bf73dde49765ed8f3556ef0b2ce63a0cb44703fbJonathan Gerrish   * The Android SDK level to emulate. This value will also be set as Build.VERSION.SDK_INT.
5429a8359eaef1ee9f40c967d3c4b5c1117c8c2a43Christian Williams   */
55b4c08d70a2f549cf344c81bb20c824d3cc31c298Vijay Nayar  int[] sdk() default {};  // DEFAULT_SDK
5629a8359eaef1ee9f40c967d3c4b5c1117c8c2a43Christian Williams
5729a8359eaef1ee9f40c967d3c4b5c1117c8c2a43Christian Williams  /**
58bf73dde49765ed8f3556ef0b2ce63a0cb44703fbJonathan Gerrish   * The minimum Android SDK level to emulate when running tests on multiple API versions.
59bf73dde49765ed8f3556ef0b2ce63a0cb44703fbJonathan Gerrish   */
60bf73dde49765ed8f3556ef0b2ce63a0cb44703fbJonathan Gerrish  int minSdk() default -1;
61bf73dde49765ed8f3556ef0b2ce63a0cb44703fbJonathan Gerrish
62bf73dde49765ed8f3556ef0b2ce63a0cb44703fbJonathan Gerrish  /**
632f3910afbc500f553a74ccff97c36635691856e4Milos Marinkovic   * The maximum Android SDK level to emulate when running tests on multiple API versions.
64bf73dde49765ed8f3556ef0b2ce63a0cb44703fbJonathan Gerrish   */
65bf73dde49765ed8f3556ef0b2ce63a0cb44703fbJonathan Gerrish  int maxSdk() default -1;
66bf73dde49765ed8f3556ef0b2ce63a0cb44703fbJonathan Gerrish
67bf73dde49765ed8f3556ef0b2ce63a0cb44703fbJonathan Gerrish  /**
6829a8359eaef1ee9f40c967d3c4b5c1117c8c2a43Christian Williams   * The Android manifest file to load; Robolectric will look relative to the current directory.
6929a8359eaef1ee9f40c967d3c4b5c1117c8c2a43Christian Williams   * Resources and assets will be loaded relative to the manifest.
7029a8359eaef1ee9f40c967d3c4b5c1117c8c2a43Christian Williams   *
7129a8359eaef1ee9f40c967d3c4b5c1117c8c2a43Christian Williams   * If not specified, Robolectric defaults to {@code AndroidManifest.xml}.
7229a8359eaef1ee9f40c967d3c4b5c1117c8c2a43Christian Williams   *
7329a8359eaef1ee9f40c967d3c4b5c1117c8c2a43Christian Williams   * If your project has no manifest or resources, use {@link Config#NONE}.
7483bcaf5aa4b64a2223cfada134ef02e5c8ff660aErich Douglass   *
7583bcaf5aa4b64a2223cfada134ef02e5c8ff660aErich Douglass   * @return The Android manifest file to load.
7629a8359eaef1ee9f40c967d3c4b5c1117c8c2a43Christian Williams   */
77b4d0e3b1d6313b7f37852f42a2b8b54cc57af17eChristian Williams  String manifest() default DEFAULT_VALUE_STRING;
7829a8359eaef1ee9f40c967d3c4b5c1117c8c2a43Christian Williams
7929a8359eaef1ee9f40c967d3c4b5c1117c8c2a43Christian Williams  /**
800bbbacc2633146b2725cce97c24dc121ffa0e89bErich Douglass   * Reference to the BuildConfig class created by the Gradle build system.
810bbbacc2633146b2725cce97c24dc121ffa0e89bErich Douglass   *
82580d2f9f1e515c9927d233020522b2c1428a3d93Jonathan Gerrish   * @deprecated If you are using at least Android Studio 3.0 alpha 5 please migrate to the preferred way to configure
83580d2f9f1e515c9927d233020522b2c1428a3d93Jonathan Gerrish   * builds for Gradle with AGP3.0 http://robolectric.org/getting-started/
840bbbacc2633146b2725cce97c24dc121ffa0e89bErich Douglass   * @return Reference to BuildConfig class.
850bbbacc2633146b2725cce97c24dc121ffa0e89bErich Douglass   */
86580d2f9f1e515c9927d233020522b2c1428a3d93Jonathan Gerrish  @Deprecated
87b4c08d70a2f549cf344c81bb20c824d3cc31c298Vijay Nayar  Class<?> constants() default Void.class;  // DEFAULT_CONSTANTS
880bbbacc2633146b2725cce97c24dc121ffa0e89bErich Douglass
890bbbacc2633146b2725cce97c24dc121ffa0e89bErich Douglass  /**
909cc9bde8928b83e5de9cd1c521e157e1a584b2fdJonathan Gerrish   * The {@link android.app.Application} class to use in the test, this takes precedence over any application
919cc9bde8928b83e5de9cd1c521e157e1a584b2fdJonathan Gerrish   * specified in the AndroidManifest.xml.
9283bcaf5aa4b64a2223cfada134ef02e5c8ff660aErich Douglass   *
9383bcaf5aa4b64a2223cfada134ef02e5c8ff660aErich Douglass   * @return The {@link android.app.Application} class to use in the test.
949cc9bde8928b83e5de9cd1c521e157e1a584b2fdJonathan Gerrish   */
95104b292a58958d310fcb27472fd7e450b3d99946Christian Williams  Class<? extends Application> application() default DefaultApplication.class;  // DEFAULT_APPLICATION
969cc9bde8928b83e5de9cd1c521e157e1a584b2fdJonathan Gerrish
979cc9bde8928b83e5de9cd1c521e157e1a584b2fdJonathan Gerrish  /**
98bbdc3ce45195e6896254a2c7aa24370f2c55d57cErich Douglass   * Java package name where the "R.class" file is located. This only needs to be specified if you define
99bbdc3ce45195e6896254a2c7aa24370f2c55d57cErich Douglass   * an {@code applicationId} associated with {@code productFlavors} or specify {@code applicationIdSuffix}
100bbdc3ce45195e6896254a2c7aa24370f2c55d57cErich Douglass   * in your build.gradle.
101bbdc3ce45195e6896254a2c7aa24370f2c55d57cErich Douglass   *
10282049a7b7c53d5a208921940bda298535697d0b7Christian Williams   * If not specified, Robolectric defaults to the {@code applicationId}.
103bbdc3ce45195e6896254a2c7aa24370f2c55d57cErich Douglass   *
104bbdc3ce45195e6896254a2c7aa24370f2c55d57cErich Douglass   * @return The java package name for R.class.
105bbdc3ce45195e6896254a2c7aa24370f2c55d57cErich Douglass   */
106b4c08d70a2f549cf344c81bb20c824d3cc31c298Vijay Nayar  String packageName() default DEFAULT_PACKAGE_NAME;
107bbdc3ce45195e6896254a2c7aa24370f2c55d57cErich Douglass
108bbdc3ce45195e6896254a2c7aa24370f2c55d57cErich Douglass  /**
1093c6572b8953e3d636cdf4d8d26583873b2dd1f25Hilal Alsibai   * The ABI split to use when locating resources and AndroidManifest.xml
1103c6572b8953e3d636cdf4d8d26583873b2dd1f25Hilal Alsibai   *
11182049a7b7c53d5a208921940bda298535697d0b7Christian Williams   * You do not typically have to set this, unless you are utilizing the ABI split feature.
1123c6572b8953e3d636cdf4d8d26583873b2dd1f25Hilal Alsibai   *
1131ecb3ad272955908af627505032195de2375baa4Jonathan Gerrish   * @deprecated If you are using at least Android Studio 3.0 alpha 5 please migrate to the preferred way to configure
1141ecb3ad272955908af627505032195de2375baa4Jonathan Gerrish   * builds for Gradle with AGP3.0 http://robolectric.org/getting-started/
1153c6572b8953e3d636cdf4d8d26583873b2dd1f25Hilal Alsibai   * @return The ABI split to test with
1163c6572b8953e3d636cdf4d8d26583873b2dd1f25Hilal Alsibai   */
1171ecb3ad272955908af627505032195de2375baa4Jonathan Gerrish  @Deprecated
118b4c08d70a2f549cf344c81bb20c824d3cc31c298Vijay Nayar  String abiSplit() default DEFAULT_ABI_SPLIT;
1193c6572b8953e3d636cdf4d8d26583873b2dd1f25Hilal Alsibai
1203c6572b8953e3d636cdf4d8d26583873b2dd1f25Hilal Alsibai  /**
1219f69dc80a8ac7e48cbf50f65974d4986ab7f00ecChristian Williams   * Qualifiers specifying device configuration for this test, such as "fr-normal-port-hdpi".
12229a8359eaef1ee9f40c967d3c4b5c1117c8c2a43Christian Williams   *
1239f69dc80a8ac7e48cbf50f65974d4986ab7f00ecChristian Williams   * If the string is prefixed with '+', the qualifiers that follow are overlayed on any more
1249f69dc80a8ac7e48cbf50f65974d4986ab7f00ecChristian Williams   * broadly-scoped qualifiers.
1259f69dc80a8ac7e48cbf50f65974d4986ab7f00ecChristian Williams   *
1269f69dc80a8ac7e48cbf50f65974d4986ab7f00ecChristian Williams   * See [Device Configuration](http://robolectric.org/device-configuration/) for details.
1279f69dc80a8ac7e48cbf50f65974d4986ab7f00ecChristian Williams   *
1289f69dc80a8ac7e48cbf50f65974d4986ab7f00ecChristian Williams   * @return Qualifiers used for device configuration and resource resolution.
12929a8359eaef1ee9f40c967d3c4b5c1117c8c2a43Christian Williams   */
130b4c08d70a2f549cf344c81bb20c824d3cc31c298Vijay Nayar  String qualifiers() default DEFAULT_QUALIFIERS;
13129a8359eaef1ee9f40c967d3c4b5c1117c8c2a43Christian Williams
13229a8359eaef1ee9f40c967d3c4b5c1117c8c2a43Christian Williams  /**
1336b00d4156e2e6bb2d262458a2650a109ddc76c76Erich Douglass   * The directory from which to load resources.  This should be relative to the directory containing AndroidManifest.xml.
13483bcaf5aa4b64a2223cfada134ef02e5c8ff660aErich Douglass   *
13582049a7b7c53d5a208921940bda298535697d0b7Christian Williams   * If not specified, Robolectric defaults to {@code res}.
13683bcaf5aa4b64a2223cfada134ef02e5c8ff660aErich Douglass   *
13783bcaf5aa4b64a2223cfada134ef02e5c8ff660aErich Douglass   * @return Android resource directory.
1385277f871bca2be31c657ace35ae305285b2e0c55Ryan Spore and Trevor John   */
1396b00d4156e2e6bb2d262458a2650a109ddc76c76Erich Douglass  String resourceDir() default DEFAULT_RES_FOLDER;
1406b00d4156e2e6bb2d262458a2650a109ddc76c76Erich Douglass
1416b00d4156e2e6bb2d262458a2650a109ddc76c76Erich Douglass  /**
1426b00d4156e2e6bb2d262458a2650a109ddc76c76Erich Douglass   * The directory from which to load assets. This should be relative to the directory containing AndroidManifest.xml.
14383bcaf5aa4b64a2223cfada134ef02e5c8ff660aErich Douglass   *
14482049a7b7c53d5a208921940bda298535697d0b7Christian Williams   * If not specified, Robolectric defaults to {@code assets}.
14583bcaf5aa4b64a2223cfada134ef02e5c8ff660aErich Douglass   *
14683bcaf5aa4b64a2223cfada134ef02e5c8ff660aErich Douglass   * @return Android asset directory.
1476b00d4156e2e6bb2d262458a2650a109ddc76c76Erich Douglass   */
1486b00d4156e2e6bb2d262458a2650a109ddc76c76Erich Douglass  String assetDir() default DEFAULT_ASSET_FOLDER;
1495277f871bca2be31c657ace35ae305285b2e0c55Ryan Spore and Trevor John
1505277f871bca2be31c657ace35ae305285b2e0c55Ryan Spore and Trevor John  /**
151ed249b15fa2ff94708d5f079f94284356a96c2a4Sean Kenny   * The directory where application files are created during the application build process.
152ed249b15fa2ff94708d5f079f94284356a96c2a4Sean Kenny   *
15382049a7b7c53d5a208921940bda298535697d0b7Christian Williams   * If not specified, Robolectric defaults to {@code build}.
154ed249b15fa2ff94708d5f079f94284356a96c2a4Sean Kenny   *
1551ecb3ad272955908af627505032195de2375baa4Jonathan Gerrish   * @deprecated If you are using at least Android Studio 3.0 alpha 5 please migrate to the preferred way to configure
1561ecb3ad272955908af627505032195de2375baa4Jonathan Gerrish   * builds for Gradle with AGP3.0 http://robolectric.org/getting-started/
157ed249b15fa2ff94708d5f079f94284356a96c2a4Sean Kenny   * @return Android build directory.
158ed249b15fa2ff94708d5f079f94284356a96c2a4Sean Kenny   */
1591ecb3ad272955908af627505032195de2375baa4Jonathan Gerrish  @Deprecated
160ed249b15fa2ff94708d5f079f94284356a96c2a4Sean Kenny  String buildDir() default DEFAULT_BUILD_FOLDER;
161ed249b15fa2ff94708d5f079f94284356a96c2a4Sean Kenny
162ed249b15fa2ff94708d5f079f94284356a96c2a4Sean Kenny  /**
16329a8359eaef1ee9f40c967d3c4b5c1117c8c2a43Christian Williams   * A list of shadow classes to enable, in addition to those that are already present.
16483bcaf5aa4b64a2223cfada134ef02e5c8ff660aErich Douglass   *
16583bcaf5aa4b64a2223cfada134ef02e5c8ff660aErich Douglass   * @return A list of additional shadow classes to enable.
16629a8359eaef1ee9f40c967d3c4b5c1117c8c2a43Christian Williams   */
167b4c08d70a2f549cf344c81bb20c824d3cc31c298Vijay Nayar  Class<?>[] shadows() default {};  // DEFAULT_SHADOWS
168b4c08d70a2f549cf344c81bb20c824d3cc31c298Vijay Nayar
169d6cef1bcc644c7152d0716b8d33eb25054894836David Sun  /**
170d6cef1bcc644c7152d0716b8d33eb25054894836David Sun   * A list of instrumented packages, in addition to those that are already instrumented.
171b4c08d70a2f549cf344c81bb20c824d3cc31c298Vijay Nayar   *
172d6cef1bcc644c7152d0716b8d33eb25054894836David Sun   * @return A list of additional instrumented packages.
173d6cef1bcc644c7152d0716b8d33eb25054894836David Sun   */
174b4c08d70a2f549cf344c81bb20c824d3cc31c298Vijay Nayar  String[] instrumentedPackages() default {};  // DEFAULT_INSTRUMENTED_PACKAGES
17529a8359eaef1ee9f40c967d3c4b5c1117c8c2a43Christian Williams
176ed898f2b5b7312af4779636638d081aa6ebd9e13Andrew Richardson  /**
177ed898f2b5b7312af4779636638d081aa6ebd9e13Andrew Richardson   * A list of folders containing Android Libraries on which this project depends.
17883bcaf5aa4b64a2223cfada134ef02e5c8ff660aErich Douglass   *
17983bcaf5aa4b64a2223cfada134ef02e5c8ff660aErich Douglass   * @return A list of Android Libraries.
180ed898f2b5b7312af4779636638d081aa6ebd9e13Andrew Richardson   */
181b4c08d70a2f549cf344c81bb20c824d3cc31c298Vijay Nayar  String[] libraries() default {};  // DEFAULT_LIBRARIES;
182ed898f2b5b7312af4779636638d081aa6ebd9e13Andrew Richardson
1830bbbacc2633146b2725cce97c24dc121ffa0e89bErich Douglass  class Implementation implements Config {
18481a928816f4cf068ff3fe636df2a25db269c73c8Jonathan Gerrish    private final int[] sdk;
185bf73dde49765ed8f3556ef0b2ce63a0cb44703fbJonathan Gerrish    private final int minSdk;
186bf73dde49765ed8f3556ef0b2ce63a0cb44703fbJonathan Gerrish    private final int maxSdk;
18729a8359eaef1ee9f40c967d3c4b5c1117c8c2a43Christian Williams    private final String manifest;
18829a8359eaef1ee9f40c967d3c4b5c1117c8c2a43Christian Williams    private final String qualifiers;
1895277f871bca2be31c657ace35ae305285b2e0c55Ryan Spore and Trevor John    private final String resourceDir;
1906b00d4156e2e6bb2d262458a2650a109ddc76c76Erich Douglass    private final String assetDir;
191ed249b15fa2ff94708d5f079f94284356a96c2a4Sean Kenny    private final String buildDir;
192bbdc3ce45195e6896254a2c7aa24370f2c55d57cErich Douglass    private final String packageName;
1933c6572b8953e3d636cdf4d8d26583873b2dd1f25Hilal Alsibai    private final String abiSplit;
1940bbbacc2633146b2725cce97c24dc121ffa0e89bErich Douglass    private final Class<?> constants;
19529a8359eaef1ee9f40c967d3c4b5c1117c8c2a43Christian Williams    private final Class<?>[] shadows;
196d6cef1bcc644c7152d0716b8d33eb25054894836David Sun    private final String[] instrumentedPackages;
1979cc9bde8928b83e5de9cd1c521e157e1a584b2fdJonathan Gerrish    private final Class<? extends Application> application;
198ed898f2b5b7312af4779636638d081aa6ebd9e13Andrew Richardson    private final String[] libraries;
19929a8359eaef1ee9f40c967d3c4b5c1117c8c2a43Christian Williams
2000bbbacc2633146b2725cce97c24dc121ffa0e89bErich Douglass    public static Config fromProperties(Properties properties) {
2010bbbacc2633146b2725cce97c24dc121ffa0e89bErich Douglass      if (properties == null || properties.size() == 0) return null;
20229a8359eaef1ee9f40c967d3c4b5c1117c8c2a43Christian Williams      return new Implementation(
203104b292a58958d310fcb27472fd7e450b3d99946Christian Williams          parseSdkArrayProperty(properties.getProperty("sdk", "")),
204104b292a58958d310fcb27472fd7e450b3d99946Christian Williams          parseSdkInt(properties.getProperty("minSdk", "-1")),
205104b292a58958d310fcb27472fd7e450b3d99946Christian Williams          parseSdkInt(properties.getProperty("maxSdk", "-1")),
206b4d0e3b1d6313b7f37852f42a2b8b54cc57af17eChristian Williams          properties.getProperty("manifest", DEFAULT_VALUE_STRING),
207b4c08d70a2f549cf344c81bb20c824d3cc31c298Vijay Nayar          properties.getProperty("qualifiers", DEFAULT_QUALIFIERS),
208b4c08d70a2f549cf344c81bb20c824d3cc31c298Vijay Nayar          properties.getProperty("packageName", DEFAULT_PACKAGE_NAME),
209b4c08d70a2f549cf344c81bb20c824d3cc31c298Vijay Nayar          properties.getProperty("abiSplit", DEFAULT_ABI_SPLIT),
210b4c08d70a2f549cf344c81bb20c824d3cc31c298Vijay Nayar          properties.getProperty("resourceDir", DEFAULT_RES_FOLDER),
211b4c08d70a2f549cf344c81bb20c824d3cc31c298Vijay Nayar          properties.getProperty("assetDir", DEFAULT_ASSET_FOLDER),
212b4c08d70a2f549cf344c81bb20c824d3cc31c298Vijay Nayar          properties.getProperty("buildDir", DEFAULT_BUILD_FOLDER),
2130bbbacc2633146b2725cce97c24dc121ffa0e89bErich Douglass          parseClasses(properties.getProperty("shadows", "")),
214d6cef1bcc644c7152d0716b8d33eb25054894836David Sun          parseStringArrayProperty(properties.getProperty("instrumentedPackages", "")),
215104b292a58958d310fcb27472fd7e450b3d99946Christian Williams          parseApplication(properties.getProperty("application", DEFAULT_APPLICATION.getCanonicalName())),
21681a928816f4cf068ff3fe636df2a25db269c73c8Jonathan Gerrish          parseStringArrayProperty(properties.getProperty("libraries", "")),
2170bbbacc2633146b2725cce97c24dc121ffa0e89bErich Douglass          parseClass(properties.getProperty("constants", ""))
21829a8359eaef1ee9f40c967d3c4b5c1117c8c2a43Christian Williams      );
21929a8359eaef1ee9f40c967d3c4b5c1117c8c2a43Christian Williams    }
22023a26cc3e5b33c0503a99847292ac99817f5af43Christian Williams
2210bbbacc2633146b2725cce97c24dc121ffa0e89bErich Douglass    private static Class<?> parseClass(String className) {
2220bbbacc2633146b2725cce97c24dc121ffa0e89bErich Douglass      if (className.isEmpty()) return null;
2230bbbacc2633146b2725cce97c24dc121ffa0e89bErich Douglass      try {
2240bbbacc2633146b2725cce97c24dc121ffa0e89bErich Douglass        return Implementation.class.getClassLoader().loadClass(className);
2250bbbacc2633146b2725cce97c24dc121ffa0e89bErich Douglass      } catch (ClassNotFoundException e) {
2260bbbacc2633146b2725cce97c24dc121ffa0e89bErich Douglass        throw new RuntimeException("Could not load class: " + className);
2270bbbacc2633146b2725cce97c24dc121ffa0e89bErich Douglass      }
2280bbbacc2633146b2725cce97c24dc121ffa0e89bErich Douglass    }
2290bbbacc2633146b2725cce97c24dc121ffa0e89bErich Douglass
2300bbbacc2633146b2725cce97c24dc121ffa0e89bErich Douglass    private static Class<?>[] parseClasses(String input) {
2310bbbacc2633146b2725cce97c24dc121ffa0e89bErich Douglass      if (input.isEmpty()) return new Class[0];
2320bbbacc2633146b2725cce97c24dc121ffa0e89bErich Douglass      final String[] classNames = input.split("[, ]+");
2330bbbacc2633146b2725cce97c24dc121ffa0e89bErich Douglass      final Class[] classes = new Class[classNames.length];
23429a8359eaef1ee9f40c967d3c4b5c1117c8c2a43Christian Williams      for (int i = 0; i < classNames.length; i++) {
2350bbbacc2633146b2725cce97c24dc121ffa0e89bErich Douglass        classes[i] = parseClass(classNames[i]);
23629a8359eaef1ee9f40c967d3c4b5c1117c8c2a43Christian Williams      }
23729a8359eaef1ee9f40c967d3c4b5c1117c8c2a43Christian Williams      return classes;
23829a8359eaef1ee9f40c967d3c4b5c1117c8c2a43Christian Williams    }
23923a26cc3e5b33c0503a99847292ac99817f5af43Christian Williams
2400bbbacc2633146b2725cce97c24dc121ffa0e89bErich Douglass    @SuppressWarnings("unchecked")
2419cc9bde8928b83e5de9cd1c521e157e1a584b2fdJonathan Gerrish    private static <T extends Application> Class<T> parseApplication(String className) {
2420bbbacc2633146b2725cce97c24dc121ffa0e89bErich Douglass      return (Class<T>) parseClass(className);
2439cc9bde8928b83e5de9cd1c521e157e1a584b2fdJonathan Gerrish    }
2449cc9bde8928b83e5de9cd1c521e157e1a584b2fdJonathan Gerrish
2456a7bdc7a1b1fbe38142995bde5f05023b8ab86adJonathan Gerrish    private static String[] parseStringArrayProperty(String property) {
2466a7bdc7a1b1fbe38142995bde5f05023b8ab86adJonathan Gerrish      if (property.isEmpty()) return new String[0];
2476a7bdc7a1b1fbe38142995bde5f05023b8ab86adJonathan Gerrish      return property.split("[, ]+");
2486a7bdc7a1b1fbe38142995bde5f05023b8ab86adJonathan Gerrish    }
2496a7bdc7a1b1fbe38142995bde5f05023b8ab86adJonathan Gerrish
2506a7bdc7a1b1fbe38142995bde5f05023b8ab86adJonathan Gerrish    private static int[] parseSdkArrayProperty(String property) {
2516a7bdc7a1b1fbe38142995bde5f05023b8ab86adJonathan Gerrish      String[] parts = parseStringArrayProperty(property);
2526a7bdc7a1b1fbe38142995bde5f05023b8ab86adJonathan Gerrish      int[] result = new int[parts.length];
2536a7bdc7a1b1fbe38142995bde5f05023b8ab86adJonathan Gerrish      for (int i = 0; i < parts.length; i++) {
2546a7bdc7a1b1fbe38142995bde5f05023b8ab86adJonathan Gerrish        result[i] = parseSdkInt(parts[i]);
2556a7bdc7a1b1fbe38142995bde5f05023b8ab86adJonathan Gerrish      }
2566a7bdc7a1b1fbe38142995bde5f05023b8ab86adJonathan Gerrish
2576a7bdc7a1b1fbe38142995bde5f05023b8ab86adJonathan Gerrish      return result;
2586a7bdc7a1b1fbe38142995bde5f05023b8ab86adJonathan Gerrish    }
2596a7bdc7a1b1fbe38142995bde5f05023b8ab86adJonathan Gerrish
2606a7bdc7a1b1fbe38142995bde5f05023b8ab86adJonathan Gerrish    private static int parseSdkInt(String part) {
2616a7bdc7a1b1fbe38142995bde5f05023b8ab86adJonathan Gerrish      String spec = part.trim();
2626a7bdc7a1b1fbe38142995bde5f05023b8ab86adJonathan Gerrish      switch (spec) {
2636a7bdc7a1b1fbe38142995bde5f05023b8ab86adJonathan Gerrish        case "ALL_SDKS":
2646a7bdc7a1b1fbe38142995bde5f05023b8ab86adJonathan Gerrish          return Config.ALL_SDKS;
2656a7bdc7a1b1fbe38142995bde5f05023b8ab86adJonathan Gerrish        case "TARGET_SDK":
2666a7bdc7a1b1fbe38142995bde5f05023b8ab86adJonathan Gerrish          return Config.TARGET_SDK;
2676a7bdc7a1b1fbe38142995bde5f05023b8ab86adJonathan Gerrish        case "OLDEST_SDK":
2686a7bdc7a1b1fbe38142995bde5f05023b8ab86adJonathan Gerrish          return Config.OLDEST_SDK;
2696a7bdc7a1b1fbe38142995bde5f05023b8ab86adJonathan Gerrish        case "NEWEST_SDK":
2706a7bdc7a1b1fbe38142995bde5f05023b8ab86adJonathan Gerrish          return Config.NEWEST_SDK;
2716a7bdc7a1b1fbe38142995bde5f05023b8ab86adJonathan Gerrish        default:
2726a7bdc7a1b1fbe38142995bde5f05023b8ab86adJonathan Gerrish          return Integer.parseInt(spec);
2736a7bdc7a1b1fbe38142995bde5f05023b8ab86adJonathan Gerrish      }
2746a7bdc7a1b1fbe38142995bde5f05023b8ab86adJonathan Gerrish    }
2756a7bdc7a1b1fbe38142995bde5f05023b8ab86adJonathan Gerrish
276104b292a58958d310fcb27472fd7e450b3d99946Christian Williams    private static void validate(Config config) {
277104b292a58958d310fcb27472fd7e450b3d99946Christian Williams      //noinspection ConstantConditions
278104b292a58958d310fcb27472fd7e450b3d99946Christian Williams      if (config.sdk() != null && config.sdk().length > 0 &&
279104b292a58958d310fcb27472fd7e450b3d99946Christian Williams          (config.minSdk() != DEFAULT_VALUE_INT || config.maxSdk() != DEFAULT_VALUE_INT)) {
280104b292a58958d310fcb27472fd7e450b3d99946Christian Williams        throw new IllegalArgumentException("sdk and minSdk/maxSdk may not be specified together" +
281104b292a58958d310fcb27472fd7e450b3d99946Christian Williams            " (sdk=" + Arrays.toString(config.sdk()) + ", minSdk=" + config.minSdk() + ", maxSdk=" + config.maxSdk() + ")");
282104b292a58958d310fcb27472fd7e450b3d99946Christian Williams      }
283104b292a58958d310fcb27472fd7e450b3d99946Christian Williams
284104b292a58958d310fcb27472fd7e450b3d99946Christian Williams      if (config.minSdk() > DEFAULT_VALUE_INT && config.maxSdk() > DEFAULT_VALUE_INT && config.minSdk() > config.maxSdk()) {
285104b292a58958d310fcb27472fd7e450b3d99946Christian Williams        throw new IllegalArgumentException("minSdk may not be larger than maxSdk" +
286104b292a58958d310fcb27472fd7e450b3d99946Christian Williams            " (minSdk=" + config.minSdk() + ", maxSdk=" + config.maxSdk() + ")");
287104b292a58958d310fcb27472fd7e450b3d99946Christian Williams      }
288104b292a58958d310fcb27472fd7e450b3d99946Christian Williams    }
289104b292a58958d310fcb27472fd7e450b3d99946Christian Williams
290bf73dde49765ed8f3556ef0b2ce63a0cb44703fbJonathan Gerrish    public Implementation(int[] sdk, int minSdk, int maxSdk, String manifest, String qualifiers, String packageName, String abiSplit, String resourceDir, String assetDir, String buildDir, Class<?>[] shadows, String[] instrumentedPackages, Class<? extends Application> application, String[] libraries, Class<?> constants) {
2918c45d4a57fa380436885166f8e89b3e20d20290cErich Douglass      this.sdk = sdk;
292bf73dde49765ed8f3556ef0b2ce63a0cb44703fbJonathan Gerrish      this.minSdk = minSdk;
293bf73dde49765ed8f3556ef0b2ce63a0cb44703fbJonathan Gerrish      this.maxSdk = maxSdk;
29429a8359eaef1ee9f40c967d3c4b5c1117c8c2a43Christian Williams      this.manifest = manifest;
29529a8359eaef1ee9f40c967d3c4b5c1117c8c2a43Christian Williams      this.qualifiers = qualifiers;
296bbdc3ce45195e6896254a2c7aa24370f2c55d57cErich Douglass      this.packageName = packageName;
2973c6572b8953e3d636cdf4d8d26583873b2dd1f25Hilal Alsibai      this.abiSplit = abiSplit;
2985277f871bca2be31c657ace35ae305285b2e0c55Ryan Spore and Trevor John      this.resourceDir = resourceDir;
2996b00d4156e2e6bb2d262458a2650a109ddc76c76Erich Douglass      this.assetDir = assetDir;
300ed249b15fa2ff94708d5f079f94284356a96c2a4Sean Kenny      this.buildDir = buildDir;
30129a8359eaef1ee9f40c967d3c4b5c1117c8c2a43Christian Williams      this.shadows = shadows;
302d6cef1bcc644c7152d0716b8d33eb25054894836David Sun      this.instrumentedPackages = instrumentedPackages;
3039cc9bde8928b83e5de9cd1c521e157e1a584b2fdJonathan Gerrish      this.application = application;
304ed898f2b5b7312af4779636638d081aa6ebd9e13Andrew Richardson      this.libraries = libraries;
3050bbbacc2633146b2725cce97c24dc121ffa0e89bErich Douglass      this.constants = constants;
306f6df8a55ac378dee35324bc865fb4d741dcb4824Christian Williams
307104b292a58958d310fcb27472fd7e450b3d99946Christian Williams      validate(this);
30881a928816f4cf068ff3fe636df2a25db269c73c8Jonathan Gerrish    }
30981a928816f4cf068ff3fe636df2a25db269c73c8Jonathan Gerrish
3106b00d4156e2e6bb2d262458a2650a109ddc76c76Erich Douglass    @Override
31181a928816f4cf068ff3fe636df2a25db269c73c8Jonathan Gerrish    public int[] sdk() {
3128c45d4a57fa380436885166f8e89b3e20d20290cErich Douglass      return sdk;
31329a8359eaef1ee9f40c967d3c4b5c1117c8c2a43Christian Williams    }
314f6df8a55ac378dee35324bc865fb4d741dcb4824Christian Williams
3156b00d4156e2e6bb2d262458a2650a109ddc76c76Erich Douglass    @Override
316bf73dde49765ed8f3556ef0b2ce63a0cb44703fbJonathan Gerrish    public int minSdk() {
317bf73dde49765ed8f3556ef0b2ce63a0cb44703fbJonathan Gerrish      return minSdk;
318bf73dde49765ed8f3556ef0b2ce63a0cb44703fbJonathan Gerrish    }
319bf73dde49765ed8f3556ef0b2ce63a0cb44703fbJonathan Gerrish
320bf73dde49765ed8f3556ef0b2ce63a0cb44703fbJonathan Gerrish    @Override
321bf73dde49765ed8f3556ef0b2ce63a0cb44703fbJonathan Gerrish    public int maxSdk() {
322bf73dde49765ed8f3556ef0b2ce63a0cb44703fbJonathan Gerrish      return maxSdk;
323bf73dde49765ed8f3556ef0b2ce63a0cb44703fbJonathan Gerrish    }
324bf73dde49765ed8f3556ef0b2ce63a0cb44703fbJonathan Gerrish
325bf73dde49765ed8f3556ef0b2ce63a0cb44703fbJonathan Gerrish    @Override
3266b00d4156e2e6bb2d262458a2650a109ddc76c76Erich Douglass    public String manifest() {
32729a8359eaef1ee9f40c967d3c4b5c1117c8c2a43Christian Williams      return manifest;
32829a8359eaef1ee9f40c967d3c4b5c1117c8c2a43Christian Williams    }
32948f95f3e0955035946f7c416dec56219a9b19886Christian Williams
3309cc9bde8928b83e5de9cd1c521e157e1a584b2fdJonathan Gerrish    @Override
3310bbbacc2633146b2725cce97c24dc121ffa0e89bErich Douglass    public Class<?> constants() {
3320bbbacc2633146b2725cce97c24dc121ffa0e89bErich Douglass      return constants;
3330bbbacc2633146b2725cce97c24dc121ffa0e89bErich Douglass    }
3340bbbacc2633146b2725cce97c24dc121ffa0e89bErich Douglass
3350bbbacc2633146b2725cce97c24dc121ffa0e89bErich Douglass    @Override
3369cc9bde8928b83e5de9cd1c521e157e1a584b2fdJonathan Gerrish    public Class<? extends Application> application() {
3379cc9bde8928b83e5de9cd1c521e157e1a584b2fdJonathan Gerrish      return application;
3389cc9bde8928b83e5de9cd1c521e157e1a584b2fdJonathan Gerrish    }
3399cc9bde8928b83e5de9cd1c521e157e1a584b2fdJonathan Gerrish
3406b00d4156e2e6bb2d262458a2650a109ddc76c76Erich Douglass    @Override
3416b00d4156e2e6bb2d262458a2650a109ddc76c76Erich Douglass    public String qualifiers() {
34229a8359eaef1ee9f40c967d3c4b5c1117c8c2a43Christian Williams      return qualifiers;
34329a8359eaef1ee9f40c967d3c4b5c1117c8c2a43Christian Williams    }
344f6df8a55ac378dee35324bc865fb4d741dcb4824Christian Williams
3455277f871bca2be31c657ace35ae305285b2e0c55Ryan Spore and Trevor John    @Override
346bbdc3ce45195e6896254a2c7aa24370f2c55d57cErich Douglass    public String packageName() {
347bbdc3ce45195e6896254a2c7aa24370f2c55d57cErich Douglass      return packageName;
348bbdc3ce45195e6896254a2c7aa24370f2c55d57cErich Douglass    }
349bbdc3ce45195e6896254a2c7aa24370f2c55d57cErich Douglass
350bbdc3ce45195e6896254a2c7aa24370f2c55d57cErich Douglass    @Override
3513c6572b8953e3d636cdf4d8d26583873b2dd1f25Hilal Alsibai    public String abiSplit() {
3523c6572b8953e3d636cdf4d8d26583873b2dd1f25Hilal Alsibai      return abiSplit;
3533c6572b8953e3d636cdf4d8d26583873b2dd1f25Hilal Alsibai    }
3543c6572b8953e3d636cdf4d8d26583873b2dd1f25Hilal Alsibai
3553c6572b8953e3d636cdf4d8d26583873b2dd1f25Hilal Alsibai    @Override
3565277f871bca2be31c657ace35ae305285b2e0c55Ryan Spore and Trevor John    public String resourceDir() {
3575277f871bca2be31c657ace35ae305285b2e0c55Ryan Spore and Trevor John      return resourceDir;
3585277f871bca2be31c657ace35ae305285b2e0c55Ryan Spore and Trevor John    }
3595277f871bca2be31c657ace35ae305285b2e0c55Ryan Spore and Trevor John
3606b00d4156e2e6bb2d262458a2650a109ddc76c76Erich Douglass    @Override
3616b00d4156e2e6bb2d262458a2650a109ddc76c76Erich Douglass    public String assetDir() {
3626b00d4156e2e6bb2d262458a2650a109ddc76c76Erich Douglass      return assetDir;
3636b00d4156e2e6bb2d262458a2650a109ddc76c76Erich Douglass    }
3646b00d4156e2e6bb2d262458a2650a109ddc76c76Erich Douglass
3656b00d4156e2e6bb2d262458a2650a109ddc76c76Erich Douglass    @Override
366ed249b15fa2ff94708d5f079f94284356a96c2a4Sean Kenny    public String buildDir() {
367ed249b15fa2ff94708d5f079f94284356a96c2a4Sean Kenny      return buildDir;
368ed249b15fa2ff94708d5f079f94284356a96c2a4Sean Kenny    }
369ed249b15fa2ff94708d5f079f94284356a96c2a4Sean Kenny
370ed249b15fa2ff94708d5f079f94284356a96c2a4Sean Kenny    @Override
3716b00d4156e2e6bb2d262458a2650a109ddc76c76Erich Douglass    public Class<?>[] shadows() {
37229a8359eaef1ee9f40c967d3c4b5c1117c8c2a43Christian Williams      return shadows;
37329a8359eaef1ee9f40c967d3c4b5c1117c8c2a43Christian Williams    }
374f6df8a55ac378dee35324bc865fb4d741dcb4824Christian Williams
3756b00d4156e2e6bb2d262458a2650a109ddc76c76Erich Douglass    @Override
376d6cef1bcc644c7152d0716b8d33eb25054894836David Sun    public String[] instrumentedPackages() {
377d6cef1bcc644c7152d0716b8d33eb25054894836David Sun      return instrumentedPackages;
378d6cef1bcc644c7152d0716b8d33eb25054894836David Sun    }
379b4c08d70a2f549cf344c81bb20c824d3cc31c298Vijay Nayar
380d6cef1bcc644c7152d0716b8d33eb25054894836David Sun    @Override
3816b00d4156e2e6bb2d262458a2650a109ddc76c76Erich Douglass    public String[] libraries() {
382ed898f2b5b7312af4779636638d081aa6ebd9e13Andrew Richardson      return libraries;
383ed898f2b5b7312af4779636638d081aa6ebd9e13Andrew Richardson    }
384ed898f2b5b7312af4779636638d081aa6ebd9e13Andrew Richardson
38568dc68433d8be4dd7eb7d8a9dda078ad37ce1d16Jonathan Gerrish    @Nonnull @Override
3866b00d4156e2e6bb2d262458a2650a109ddc76c76Erich Douglass    public Class<? extends Annotation> annotationType() {
38729a8359eaef1ee9f40c967d3c4b5c1117c8c2a43Christian Williams      return Config.class;
38829a8359eaef1ee9f40c967d3c4b5c1117c8c2a43Christian Williams    }
38929a8359eaef1ee9f40c967d3c4b5c1117c8c2a43Christian Williams  }
39055b52578fdaca7097ea4b28b3daebac84094dab4Christian Williams
39155b52578fdaca7097ea4b28b3daebac84094dab4Christian Williams  class Builder {
392704d59a9e57b28939ba5c709cf4b50d72aa072e6Christian Williams    protected int[] sdk = new int[0];
393704d59a9e57b28939ba5c709cf4b50d72aa072e6Christian Williams    protected int minSdk = -1;
394704d59a9e57b28939ba5c709cf4b50d72aa072e6Christian Williams    protected int maxSdk = -1;
395704d59a9e57b28939ba5c709cf4b50d72aa072e6Christian Williams    protected String manifest = Config.DEFAULT_VALUE_STRING;
396704d59a9e57b28939ba5c709cf4b50d72aa072e6Christian Williams    protected String qualifiers = Config.DEFAULT_QUALIFIERS;
397704d59a9e57b28939ba5c709cf4b50d72aa072e6Christian Williams    protected String packageName = Config.DEFAULT_PACKAGE_NAME;
398704d59a9e57b28939ba5c709cf4b50d72aa072e6Christian Williams    protected String abiSplit = Config.DEFAULT_ABI_SPLIT;
399704d59a9e57b28939ba5c709cf4b50d72aa072e6Christian Williams    protected String resourceDir = Config.DEFAULT_RES_FOLDER;
400704d59a9e57b28939ba5c709cf4b50d72aa072e6Christian Williams    protected String assetDir = Config.DEFAULT_ASSET_FOLDER;
401704d59a9e57b28939ba5c709cf4b50d72aa072e6Christian Williams    protected String buildDir = Config.DEFAULT_BUILD_FOLDER;
402704d59a9e57b28939ba5c709cf4b50d72aa072e6Christian Williams    protected Class<?>[] shadows = new Class[0];
403704d59a9e57b28939ba5c709cf4b50d72aa072e6Christian Williams    protected String[] instrumentedPackages = new String[0];
404704d59a9e57b28939ba5c709cf4b50d72aa072e6Christian Williams    protected Class<? extends Application> application = DEFAULT_APPLICATION;
405704d59a9e57b28939ba5c709cf4b50d72aa072e6Christian Williams    protected String[] libraries = new String[0];
406704d59a9e57b28939ba5c709cf4b50d72aa072e6Christian Williams    protected Class<?> constants = Void.class;
40755b52578fdaca7097ea4b28b3daebac84094dab4Christian Williams
408104b292a58958d310fcb27472fd7e450b3d99946Christian Williams    public Builder() {
409104b292a58958d310fcb27472fd7e450b3d99946Christian Williams    }
410104b292a58958d310fcb27472fd7e450b3d99946Christian Williams
411104b292a58958d310fcb27472fd7e450b3d99946Christian Williams    public Builder(Config config) {
412104b292a58958d310fcb27472fd7e450b3d99946Christian Williams      sdk = config.sdk();
413104b292a58958d310fcb27472fd7e450b3d99946Christian Williams      minSdk = config.minSdk();
414104b292a58958d310fcb27472fd7e450b3d99946Christian Williams      maxSdk = config.maxSdk();
415104b292a58958d310fcb27472fd7e450b3d99946Christian Williams      manifest = config.manifest();
416104b292a58958d310fcb27472fd7e450b3d99946Christian Williams      qualifiers = config.qualifiers();
417104b292a58958d310fcb27472fd7e450b3d99946Christian Williams      packageName = config.packageName();
418104b292a58958d310fcb27472fd7e450b3d99946Christian Williams      abiSplit = config.abiSplit();
419104b292a58958d310fcb27472fd7e450b3d99946Christian Williams      resourceDir = config.resourceDir();
420104b292a58958d310fcb27472fd7e450b3d99946Christian Williams      assetDir = config.assetDir();
421104b292a58958d310fcb27472fd7e450b3d99946Christian Williams      buildDir = config.buildDir();
422104b292a58958d310fcb27472fd7e450b3d99946Christian Williams      shadows = config.shadows();
423104b292a58958d310fcb27472fd7e450b3d99946Christian Williams      instrumentedPackages = config.instrumentedPackages();
424104b292a58958d310fcb27472fd7e450b3d99946Christian Williams      application = config.application();
425104b292a58958d310fcb27472fd7e450b3d99946Christian Williams      libraries = config.libraries();
426104b292a58958d310fcb27472fd7e450b3d99946Christian Williams      constants = config.constants();
427104b292a58958d310fcb27472fd7e450b3d99946Christian Williams    }
428104b292a58958d310fcb27472fd7e450b3d99946Christian Williams
429104b292a58958d310fcb27472fd7e450b3d99946Christian Williams    public Builder setSdk(int... sdk) {
43055b52578fdaca7097ea4b28b3daebac84094dab4Christian Williams      this.sdk = sdk;
43155b52578fdaca7097ea4b28b3daebac84094dab4Christian Williams      return this;
43255b52578fdaca7097ea4b28b3daebac84094dab4Christian Williams    }
43355b52578fdaca7097ea4b28b3daebac84094dab4Christian Williams
434bf73dde49765ed8f3556ef0b2ce63a0cb44703fbJonathan Gerrish    public Builder setMinSdk(int minSdk) {
435bf73dde49765ed8f3556ef0b2ce63a0cb44703fbJonathan Gerrish      this.minSdk = minSdk;
436bf73dde49765ed8f3556ef0b2ce63a0cb44703fbJonathan Gerrish      return this;
437bf73dde49765ed8f3556ef0b2ce63a0cb44703fbJonathan Gerrish    }
438bf73dde49765ed8f3556ef0b2ce63a0cb44703fbJonathan Gerrish
439bf73dde49765ed8f3556ef0b2ce63a0cb44703fbJonathan Gerrish    public Builder setMaxSdk(int maxSdk) {
440bf73dde49765ed8f3556ef0b2ce63a0cb44703fbJonathan Gerrish      this.maxSdk = maxSdk;
441bf73dde49765ed8f3556ef0b2ce63a0cb44703fbJonathan Gerrish      return this;
442bf73dde49765ed8f3556ef0b2ce63a0cb44703fbJonathan Gerrish    }
443bf73dde49765ed8f3556ef0b2ce63a0cb44703fbJonathan Gerrish
44455b52578fdaca7097ea4b28b3daebac84094dab4Christian Williams    public Builder setManifest(String manifest) {
44555b52578fdaca7097ea4b28b3daebac84094dab4Christian Williams      this.manifest = manifest;
44655b52578fdaca7097ea4b28b3daebac84094dab4Christian Williams      return this;
44755b52578fdaca7097ea4b28b3daebac84094dab4Christian Williams    }
44855b52578fdaca7097ea4b28b3daebac84094dab4Christian Williams
44955b52578fdaca7097ea4b28b3daebac84094dab4Christian Williams    public Builder setQualifiers(String qualifiers) {
45055b52578fdaca7097ea4b28b3daebac84094dab4Christian Williams      this.qualifiers = qualifiers;
45155b52578fdaca7097ea4b28b3daebac84094dab4Christian Williams      return this;
45255b52578fdaca7097ea4b28b3daebac84094dab4Christian Williams    }
45355b52578fdaca7097ea4b28b3daebac84094dab4Christian Williams
45455b52578fdaca7097ea4b28b3daebac84094dab4Christian Williams    public Builder setPackageName(String packageName) {
45555b52578fdaca7097ea4b28b3daebac84094dab4Christian Williams      this.packageName = packageName;
45655b52578fdaca7097ea4b28b3daebac84094dab4Christian Williams      return this;
45755b52578fdaca7097ea4b28b3daebac84094dab4Christian Williams    }
45855b52578fdaca7097ea4b28b3daebac84094dab4Christian Williams
45955b52578fdaca7097ea4b28b3daebac84094dab4Christian Williams    public Builder setAbiSplit(String abiSplit) {
46055b52578fdaca7097ea4b28b3daebac84094dab4Christian Williams      this.abiSplit = abiSplit;
46155b52578fdaca7097ea4b28b3daebac84094dab4Christian Williams      return this;
46255b52578fdaca7097ea4b28b3daebac84094dab4Christian Williams    }
46355b52578fdaca7097ea4b28b3daebac84094dab4Christian Williams
46455b52578fdaca7097ea4b28b3daebac84094dab4Christian Williams    public Builder setResourceDir(String resourceDir) {
46555b52578fdaca7097ea4b28b3daebac84094dab4Christian Williams      this.resourceDir = resourceDir;
46655b52578fdaca7097ea4b28b3daebac84094dab4Christian Williams      return this;
46755b52578fdaca7097ea4b28b3daebac84094dab4Christian Williams    }
46855b52578fdaca7097ea4b28b3daebac84094dab4Christian Williams
46955b52578fdaca7097ea4b28b3daebac84094dab4Christian Williams    public Builder setAssetDir(String assetDir) {
47055b52578fdaca7097ea4b28b3daebac84094dab4Christian Williams      this.assetDir = assetDir;
47155b52578fdaca7097ea4b28b3daebac84094dab4Christian Williams      return this;
47255b52578fdaca7097ea4b28b3daebac84094dab4Christian Williams    }
47355b52578fdaca7097ea4b28b3daebac84094dab4Christian Williams
47455b52578fdaca7097ea4b28b3daebac84094dab4Christian Williams    public Builder setBuildDir(String buildDir) {
47555b52578fdaca7097ea4b28b3daebac84094dab4Christian Williams      this.buildDir = buildDir;
47655b52578fdaca7097ea4b28b3daebac84094dab4Christian Williams      return this;
47755b52578fdaca7097ea4b28b3daebac84094dab4Christian Williams    }
47855b52578fdaca7097ea4b28b3daebac84094dab4Christian Williams
47955b52578fdaca7097ea4b28b3daebac84094dab4Christian Williams    public Builder setShadows(Class<?>[] shadows) {
48055b52578fdaca7097ea4b28b3daebac84094dab4Christian Williams      this.shadows = shadows;
48155b52578fdaca7097ea4b28b3daebac84094dab4Christian Williams      return this;
48255b52578fdaca7097ea4b28b3daebac84094dab4Christian Williams    }
48355b52578fdaca7097ea4b28b3daebac84094dab4Christian Williams
48455b52578fdaca7097ea4b28b3daebac84094dab4Christian Williams    public Builder setInstrumentedPackages(String[] instrumentedPackages) {
48555b52578fdaca7097ea4b28b3daebac84094dab4Christian Williams      this.instrumentedPackages = instrumentedPackages;
48655b52578fdaca7097ea4b28b3daebac84094dab4Christian Williams      return this;
48755b52578fdaca7097ea4b28b3daebac84094dab4Christian Williams    }
48855b52578fdaca7097ea4b28b3daebac84094dab4Christian Williams
48955b52578fdaca7097ea4b28b3daebac84094dab4Christian Williams    public Builder setApplication(Class<? extends Application> application) {
49055b52578fdaca7097ea4b28b3daebac84094dab4Christian Williams      this.application = application;
49155b52578fdaca7097ea4b28b3daebac84094dab4Christian Williams      return this;
49255b52578fdaca7097ea4b28b3daebac84094dab4Christian Williams    }
49355b52578fdaca7097ea4b28b3daebac84094dab4Christian Williams
49455b52578fdaca7097ea4b28b3daebac84094dab4Christian Williams    public Builder setLibraries(String[] libraries) {
49555b52578fdaca7097ea4b28b3daebac84094dab4Christian Williams      this.libraries = libraries;
49655b52578fdaca7097ea4b28b3daebac84094dab4Christian Williams      return this;
49755b52578fdaca7097ea4b28b3daebac84094dab4Christian Williams    }
49855b52578fdaca7097ea4b28b3daebac84094dab4Christian Williams
49955b52578fdaca7097ea4b28b3daebac84094dab4Christian Williams    public Builder setConstants(Class<?> constants) {
50055b52578fdaca7097ea4b28b3daebac84094dab4Christian Williams      this.constants = constants;
50155b52578fdaca7097ea4b28b3daebac84094dab4Christian Williams      return this;
50255b52578fdaca7097ea4b28b3daebac84094dab4Christian Williams    }
50355b52578fdaca7097ea4b28b3daebac84094dab4Christian Williams
504b4d0e3b1d6313b7f37852f42a2b8b54cc57af17eChristian Williams    /**
505b4d0e3b1d6313b7f37852f42a2b8b54cc57af17eChristian Williams     * This returns actual default values where they exist, in the sense that we could use
5067d074bb6c8e8c5e3f73faec0f35a6cf129227ebaChristian Williams     * the values, rather than markers like {@code -1} or {@code --default}.
507b4d0e3b1d6313b7f37852f42a2b8b54cc57af17eChristian Williams     */
508b4d0e3b1d6313b7f37852f42a2b8b54cc57af17eChristian Williams    public static Builder defaults() {
509b4d0e3b1d6313b7f37852f42a2b8b54cc57af17eChristian Williams      return new Builder()
510b4d0e3b1d6313b7f37852f42a2b8b54cc57af17eChristian Williams          .setManifest(DEFAULT_MANIFEST_NAME)
511b4d0e3b1d6313b7f37852f42a2b8b54cc57af17eChristian Williams          .setResourceDir(DEFAULT_RES_FOLDER)
512b4d0e3b1d6313b7f37852f42a2b8b54cc57af17eChristian Williams          .setAssetDir(DEFAULT_ASSET_FOLDER);
513b4d0e3b1d6313b7f37852f42a2b8b54cc57af17eChristian Williams    }
514b4d0e3b1d6313b7f37852f42a2b8b54cc57af17eChristian Williams
515104b292a58958d310fcb27472fd7e450b3d99946Christian Williams    public Builder overlay(Config overlayConfig) {
516104b292a58958d310fcb27472fd7e450b3d99946Christian Williams      int[] overlaySdk = overlayConfig.sdk();
517104b292a58958d310fcb27472fd7e450b3d99946Christian Williams      int overlayMinSdk = overlayConfig.minSdk();
518104b292a58958d310fcb27472fd7e450b3d99946Christian Williams      int overlayMaxSdk = overlayConfig.maxSdk();
519104b292a58958d310fcb27472fd7e450b3d99946Christian Williams
520104b292a58958d310fcb27472fd7e450b3d99946Christian Williams      //noinspection ConstantConditions
521104b292a58958d310fcb27472fd7e450b3d99946Christian Williams      if (overlaySdk != null && overlaySdk.length > 0) {
522104b292a58958d310fcb27472fd7e450b3d99946Christian Williams        this.sdk = overlaySdk;
523104b292a58958d310fcb27472fd7e450b3d99946Christian Williams        this.minSdk = overlayMinSdk;
524104b292a58958d310fcb27472fd7e450b3d99946Christian Williams        this.maxSdk = overlayMaxSdk;
525104b292a58958d310fcb27472fd7e450b3d99946Christian Williams      } else {
526104b292a58958d310fcb27472fd7e450b3d99946Christian Williams        if (overlayMinSdk != DEFAULT_VALUE_INT || overlayMaxSdk != DEFAULT_VALUE_INT) {
527104b292a58958d310fcb27472fd7e450b3d99946Christian Williams          this.sdk = new int[0];
528104b292a58958d310fcb27472fd7e450b3d99946Christian Williams        } else {
529104b292a58958d310fcb27472fd7e450b3d99946Christian Williams          this.sdk = pickSdk(this.sdk, overlaySdk, new int[0]);
530104b292a58958d310fcb27472fd7e450b3d99946Christian Williams        }
531104b292a58958d310fcb27472fd7e450b3d99946Christian Williams        this.minSdk = pick(this.minSdk, overlayMinSdk, DEFAULT_VALUE_INT);
532104b292a58958d310fcb27472fd7e450b3d99946Christian Williams        this.maxSdk = pick(this.maxSdk, overlayMaxSdk, DEFAULT_VALUE_INT);
533104b292a58958d310fcb27472fd7e450b3d99946Christian Williams      }
534104b292a58958d310fcb27472fd7e450b3d99946Christian Williams      this.manifest = pick(this.manifest, overlayConfig.manifest(), DEFAULT_VALUE_STRING);
5359f69dc80a8ac7e48cbf50f65974d4986ab7f00ecChristian Williams
5369f69dc80a8ac7e48cbf50f65974d4986ab7f00ecChristian Williams      String qualifiersOverlayValue = overlayConfig.qualifiers();
5379f69dc80a8ac7e48cbf50f65974d4986ab7f00ecChristian Williams      if (qualifiersOverlayValue != null && !qualifiersOverlayValue.equals("")) {
5389f69dc80a8ac7e48cbf50f65974d4986ab7f00ecChristian Williams        if (qualifiersOverlayValue.startsWith("+")) {
53998100e80de9254ef6b8eebf3b1a43318be9210e9Christian Williams          this.qualifiers = this.qualifiers + " " + qualifiersOverlayValue;
5409f69dc80a8ac7e48cbf50f65974d4986ab7f00ecChristian Williams        } else {
5419f69dc80a8ac7e48cbf50f65974d4986ab7f00ecChristian Williams          this.qualifiers = qualifiersOverlayValue;
5429f69dc80a8ac7e48cbf50f65974d4986ab7f00ecChristian Williams        }
5439f69dc80a8ac7e48cbf50f65974d4986ab7f00ecChristian Williams      }
5449f69dc80a8ac7e48cbf50f65974d4986ab7f00ecChristian Williams
545104b292a58958d310fcb27472fd7e450b3d99946Christian Williams      this.packageName = pick(this.packageName, overlayConfig.packageName(), "");
546104b292a58958d310fcb27472fd7e450b3d99946Christian Williams      this.abiSplit = pick(this.abiSplit, overlayConfig.abiSplit(), "");
547104b292a58958d310fcb27472fd7e450b3d99946Christian Williams      this.resourceDir = pick(this.resourceDir, overlayConfig.resourceDir(), Config.DEFAULT_RES_FOLDER);
548104b292a58958d310fcb27472fd7e450b3d99946Christian Williams      this.assetDir = pick(this.assetDir, overlayConfig.assetDir(), Config.DEFAULT_ASSET_FOLDER);
549104b292a58958d310fcb27472fd7e450b3d99946Christian Williams      this.buildDir = pick(this.buildDir, overlayConfig.buildDir(), Config.DEFAULT_BUILD_FOLDER);
550104b292a58958d310fcb27472fd7e450b3d99946Christian Williams      this.constants = pick(this.constants, overlayConfig.constants(), Void.class);
551104b292a58958d310fcb27472fd7e450b3d99946Christian Williams
552084d588b645d53c1110ff24b82433b5a331cc6d3James Lemieux      List<Class<?>> shadows = new ArrayList<>(Arrays.asList(this.shadows));
553104b292a58958d310fcb27472fd7e450b3d99946Christian Williams      shadows.addAll(Arrays.asList(overlayConfig.shadows()));
554104b292a58958d310fcb27472fd7e450b3d99946Christian Williams      this.shadows = shadows.toArray(new Class[shadows.size()]);
555104b292a58958d310fcb27472fd7e450b3d99946Christian Williams
556104b292a58958d310fcb27472fd7e450b3d99946Christian Williams      Set<String> instrumentedPackages = new HashSet<>();
557104b292a58958d310fcb27472fd7e450b3d99946Christian Williams      instrumentedPackages.addAll(Arrays.asList(this.instrumentedPackages));
558104b292a58958d310fcb27472fd7e450b3d99946Christian Williams      instrumentedPackages.addAll(Arrays.asList(overlayConfig.instrumentedPackages()));
559104b292a58958d310fcb27472fd7e450b3d99946Christian Williams      this.instrumentedPackages = instrumentedPackages.toArray(new String[instrumentedPackages.size()]);
560104b292a58958d310fcb27472fd7e450b3d99946Christian Williams
561104b292a58958d310fcb27472fd7e450b3d99946Christian Williams      this.application = pick(this.application, overlayConfig.application(), DEFAULT_APPLICATION);
562104b292a58958d310fcb27472fd7e450b3d99946Christian Williams
563104b292a58958d310fcb27472fd7e450b3d99946Christian Williams      Set<String> libraries = new HashSet<>();
564104b292a58958d310fcb27472fd7e450b3d99946Christian Williams      libraries.addAll(Arrays.asList(this.libraries));
565104b292a58958d310fcb27472fd7e450b3d99946Christian Williams      libraries.addAll(Arrays.asList(overlayConfig.libraries()));
566104b292a58958d310fcb27472fd7e450b3d99946Christian Williams      this.libraries = libraries.toArray(new String[libraries.size()]);
567104b292a58958d310fcb27472fd7e450b3d99946Christian Williams
568104b292a58958d310fcb27472fd7e450b3d99946Christian Williams      return this;
569104b292a58958d310fcb27472fd7e450b3d99946Christian Williams    }
570104b292a58958d310fcb27472fd7e450b3d99946Christian Williams
571104b292a58958d310fcb27472fd7e450b3d99946Christian Williams    private <T> T pick(T baseValue, T overlayValue, T nullValue) {
572104b292a58958d310fcb27472fd7e450b3d99946Christian Williams      return overlayValue != null ? (overlayValue.equals(nullValue) ? baseValue : overlayValue) : null;
573104b292a58958d310fcb27472fd7e450b3d99946Christian Williams    }
574104b292a58958d310fcb27472fd7e450b3d99946Christian Williams
575104b292a58958d310fcb27472fd7e450b3d99946Christian Williams    private int[] pickSdk(int[] baseValue, int[] overlayValue, int[] nullValue) {
576104b292a58958d310fcb27472fd7e450b3d99946Christian Williams      return Arrays.equals(overlayValue, nullValue) ? baseValue : overlayValue;
577104b292a58958d310fcb27472fd7e450b3d99946Christian Williams    }
578104b292a58958d310fcb27472fd7e450b3d99946Christian Williams
57955b52578fdaca7097ea4b28b3daebac84094dab4Christian Williams    public Implementation build() {
580bf73dde49765ed8f3556ef0b2ce63a0cb44703fbJonathan Gerrish      return new Implementation(sdk, minSdk, maxSdk, manifest, qualifiers, packageName, abiSplit, resourceDir, assetDir, buildDir, shadows, instrumentedPackages, application, libraries, constants);
58155b52578fdaca7097ea4b28b3daebac84094dab4Christian Williams    }
582104b292a58958d310fcb27472fd7e450b3d99946Christian Williams
583104b292a58958d310fcb27472fd7e450b3d99946Christian Williams    public static boolean isDefaultApplication(Class<? extends Application> clazz) {
584104b292a58958d310fcb27472fd7e450b3d99946Christian Williams      return clazz == null || clazz.getCanonicalName().equals(DEFAULT_APPLICATION.getCanonicalName());
585104b292a58958d310fcb27472fd7e450b3d99946Christian Williams    }
58655b52578fdaca7097ea4b28b3daebac84094dab4Christian Williams  }
587dd40f718cf785a56e63c0685feeb73d266c13e3fWenhui Yao}
588