• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 package org.robolectric.android.plugins;
2 
3 import com.google.auto.service.AutoService;
4 
5 import org.robolectric.internal.dependency.DependencyResolver;
6 import org.robolectric.pluginapi.Sdk;
7 import org.robolectric.pluginapi.SdkProvider;
8 import org.robolectric.plugins.DefaultSdkProvider;
9 import org.robolectric.versioning.AndroidVersionInitTools;
10 import org.robolectric.versioning.AndroidVersions;
11 
12 import java.io.IOException;
13 import java.nio.file.Path;
14 import java.util.List;
15 import java.util.Map.Entry;
16 import java.util.TreeMap;
17 import java.util.jar.JarFile;
18 import java.util.stream.Collectors;
19 
20 import javax.annotation.Priority;
21 
22 import org.robolectric.util.Logger;
23 
24 @AutoService(SdkProvider.class)
25 @Priority(2)
26 public class AndroidLocalSdkProvider extends DefaultSdkProvider {
27 
28     static {
29       System.setProperty("robolectric.offline", "true");
30       Logger.info("Offline mode set by AndroidLocalSdkProvider.class");
31       System.setProperty("robolectric.usePreinstrumentedJars", "false");
32       Logger.info("Disable preinstrumented jars in AndroidLocalSdkProvider.class");
33     }
34 
35 
AndroidLocalSdkProvider(DependencyResolver dependencyResolver)36     public AndroidLocalSdkProvider(DependencyResolver dependencyResolver) {
37         super(dependencyResolver);
38     }
39 
40     /**
41      * In this method, a default known name for all android-all jars that are compiled in android's
42      * default build system, soong, and currently produced by /external/robolectric-shadows/android.b
43      */
findTargetJar()44     protected Path findTargetJar() throws IOException {
45         DefaultSdk localBuiltSdk = new DefaultSdk(10000, "current", "r0", "UpsideDownCake", getJdkVersion());
46         return localBuiltSdk.getJarPath();
47     }
48 
getJdkVersion()49     protected int getJdkVersion(){
50         String fullVersionStr = System.getProperty("java.version");
51         if (fullVersionStr != null) {
52             String[] parts = fullVersionStr.split("\\.");
53             String versionStr = parts[0];
54             if ("1".equals(parts[0]) && parts.length > 1) {
55                 versionStr = parts[1];
56             }
57             try {
58                 return Integer.parseInt(versionStr);
59             } catch (NumberFormatException ex) {
60                 throw new RuntimeException("Could not determine jdk version ", ex);
61             }
62         }
63         throw new RuntimeException("Could not determine jdk version");
64     }
65 
populateSdks(TreeMap<Integer, Sdk> knownSdks)66     protected void populateSdks(TreeMap<Integer, Sdk> knownSdks) {
67         try {
68             Path location = findTargetJar();
69             try {
70                 JarFile jarFile = new JarFile(location.toFile());
71                 final AndroidVersions.AndroidRelease release = AndroidVersionInitTools.computeReleaseVersion(jarFile);
72                 if (release != null) {
73                     DefaultSdk currentSdk = new ProvidedJarSdk(release.getSdkInt(), "current",
74                             release.getShortCode(), location);
75                     knownSdks.keySet()
76                             .stream()
77                             .filter(entry -> entry >= release.getSdkInt())
78                             .forEach(entry -> knownSdks.remove(entry));
79                     knownSdks.put(release.getSdkInt(), currentSdk);
80                 } else {
81                     throw new RuntimeException(
82                             "Could not read the version of the current android-all sdk"
83                                     + "this prevents robolectric from determining which shadows to apply.");
84                 }
85             } catch (IOException ioe) {
86                 throw new RuntimeException(
87                         "Could not read the version of the current android-all sdk"
88                                 + "this prevents robolectric from determining which shadows to apply.",
89                         ioe);
90             }
91         } catch (IOException ioe) {
92             throw new RuntimeException("Could not populate robolectric sdks as dynamic config failed", ioe);
93         }
94         super.populateSdks(knownSdks);
95     }
96 
97     /**
98      * Provides an sdk that is detected from a Jar path.
99      */
100     private class ProvidedJarSdk extends DefaultSdk {
101 
102         private Path mJarPath;
103 
ProvidedJarSdk(int apiLevel, String androidVersion, String codeName, Path jarPath)104         ProvidedJarSdk(int apiLevel, String androidVersion, String codeName, Path jarPath) {
105             super(apiLevel, androidVersion, "", codeName, getJdkVersion());
106             this.mJarPath = jarPath;
107         }
108 
109         @Override
getJarPath()110         public synchronized Path getJarPath() {
111             return mJarPath;
112         }
113     }
114 
115 }
116