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               // BEGIN-INTERNAL
33               addSdk(Build.VERSION_CODES.Q, "Q", "r0", "Q");
34               // END-INTERNAL
35             }
36 
37             private void addSdk(
38                 int sdkVersion,
39                 String androidVersion,
40                 String frameworkSdkBuildVersion,
41                 String codeName) {
42               put(sdkVersion, new SdkVersion(androidVersion, frameworkSdkBuildVersion, codeName));
43             }
44           });
45 
46   public static final int FALLBACK_SDK_VERSION = Build.VERSION_CODES.JELLY_BEAN;
47   public static final int MAX_SDK_VERSION = Collections.max(getSupportedApis());
48 
49   private final int apiLevel;
50 
getSupportedApis()51   public static Set<Integer> getSupportedApis() {
52     return SUPPORTED_APIS.keySet();
53   }
54 
getSupportedSdkConfigs()55   public static Collection<SdkConfig> getSupportedSdkConfigs() {
56     ArrayList<SdkConfig> sdkConfigs = new ArrayList<>();
57     for (int sdkVersion : getSupportedApis()) {
58       sdkConfigs.add(new SdkConfig(sdkVersion));
59     }
60     return sdkConfigs;
61   }
62 
SdkConfig(int apiLevel)63   public SdkConfig(int apiLevel) {
64     this.apiLevel = apiLevel;
65   }
66 
getApiLevel()67   public int getApiLevel() {
68     return apiLevel;
69   }
70 
getAndroidVersion()71   public String getAndroidVersion() {
72     return getSdkVersion().androidVersion;
73   }
74 
getAndroidCodeName()75   public String getAndroidCodeName() {
76     return getSdkVersion().codeName;
77   }
78 
getAndroidSdkDependency()79   public DependencyJar getAndroidSdkDependency() {
80     return createDependency("org.robolectric", "android-all", getSdkVersion().getAndroidVersion() + "-robolectric-" + getSdkVersion().getRobolectricVersion(), null);
81   }
82 
83   @Override
equals(Object that)84   public boolean equals(Object that) {
85     return that == this || (that instanceof SdkConfig && ((SdkConfig) that).apiLevel == (apiLevel));
86   }
87 
88   @Override
hashCode()89   public int hashCode() {
90     return apiLevel;
91   }
92 
93   @Override
toString()94   public String toString() {
95     return "API Level " + apiLevel;
96   }
97 
98   @Override
compareTo(@onnull SdkConfig o)99   public int compareTo(@Nonnull SdkConfig o) {
100     return apiLevel - o.apiLevel;
101   }
102 
getSdkVersion()103   private SdkVersion getSdkVersion() {
104     final SdkVersion sdkVersion = SUPPORTED_APIS.get(apiLevel);
105     if (sdkVersion == null) {
106       throw new UnsupportedOperationException("Robolectric does not support API level " + apiLevel + ".");
107     }
108     return sdkVersion;
109   }
110 
createDependency(String groupId, String artifactId, String version, String classifier)111   private DependencyJar createDependency(String groupId, String artifactId, String version, String classifier) {
112     return new DependencyJar(groupId, artifactId, version, classifier);
113   }
114 
115   private static final class SdkVersion {
116     private final String androidVersion;
117     private final String robolectricVersion;
118     private final String codeName;
119 
SdkVersion(String androidVersion, String robolectricVersion, String codeName)120     SdkVersion(String androidVersion, String robolectricVersion, String codeName) {
121       this.androidVersion = androidVersion;
122       this.robolectricVersion = robolectricVersion;
123       this.codeName = codeName;
124     }
125 
126     @Override
equals(Object that)127     public boolean equals(Object that) {
128       return that == this || (that instanceof SdkVersion && isEqualTo((SdkVersion) that));
129     }
130 
131     @SuppressWarnings("ReferenceEquality")
isEqualTo(SdkVersion that)132     public boolean isEqualTo(SdkVersion that) {
133       return that == this ||
134           (Objects.equals(that.androidVersion, androidVersion) &&
135               Objects.equals(that.robolectricVersion, robolectricVersion));
136     }
137 
138     @Override
hashCode()139     public int hashCode() {
140       return androidVersion.hashCode() * 31 + robolectricVersion.hashCode();
141     }
142 
getAndroidVersion()143     public String getAndroidVersion() {
144       return androidVersion;
145     }
146 
getRobolectricVersion()147     public String getRobolectricVersion() {
148       return robolectricVersion;
149     }
150   }
151 }
152