1 package org.robolectric;
2 
3 import static android.os.Build.VERSION_CODES.LOLLIPOP;
4 
5 import android.app.Application;
6 import android.content.Context;
7 import android.content.res.Configuration;
8 import android.content.res.Resources;
9 import android.util.DisplayMetrics;
10 import org.robolectric.android.Bootstrap;
11 import org.robolectric.android.ConfigurationV25;
12 import org.robolectric.res.FsFile;
13 import org.robolectric.res.ResourceTable;
14 import org.robolectric.util.Scheduler;
15 import org.robolectric.util.TempDirectory;
16 
17 public class RuntimeEnvironment {
18   public static Context systemContext;
19 
20   /**
21    * @deprecated Please migrate to {@link
22    *     androidx.test.core.app.ApplicationProvider#getApplicationContext}
23    */
24   @Deprecated public static Application application;
25 
26   private volatile static Thread mainThread = Thread.currentThread();
27   private static Object activityThread;
28   private static int apiLevel;
29   private static Scheduler masterScheduler;
30   private static ResourceTable systemResourceTable;
31   private static ResourceTable appResourceTable;
32   private static ResourceTable compileTimeResourceTable;
33   private static TempDirectory tempDirectory = new TempDirectory("no-test-yet");
34   private static String androidFrameworkJar;
35   public static FsFile compileTimeSystemResourcesFile;
36 
37   private static boolean useLegacyResources;
38 
39   /**
40    * Tests if the given thread is currently set as the main thread.
41    *
42    * @param thread the thread to test.
43    * @return <tt>true</tt> if the specified thread is the main thread, <tt>false</tt> otherwise.
44    * @see #isMainThread()
45    */
isMainThread(Thread thread)46   public static boolean isMainThread(Thread thread) {
47     return thread == mainThread;
48   }
49 
50   /**
51    * Tests if the current thread is currently set as the main thread.
52    *
53    * @return <tt>true</tt> if the current thread is the main thread, <tt>false</tt> otherwise.
54    */
isMainThread()55   public static boolean isMainThread() {
56     return isMainThread(Thread.currentThread());
57   }
58 
59   /**
60    * Retrieves the main thread. The main thread is the thread to which the main looper is attached.
61    * Defaults to the thread that initialises the <tt>RuntimeEnvironment</tt> class.
62    *
63    * @return The main thread.
64    * @see #setMainThread(Thread)
65    * @see #isMainThread()
66    */
getMainThread()67   public static Thread getMainThread() {
68     return mainThread;
69   }
70 
71   /**
72    * Sets the main thread. The main thread is the thread to which the main looper is attached.
73    * Defaults to the thread that initialises the <tt>RuntimeEnvironment</tt> class.
74    *
75    * @param newMainThread the new main thread.
76    * @see #setMainThread(Thread)
77    * @see #isMainThread()
78    */
setMainThread(Thread newMainThread)79   public static void setMainThread(Thread newMainThread) {
80     mainThread = newMainThread;
81   }
82 
getActivityThread()83   public static Object getActivityThread() {
84     return activityThread;
85   }
86 
setActivityThread(Object newActivityThread)87   public static void setActivityThread(Object newActivityThread) {
88     activityThread = newActivityThread;
89   }
90 
91   /**
92    * Returns a qualifier string describing the current {@link Configuration} of the system resources.
93    *
94    * @return a qualifier string as described (https://developer.android.com/guide/topics/resources/providing-resources.html#QualifierRules)[here].
95    */
getQualifiers()96   public static String getQualifiers() {
97     Resources systemResources = Resources.getSystem();
98     return getQualifiers(systemResources.getConfiguration(), systemResources.getDisplayMetrics());
99   }
100 
101   /**
102    * Returns a qualifier string describing the given configuration and display metrics.
103    *
104    * @param configuration the configuration.
105    * @param displayMetrics the display metrics.
106    * @return a qualifier string as described (https://developer.android.com/guide/topics/resources/providing-resources.html#QualifierRules)[here].
107    */
getQualifiers(Configuration configuration, DisplayMetrics displayMetrics)108   public static String getQualifiers(Configuration configuration, DisplayMetrics displayMetrics) {
109     return ConfigurationV25.resourceQualifierString(configuration, displayMetrics);
110   }
111 
112   /**
113    * Overrides the current device configuration.
114    *
115    * If `newQualifiers` starts with a plus (`+`), the prior configuration is used as the base
116    * configuration, with the given changes applied additively. Otherwise, default values are used
117    * for unspecified properties, as described [here](http://robolectric.org/device-configuration/).
118    *
119    * @param newQualifiers the qualifiers to apply
120    */
setQualifiers(String newQualifiers)121   public static void setQualifiers(String newQualifiers) {
122     Configuration configuration;
123     DisplayMetrics displayMetrics = new DisplayMetrics();
124     if (newQualifiers.startsWith("+")) {
125       configuration = new Configuration(Resources.getSystem().getConfiguration());
126       displayMetrics.setTo(Resources.getSystem().getDisplayMetrics());
127     } else {
128       configuration = new Configuration();
129     }
130     Bootstrap.applyQualifiers(newQualifiers, getApiLevel(), configuration, displayMetrics);
131 
132     Resources systemResources = Resources.getSystem();
133     systemResources.updateConfiguration(configuration, displayMetrics);
134 
135     if (application != null) {
136       application.getResources().updateConfiguration(configuration, displayMetrics);
137     }
138   }
139 
getApiLevel()140   public static int getApiLevel() {
141     return apiLevel;
142   }
143 
castNativePtr(long ptr)144   public static Number castNativePtr(long ptr) {
145     // Weird, using a ternary here doesn't work, there's some auto promotion of boxed types happening.
146     if (getApiLevel() >= LOLLIPOP) {
147       return ptr;
148     } else {
149       return (int) ptr;
150     }
151   }
152 
153   /**
154    * Retrieves the current master scheduler. This scheduler is always used by the main
155    * {@link android.os.Looper Looper}, and if the global scheduler option is set it is also used for
156    * the background scheduler and for all other {@link android.os.Looper Looper}s
157    * @return The current master scheduler.
158    * @see #setMasterScheduler(Scheduler)
159    * see org.robolectric.Robolectric#getForegroundThreadScheduler()
160    * see org.robolectric.Robolectric#getBackgroundThreadScheduler()
161    */
getMasterScheduler()162   public static Scheduler getMasterScheduler() {
163     return masterScheduler;
164   }
165 
166   /**
167    * Sets the current master scheduler. See {@link #getMasterScheduler()} for details.
168    * Note that this method is primarily intended to be called by the Robolectric core setup code.
169    * Changing the master scheduler during a test will have unpredictable results.
170    * @param masterScheduler the new master scheduler.
171    * @see #getMasterScheduler()
172    * see org.robolectric.Robolectric#getForegroundThreadScheduler()
173    * see org.robolectric.Robolectric#getBackgroundThreadScheduler()
174    */
setMasterScheduler(Scheduler masterScheduler)175   public static void setMasterScheduler(Scheduler masterScheduler) {
176     RuntimeEnvironment.masterScheduler = masterScheduler;
177   }
178 
setSystemResourceTable(ResourceTable systemResourceTable)179   public static void setSystemResourceTable(ResourceTable systemResourceTable) {
180     RuntimeEnvironment.systemResourceTable = systemResourceTable;
181   }
182 
setAppResourceTable(ResourceTable appResourceTable)183   public static void setAppResourceTable(ResourceTable appResourceTable) {
184     RuntimeEnvironment.appResourceTable = appResourceTable;
185   }
186 
getSystemResourceTable()187   public static ResourceTable getSystemResourceTable() {
188     return systemResourceTable;
189   }
190 
getAppResourceTable()191   public static ResourceTable getAppResourceTable() {
192     return appResourceTable;
193   }
194 
setCompileTimeResourceTable(ResourceTable compileTimeResourceTable)195   public static void setCompileTimeResourceTable(ResourceTable compileTimeResourceTable) {
196     RuntimeEnvironment.compileTimeResourceTable = compileTimeResourceTable;
197   }
198 
getCompileTimeResourceTable()199   public static ResourceTable getCompileTimeResourceTable() {
200     return compileTimeResourceTable;
201   }
202 
setTempDirectory(TempDirectory tempDirectory)203   public static void setTempDirectory(TempDirectory tempDirectory) {
204     RuntimeEnvironment.tempDirectory = tempDirectory;
205   }
206 
getTempDirectory()207   public static TempDirectory getTempDirectory() {
208     return tempDirectory;
209   }
210 
setAndroidFrameworkJarPath(String localArtifactPath)211   public static void setAndroidFrameworkJarPath(String localArtifactPath) {
212     RuntimeEnvironment.androidFrameworkJar = localArtifactPath;
213   }
214 
getAndroidFrameworkJarPath()215   public static String getAndroidFrameworkJarPath() {
216     return RuntimeEnvironment.androidFrameworkJar;
217   }
218 
219   /**
220    * Internal only.
221    *
222    * @deprecated Do not use.
223    */
224   @Deprecated
useLegacyResources()225   public static boolean useLegacyResources() {
226     return useLegacyResources;
227   }
228 
229   /**
230    * Internal only.
231    *
232    * @deprecated Do not use.
233    */
234   @Deprecated
setUseLegacyResources(boolean useLegacyResources)235   public static void setUseLegacyResources(boolean useLegacyResources) {
236     RuntimeEnvironment.useLegacyResources = useLegacyResources;
237   }
238 }
239