blob: cf2fd6f59b87ab59c3b7f995232237dd78f11d61 [file] [log] [blame]
Adam Lesinski6f6ceb72014-11-14 14:48:12 -08001/*
2 * Copyright (C) 2015 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
Mårten Kongstad5c541f62018-06-20 08:46:41 +020017#include "androidfw/ConfigDescription.h"
18#include "androidfw/Locale.h"
19#include "androidfw/ResourceTypes.h"
20#include "androidfw/StringPiece.h"
21#include "androidfw/Util.h"
Adam Lesinskice5e56e2016-10-21 17:56:45 -070022
23#include <string>
Yurii Zubrytskyi02d89192023-01-04 08:44:34 -080024#include <string_view>
Adam Lesinskice5e56e2016-10-21 17:56:45 -070025#include <vector>
26
Mårten Kongstad5c541f62018-06-20 08:46:41 +020027namespace android {
Adam Lesinski6f6ceb72014-11-14 14:48:12 -080028
29static const char* kWildcardName = "any";
30
Adam Lesinskice5e56e2016-10-21 17:56:45 -070031const ConfigDescription& ConfigDescription::DefaultConfig() {
Adam Lesinskicacb28f2016-10-19 12:18:14 -070032 static ConfigDescription config = {};
33 return config;
Adam Lesinski52364f72016-01-11 13:10:24 -080034}
35
Adam Lesinski6f6ceb72014-11-14 14:48:12 -080036static bool parseMcc(const char* name, ResTable_config* out) {
Adam Lesinskicacb28f2016-10-19 12:18:14 -070037 if (strcmp(name, kWildcardName) == 0) {
38 if (out) out->mcc = 0;
39 return true;
40 }
41 const char* c = name;
Yurii Zubrytskyi02d89192023-01-04 08:44:34 -080042 if (*c != 'm') return false;
Adam Lesinskicacb28f2016-10-19 12:18:14 -070043 c++;
Yurii Zubrytskyi02d89192023-01-04 08:44:34 -080044 if (*c != 'c') return false;
Adam Lesinskicacb28f2016-10-19 12:18:14 -070045 c++;
Yurii Zubrytskyi02d89192023-01-04 08:44:34 -080046 if (*c != 'c') return false;
Adam Lesinskicacb28f2016-10-19 12:18:14 -070047 c++;
48
49 const char* val = c;
50
51 while (*c >= '0' && *c <= '9') {
Adam Lesinski6f6ceb72014-11-14 14:48:12 -080052 c++;
Adam Lesinskicacb28f2016-10-19 12:18:14 -070053 }
54 if (*c != 0) return false;
55 if (c - val != 3) return false;
Adam Lesinski6f6ceb72014-11-14 14:48:12 -080056
Adam Lesinskicacb28f2016-10-19 12:18:14 -070057 int d = atoi(val);
58 if (d != 0) {
59 if (out) out->mcc = d;
60 return true;
61 }
Adam Lesinski6f6ceb72014-11-14 14:48:12 -080062
Adam Lesinskicacb28f2016-10-19 12:18:14 -070063 return false;
Adam Lesinski6f6ceb72014-11-14 14:48:12 -080064}
65
66static bool parseMnc(const char* name, ResTable_config* out) {
Adam Lesinskicacb28f2016-10-19 12:18:14 -070067 if (strcmp(name, kWildcardName) == 0) {
Adam Lesinski13c0c742017-08-07 10:32:18 -070068 if (out) out->mnc = 0;
Adam Lesinski6f6ceb72014-11-14 14:48:12 -080069 return true;
Adam Lesinskicacb28f2016-10-19 12:18:14 -070070 }
71 const char* c = name;
Yurii Zubrytskyi02d89192023-01-04 08:44:34 -080072 if (*c != 'm') return false;
Adam Lesinskicacb28f2016-10-19 12:18:14 -070073 c++;
Yurii Zubrytskyi02d89192023-01-04 08:44:34 -080074 if (*c != 'n') return false;
Adam Lesinskicacb28f2016-10-19 12:18:14 -070075 c++;
Yurii Zubrytskyi02d89192023-01-04 08:44:34 -080076 if (*c != 'c') return false;
Adam Lesinskicacb28f2016-10-19 12:18:14 -070077 c++;
78
79 const char* val = c;
80
81 while (*c >= '0' && *c <= '9') {
82 c++;
83 }
84 if (*c != 0) return false;
85 if (c - val == 0 || c - val > 3) return false;
86
87 if (out) {
88 out->mnc = atoi(val);
89 if (out->mnc == 0) {
90 out->mnc = ACONFIGURATION_MNC_ZERO;
91 }
92 }
93
94 return true;
Adam Lesinski6f6ceb72014-11-14 14:48:12 -080095}
96
Yurii Zubrytskyi02d89192023-01-04 08:44:34 -080097static bool parseGrammaticalInflection(const std::string& name, ResTable_config* out) {
98 using namespace std::literals;
99 if (name == "feminine"sv) {
100 if (out) out->grammaticalInflection = ResTable_config::GRAMMATICAL_GENDER_FEMININE;
101 return true;
102 }
103 if (name == "masculine"sv) {
104 if (out) out->grammaticalInflection = ResTable_config::GRAMMATICAL_GENDER_MASCULINE;
105 return true;
106 }
107 if (name == "neuter"sv) {
108 if (out) out->grammaticalInflection = ResTable_config::GRAMMATICAL_GENDER_NEUTER;
109 return true;
110 }
111 return false;
112}
113
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800114static bool parseLayoutDirection(const char* name, ResTable_config* out) {
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700115 if (strcmp(name, kWildcardName) == 0) {
116 if (out)
117 out->screenLayout =
118 (out->screenLayout & ~ResTable_config::MASK_LAYOUTDIR) |
119 ResTable_config::LAYOUTDIR_ANY;
120 return true;
121 } else if (strcmp(name, "ldltr") == 0) {
122 if (out)
123 out->screenLayout =
124 (out->screenLayout & ~ResTable_config::MASK_LAYOUTDIR) |
125 ResTable_config::LAYOUTDIR_LTR;
126 return true;
127 } else if (strcmp(name, "ldrtl") == 0) {
128 if (out)
129 out->screenLayout =
130 (out->screenLayout & ~ResTable_config::MASK_LAYOUTDIR) |
131 ResTable_config::LAYOUTDIR_RTL;
132 return true;
133 }
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800134
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700135 return false;
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800136}
137
138static bool parseScreenLayoutSize(const char* name, ResTable_config* out) {
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700139 if (strcmp(name, kWildcardName) == 0) {
140 if (out)
141 out->screenLayout =
142 (out->screenLayout & ~ResTable_config::MASK_SCREENSIZE) |
143 ResTable_config::SCREENSIZE_ANY;
144 return true;
145 } else if (strcmp(name, "small") == 0) {
146 if (out)
147 out->screenLayout =
148 (out->screenLayout & ~ResTable_config::MASK_SCREENSIZE) |
149 ResTable_config::SCREENSIZE_SMALL;
150 return true;
151 } else if (strcmp(name, "normal") == 0) {
152 if (out)
153 out->screenLayout =
154 (out->screenLayout & ~ResTable_config::MASK_SCREENSIZE) |
155 ResTable_config::SCREENSIZE_NORMAL;
156 return true;
157 } else if (strcmp(name, "large") == 0) {
158 if (out)
159 out->screenLayout =
160 (out->screenLayout & ~ResTable_config::MASK_SCREENSIZE) |
161 ResTable_config::SCREENSIZE_LARGE;
162 return true;
163 } else if (strcmp(name, "xlarge") == 0) {
164 if (out)
165 out->screenLayout =
166 (out->screenLayout & ~ResTable_config::MASK_SCREENSIZE) |
167 ResTable_config::SCREENSIZE_XLARGE;
168 return true;
169 }
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800170
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700171 return false;
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800172}
173
174static bool parseScreenLayoutLong(const char* name, ResTable_config* out) {
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700175 if (strcmp(name, kWildcardName) == 0) {
176 if (out)
177 out->screenLayout =
178 (out->screenLayout & ~ResTable_config::MASK_SCREENLONG) |
179 ResTable_config::SCREENLONG_ANY;
180 return true;
181 } else if (strcmp(name, "long") == 0) {
182 if (out)
183 out->screenLayout =
184 (out->screenLayout & ~ResTable_config::MASK_SCREENLONG) |
185 ResTable_config::SCREENLONG_YES;
186 return true;
187 } else if (strcmp(name, "notlong") == 0) {
188 if (out)
189 out->screenLayout =
190 (out->screenLayout & ~ResTable_config::MASK_SCREENLONG) |
191 ResTable_config::SCREENLONG_NO;
192 return true;
193 }
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800194
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700195 return false;
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800196}
197
Adam Lesinski64254972015-11-03 16:16:17 -0800198static bool parseScreenRound(const char* name, ResTable_config* out) {
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700199 if (strcmp(name, kWildcardName) == 0) {
200 if (out)
201 out->screenLayout2 =
202 (out->screenLayout2 & ~ResTable_config::MASK_SCREENROUND) |
203 ResTable_config::SCREENROUND_ANY;
204 return true;
205 } else if (strcmp(name, "round") == 0) {
206 if (out)
207 out->screenLayout2 =
208 (out->screenLayout2 & ~ResTable_config::MASK_SCREENROUND) |
209 ResTable_config::SCREENROUND_YES;
210 return true;
211 } else if (strcmp(name, "notround") == 0) {
212 if (out)
213 out->screenLayout2 =
214 (out->screenLayout2 & ~ResTable_config::MASK_SCREENROUND) |
215 ResTable_config::SCREENROUND_NO;
216 return true;
217 }
218 return false;
Adam Lesinski64254972015-11-03 16:16:17 -0800219}
220
Romain Guyc9ba5592017-01-18 16:34:42 -0800221static bool parseWideColorGamut(const char* name, ResTable_config* out) {
222 if (strcmp(name, kWildcardName) == 0) {
223 if (out)
Romain Guy4832745b2017-01-23 17:03:35 -0800224 out->colorMode =
225 (out->colorMode & ~ResTable_config::MASK_WIDE_COLOR_GAMUT) |
Romain Guyc9ba5592017-01-18 16:34:42 -0800226 ResTable_config::WIDE_COLOR_GAMUT_ANY;
227 return true;
228 } else if (strcmp(name, "widecg") == 0) {
229 if (out)
Romain Guy4832745b2017-01-23 17:03:35 -0800230 out->colorMode =
231 (out->colorMode & ~ResTable_config::MASK_WIDE_COLOR_GAMUT) |
Romain Guyc9ba5592017-01-18 16:34:42 -0800232 ResTable_config::WIDE_COLOR_GAMUT_YES;
233 return true;
234 } else if (strcmp(name, "nowidecg") == 0) {
235 if (out)
Romain Guy4832745b2017-01-23 17:03:35 -0800236 out->colorMode =
237 (out->colorMode & ~ResTable_config::MASK_WIDE_COLOR_GAMUT) |
Romain Guyc9ba5592017-01-18 16:34:42 -0800238 ResTable_config::WIDE_COLOR_GAMUT_NO;
239 return true;
240 }
241 return false;
242}
243
244static bool parseHdr(const char* name, ResTable_config* out) {
245 if (strcmp(name, kWildcardName) == 0) {
246 if (out)
Romain Guy4832745b2017-01-23 17:03:35 -0800247 out->colorMode =
248 (out->colorMode & ~ResTable_config::MASK_HDR) |
Romain Guyc9ba5592017-01-18 16:34:42 -0800249 ResTable_config::HDR_ANY;
250 return true;
251 } else if (strcmp(name, "highdr") == 0) {
252 if (out)
Romain Guy4832745b2017-01-23 17:03:35 -0800253 out->colorMode =
254 (out->colorMode & ~ResTable_config::MASK_HDR) |
Romain Guyc9ba5592017-01-18 16:34:42 -0800255 ResTable_config::HDR_YES;
256 return true;
257 } else if (strcmp(name, "lowdr") == 0) {
258 if (out)
Romain Guy4832745b2017-01-23 17:03:35 -0800259 out->colorMode =
260 (out->colorMode & ~ResTable_config::MASK_HDR) |
Romain Guyc9ba5592017-01-18 16:34:42 -0800261 ResTable_config::HDR_NO;
262 return true;
263 }
264 return false;
265}
266
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800267static bool parseOrientation(const char* name, ResTable_config* out) {
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700268 if (strcmp(name, kWildcardName) == 0) {
269 if (out) out->orientation = out->ORIENTATION_ANY;
270 return true;
271 } else if (strcmp(name, "port") == 0) {
272 if (out) out->orientation = out->ORIENTATION_PORT;
273 return true;
274 } else if (strcmp(name, "land") == 0) {
275 if (out) out->orientation = out->ORIENTATION_LAND;
276 return true;
277 } else if (strcmp(name, "square") == 0) {
278 if (out) out->orientation = out->ORIENTATION_SQUARE;
279 return true;
280 }
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800281
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700282 return false;
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800283}
284
285static bool parseUiModeType(const char* name, ResTable_config* out) {
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700286 if (strcmp(name, kWildcardName) == 0) {
287 if (out)
288 out->uiMode = (out->uiMode & ~ResTable_config::MASK_UI_MODE_TYPE) |
289 ResTable_config::UI_MODE_TYPE_ANY;
290 return true;
291 } else if (strcmp(name, "desk") == 0) {
292 if (out)
293 out->uiMode = (out->uiMode & ~ResTable_config::MASK_UI_MODE_TYPE) |
294 ResTable_config::UI_MODE_TYPE_DESK;
295 return true;
296 } else if (strcmp(name, "car") == 0) {
297 if (out)
298 out->uiMode = (out->uiMode & ~ResTable_config::MASK_UI_MODE_TYPE) |
299 ResTable_config::UI_MODE_TYPE_CAR;
300 return true;
301 } else if (strcmp(name, "television") == 0) {
302 if (out)
303 out->uiMode = (out->uiMode & ~ResTable_config::MASK_UI_MODE_TYPE) |
304 ResTable_config::UI_MODE_TYPE_TELEVISION;
305 return true;
306 } else if (strcmp(name, "appliance") == 0) {
307 if (out)
308 out->uiMode = (out->uiMode & ~ResTable_config::MASK_UI_MODE_TYPE) |
309 ResTable_config::UI_MODE_TYPE_APPLIANCE;
310 return true;
311 } else if (strcmp(name, "watch") == 0) {
312 if (out)
313 out->uiMode = (out->uiMode & ~ResTable_config::MASK_UI_MODE_TYPE) |
314 ResTable_config::UI_MODE_TYPE_WATCH;
315 return true;
Zak Cohen1a6acdb2016-12-12 15:21:21 -0800316 } else if (strcmp(name, "vrheadset") == 0) {
317 if (out)
318 out->uiMode = (out->uiMode & ~ResTable_config::MASK_UI_MODE_TYPE) |
319 ResTable_config::UI_MODE_TYPE_VR_HEADSET;
320 return true;
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700321 }
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800322
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700323 return false;
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800324}
325
326static bool parseUiModeNight(const char* name, ResTable_config* out) {
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700327 if (strcmp(name, kWildcardName) == 0) {
328 if (out)
329 out->uiMode = (out->uiMode & ~ResTable_config::MASK_UI_MODE_NIGHT) |
330 ResTable_config::UI_MODE_NIGHT_ANY;
331 return true;
332 } else if (strcmp(name, "night") == 0) {
333 if (out)
334 out->uiMode = (out->uiMode & ~ResTable_config::MASK_UI_MODE_NIGHT) |
335 ResTable_config::UI_MODE_NIGHT_YES;
336 return true;
337 } else if (strcmp(name, "notnight") == 0) {
338 if (out)
339 out->uiMode = (out->uiMode & ~ResTable_config::MASK_UI_MODE_NIGHT) |
340 ResTable_config::UI_MODE_NIGHT_NO;
341 return true;
342 }
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800343
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700344 return false;
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800345}
346
347static bool parseDensity(const char* name, ResTable_config* out) {
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700348 if (strcmp(name, kWildcardName) == 0) {
349 if (out) out->density = ResTable_config::DENSITY_DEFAULT;
350 return true;
351 }
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800352
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700353 if (strcmp(name, "anydpi") == 0) {
354 if (out) out->density = ResTable_config::DENSITY_ANY;
355 return true;
356 }
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800357
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700358 if (strcmp(name, "nodpi") == 0) {
359 if (out) out->density = ResTable_config::DENSITY_NONE;
360 return true;
361 }
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800362
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700363 if (strcmp(name, "ldpi") == 0) {
364 if (out) out->density = ResTable_config::DENSITY_LOW;
365 return true;
366 }
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800367
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700368 if (strcmp(name, "mdpi") == 0) {
369 if (out) out->density = ResTable_config::DENSITY_MEDIUM;
370 return true;
371 }
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800372
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700373 if (strcmp(name, "tvdpi") == 0) {
374 if (out) out->density = ResTable_config::DENSITY_TV;
375 return true;
376 }
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800377
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700378 if (strcmp(name, "hdpi") == 0) {
379 if (out) out->density = ResTable_config::DENSITY_HIGH;
380 return true;
381 }
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800382
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700383 if (strcmp(name, "xhdpi") == 0) {
384 if (out) out->density = ResTable_config::DENSITY_XHIGH;
385 return true;
386 }
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800387
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700388 if (strcmp(name, "xxhdpi") == 0) {
389 if (out) out->density = ResTable_config::DENSITY_XXHIGH;
390 return true;
391 }
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800392
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700393 if (strcmp(name, "xxxhdpi") == 0) {
394 if (out) out->density = ResTable_config::DENSITY_XXXHIGH;
395 return true;
396 }
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800397
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700398 char* c = (char*)name;
399 while (*c >= '0' && *c <= '9') {
400 c++;
401 }
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800402
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700403 // check that we have 'dpi' after the last digit.
404 if (toupper(c[0]) != 'D' || toupper(c[1]) != 'P' || toupper(c[2]) != 'I' ||
405 c[3] != 0) {
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800406 return false;
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700407 }
408
409 // temporarily replace the first letter with \0 to
410 // use atoi.
411 char tmp = c[0];
412 c[0] = '\0';
413
414 int d = atoi(name);
415 c[0] = tmp;
416
417 if (d != 0) {
418 if (out) out->density = d;
419 return true;
420 }
421
422 return false;
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800423}
424
425static bool parseTouchscreen(const char* name, ResTable_config* out) {
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700426 if (strcmp(name, kWildcardName) == 0) {
427 if (out) out->touchscreen = out->TOUCHSCREEN_ANY;
428 return true;
429 } else if (strcmp(name, "notouch") == 0) {
430 if (out) out->touchscreen = out->TOUCHSCREEN_NOTOUCH;
431 return true;
432 } else if (strcmp(name, "stylus") == 0) {
433 if (out) out->touchscreen = out->TOUCHSCREEN_STYLUS;
434 return true;
435 } else if (strcmp(name, "finger") == 0) {
436 if (out) out->touchscreen = out->TOUCHSCREEN_FINGER;
437 return true;
438 }
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800439
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700440 return false;
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800441}
442
443static bool parseKeysHidden(const char* name, ResTable_config* out) {
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700444 uint8_t mask = 0;
445 uint8_t value = 0;
446 if (strcmp(name, kWildcardName) == 0) {
447 mask = ResTable_config::MASK_KEYSHIDDEN;
448 value = ResTable_config::KEYSHIDDEN_ANY;
449 } else if (strcmp(name, "keysexposed") == 0) {
450 mask = ResTable_config::MASK_KEYSHIDDEN;
451 value = ResTable_config::KEYSHIDDEN_NO;
452 } else if (strcmp(name, "keyshidden") == 0) {
453 mask = ResTable_config::MASK_KEYSHIDDEN;
454 value = ResTable_config::KEYSHIDDEN_YES;
455 } else if (strcmp(name, "keyssoft") == 0) {
456 mask = ResTable_config::MASK_KEYSHIDDEN;
457 value = ResTable_config::KEYSHIDDEN_SOFT;
458 }
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800459
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700460 if (mask != 0) {
461 if (out) out->inputFlags = (out->inputFlags & ~mask) | value;
462 return true;
463 }
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800464
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700465 return false;
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800466}
467
468static bool parseKeyboard(const char* name, ResTable_config* out) {
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700469 if (strcmp(name, kWildcardName) == 0) {
470 if (out) out->keyboard = out->KEYBOARD_ANY;
471 return true;
472 } else if (strcmp(name, "nokeys") == 0) {
473 if (out) out->keyboard = out->KEYBOARD_NOKEYS;
474 return true;
475 } else if (strcmp(name, "qwerty") == 0) {
476 if (out) out->keyboard = out->KEYBOARD_QWERTY;
477 return true;
478 } else if (strcmp(name, "12key") == 0) {
479 if (out) out->keyboard = out->KEYBOARD_12KEY;
480 return true;
481 }
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800482
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700483 return false;
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800484}
485
486static bool parseNavHidden(const char* name, ResTable_config* out) {
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700487 uint8_t mask = 0;
488 uint8_t value = 0;
489 if (strcmp(name, kWildcardName) == 0) {
490 mask = ResTable_config::MASK_NAVHIDDEN;
491 value = ResTable_config::NAVHIDDEN_ANY;
492 } else if (strcmp(name, "navexposed") == 0) {
493 mask = ResTable_config::MASK_NAVHIDDEN;
494 value = ResTable_config::NAVHIDDEN_NO;
495 } else if (strcmp(name, "navhidden") == 0) {
496 mask = ResTable_config::MASK_NAVHIDDEN;
497 value = ResTable_config::NAVHIDDEN_YES;
498 }
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800499
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700500 if (mask != 0) {
501 if (out) out->inputFlags = (out->inputFlags & ~mask) | value;
502 return true;
503 }
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800504
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700505 return false;
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800506}
507
508static bool parseNavigation(const char* name, ResTable_config* out) {
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700509 if (strcmp(name, kWildcardName) == 0) {
510 if (out) out->navigation = out->NAVIGATION_ANY;
511 return true;
512 } else if (strcmp(name, "nonav") == 0) {
513 if (out) out->navigation = out->NAVIGATION_NONAV;
514 return true;
515 } else if (strcmp(name, "dpad") == 0) {
516 if (out) out->navigation = out->NAVIGATION_DPAD;
517 return true;
518 } else if (strcmp(name, "trackball") == 0) {
519 if (out) out->navigation = out->NAVIGATION_TRACKBALL;
520 return true;
521 } else if (strcmp(name, "wheel") == 0) {
522 if (out) out->navigation = out->NAVIGATION_WHEEL;
523 return true;
524 }
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800525
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700526 return false;
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800527}
528
529static bool parseScreenSize(const char* name, ResTable_config* out) {
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700530 if (strcmp(name, kWildcardName) == 0) {
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800531 if (out) {
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700532 out->screenWidth = out->SCREENWIDTH_ANY;
533 out->screenHeight = out->SCREENHEIGHT_ANY;
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800534 }
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800535 return true;
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700536 }
537
538 const char* x = name;
539 while (*x >= '0' && *x <= '9') x++;
540 if (x == name || *x != 'x') return false;
541 std::string xName(name, x - name);
542 x++;
543
544 const char* y = x;
545 while (*y >= '0' && *y <= '9') y++;
546 if (y == name || *y != 0) return false;
547 std::string yName(x, y - x);
548
549 uint16_t w = (uint16_t)atoi(xName.c_str());
550 uint16_t h = (uint16_t)atoi(yName.c_str());
551 if (w < h) {
552 return false;
553 }
554
555 if (out) {
556 out->screenWidth = w;
557 out->screenHeight = h;
558 }
559
560 return true;
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800561}
562
563static bool parseSmallestScreenWidthDp(const char* name, ResTable_config* out) {
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700564 if (strcmp(name, kWildcardName) == 0) {
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800565 if (out) {
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700566 out->smallestScreenWidthDp = out->SCREENWIDTH_ANY;
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800567 }
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800568 return true;
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700569 }
570
571 if (*name != 's') return false;
572 name++;
573 if (*name != 'w') return false;
574 name++;
575 const char* x = name;
576 while (*x >= '0' && *x <= '9') x++;
577 if (x == name || x[0] != 'd' || x[1] != 'p' || x[2] != 0) return false;
578 std::string xName(name, x - name);
579
580 if (out) {
581 out->smallestScreenWidthDp = (uint16_t)atoi(xName.c_str());
582 }
583
584 return true;
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800585}
586
587static bool parseScreenWidthDp(const char* name, ResTable_config* out) {
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700588 if (strcmp(name, kWildcardName) == 0) {
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800589 if (out) {
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700590 out->screenWidthDp = out->SCREENWIDTH_ANY;
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800591 }
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800592 return true;
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700593 }
594
595 if (*name != 'w') return false;
596 name++;
597 const char* x = name;
598 while (*x >= '0' && *x <= '9') x++;
599 if (x == name || x[0] != 'd' || x[1] != 'p' || x[2] != 0) return false;
600 std::string xName(name, x - name);
601
602 if (out) {
603 out->screenWidthDp = (uint16_t)atoi(xName.c_str());
604 }
605
606 return true;
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800607}
608
609static bool parseScreenHeightDp(const char* name, ResTable_config* out) {
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700610 if (strcmp(name, kWildcardName) == 0) {
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800611 if (out) {
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700612 out->screenHeightDp = out->SCREENWIDTH_ANY;
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800613 }
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800614 return true;
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700615 }
616
617 if (*name != 'h') return false;
618 name++;
619 const char* x = name;
620 while (*x >= '0' && *x <= '9') x++;
621 if (x == name || x[0] != 'd' || x[1] != 'p' || x[2] != 0) return false;
622 std::string xName(name, x - name);
623
624 if (out) {
625 out->screenHeightDp = (uint16_t)atoi(xName.c_str());
626 }
627
628 return true;
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800629}
630
631static bool parseVersion(const char* name, ResTable_config* out) {
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700632 if (strcmp(name, kWildcardName) == 0) {
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800633 if (out) {
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700634 out->sdkVersion = out->SDKVERSION_ANY;
635 out->minorVersion = out->MINORVERSION_ANY;
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800636 }
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800637 return true;
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700638 }
639
640 if (*name != 'v') {
641 return false;
642 }
643
644 name++;
645 const char* s = name;
646 while (*s >= '0' && *s <= '9') s++;
647 if (s == name || *s != 0) return false;
648 std::string sdkName(name, s - name);
649
650 if (out) {
651 out->sdkVersion = (uint16_t)atoi(sdkName.c_str());
652 out->minorVersion = 0;
653 }
654
655 return true;
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800656}
657
Yurii Zubrytskyia5775142022-11-02 17:49:49 -0700658bool ConfigDescription::Parse(StringPiece str, ConfigDescription* out) {
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700659 std::vector<std::string> parts = util::SplitAndLowercase(str, '-');
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800660
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700661 ConfigDescription config;
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700662 ssize_t parts_consumed = 0;
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700663 LocaleValue locale;
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800664
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700665 const auto parts_end = parts.end();
666 auto part_iter = parts.begin();
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800667
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700668 if (str.size() == 0) {
669 goto success;
670 }
671
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700672 if (parseMcc(part_iter->c_str(), &config)) {
673 ++part_iter;
674 if (part_iter == parts_end) {
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700675 goto success;
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800676 }
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700677 }
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800678
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700679 if (parseMnc(part_iter->c_str(), &config)) {
680 ++part_iter;
681 if (part_iter == parts_end) {
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700682 goto success;
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800683 }
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700684 }
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800685
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700686 // Locale spans a few '-' separators, so we let it
687 // control the index.
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700688 parts_consumed = locale.InitFromParts(part_iter, parts_end);
689 if (parts_consumed < 0) {
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800690 return false;
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700691 } else {
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700692 locale.WriteTo(&config);
693 part_iter += parts_consumed;
694 if (part_iter == parts_end) {
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700695 goto success;
696 }
697 }
698
Yurii Zubrytskyi02d89192023-01-04 08:44:34 -0800699 if (parseGrammaticalInflection(*part_iter, &config)) {
700 ++part_iter;
701 if (part_iter == parts_end) {
702 goto success;
703 }
704 }
705
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700706 if (parseLayoutDirection(part_iter->c_str(), &config)) {
707 ++part_iter;
708 if (part_iter == parts_end) {
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700709 goto success;
710 }
711 }
712
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700713 if (parseSmallestScreenWidthDp(part_iter->c_str(), &config)) {
714 ++part_iter;
715 if (part_iter == parts_end) {
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700716 goto success;
717 }
718 }
719
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700720 if (parseScreenWidthDp(part_iter->c_str(), &config)) {
721 ++part_iter;
722 if (part_iter == parts_end) {
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700723 goto success;
724 }
725 }
726
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700727 if (parseScreenHeightDp(part_iter->c_str(), &config)) {
728 ++part_iter;
729 if (part_iter == parts_end) {
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700730 goto success;
731 }
732 }
733
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700734 if (parseScreenLayoutSize(part_iter->c_str(), &config)) {
735 ++part_iter;
736 if (part_iter == parts_end) {
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700737 goto success;
738 }
739 }
740
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700741 if (parseScreenLayoutLong(part_iter->c_str(), &config)) {
742 ++part_iter;
743 if (part_iter == parts_end) {
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700744 goto success;
745 }
746 }
747
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700748 if (parseScreenRound(part_iter->c_str(), &config)) {
749 ++part_iter;
750 if (part_iter == parts_end) {
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700751 goto success;
752 }
753 }
754
Romain Guyc9ba5592017-01-18 16:34:42 -0800755 if (parseWideColorGamut(part_iter->c_str(), &config)) {
756 ++part_iter;
757 if (part_iter == parts_end) {
758 goto success;
759 }
760 }
761
762 if (parseHdr(part_iter->c_str(), &config)) {
763 ++part_iter;
764 if (part_iter == parts_end) {
765 goto success;
766 }
767 }
768
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700769 if (parseOrientation(part_iter->c_str(), &config)) {
770 ++part_iter;
771 if (part_iter == parts_end) {
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700772 goto success;
773 }
774 }
775
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700776 if (parseUiModeType(part_iter->c_str(), &config)) {
777 ++part_iter;
778 if (part_iter == parts_end) {
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700779 goto success;
780 }
781 }
782
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700783 if (parseUiModeNight(part_iter->c_str(), &config)) {
784 ++part_iter;
785 if (part_iter == parts_end) {
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700786 goto success;
787 }
788 }
789
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700790 if (parseDensity(part_iter->c_str(), &config)) {
791 ++part_iter;
792 if (part_iter == parts_end) {
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700793 goto success;
794 }
795 }
796
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700797 if (parseTouchscreen(part_iter->c_str(), &config)) {
798 ++part_iter;
799 if (part_iter == parts_end) {
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700800 goto success;
801 }
802 }
803
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700804 if (parseKeysHidden(part_iter->c_str(), &config)) {
805 ++part_iter;
806 if (part_iter == parts_end) {
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700807 goto success;
808 }
809 }
810
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700811 if (parseKeyboard(part_iter->c_str(), &config)) {
812 ++part_iter;
813 if (part_iter == parts_end) {
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700814 goto success;
815 }
816 }
817
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700818 if (parseNavHidden(part_iter->c_str(), &config)) {
819 ++part_iter;
820 if (part_iter == parts_end) {
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700821 goto success;
822 }
823 }
824
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700825 if (parseNavigation(part_iter->c_str(), &config)) {
826 ++part_iter;
827 if (part_iter == parts_end) {
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700828 goto success;
829 }
830 }
831
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700832 if (parseScreenSize(part_iter->c_str(), &config)) {
833 ++part_iter;
834 if (part_iter == parts_end) {
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700835 goto success;
836 }
837 }
838
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700839 if (parseVersion(part_iter->c_str(), &config)) {
840 ++part_iter;
841 if (part_iter == parts_end) {
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700842 goto success;
843 }
844 }
845
846 // Unrecognized.
847 return false;
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800848
849success:
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700850 if (out != NULL) {
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700851 ApplyVersionForCompatibility(&config);
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700852 *out = config;
853 }
854 return true;
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800855}
856
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700857void ConfigDescription::ApplyVersionForCompatibility(
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700858 ConfigDescription* config) {
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700859 uint16_t min_sdk = 0;
Yurii Zubrytskyi02d89192023-01-04 08:44:34 -0800860 if (config->grammaticalInflection != 0) {
861 min_sdk = SDK_U;
862 } else if ((config->uiMode & ResTable_config::MASK_UI_MODE_TYPE)
Romain Guyc9ba5592017-01-18 16:34:42 -0800863 == ResTable_config::UI_MODE_TYPE_VR_HEADSET ||
Romain Guy4832745b2017-01-23 17:03:35 -0800864 config->colorMode & ResTable_config::MASK_WIDE_COLOR_GAMUT ||
865 config->colorMode & ResTable_config::MASK_HDR) {
Yurii Zubrytskyi02d89192023-01-04 08:44:34 -0800866 min_sdk = SDK_O;
Zak Cohen1a6acdb2016-12-12 15:21:21 -0800867 } else if (config->screenLayout2 & ResTable_config::MASK_SCREENROUND) {
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700868 min_sdk = SDK_MARSHMALLOW;
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700869 } else if (config->density == ResTable_config::DENSITY_ANY) {
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700870 min_sdk = SDK_LOLLIPOP;
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700871 } else if (config->smallestScreenWidthDp !=
872 ResTable_config::SCREENWIDTH_ANY ||
873 config->screenWidthDp != ResTable_config::SCREENWIDTH_ANY ||
874 config->screenHeightDp != ResTable_config::SCREENHEIGHT_ANY) {
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700875 min_sdk = SDK_HONEYCOMB_MR2;
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700876 } else if ((config->uiMode & ResTable_config::MASK_UI_MODE_TYPE) !=
877 ResTable_config::UI_MODE_TYPE_ANY ||
878 (config->uiMode & ResTable_config::MASK_UI_MODE_NIGHT) !=
879 ResTable_config::UI_MODE_NIGHT_ANY) {
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700880 min_sdk = SDK_FROYO;
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700881 } else if ((config->screenLayout & ResTable_config::MASK_SCREENSIZE) !=
882 ResTable_config::SCREENSIZE_ANY ||
883 (config->screenLayout & ResTable_config::MASK_SCREENLONG) !=
884 ResTable_config::SCREENLONG_ANY ||
885 config->density != ResTable_config::DENSITY_DEFAULT) {
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700886 min_sdk = SDK_DONUT;
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700887 }
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800888
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700889 if (min_sdk > config->sdkVersion) {
890 config->sdkVersion = min_sdk;
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700891 }
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800892}
893
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700894ConfigDescription ConfigDescription::CopyWithoutSdkVersion() const {
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700895 ConfigDescription copy = *this;
896 copy.sdkVersion = 0;
897 return copy;
Adam Lesinski87675ad2016-07-15 17:03:03 -0700898}
899
Adam Lesinskib58c3ef2017-09-12 17:39:52 -0700900std::string ConfigDescription::GetBcp47LanguageTag(bool canonicalize) const {
901 char locale[RESTABLE_MAX_LOCALE_LEN];
902 getBcp47Locale(locale, canonicalize);
903 return std::string(locale);
904}
905
Adam Lesinski93190b72017-11-03 15:20:17 -0700906std::string ConfigDescription::to_string() const {
Mårten Kongstad5c541f62018-06-20 08:46:41 +0200907 const String8 str = toString();
Adam Lesinski93190b72017-11-03 15:20:17 -0700908 return std::string(str.string(), str.size());
909}
910
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700911bool ConfigDescription::Dominates(const ConfigDescription& o) const {
Adam Lesinskie3856742017-06-12 14:55:58 -0700912 if (*this == o) {
913 return true;
914 }
915
916 // Locale de-duping is not-trivial, disable for now (b/62409213).
Ryan Mitchell527ebba2020-10-30 12:32:47 -0700917 // We must also disable de-duping for all configuration qualifiers with precedence higher than
918 // locale (b/171892595)
919 if (diff(o) & (CONFIG_LOCALE | CONFIG_MCC | CONFIG_MNC)) {
Adam Lesinskie3856742017-06-12 14:55:58 -0700920 return false;
921 }
922
923 if (*this == DefaultConfig()) {
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700924 return true;
925 }
Ryan Mitchell527ebba2020-10-30 12:32:47 -0700926
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700927 return MatchWithDensity(o) && !o.MatchWithDensity(*this) &&
928 !isMoreSpecificThan(o) && !o.HasHigherPrecedenceThan(*this);
Alexandria Cornwall77788eb2016-09-06 15:16:49 -0700929}
930
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700931bool ConfigDescription::HasHigherPrecedenceThan(
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700932 const ConfigDescription& o) const {
933 // The order of the following tests defines the importance of one
934 // configuration parameter over another. Those tests first are more
935 // important, trumping any values in those following them.
936 // The ordering should be the same as ResTable_config#isBetterThan.
937 if (mcc || o.mcc) return (!o.mcc);
938 if (mnc || o.mnc) return (!o.mnc);
939 if (language[0] || o.language[0]) return (!o.language[0]);
940 if (country[0] || o.country[0]) return (!o.country[0]);
941 // Script and variant require either a language or country, both of which
942 // have higher precedence.
Yurii Zubrytskyi02d89192023-01-04 08:44:34 -0800943 if (grammaticalInflection || o.grammaticalInflection) return !o.grammaticalInflection;
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700944 if ((screenLayout | o.screenLayout) & MASK_LAYOUTDIR) {
945 return !(o.screenLayout & MASK_LAYOUTDIR);
946 }
947 if (smallestScreenWidthDp || o.smallestScreenWidthDp)
948 return (!o.smallestScreenWidthDp);
949 if (screenWidthDp || o.screenWidthDp) return (!o.screenWidthDp);
950 if (screenHeightDp || o.screenHeightDp) return (!o.screenHeightDp);
951 if ((screenLayout | o.screenLayout) & MASK_SCREENSIZE) {
952 return !(o.screenLayout & MASK_SCREENSIZE);
953 }
954 if ((screenLayout | o.screenLayout) & MASK_SCREENLONG) {
955 return !(o.screenLayout & MASK_SCREENLONG);
956 }
957 if ((screenLayout2 | o.screenLayout2) & MASK_SCREENROUND) {
958 return !(o.screenLayout2 & MASK_SCREENROUND);
959 }
Romain Guy4832745b2017-01-23 17:03:35 -0800960 if ((colorMode | o.colorMode) & MASK_HDR) {
961 return !(o.colorMode & MASK_HDR);
Romain Guyc9ba5592017-01-18 16:34:42 -0800962 }
Romain Guy4832745b2017-01-23 17:03:35 -0800963 if ((colorMode | o.colorMode) & MASK_WIDE_COLOR_GAMUT) {
964 return !(o.colorMode & MASK_WIDE_COLOR_GAMUT);
Romain Guyc9ba5592017-01-18 16:34:42 -0800965 }
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700966 if (orientation || o.orientation) return (!o.orientation);
967 if ((uiMode | o.uiMode) & MASK_UI_MODE_TYPE) {
968 return !(o.uiMode & MASK_UI_MODE_TYPE);
969 }
970 if ((uiMode | o.uiMode) & MASK_UI_MODE_NIGHT) {
971 return !(o.uiMode & MASK_UI_MODE_NIGHT);
972 }
973 if (density || o.density) return (!o.density);
974 if (touchscreen || o.touchscreen) return (!o.touchscreen);
975 if ((inputFlags | o.inputFlags) & MASK_KEYSHIDDEN) {
976 return !(o.inputFlags & MASK_KEYSHIDDEN);
977 }
978 if ((inputFlags | o.inputFlags) & MASK_NAVHIDDEN) {
979 return !(o.inputFlags & MASK_NAVHIDDEN);
980 }
981 if (keyboard || o.keyboard) return (!o.keyboard);
982 if (navigation || o.navigation) return (!o.navigation);
983 if (screenWidth || o.screenWidth) return (!o.screenWidth);
984 if (screenHeight || o.screenHeight) return (!o.screenHeight);
985 if (sdkVersion || o.sdkVersion) return (!o.sdkVersion);
986 if (minorVersion || o.minorVersion) return (!o.minorVersion);
987 // Both configurations have nothing defined except some possible future
988 // value. Returning the comparison of the two configurations is a
989 // "best effort" at this point to protect against incorrect dominations.
990 return *this != o;
Alexandria Cornwall77788eb2016-09-06 15:16:49 -0700991}
992
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700993bool ConfigDescription::ConflictsWith(const ConfigDescription& o) const {
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700994 // This method should be updated as new configuration parameters are
995 // introduced (e.g. screenConfig2).
996 auto pred = [](const uint32_t a, const uint32_t b) -> bool {
997 return a == 0 || b == 0 || a == b;
998 };
999 // The values here can be found in ResTable_config#match. Density and range
1000 // values can't lead to conflicts, and are ignored.
1001 return !pred(mcc, o.mcc) || !pred(mnc, o.mnc) || !pred(locale, o.locale) ||
Yurii Zubrytskyi02d89192023-01-04 08:44:34 -08001002 !pred(grammaticalInflection, o.grammaticalInflection) ||
Adam Lesinskicacb28f2016-10-19 12:18:14 -07001003 !pred(screenLayout & MASK_LAYOUTDIR,
1004 o.screenLayout & MASK_LAYOUTDIR) ||
1005 !pred(screenLayout & MASK_SCREENLONG,
1006 o.screenLayout & MASK_SCREENLONG) ||
Adam Lesinskicacb28f2016-10-19 12:18:14 -07001007 !pred(uiMode & MASK_UI_MODE_TYPE, o.uiMode & MASK_UI_MODE_TYPE) ||
1008 !pred(uiMode & MASK_UI_MODE_NIGHT, o.uiMode & MASK_UI_MODE_NIGHT) ||
1009 !pred(screenLayout2 & MASK_SCREENROUND,
1010 o.screenLayout2 & MASK_SCREENROUND) ||
Romain Guy4832745b2017-01-23 17:03:35 -08001011 !pred(colorMode & MASK_HDR, o.colorMode & MASK_HDR) ||
1012 !pred(colorMode & MASK_WIDE_COLOR_GAMUT,
1013 o.colorMode & MASK_WIDE_COLOR_GAMUT) ||
Adam Lesinskicacb28f2016-10-19 12:18:14 -07001014 !pred(orientation, o.orientation) ||
1015 !pred(touchscreen, o.touchscreen) ||
1016 !pred(inputFlags & MASK_KEYSHIDDEN, o.inputFlags & MASK_KEYSHIDDEN) ||
1017 !pred(inputFlags & MASK_NAVHIDDEN, o.inputFlags & MASK_NAVHIDDEN) ||
1018 !pred(keyboard, o.keyboard) || !pred(navigation, o.navigation);
Alexandria Cornwall77788eb2016-09-06 15:16:49 -07001019}
1020
Adam Lesinskice5e56e2016-10-21 17:56:45 -07001021bool ConfigDescription::IsCompatibleWith(const ConfigDescription& o) const {
1022 return !ConflictsWith(o) && !Dominates(o) && !o.Dominates(*this);
Alexandria Cornwall77788eb2016-09-06 15:16:49 -07001023}
1024
Mårten Kongstad5c541f62018-06-20 08:46:41 +02001025} // namespace android