Config.java revision 23a26cc3e5b33c0503a99847292ac99817f5af43
1cfb3d242306311ce27ec51bf511764377c173a7cKiran Ryali + Christian Williamspackage org.robolectric.annotation;
2dd40f718cf785a56e63c0685feeb73d266c13e3fWenhui Yao
3f6df8a55ac378dee35324bc865fb4d741dcb4824Christian Williamsimport org.jetbrains.annotations.NotNull;
4f6df8a55ac378dee35324bc865fb4d741dcb4824Christian Williams
5f6df8a55ac378dee35324bc865fb4d741dcb4824Christian Williamsimport java.lang.annotation.Annotation;
6f6df8a55ac378dee35324bc865fb4d741dcb4824Christian Williamsimport java.lang.annotation.Documented;
7f6df8a55ac378dee35324bc865fb4d741dcb4824Christian Williamsimport java.lang.annotation.ElementType;
8f6df8a55ac378dee35324bc865fb4d741dcb4824Christian Williamsimport java.lang.annotation.Retention;
9f6df8a55ac378dee35324bc865fb4d741dcb4824Christian Williamsimport java.lang.annotation.RetentionPolicy;
10f6df8a55ac378dee35324bc865fb4d741dcb4824Christian Williamsimport java.lang.annotation.Target;
11f6df8a55ac378dee35324bc865fb4d741dcb4824Christian Williamsimport java.util.ArrayList;
12f6df8a55ac378dee35324bc865fb4d741dcb4824Christian Williamsimport java.util.Arrays;
1323a26cc3e5b33c0503a99847292ac99817f5af43Christian Williamsimport java.util.Properties;
14f6df8a55ac378dee35324bc865fb4d741dcb4824Christian Williams
15dd40f718cf785a56e63c0685feeb73d266c13e3fWenhui Yao/**
1680c8a1718d42c7e2165289a7bbfab5e7f3dc0513Christian Williams & Dimitris Couchell * Indicate that robolectric should look for values that is specific by those qualifiers
17dd40f718cf785a56e63c0685feeb73d266c13e3fWenhui Yao */
18f6df8a55ac378dee35324bc865fb4d741dcb4824Christian Williams@Documented
19f6df8a55ac378dee35324bc865fb4d741dcb4824Christian Williams@Retention(RetentionPolicy.RUNTIME)
20f6df8a55ac378dee35324bc865fb4d741dcb4824Christian Williams@Target({ElementType.TYPE, ElementType.METHOD})
217be4d2ba0e45483ad70cbd994955ae1b70afafdcKiran Ryali + Christian Williamspublic @interface Config {
2248f95f3e0955035946f7c416dec56219a9b19886Christian Williams    @SuppressWarnings("UnusedDeclaration")
2348f95f3e0955035946f7c416dec56219a9b19886Christian Williams    public static final String NONE = "--none";
2448f95f3e0955035946f7c416dec56219a9b19886Christian Williams    public static final String DEFAULT = "--default";
257be4d2ba0e45483ad70cbd994955ae1b70afafdcKiran Ryali + Christian Williams
267be4d2ba0e45483ad70cbd994955ae1b70afafdcKiran Ryali + Christian Williams    /**
278084b47f2133fc32630fabb46f2e8a259bcd8735Christian Williams     * The Android SDK level to emulate. If not specified, Robolectric defaults to the targetSdkVersion in your app's manifest.
2813e56890ba2f0206bc4d68fb536484c9ae287e1eChristian Williams     *
2913e56890ba2f0206bc4d68fb536484c9ae287e1eChristian Williams     * Not yet supported as of Robolectric 2.0.
307be4d2ba0e45483ad70cbd994955ae1b70afafdcKiran Ryali + Christian Williams     */
318084b47f2133fc32630fabb46f2e8a259bcd8735Christian Williams    int emulateSdk() default -1;
327be4d2ba0e45483ad70cbd994955ae1b70afafdcKiran Ryali + Christian Williams
338084b47f2133fc32630fabb46f2e8a259bcd8735Christian Williams    /**
3448f95f3e0955035946f7c416dec56219a9b19886Christian Williams     * The Android manifest file to load; Robolectric will look relative to the current directory.
3548f95f3e0955035946f7c416dec56219a9b19886Christian Williams     * Resources and assets will be loaded relative to the manifest.
3648f95f3e0955035946f7c416dec56219a9b19886Christian Williams     *
3748f95f3e0955035946f7c416dec56219a9b19886Christian Williams     * If not specified, Robolectric defaults to {@code AndroidManifest.xml}.
3848f95f3e0955035946f7c416dec56219a9b19886Christian Williams     *
3948f95f3e0955035946f7c416dec56219a9b19886Christian Williams     * If your project has no manifest or resources, use {@link Config#NONE}.
4048f95f3e0955035946f7c416dec56219a9b19886Christian Williams     */
4148f95f3e0955035946f7c416dec56219a9b19886Christian Williams    String manifest() default DEFAULT;
4248f95f3e0955035946f7c416dec56219a9b19886Christian Williams
4348f95f3e0955035946f7c416dec56219a9b19886Christian Williams    /**
448084b47f2133fc32630fabb46f2e8a259bcd8735Christian Williams     * Qualifiers for the resource resolution, such as "fr-normal-port-hdpi".
4513e56890ba2f0206bc4d68fb536484c9ae287e1eChristian Williams     *
4613e56890ba2f0206bc4d68fb536484c9ae287e1eChristian 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.
478084b47f2133fc32630fabb46f2e8a259bcd8735Christian Williams     */
488084b47f2133fc32630fabb46f2e8a259bcd8735Christian Williams    String qualifiers() default "";
497be4d2ba0e45483ad70cbd994955ae1b70afafdcKiran Ryali + Christian Williams
508084b47f2133fc32630fabb46f2e8a259bcd8735Christian Williams    /**
518084b47f2133fc32630fabb46f2e8a259bcd8735Christian Williams     * The Android SDK level to report in Build.VERSION.SDK_INT.
5213e56890ba2f0206bc4d68fb536484c9ae287e1eChristian Williams     *
5313e56890ba2f0206bc4d68fb536484c9ae287e1eChristian Williams     * @see <a href="http://en.wikipedia.org/wiki/Android_version_history">Android Version History</a>.
548084b47f2133fc32630fabb46f2e8a259bcd8735Christian Williams     */
557be4d2ba0e45483ad70cbd994955ae1b70afafdcKiran Ryali + Christian Williams    int reportSdk() default -1;
568084b47f2133fc32630fabb46f2e8a259bcd8735Christian Williams
578084b47f2133fc32630fabb46f2e8a259bcd8735Christian Williams    /**
588084b47f2133fc32630fabb46f2e8a259bcd8735Christian Williams     * A list of shadow classes to enable, in addition to those that are already present.
598084b47f2133fc32630fabb46f2e8a259bcd8735Christian Williams     */
608084b47f2133fc32630fabb46f2e8a259bcd8735Christian Williams    Class<?>[] shadows() default {};
61f6df8a55ac378dee35324bc865fb4d741dcb4824Christian Williams
62f6df8a55ac378dee35324bc865fb4d741dcb4824Christian Williams    public class Implementation implements Config {
63f6df8a55ac378dee35324bc865fb4d741dcb4824Christian Williams        private final int emulateSdk;
6448f95f3e0955035946f7c416dec56219a9b19886Christian Williams        private final String manifest;
65f6df8a55ac378dee35324bc865fb4d741dcb4824Christian Williams        private final String qualifiers;
66f6df8a55ac378dee35324bc865fb4d741dcb4824Christian Williams        private final int reportSdk;
67f6df8a55ac378dee35324bc865fb4d741dcb4824Christian Williams        private final Class<?>[] shadows;
68f6df8a55ac378dee35324bc865fb4d741dcb4824Christian Williams
6923a26cc3e5b33c0503a99847292ac99817f5af43Christian Williams        public static Config fromProperties(Properties configProperties) {
7023a26cc3e5b33c0503a99847292ac99817f5af43Christian Williams            if (configProperties == null || configProperties.size() == 0) return null;
7123a26cc3e5b33c0503a99847292ac99817f5af43Christian Williams            return new Implementation(
7223a26cc3e5b33c0503a99847292ac99817f5af43Christian Williams                    Integer.parseInt(configProperties.getProperty("emulateSdk", "-1")),
7323a26cc3e5b33c0503a99847292ac99817f5af43Christian Williams                    configProperties.getProperty("manifest", DEFAULT),
7423a26cc3e5b33c0503a99847292ac99817f5af43Christian Williams                    configProperties.getProperty("qualifiers", ""),
7523a26cc3e5b33c0503a99847292ac99817f5af43Christian Williams                    Integer.parseInt(configProperties.getProperty("reportSdk", "-1")),
7623a26cc3e5b33c0503a99847292ac99817f5af43Christian Williams                    parseClasses(configProperties.getProperty("shadows", ""))
7723a26cc3e5b33c0503a99847292ac99817f5af43Christian Williams            );
7823a26cc3e5b33c0503a99847292ac99817f5af43Christian Williams        }
7923a26cc3e5b33c0503a99847292ac99817f5af43Christian Williams
8023a26cc3e5b33c0503a99847292ac99817f5af43Christian Williams        private static Class<?>[] parseClasses(String classList) {
8123a26cc3e5b33c0503a99847292ac99817f5af43Christian Williams            String[] classNames = classList.split("[, ]+");
8223a26cc3e5b33c0503a99847292ac99817f5af43Christian Williams            Class[] classes = new Class[classNames.length];
8323a26cc3e5b33c0503a99847292ac99817f5af43Christian Williams            for (int i = 0; i < classNames.length; i++) {
8423a26cc3e5b33c0503a99847292ac99817f5af43Christian Williams                try {
8523a26cc3e5b33c0503a99847292ac99817f5af43Christian Williams                    classes[i] = Implementation.class.getClassLoader().loadClass(classNames[i]);
8623a26cc3e5b33c0503a99847292ac99817f5af43Christian Williams                } catch (ClassNotFoundException e) {
8723a26cc3e5b33c0503a99847292ac99817f5af43Christian Williams                    throw new RuntimeException(e);
8823a26cc3e5b33c0503a99847292ac99817f5af43Christian Williams                }
8923a26cc3e5b33c0503a99847292ac99817f5af43Christian Williams            }
9023a26cc3e5b33c0503a99847292ac99817f5af43Christian Williams            return classes;
9123a26cc3e5b33c0503a99847292ac99817f5af43Christian Williams        }
9223a26cc3e5b33c0503a99847292ac99817f5af43Christian Williams
9348f95f3e0955035946f7c416dec56219a9b19886Christian Williams        public Implementation(int emulateSdk, String manifest, String qualifiers, int reportSdk, Class<?>[] shadows) {
94f6df8a55ac378dee35324bc865fb4d741dcb4824Christian Williams            this.emulateSdk = emulateSdk;
9548f95f3e0955035946f7c416dec56219a9b19886Christian Williams            this.manifest = manifest;
96f6df8a55ac378dee35324bc865fb4d741dcb4824Christian Williams            this.qualifiers = qualifiers;
97f6df8a55ac378dee35324bc865fb4d741dcb4824Christian Williams            this.reportSdk = reportSdk;
98f6df8a55ac378dee35324bc865fb4d741dcb4824Christian Williams            this.shadows = shadows;
99f6df8a55ac378dee35324bc865fb4d741dcb4824Christian Williams        }
100f6df8a55ac378dee35324bc865fb4d741dcb4824Christian Williams
101f6df8a55ac378dee35324bc865fb4d741dcb4824Christian Williams        public Implementation(Config baseConfig, Config overlayConfig) {
102f6df8a55ac378dee35324bc865fb4d741dcb4824Christian Williams            this.emulateSdk = pick(baseConfig.emulateSdk(), overlayConfig.emulateSdk(), -1);
10348f95f3e0955035946f7c416dec56219a9b19886Christian Williams            this.manifest = pick(baseConfig.manifest(), overlayConfig.manifest(), DEFAULT);
104f6df8a55ac378dee35324bc865fb4d741dcb4824Christian Williams            this.qualifiers = pick(baseConfig.qualifiers(), overlayConfig.qualifiers(), "");
105f6df8a55ac378dee35324bc865fb4d741dcb4824Christian Williams            this.reportSdk = pick(baseConfig.reportSdk(), overlayConfig.reportSdk(), -1);
106f6df8a55ac378dee35324bc865fb4d741dcb4824Christian Williams            ArrayList<Class<?>> shadows = new ArrayList<Class<?>>();
107f6df8a55ac378dee35324bc865fb4d741dcb4824Christian Williams            shadows.addAll(Arrays.asList(baseConfig.shadows()));
108f6df8a55ac378dee35324bc865fb4d741dcb4824Christian Williams            shadows.addAll(Arrays.asList(overlayConfig.shadows()));
109f6df8a55ac378dee35324bc865fb4d741dcb4824Christian Williams            this.shadows = shadows.toArray(new Class[shadows.size()]);
110f6df8a55ac378dee35324bc865fb4d741dcb4824Christian Williams        }
111f6df8a55ac378dee35324bc865fb4d741dcb4824Christian Williams
112f6df8a55ac378dee35324bc865fb4d741dcb4824Christian Williams        private <T> T pick(T baseValue, T overlayValue, T nullValue) {
113f6df8a55ac378dee35324bc865fb4d741dcb4824Christian Williams            return overlayValue.equals(nullValue) ? baseValue : overlayValue;
114f6df8a55ac378dee35324bc865fb4d741dcb4824Christian Williams        }
115f6df8a55ac378dee35324bc865fb4d741dcb4824Christian Williams
116f6df8a55ac378dee35324bc865fb4d741dcb4824Christian Williams        @Override public int emulateSdk() {
117f6df8a55ac378dee35324bc865fb4d741dcb4824Christian Williams            return emulateSdk;
118f6df8a55ac378dee35324bc865fb4d741dcb4824Christian Williams        }
119f6df8a55ac378dee35324bc865fb4d741dcb4824Christian Williams
12048f95f3e0955035946f7c416dec56219a9b19886Christian Williams        @Override public String manifest() {
12148f95f3e0955035946f7c416dec56219a9b19886Christian Williams            return manifest;
12248f95f3e0955035946f7c416dec56219a9b19886Christian Williams        }
12348f95f3e0955035946f7c416dec56219a9b19886Christian Williams
124f6df8a55ac378dee35324bc865fb4d741dcb4824Christian Williams        @Override public String qualifiers() {
125f6df8a55ac378dee35324bc865fb4d741dcb4824Christian Williams            return qualifiers;
126f6df8a55ac378dee35324bc865fb4d741dcb4824Christian Williams        }
127f6df8a55ac378dee35324bc865fb4d741dcb4824Christian Williams
128f6df8a55ac378dee35324bc865fb4d741dcb4824Christian Williams        @Override public int reportSdk() {
129f6df8a55ac378dee35324bc865fb4d741dcb4824Christian Williams            return reportSdk;
130f6df8a55ac378dee35324bc865fb4d741dcb4824Christian Williams        }
131f6df8a55ac378dee35324bc865fb4d741dcb4824Christian Williams
132f6df8a55ac378dee35324bc865fb4d741dcb4824Christian Williams        @Override public Class<?>[] shadows() {
133f6df8a55ac378dee35324bc865fb4d741dcb4824Christian Williams            return shadows;
134f6df8a55ac378dee35324bc865fb4d741dcb4824Christian Williams        }
135f6df8a55ac378dee35324bc865fb4d741dcb4824Christian Williams
136f6df8a55ac378dee35324bc865fb4d741dcb4824Christian Williams        @NotNull @Override public Class<? extends Annotation> annotationType() {
137f6df8a55ac378dee35324bc865fb4d741dcb4824Christian Williams            return Config.class;
138f6df8a55ac378dee35324bc865fb4d741dcb4824Christian Williams        }
139f6df8a55ac378dee35324bc865fb4d741dcb4824Christian Williams
140f6df8a55ac378dee35324bc865fb4d741dcb4824Christian Williams        @Override
141f6df8a55ac378dee35324bc865fb4d741dcb4824Christian Williams        public boolean equals(Object o) {
142f6df8a55ac378dee35324bc865fb4d741dcb4824Christian Williams            if (this == o) return true;
143f6df8a55ac378dee35324bc865fb4d741dcb4824Christian Williams            if (o == null || getClass() != o.getClass()) return false;
144f6df8a55ac378dee35324bc865fb4d741dcb4824Christian Williams
145f6df8a55ac378dee35324bc865fb4d741dcb4824Christian Williams            Implementation other = (Implementation) o;
146f6df8a55ac378dee35324bc865fb4d741dcb4824Christian Williams
147f6df8a55ac378dee35324bc865fb4d741dcb4824Christian Williams            if (emulateSdk != other.emulateSdk) return false;
148f6df8a55ac378dee35324bc865fb4d741dcb4824Christian Williams            if (reportSdk != other.reportSdk) return false;
149f6df8a55ac378dee35324bc865fb4d741dcb4824Christian Williams            if (!qualifiers.equals(other.qualifiers)) return false;
150f6df8a55ac378dee35324bc865fb4d741dcb4824Christian Williams            if (!Arrays.equals(shadows, other.shadows)) return false;
151f6df8a55ac378dee35324bc865fb4d741dcb4824Christian Williams
152f6df8a55ac378dee35324bc865fb4d741dcb4824Christian Williams            return true;
153f6df8a55ac378dee35324bc865fb4d741dcb4824Christian Williams        }
154f6df8a55ac378dee35324bc865fb4d741dcb4824Christian Williams
155f6df8a55ac378dee35324bc865fb4d741dcb4824Christian Williams        @Override
156f6df8a55ac378dee35324bc865fb4d741dcb4824Christian Williams        public int hashCode() {
157f6df8a55ac378dee35324bc865fb4d741dcb4824Christian Williams            int result = emulateSdk;
158f6df8a55ac378dee35324bc865fb4d741dcb4824Christian Williams            result = 31 * result + qualifiers.hashCode();
159f6df8a55ac378dee35324bc865fb4d741dcb4824Christian Williams            result = 31 * result + reportSdk;
160f6df8a55ac378dee35324bc865fb4d741dcb4824Christian Williams            result = 31 * result + Arrays.hashCode(shadows);
161f6df8a55ac378dee35324bc865fb4d741dcb4824Christian Williams            return result;
162f6df8a55ac378dee35324bc865fb4d741dcb4824Christian Williams        }
163f6df8a55ac378dee35324bc865fb4d741dcb4824Christian Williams    }
164dd40f718cf785a56e63c0685feeb73d266c13e3fWenhui Yao}
165