• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 package org.robolectric.android;
2 
3 import static android.content.res.Configuration.DENSITY_DPI_ANY;
4 import static android.content.res.Configuration.DENSITY_DPI_NONE;
5 import static android.content.res.Configuration.DENSITY_DPI_UNDEFINED;
6 
7 import android.content.res.Configuration;
8 import android.os.Build;
9 import android.os.Build.VERSION_CODES;
10 import android.os.LocaleList;
11 import android.text.TextUtils;
12 import android.util.DisplayMetrics;
13 import java.util.ArrayList;
14 import java.util.List;
15 import java.util.Locale;
16 import org.robolectric.RuntimeEnvironment;
17 
18 // adapted from https://android.googlesource.com/platform/frameworks/base/+/android-9.0.0_r12/core/java/android/content/res/Configuration.java
19 public class ConfigurationV25 {
20 
localesToResourceQualifier(List<Locale> locs)21   private static String localesToResourceQualifier(List<Locale> locs) {
22     final StringBuilder sb = new StringBuilder();
23     for (int i = 0; i < locs.size(); i++) {
24       final Locale loc = locs.get(i);
25       final int l = loc.getLanguage().length();
26       if (l == 0) {
27         continue;
28       }
29       final int s = loc.getScript().length();
30       final int c = loc.getCountry().length();
31       final int v = loc.getVariant().length();
32       // We ignore locale extensions, since they are not supported by AAPT
33 
34       if (sb.length() != 0) {
35         sb.append(",");
36       }
37       if (l == 2 && s == 0 && (c == 0 || c == 2) && v == 0) {
38         // Traditional locale format: xx or xx-rYY
39         sb.append(loc.getLanguage());
40         if (c == 2) {
41           sb.append("-r").append(loc.getCountry());
42         }
43       } else {
44         sb.append("b+");
45         sb.append(loc.getLanguage());
46         if (s != 0) {
47           sb.append("+");
48           sb.append(loc.getScript());
49         }
50         if (c != 0) {
51           sb.append("+");
52           sb.append(loc.getCountry());
53         }
54         if (v != 0) {
55           sb.append("+");
56           sb.append(loc.getVariant());
57         }
58       }
59     }
60     return sb.toString();
61   }
62 
resourceQualifierString( Configuration config, DisplayMetrics displayMetrics)63   public static String resourceQualifierString(
64       Configuration config, DisplayMetrics displayMetrics) {
65     ArrayList<String> parts = new ArrayList<String>();
66 
67     if (config.mcc != 0) {
68       parts.add("mcc" + config.mcc);
69       if (config.mnc != 0) {
70         parts.add("mnc" + config.mnc);
71       }
72     }
73 
74     List<Locale> locales = getLocales(config);
75     if (!locales.isEmpty()) {
76       final String resourceQualifier = localesToResourceQualifier(locales);
77       if (!resourceQualifier.isEmpty()) {
78         parts.add(resourceQualifier);
79       }
80     }
81 
82     switch (config.screenLayout & Configuration.SCREENLAYOUT_LAYOUTDIR_MASK) {
83       case Configuration.SCREENLAYOUT_LAYOUTDIR_LTR:
84         parts.add("ldltr");
85         break;
86       case Configuration.SCREENLAYOUT_LAYOUTDIR_RTL:
87         parts.add("ldrtl");
88         break;
89       default:
90         break;
91     }
92 
93     if (config.smallestScreenWidthDp != 0) {
94       parts.add("sw" + config.smallestScreenWidthDp + "dp");
95     }
96 
97     if (config.screenWidthDp != 0) {
98       parts.add("w" + config.screenWidthDp + "dp");
99     }
100 
101     if (config.screenHeightDp != 0) {
102       parts.add("h" + config.screenHeightDp + "dp");
103     }
104 
105     switch (config.screenLayout & Configuration.SCREENLAYOUT_SIZE_MASK) {
106       case Configuration.SCREENLAYOUT_SIZE_SMALL:
107         parts.add("small");
108         break;
109       case Configuration.SCREENLAYOUT_SIZE_NORMAL:
110         parts.add("normal");
111         break;
112       case Configuration.SCREENLAYOUT_SIZE_LARGE:
113         parts.add("large");
114         break;
115       case Configuration.SCREENLAYOUT_SIZE_XLARGE:
116         parts.add("xlarge");
117         break;
118       default:
119         break;
120     }
121 
122     switch (config.screenLayout & Configuration.SCREENLAYOUT_LONG_MASK) {
123       case Configuration.SCREENLAYOUT_LONG_YES:
124         parts.add("long");
125         break;
126       case Configuration.SCREENLAYOUT_LONG_NO:
127         parts.add("notlong");
128         break;
129       default:
130         break;
131     }
132 
133     switch (config.screenLayout & Configuration.SCREENLAYOUT_ROUND_MASK) {
134       case Configuration.SCREENLAYOUT_ROUND_YES:
135         parts.add("round");
136         break;
137       case Configuration.SCREENLAYOUT_ROUND_NO:
138         parts.add("notround");
139         break;
140       default:
141         break;
142     }
143 
144     if (RuntimeEnvironment.getApiLevel() >= VERSION_CODES.O) {
145       switch (config.colorMode & Configuration.COLOR_MODE_WIDE_COLOR_GAMUT_MASK) {
146         case Configuration.COLOR_MODE_WIDE_COLOR_GAMUT_YES:
147           parts.add("widecg");
148           break;
149         case Configuration.COLOR_MODE_WIDE_COLOR_GAMUT_NO:
150           parts.add("nowidecg");
151           break;
152         default:
153           break;
154       }
155 
156       switch (config.colorMode & Configuration.COLOR_MODE_HDR_MASK) {
157         case Configuration.COLOR_MODE_HDR_YES:
158           parts.add("highdr");
159           break;
160         case Configuration.COLOR_MODE_HDR_NO:
161           parts.add("lowdr");
162           break;
163         default:
164           break;
165       }
166     }
167 
168     switch (config.orientation) {
169       case Configuration.ORIENTATION_LANDSCAPE:
170         parts.add("land");
171         break;
172       case Configuration.ORIENTATION_PORTRAIT:
173         parts.add("port");
174         break;
175       default:
176         break;
177     }
178 
179     switch (config.uiMode & Configuration.UI_MODE_TYPE_MASK) {
180       case Configuration.UI_MODE_TYPE_APPLIANCE:
181         parts.add("appliance");
182         break;
183       case Configuration.UI_MODE_TYPE_DESK:
184         parts.add("desk");
185         break;
186       case Configuration.UI_MODE_TYPE_TELEVISION:
187         parts.add("television");
188         break;
189       case Configuration.UI_MODE_TYPE_CAR:
190         parts.add("car");
191         break;
192       case Configuration.UI_MODE_TYPE_WATCH:
193         parts.add("watch");
194         break;
195       case Configuration.UI_MODE_TYPE_VR_HEADSET:
196         parts.add("vrheadset");
197         break;
198       case Configuration.UI_MODE_TYPE_NORMAL:
199       default:
200         break;
201     }
202 
203     switch (config.uiMode & Configuration.UI_MODE_NIGHT_MASK) {
204       case Configuration.UI_MODE_NIGHT_YES:
205         parts.add("night");
206         break;
207       case Configuration.UI_MODE_NIGHT_NO:
208         parts.add("notnight");
209         break;
210       default:
211         break;
212     }
213 
214     int densityDpi = config.densityDpi;
215 
216     switch (densityDpi) {
217       case DENSITY_DPI_UNDEFINED:
218         break;
219       case 120:
220         parts.add("ldpi");
221         break;
222       case 160:
223         parts.add("mdpi");
224         break;
225       case 213:
226         parts.add("tvdpi");
227         break;
228       case 240:
229         parts.add("hdpi");
230         break;
231       case 320:
232         parts.add("xhdpi");
233         break;
234       case 480:
235         parts.add("xxhdpi");
236         break;
237       case 640:
238         parts.add("xxxhdpi");
239         break;
240       case DENSITY_DPI_ANY:
241         parts.add("anydpi");
242         break;
243       case DENSITY_DPI_NONE:
244         parts.add("nodpi");
245         break;
246       default:
247         parts.add(densityDpi + "dpi");
248         break;
249     }
250 
251     switch (config.touchscreen) {
252       case Configuration.TOUCHSCREEN_NOTOUCH:
253         parts.add("notouch");
254         break;
255       case Configuration.TOUCHSCREEN_FINGER:
256         parts.add("finger");
257         break;
258       default:
259         break;
260     }
261 
262     switch (config.keyboardHidden) {
263       case Configuration.KEYBOARDHIDDEN_NO:
264         parts.add("keysexposed");
265         break;
266       case Configuration.KEYBOARDHIDDEN_YES:
267         parts.add("keyshidden");
268         break;
269       case Configuration.KEYBOARDHIDDEN_SOFT:
270         parts.add("keyssoft");
271         break;
272       default:
273         break;
274     }
275 
276     switch (config.keyboard) {
277       case Configuration.KEYBOARD_NOKEYS:
278         parts.add("nokeys");
279         break;
280       case Configuration.KEYBOARD_QWERTY:
281         parts.add("qwerty");
282         break;
283       case Configuration.KEYBOARD_12KEY:
284         parts.add("12key");
285         break;
286       default:
287         break;
288     }
289 
290     switch (config.navigationHidden) {
291       case Configuration.NAVIGATIONHIDDEN_NO:
292         parts.add("navexposed");
293         break;
294       case Configuration.NAVIGATIONHIDDEN_YES:
295         parts.add("navhidden");
296         break;
297       default:
298         break;
299     }
300 
301     switch (config.navigation) {
302       case Configuration.NAVIGATION_NONAV:
303         parts.add("nonav");
304         break;
305       case Configuration.NAVIGATION_DPAD:
306         parts.add("dpad");
307         break;
308       case Configuration.NAVIGATION_TRACKBALL:
309         parts.add("trackball");
310         break;
311       case Configuration.NAVIGATION_WHEEL:
312         parts.add("wheel");
313         break;
314       default:
315         break;
316     }
317 
318     return TextUtils.join("-", parts);
319   }
320 
getLocales(Configuration config)321   private static List<Locale> getLocales(Configuration config) {
322     List<Locale> locales = new ArrayList<>();
323     if (RuntimeEnvironment.getApiLevel() > Build.VERSION_CODES.M) {
324       LocaleList localeList = config.getLocales();
325       for (int i = 0; i < localeList.size(); i++) {
326         locales.add(localeList.get(i));
327       }
328     } else if (config.locale != null) {
329       locales.add(config.locale);
330     }
331     return locales;
332   }
333 }
334