1 package org.robolectric.internal;
2 
3 import android.os.Build;
4 import java.util.ArrayList;
5 import java.util.Collection;
6 import java.util.Collections;
7 import java.util.HashMap;
8 import java.util.Map;
9 import java.util.Objects;
10 import java.util.Set;
11 import javax.annotation.Nonnull;
12 import org.robolectric.internal.dependency.DependencyJar;
13 
14 public class SdkConfig implements Comparable<SdkConfig> {
15 
16   private static final Map<Integer, SdkVersion> SUPPORTED_APIS =
17       Collections.unmodifiableMap(
18           new HashMap<Integer, SdkVersion>() {
19             {
20               addSdk(Build.VERSION_CODES.JELLY_BEAN, "4.1.2_r1", "r1", "REL");
21               addSdk(Build.VERSION_CODES.JELLY_BEAN_MR1, "4.2.2_r1.2", "r1", "REL");
22               addSdk(Build.VERSION_CODES.JELLY_BEAN_MR2, "4.3_r2", "r1", "REL");
23               addSdk(Build.VERSION_CODES.KITKAT, "4.4_r1", "r2", "REL");
24               addSdk(Build.VERSION_CODES.LOLLIPOP, "5.0.2_r3", "r0", "REL");
25               addSdk(Build.VERSION_CODES.LOLLIPOP_MR1, "5.1.1_r9", "r2", "REL");
26               addSdk(Build.VERSION_CODES.M, "6.0.1_r3", "r1", "REL");
27               addSdk(Build.VERSION_CODES.N, "7.0.0_r1", "r1", "REL");
28               addSdk(Build.VERSION_CODES.N_MR1, "7.1.0_r7", "r1", "REL");
29               addSdk(Build.VERSION_CODES.O, "8.0.0_r4", "r1", "REL");
30               addSdk(Build.VERSION_CODES.O_MR1, "8.1.0", "4611349", "REL");
31               addSdk(Build.VERSION_CODES.P, "9", "4913185-2", "REL");
32               addSdk(Build.VERSION_CODES.Q, "10", "5803371", "REL");
33               // BEGIN-INTERNAL
34               // TODO: Update jar with final R release.
35               addSdk(Build.VERSION_CODES.R, "R-beta2", "6625208", "REL");
36               addSdk(Build.VERSION_CODES.S, "S", "r0", "S");
37               // END-INTERNAL
38             }
39 
40             private void addSdk(
41                 int sdkVersion,
42                 String androidVersion,
43                 String frameworkSdkBuildVersion,
44                 String codeName) {
45               put(sdkVersion, new SdkVersion(androidVersion, frameworkSdkBuildVersion, codeName));
46             }
47           });
48 
49   public static final int FALLBACK_SDK_VERSION = Build.VERSION_CODES.JELLY_BEAN;
50   public static final int MAX_SDK_VERSION = Collections.max(getSupportedApis());
51 
52   private final int apiLevel;
53 
getSupportedApis()54   public static Set<Integer> getSupportedApis() {
55     return SUPPORTED_APIS.keySet();
56   }
57 
getSupportedSdkConfigs()58   public static Collection<SdkConfig> getSupportedSdkConfigs() {
59     ArrayList<SdkConfig> sdkConfigs = new ArrayList<>();
60     for (int sdkVersion : getSupportedApis()) {
61       sdkConfigs.add(new SdkConfig(sdkVersion));
62     }
63     return sdkConfigs;
64   }
65 
SdkConfig(int apiLevel)66   public SdkConfig(int apiLevel) {
67     this.apiLevel = apiLevel;
68   }
69 
getApiLevel()70   public int getApiLevel() {
71     return apiLevel;
72   }
73 
getAndroidVersion()74   public String getAndroidVersion() {
75     return getSdkVersion().androidVersion;
76   }
77 
getAndroidCodeName()78   public String getAndroidCodeName() {
79     return getSdkVersion().codeName;
80   }
81 
getAndroidSdkDependency()82   public DependencyJar getAndroidSdkDependency() {
83     return createDependency("org.robolectric", "android-all", getSdkVersion().getAndroidVersion() + "-robolectric-" + getSdkVersion().getRobolectricVersion(), null);
84   }
85 
86   @Override
equals(Object that)87   public boolean equals(Object that) {
88     return that == this || (that instanceof SdkConfig && ((SdkConfig) that).apiLevel == (apiLevel));
89   }
90 
91   @Override
hashCode()92   public int hashCode() {
93     return apiLevel;
94   }
95 
96   @Override
toString()97   public String toString() {
98     return "API Level " + apiLevel;
99   }
100 
101   @Override
compareTo(@onnull SdkConfig o)102   public int compareTo(@Nonnull SdkConfig o) {
103     return apiLevel - o.apiLevel;
104   }
105 
getSdkVersion()106   private SdkVersion getSdkVersion() {
107     final SdkVersion sdkVersion = SUPPORTED_APIS.get(apiLevel);
108     if (sdkVersion == null) {
109       throw new UnsupportedOperationException("Robolectric does not support API level " + apiLevel + ".");
110     }
111     return sdkVersion;
112   }
113 
createDependency(String groupId, String artifactId, String version, String classifier)114   private DependencyJar createDependency(String groupId, String artifactId, String version, String classifier) {
115     return new DependencyJar(groupId, artifactId, version, classifier);
116   }
117 
118   private static final class SdkVersion {
119     private final String androidVersion;
120     private final String robolectricVersion;
121     private final String codeName;
122 
SdkVersion(String androidVersion, String robolectricVersion, String codeName)123     SdkVersion(String androidVersion, String robolectricVersion, String codeName) {
124       this.androidVersion = androidVersion;
125       this.robolectricVersion = robolectricVersion;
126       this.codeName = codeName;
127     }
128 
129     @Override
equals(Object that)130     public boolean equals(Object that) {
131       return that == this || (that instanceof SdkVersion && isEqualTo((SdkVersion) that));
132     }
133 
134     @SuppressWarnings("ReferenceEquality")
isEqualTo(SdkVersion that)135     public boolean isEqualTo(SdkVersion that) {
136       return that == this ||
137           (Objects.equals(that.androidVersion, androidVersion) &&
138               Objects.equals(that.robolectricVersion, robolectricVersion));
139     }
140 
141     @Override
hashCode()142     public int hashCode() {
143       return androidVersion.hashCode() * 31 + robolectricVersion.hashCode();
144     }
145 
getAndroidVersion()146     public String getAndroidVersion() {
147       return androidVersion;
148     }
149 
getRobolectricVersion()150     public String getRobolectricVersion() {
151       return robolectricVersion;
152     }
153   }
154 }
155