SdkConfig.java revision 104b292a58958d310fcb27472fd7e450b3d99946
1package org.robolectric.internal;
2
3import android.os.Build;
4import org.jetbrains.annotations.NotNull;
5import org.robolectric.internal.dependency.DependencyJar;
6import org.robolectric.util.Logger;
7
8import java.io.IOException;
9import java.io.InputStream;
10import java.util.Collections;
11import java.util.HashMap;
12import java.util.Map;
13import java.util.Objects;
14import java.util.Properties;
15import java.util.Set;
16
17public class SdkConfig implements Comparable<SdkConfig> {
18  private static final String ROBOLECTRIC_VERSION = getRobolectricVersion();
19
20  private static final Map<Integer, SdkVersion> SUPPORTED_APIS = Collections.unmodifiableMap(new HashMap<Integer, SdkVersion>() {
21    private final double jdkVersion = Double.parseDouble(System.getProperty("java.specification.version"));
22
23    {
24      addSdk(Build.VERSION_CODES.JELLY_BEAN, "4.1.2_r1", "0", "1.6");
25      addSdk(Build.VERSION_CODES.JELLY_BEAN_MR1, "4.2.2_r1.2", "0", "1.6");
26      addSdk(Build.VERSION_CODES.JELLY_BEAN_MR2, "4.3_r2", "0", "1.6");
27      addSdk(Build.VERSION_CODES.KITKAT, "4.4_r1", "1", "1.7");
28      addSdk(Build.VERSION_CODES.LOLLIPOP, "5.0.0_r2", "1", "1.7");
29      addSdk(Build.VERSION_CODES.LOLLIPOP_MR1, "5.1.1_r9", "1", "1.7");
30      addSdk(Build.VERSION_CODES.M, "6.0.1_r3", "0", "1.7");
31      addSdk(Build.VERSION_CODES.N, "7.0.0_r1", "0", "1.8");
32      addSdk(Build.VERSION_CODES.N_MR1, "7.1.0_r7", "0", "1.8");
33    }
34
35    private void addSdk(int sdkVersion, String androidVersion, String frameworkSdkBuildVersion, String minJdkVersion) {
36      if (jdkVersion >= Double.parseDouble(minJdkVersion)) {
37        put(sdkVersion, new SdkVersion(androidVersion, frameworkSdkBuildVersion));
38      } else {
39        Logger.info("Android SDK %s not supported on JDK %s (it requires %s)", sdkVersion, jdkVersion, minJdkVersion);
40      }
41    }
42  });
43
44  public static final int FALLBACK_SDK_VERSION = Build.VERSION_CODES.JELLY_BEAN;
45  public static final int MAX_SDK_VERSION = Collections.max(getSupportedApis());
46
47  private final int apiLevel;
48  private final SdkVersion sdkVersion;
49
50  public static Set<Integer> getSupportedApis() {
51    return SUPPORTED_APIS.keySet();
52  }
53
54  public SdkConfig(int apiLevel) {
55    this.apiLevel = apiLevel;
56    sdkVersion = SUPPORTED_APIS.get(apiLevel);
57    if (sdkVersion == null) {
58      throw new UnsupportedOperationException("Robolectric does not support API level " + apiLevel + ".");
59    }
60  }
61
62  public int getApiLevel() {
63    return apiLevel;
64  }
65
66  public String getAndroidVersion() {
67    return sdkVersion.androidVersion;
68  }
69
70  public DependencyJar getAndroidSdkDependency() {
71    return createDependency("org.robolectric", "android-all", sdkVersion.toString(), null);
72  }
73
74  public DependencyJar getCoreShadowsDependency() {
75    return createDependency("org.robolectric", "shadows-core", ROBOLECTRIC_VERSION, null);
76  }
77
78  @Override
79  public boolean equals(Object that) {
80    return that == this || that instanceof SdkConfig && ((SdkConfig) that).sdkVersion.equals(sdkVersion);
81  }
82
83  @Override
84  public String toString() {
85    return "API Level " + apiLevel;
86  }
87
88  @Override
89  public int hashCode() {
90    return sdkVersion.hashCode();
91  }
92
93  @Override
94  public int compareTo(@NotNull SdkConfig o) {
95    return getApiLevel() - o.getApiLevel();
96  }
97
98  private DependencyJar createDependency(String groupId, String artifactId, String version, String classifier) {
99    return new DependencyJar(groupId, artifactId, version, classifier);
100  }
101
102  private static String getRobolectricVersion() {
103    ClassLoader classLoader = SdkVersion.class.getClassLoader();
104    try (InputStream is = classLoader.getResourceAsStream("robolectric-version.properties")) {
105      final Properties properties = new Properties();
106      properties.load(is);
107      return properties.getProperty("robolectric.version");
108    } catch (IOException e) {
109      throw new RuntimeException("Error determining Robolectric version: " + e.getMessage());
110    }
111  }
112
113  private static final class SdkVersion {
114    private final String androidVersion;
115    private final String robolectricVersion;
116
117    SdkVersion(String androidVersion, String robolectricVersion) {
118      this.androidVersion = androidVersion;
119      this.robolectricVersion = robolectricVersion;
120    }
121
122    @Override
123    public boolean equals(Object that) {
124      return that == this || that instanceof SdkVersion && equals((SdkVersion) that);
125    }
126
127    public boolean equals(SdkVersion that) {
128      return that == this ||
129          Objects.equals(that.androidVersion, androidVersion) &&
130              Objects.equals(that.robolectricVersion, robolectricVersion);
131    }
132
133    @Override
134    public int hashCode() {
135      return androidVersion.hashCode() * 31 + robolectricVersion.hashCode();
136    }
137
138    @Override
139    public String toString() {
140      return androidVersion + "-robolectric-" + robolectricVersion;
141    }
142  }
143}
144