blob: b1bd4012c1dfa78fdc861d30f746fc7be8772522 [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
17#include "ConfigDescription.h"
Adam Lesinskice5e56e2016-10-21 17:56:45 -070018
19#include <string>
20#include <vector>
21
22#include "androidfw/ResourceTypes.h"
23
Adam Lesinski6f6ceb72014-11-14 14:48:12 -080024#include "Locale.h"
25#include "SdkConstants.h"
Adam Lesinski1ab598f2015-08-14 14:26:04 -070026#include "util/StringPiece.h"
27#include "util/Util.h"
Adam Lesinski6f6ceb72014-11-14 14:48:12 -080028
Adam Lesinski6f6ceb72014-11-14 14:48:12 -080029namespace aapt {
30
31using android::ResTable_config;
32
33static const char* kWildcardName = "any";
34
Adam Lesinskice5e56e2016-10-21 17:56:45 -070035const ConfigDescription& ConfigDescription::DefaultConfig() {
Adam Lesinskicacb28f2016-10-19 12:18:14 -070036 static ConfigDescription config = {};
37 return config;
Adam Lesinski52364f72016-01-11 13:10:24 -080038}
39
Adam Lesinski6f6ceb72014-11-14 14:48:12 -080040static bool parseMcc(const char* name, ResTable_config* out) {
Adam Lesinskicacb28f2016-10-19 12:18:14 -070041 if (strcmp(name, kWildcardName) == 0) {
42 if (out) out->mcc = 0;
43 return true;
44 }
45 const char* c = name;
46 if (tolower(*c) != 'm') return false;
47 c++;
48 if (tolower(*c) != 'c') return false;
49 c++;
50 if (tolower(*c) != 'c') return false;
51 c++;
52
53 const char* val = c;
54
55 while (*c >= '0' && *c <= '9') {
Adam Lesinski6f6ceb72014-11-14 14:48:12 -080056 c++;
Adam Lesinskicacb28f2016-10-19 12:18:14 -070057 }
58 if (*c != 0) return false;
59 if (c - val != 3) return false;
Adam Lesinski6f6ceb72014-11-14 14:48:12 -080060
Adam Lesinskicacb28f2016-10-19 12:18:14 -070061 int d = atoi(val);
62 if (d != 0) {
63 if (out) out->mcc = d;
64 return true;
65 }
Adam Lesinski6f6ceb72014-11-14 14:48:12 -080066
Adam Lesinskicacb28f2016-10-19 12:18:14 -070067 return false;
Adam Lesinski6f6ceb72014-11-14 14:48:12 -080068}
69
70static bool parseMnc(const char* name, ResTable_config* out) {
Adam Lesinskicacb28f2016-10-19 12:18:14 -070071 if (strcmp(name, kWildcardName) == 0) {
72 if (out) out->mcc = 0;
Adam Lesinski6f6ceb72014-11-14 14:48:12 -080073 return true;
Adam Lesinskicacb28f2016-10-19 12:18:14 -070074 }
75 const char* c = name;
76 if (tolower(*c) != 'm') return false;
77 c++;
78 if (tolower(*c) != 'n') return false;
79 c++;
80 if (tolower(*c) != 'c') return false;
81 c++;
82
83 const char* val = c;
84
85 while (*c >= '0' && *c <= '9') {
86 c++;
87 }
88 if (*c != 0) return false;
89 if (c - val == 0 || c - val > 3) return false;
90
91 if (out) {
92 out->mnc = atoi(val);
93 if (out->mnc == 0) {
94 out->mnc = ACONFIGURATION_MNC_ZERO;
95 }
96 }
97
98 return true;
Adam Lesinski6f6ceb72014-11-14 14:48:12 -080099}
100
101static bool parseLayoutDirection(const char* name, ResTable_config* out) {
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700102 if (strcmp(name, kWildcardName) == 0) {
103 if (out)
104 out->screenLayout =
105 (out->screenLayout & ~ResTable_config::MASK_LAYOUTDIR) |
106 ResTable_config::LAYOUTDIR_ANY;
107 return true;
108 } else if (strcmp(name, "ldltr") == 0) {
109 if (out)
110 out->screenLayout =
111 (out->screenLayout & ~ResTable_config::MASK_LAYOUTDIR) |
112 ResTable_config::LAYOUTDIR_LTR;
113 return true;
114 } else if (strcmp(name, "ldrtl") == 0) {
115 if (out)
116 out->screenLayout =
117 (out->screenLayout & ~ResTable_config::MASK_LAYOUTDIR) |
118 ResTable_config::LAYOUTDIR_RTL;
119 return true;
120 }
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800121
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700122 return false;
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800123}
124
125static bool parseScreenLayoutSize(const char* name, ResTable_config* out) {
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700126 if (strcmp(name, kWildcardName) == 0) {
127 if (out)
128 out->screenLayout =
129 (out->screenLayout & ~ResTable_config::MASK_SCREENSIZE) |
130 ResTable_config::SCREENSIZE_ANY;
131 return true;
132 } else if (strcmp(name, "small") == 0) {
133 if (out)
134 out->screenLayout =
135 (out->screenLayout & ~ResTable_config::MASK_SCREENSIZE) |
136 ResTable_config::SCREENSIZE_SMALL;
137 return true;
138 } else if (strcmp(name, "normal") == 0) {
139 if (out)
140 out->screenLayout =
141 (out->screenLayout & ~ResTable_config::MASK_SCREENSIZE) |
142 ResTable_config::SCREENSIZE_NORMAL;
143 return true;
144 } else if (strcmp(name, "large") == 0) {
145 if (out)
146 out->screenLayout =
147 (out->screenLayout & ~ResTable_config::MASK_SCREENSIZE) |
148 ResTable_config::SCREENSIZE_LARGE;
149 return true;
150 } else if (strcmp(name, "xlarge") == 0) {
151 if (out)
152 out->screenLayout =
153 (out->screenLayout & ~ResTable_config::MASK_SCREENSIZE) |
154 ResTable_config::SCREENSIZE_XLARGE;
155 return true;
156 }
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800157
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700158 return false;
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800159}
160
161static bool parseScreenLayoutLong(const char* name, ResTable_config* out) {
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700162 if (strcmp(name, kWildcardName) == 0) {
163 if (out)
164 out->screenLayout =
165 (out->screenLayout & ~ResTable_config::MASK_SCREENLONG) |
166 ResTable_config::SCREENLONG_ANY;
167 return true;
168 } else if (strcmp(name, "long") == 0) {
169 if (out)
170 out->screenLayout =
171 (out->screenLayout & ~ResTable_config::MASK_SCREENLONG) |
172 ResTable_config::SCREENLONG_YES;
173 return true;
174 } else if (strcmp(name, "notlong") == 0) {
175 if (out)
176 out->screenLayout =
177 (out->screenLayout & ~ResTable_config::MASK_SCREENLONG) |
178 ResTable_config::SCREENLONG_NO;
179 return true;
180 }
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800181
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700182 return false;
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800183}
184
Adam Lesinski64254972015-11-03 16:16:17 -0800185static bool parseScreenRound(const char* name, ResTable_config* out) {
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700186 if (strcmp(name, kWildcardName) == 0) {
187 if (out)
188 out->screenLayout2 =
189 (out->screenLayout2 & ~ResTable_config::MASK_SCREENROUND) |
190 ResTable_config::SCREENROUND_ANY;
191 return true;
192 } else if (strcmp(name, "round") == 0) {
193 if (out)
194 out->screenLayout2 =
195 (out->screenLayout2 & ~ResTable_config::MASK_SCREENROUND) |
196 ResTable_config::SCREENROUND_YES;
197 return true;
198 } else if (strcmp(name, "notround") == 0) {
199 if (out)
200 out->screenLayout2 =
201 (out->screenLayout2 & ~ResTable_config::MASK_SCREENROUND) |
202 ResTable_config::SCREENROUND_NO;
203 return true;
204 }
205 return false;
Adam Lesinski64254972015-11-03 16:16:17 -0800206}
207
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800208static bool parseOrientation(const char* name, ResTable_config* out) {
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700209 if (strcmp(name, kWildcardName) == 0) {
210 if (out) out->orientation = out->ORIENTATION_ANY;
211 return true;
212 } else if (strcmp(name, "port") == 0) {
213 if (out) out->orientation = out->ORIENTATION_PORT;
214 return true;
215 } else if (strcmp(name, "land") == 0) {
216 if (out) out->orientation = out->ORIENTATION_LAND;
217 return true;
218 } else if (strcmp(name, "square") == 0) {
219 if (out) out->orientation = out->ORIENTATION_SQUARE;
220 return true;
221 }
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800222
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700223 return false;
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800224}
225
226static bool parseUiModeType(const char* name, ResTable_config* out) {
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700227 if (strcmp(name, kWildcardName) == 0) {
228 if (out)
229 out->uiMode = (out->uiMode & ~ResTable_config::MASK_UI_MODE_TYPE) |
230 ResTable_config::UI_MODE_TYPE_ANY;
231 return true;
232 } else if (strcmp(name, "desk") == 0) {
233 if (out)
234 out->uiMode = (out->uiMode & ~ResTable_config::MASK_UI_MODE_TYPE) |
235 ResTable_config::UI_MODE_TYPE_DESK;
236 return true;
237 } else if (strcmp(name, "car") == 0) {
238 if (out)
239 out->uiMode = (out->uiMode & ~ResTable_config::MASK_UI_MODE_TYPE) |
240 ResTable_config::UI_MODE_TYPE_CAR;
241 return true;
242 } else if (strcmp(name, "television") == 0) {
243 if (out)
244 out->uiMode = (out->uiMode & ~ResTable_config::MASK_UI_MODE_TYPE) |
245 ResTable_config::UI_MODE_TYPE_TELEVISION;
246 return true;
247 } else if (strcmp(name, "appliance") == 0) {
248 if (out)
249 out->uiMode = (out->uiMode & ~ResTable_config::MASK_UI_MODE_TYPE) |
250 ResTable_config::UI_MODE_TYPE_APPLIANCE;
251 return true;
252 } else if (strcmp(name, "watch") == 0) {
253 if (out)
254 out->uiMode = (out->uiMode & ~ResTable_config::MASK_UI_MODE_TYPE) |
255 ResTable_config::UI_MODE_TYPE_WATCH;
256 return true;
Zak Cohen1a6acdb2016-12-12 15:21:21 -0800257 } else if (strcmp(name, "vrheadset") == 0) {
258 if (out)
259 out->uiMode = (out->uiMode & ~ResTable_config::MASK_UI_MODE_TYPE) |
260 ResTable_config::UI_MODE_TYPE_VR_HEADSET;
261 return true;
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700262 }
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800263
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700264 return false;
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800265}
266
267static bool parseUiModeNight(const char* name, ResTable_config* out) {
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700268 if (strcmp(name, kWildcardName) == 0) {
269 if (out)
270 out->uiMode = (out->uiMode & ~ResTable_config::MASK_UI_MODE_NIGHT) |
271 ResTable_config::UI_MODE_NIGHT_ANY;
272 return true;
273 } else if (strcmp(name, "night") == 0) {
274 if (out)
275 out->uiMode = (out->uiMode & ~ResTable_config::MASK_UI_MODE_NIGHT) |
276 ResTable_config::UI_MODE_NIGHT_YES;
277 return true;
278 } else if (strcmp(name, "notnight") == 0) {
279 if (out)
280 out->uiMode = (out->uiMode & ~ResTable_config::MASK_UI_MODE_NIGHT) |
281 ResTable_config::UI_MODE_NIGHT_NO;
282 return true;
283 }
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800284
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700285 return false;
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800286}
287
288static bool parseDensity(const char* name, ResTable_config* out) {
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700289 if (strcmp(name, kWildcardName) == 0) {
290 if (out) out->density = ResTable_config::DENSITY_DEFAULT;
291 return true;
292 }
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800293
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700294 if (strcmp(name, "anydpi") == 0) {
295 if (out) out->density = ResTable_config::DENSITY_ANY;
296 return true;
297 }
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800298
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700299 if (strcmp(name, "nodpi") == 0) {
300 if (out) out->density = ResTable_config::DENSITY_NONE;
301 return true;
302 }
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800303
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700304 if (strcmp(name, "ldpi") == 0) {
305 if (out) out->density = ResTable_config::DENSITY_LOW;
306 return true;
307 }
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800308
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700309 if (strcmp(name, "mdpi") == 0) {
310 if (out) out->density = ResTable_config::DENSITY_MEDIUM;
311 return true;
312 }
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800313
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700314 if (strcmp(name, "tvdpi") == 0) {
315 if (out) out->density = ResTable_config::DENSITY_TV;
316 return true;
317 }
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800318
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700319 if (strcmp(name, "hdpi") == 0) {
320 if (out) out->density = ResTable_config::DENSITY_HIGH;
321 return true;
322 }
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800323
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700324 if (strcmp(name, "xhdpi") == 0) {
325 if (out) out->density = ResTable_config::DENSITY_XHIGH;
326 return true;
327 }
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800328
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700329 if (strcmp(name, "xxhdpi") == 0) {
330 if (out) out->density = ResTable_config::DENSITY_XXHIGH;
331 return true;
332 }
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800333
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700334 if (strcmp(name, "xxxhdpi") == 0) {
335 if (out) out->density = ResTable_config::DENSITY_XXXHIGH;
336 return true;
337 }
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800338
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700339 char* c = (char*)name;
340 while (*c >= '0' && *c <= '9') {
341 c++;
342 }
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800343
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700344 // check that we have 'dpi' after the last digit.
345 if (toupper(c[0]) != 'D' || toupper(c[1]) != 'P' || toupper(c[2]) != 'I' ||
346 c[3] != 0) {
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800347 return false;
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700348 }
349
350 // temporarily replace the first letter with \0 to
351 // use atoi.
352 char tmp = c[0];
353 c[0] = '\0';
354
355 int d = atoi(name);
356 c[0] = tmp;
357
358 if (d != 0) {
359 if (out) out->density = d;
360 return true;
361 }
362
363 return false;
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800364}
365
366static bool parseTouchscreen(const char* name, ResTable_config* out) {
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700367 if (strcmp(name, kWildcardName) == 0) {
368 if (out) out->touchscreen = out->TOUCHSCREEN_ANY;
369 return true;
370 } else if (strcmp(name, "notouch") == 0) {
371 if (out) out->touchscreen = out->TOUCHSCREEN_NOTOUCH;
372 return true;
373 } else if (strcmp(name, "stylus") == 0) {
374 if (out) out->touchscreen = out->TOUCHSCREEN_STYLUS;
375 return true;
376 } else if (strcmp(name, "finger") == 0) {
377 if (out) out->touchscreen = out->TOUCHSCREEN_FINGER;
378 return true;
379 }
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800380
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700381 return false;
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800382}
383
384static bool parseKeysHidden(const char* name, ResTable_config* out) {
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700385 uint8_t mask = 0;
386 uint8_t value = 0;
387 if (strcmp(name, kWildcardName) == 0) {
388 mask = ResTable_config::MASK_KEYSHIDDEN;
389 value = ResTable_config::KEYSHIDDEN_ANY;
390 } else if (strcmp(name, "keysexposed") == 0) {
391 mask = ResTable_config::MASK_KEYSHIDDEN;
392 value = ResTable_config::KEYSHIDDEN_NO;
393 } else if (strcmp(name, "keyshidden") == 0) {
394 mask = ResTable_config::MASK_KEYSHIDDEN;
395 value = ResTable_config::KEYSHIDDEN_YES;
396 } else if (strcmp(name, "keyssoft") == 0) {
397 mask = ResTable_config::MASK_KEYSHIDDEN;
398 value = ResTable_config::KEYSHIDDEN_SOFT;
399 }
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800400
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700401 if (mask != 0) {
402 if (out) out->inputFlags = (out->inputFlags & ~mask) | value;
403 return true;
404 }
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800405
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700406 return false;
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800407}
408
409static bool parseKeyboard(const char* name, ResTable_config* out) {
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700410 if (strcmp(name, kWildcardName) == 0) {
411 if (out) out->keyboard = out->KEYBOARD_ANY;
412 return true;
413 } else if (strcmp(name, "nokeys") == 0) {
414 if (out) out->keyboard = out->KEYBOARD_NOKEYS;
415 return true;
416 } else if (strcmp(name, "qwerty") == 0) {
417 if (out) out->keyboard = out->KEYBOARD_QWERTY;
418 return true;
419 } else if (strcmp(name, "12key") == 0) {
420 if (out) out->keyboard = out->KEYBOARD_12KEY;
421 return true;
422 }
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800423
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700424 return false;
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800425}
426
427static bool parseNavHidden(const char* name, ResTable_config* out) {
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700428 uint8_t mask = 0;
429 uint8_t value = 0;
430 if (strcmp(name, kWildcardName) == 0) {
431 mask = ResTable_config::MASK_NAVHIDDEN;
432 value = ResTable_config::NAVHIDDEN_ANY;
433 } else if (strcmp(name, "navexposed") == 0) {
434 mask = ResTable_config::MASK_NAVHIDDEN;
435 value = ResTable_config::NAVHIDDEN_NO;
436 } else if (strcmp(name, "navhidden") == 0) {
437 mask = ResTable_config::MASK_NAVHIDDEN;
438 value = ResTable_config::NAVHIDDEN_YES;
439 }
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800440
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700441 if (mask != 0) {
442 if (out) out->inputFlags = (out->inputFlags & ~mask) | value;
443 return true;
444 }
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800445
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700446 return false;
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800447}
448
449static bool parseNavigation(const char* name, ResTable_config* out) {
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700450 if (strcmp(name, kWildcardName) == 0) {
451 if (out) out->navigation = out->NAVIGATION_ANY;
452 return true;
453 } else if (strcmp(name, "nonav") == 0) {
454 if (out) out->navigation = out->NAVIGATION_NONAV;
455 return true;
456 } else if (strcmp(name, "dpad") == 0) {
457 if (out) out->navigation = out->NAVIGATION_DPAD;
458 return true;
459 } else if (strcmp(name, "trackball") == 0) {
460 if (out) out->navigation = out->NAVIGATION_TRACKBALL;
461 return true;
462 } else if (strcmp(name, "wheel") == 0) {
463 if (out) out->navigation = out->NAVIGATION_WHEEL;
464 return true;
465 }
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800466
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700467 return false;
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800468}
469
470static bool parseScreenSize(const char* name, ResTable_config* out) {
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700471 if (strcmp(name, kWildcardName) == 0) {
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800472 if (out) {
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700473 out->screenWidth = out->SCREENWIDTH_ANY;
474 out->screenHeight = out->SCREENHEIGHT_ANY;
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800475 }
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800476 return true;
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700477 }
478
479 const char* x = name;
480 while (*x >= '0' && *x <= '9') x++;
481 if (x == name || *x != 'x') return false;
482 std::string xName(name, x - name);
483 x++;
484
485 const char* y = x;
486 while (*y >= '0' && *y <= '9') y++;
487 if (y == name || *y != 0) return false;
488 std::string yName(x, y - x);
489
490 uint16_t w = (uint16_t)atoi(xName.c_str());
491 uint16_t h = (uint16_t)atoi(yName.c_str());
492 if (w < h) {
493 return false;
494 }
495
496 if (out) {
497 out->screenWidth = w;
498 out->screenHeight = h;
499 }
500
501 return true;
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800502}
503
504static bool parseSmallestScreenWidthDp(const char* name, ResTable_config* out) {
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700505 if (strcmp(name, kWildcardName) == 0) {
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800506 if (out) {
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700507 out->smallestScreenWidthDp = out->SCREENWIDTH_ANY;
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800508 }
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800509 return true;
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700510 }
511
512 if (*name != 's') return false;
513 name++;
514 if (*name != 'w') return false;
515 name++;
516 const char* x = name;
517 while (*x >= '0' && *x <= '9') x++;
518 if (x == name || x[0] != 'd' || x[1] != 'p' || x[2] != 0) return false;
519 std::string xName(name, x - name);
520
521 if (out) {
522 out->smallestScreenWidthDp = (uint16_t)atoi(xName.c_str());
523 }
524
525 return true;
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800526}
527
528static bool parseScreenWidthDp(const char* name, ResTable_config* out) {
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700529 if (strcmp(name, kWildcardName) == 0) {
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800530 if (out) {
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700531 out->screenWidthDp = out->SCREENWIDTH_ANY;
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800532 }
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800533 return true;
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700534 }
535
536 if (*name != 'w') return false;
537 name++;
538 const char* x = name;
539 while (*x >= '0' && *x <= '9') x++;
540 if (x == name || x[0] != 'd' || x[1] != 'p' || x[2] != 0) return false;
541 std::string xName(name, x - name);
542
543 if (out) {
544 out->screenWidthDp = (uint16_t)atoi(xName.c_str());
545 }
546
547 return true;
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800548}
549
550static bool parseScreenHeightDp(const char* name, ResTable_config* out) {
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700551 if (strcmp(name, kWildcardName) == 0) {
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800552 if (out) {
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700553 out->screenHeightDp = out->SCREENWIDTH_ANY;
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800554 }
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800555 return true;
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700556 }
557
558 if (*name != 'h') return false;
559 name++;
560 const char* x = name;
561 while (*x >= '0' && *x <= '9') x++;
562 if (x == name || x[0] != 'd' || x[1] != 'p' || x[2] != 0) return false;
563 std::string xName(name, x - name);
564
565 if (out) {
566 out->screenHeightDp = (uint16_t)atoi(xName.c_str());
567 }
568
569 return true;
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800570}
571
572static bool parseVersion(const char* name, ResTable_config* out) {
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700573 if (strcmp(name, kWildcardName) == 0) {
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800574 if (out) {
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700575 out->sdkVersion = out->SDKVERSION_ANY;
576 out->minorVersion = out->MINORVERSION_ANY;
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800577 }
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800578 return true;
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700579 }
580
581 if (*name != 'v') {
582 return false;
583 }
584
585 name++;
586 const char* s = name;
587 while (*s >= '0' && *s <= '9') s++;
588 if (s == name || *s != 0) return false;
589 std::string sdkName(name, s - name);
590
591 if (out) {
592 out->sdkVersion = (uint16_t)atoi(sdkName.c_str());
593 out->minorVersion = 0;
594 }
595
596 return true;
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800597}
598
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700599bool ConfigDescription::Parse(const StringPiece& str, ConfigDescription* out) {
600 std::vector<std::string> parts = util::SplitAndLowercase(str, '-');
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800601
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700602 ConfigDescription config;
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700603 ssize_t parts_consumed = 0;
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700604 LocaleValue locale;
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800605
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700606 const auto parts_end = parts.end();
607 auto part_iter = parts.begin();
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800608
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700609 if (str.size() == 0) {
610 goto success;
611 }
612
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700613 if (parseMcc(part_iter->c_str(), &config)) {
614 ++part_iter;
615 if (part_iter == parts_end) {
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700616 goto success;
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800617 }
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700618 }
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800619
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700620 if (parseMnc(part_iter->c_str(), &config)) {
621 ++part_iter;
622 if (part_iter == parts_end) {
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700623 goto success;
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800624 }
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700625 }
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800626
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700627 // Locale spans a few '-' separators, so we let it
628 // control the index.
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700629 parts_consumed = locale.InitFromParts(part_iter, parts_end);
630 if (parts_consumed < 0) {
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800631 return false;
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700632 } else {
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700633 locale.WriteTo(&config);
634 part_iter += parts_consumed;
635 if (part_iter == parts_end) {
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700636 goto success;
637 }
638 }
639
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700640 if (parseLayoutDirection(part_iter->c_str(), &config)) {
641 ++part_iter;
642 if (part_iter == parts_end) {
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700643 goto success;
644 }
645 }
646
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700647 if (parseSmallestScreenWidthDp(part_iter->c_str(), &config)) {
648 ++part_iter;
649 if (part_iter == parts_end) {
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700650 goto success;
651 }
652 }
653
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700654 if (parseScreenWidthDp(part_iter->c_str(), &config)) {
655 ++part_iter;
656 if (part_iter == parts_end) {
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700657 goto success;
658 }
659 }
660
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700661 if (parseScreenHeightDp(part_iter->c_str(), &config)) {
662 ++part_iter;
663 if (part_iter == parts_end) {
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700664 goto success;
665 }
666 }
667
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700668 if (parseScreenLayoutSize(part_iter->c_str(), &config)) {
669 ++part_iter;
670 if (part_iter == parts_end) {
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700671 goto success;
672 }
673 }
674
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700675 if (parseScreenLayoutLong(part_iter->c_str(), &config)) {
676 ++part_iter;
677 if (part_iter == parts_end) {
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700678 goto success;
679 }
680 }
681
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700682 if (parseScreenRound(part_iter->c_str(), &config)) {
683 ++part_iter;
684 if (part_iter == parts_end) {
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700685 goto success;
686 }
687 }
688
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700689 if (parseOrientation(part_iter->c_str(), &config)) {
690 ++part_iter;
691 if (part_iter == parts_end) {
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700692 goto success;
693 }
694 }
695
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700696 if (parseUiModeType(part_iter->c_str(), &config)) {
697 ++part_iter;
698 if (part_iter == parts_end) {
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700699 goto success;
700 }
701 }
702
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700703 if (parseUiModeNight(part_iter->c_str(), &config)) {
704 ++part_iter;
705 if (part_iter == parts_end) {
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700706 goto success;
707 }
708 }
709
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700710 if (parseDensity(part_iter->c_str(), &config)) {
711 ++part_iter;
712 if (part_iter == parts_end) {
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700713 goto success;
714 }
715 }
716
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700717 if (parseTouchscreen(part_iter->c_str(), &config)) {
718 ++part_iter;
719 if (part_iter == parts_end) {
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700720 goto success;
721 }
722 }
723
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700724 if (parseKeysHidden(part_iter->c_str(), &config)) {
725 ++part_iter;
726 if (part_iter == parts_end) {
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700727 goto success;
728 }
729 }
730
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700731 if (parseKeyboard(part_iter->c_str(), &config)) {
732 ++part_iter;
733 if (part_iter == parts_end) {
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700734 goto success;
735 }
736 }
737
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700738 if (parseNavHidden(part_iter->c_str(), &config)) {
739 ++part_iter;
740 if (part_iter == parts_end) {
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700741 goto success;
742 }
743 }
744
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700745 if (parseNavigation(part_iter->c_str(), &config)) {
746 ++part_iter;
747 if (part_iter == parts_end) {
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700748 goto success;
749 }
750 }
751
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700752 if (parseScreenSize(part_iter->c_str(), &config)) {
753 ++part_iter;
754 if (part_iter == parts_end) {
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700755 goto success;
756 }
757 }
758
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700759 if (parseVersion(part_iter->c_str(), &config)) {
760 ++part_iter;
761 if (part_iter == parts_end) {
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700762 goto success;
763 }
764 }
765
766 // Unrecognized.
767 return false;
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800768
769success:
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700770 if (out != NULL) {
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700771 ApplyVersionForCompatibility(&config);
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700772 *out = config;
773 }
774 return true;
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800775}
776
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700777void ConfigDescription::ApplyVersionForCompatibility(
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700778 ConfigDescription* config) {
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700779 uint16_t min_sdk = 0;
Zak Cohen1a6acdb2016-12-12 15:21:21 -0800780 if ((config->uiMode & ResTable_config::MASK_UI_MODE_TYPE)
781 == ResTable_config::UI_MODE_TYPE_VR_HEADSET) {
782 min_sdk = SDK_O;
783 } else if (config->screenLayout2 & ResTable_config::MASK_SCREENROUND) {
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700784 min_sdk = SDK_MARSHMALLOW;
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700785 } else if (config->density == ResTable_config::DENSITY_ANY) {
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700786 min_sdk = SDK_LOLLIPOP;
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700787 } else if (config->smallestScreenWidthDp !=
788 ResTable_config::SCREENWIDTH_ANY ||
789 config->screenWidthDp != ResTable_config::SCREENWIDTH_ANY ||
790 config->screenHeightDp != ResTable_config::SCREENHEIGHT_ANY) {
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700791 min_sdk = SDK_HONEYCOMB_MR2;
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700792 } else if ((config->uiMode & ResTable_config::MASK_UI_MODE_TYPE) !=
793 ResTable_config::UI_MODE_TYPE_ANY ||
794 (config->uiMode & ResTable_config::MASK_UI_MODE_NIGHT) !=
795 ResTable_config::UI_MODE_NIGHT_ANY) {
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700796 min_sdk = SDK_FROYO;
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700797 } else if ((config->screenLayout & ResTable_config::MASK_SCREENSIZE) !=
798 ResTable_config::SCREENSIZE_ANY ||
799 (config->screenLayout & ResTable_config::MASK_SCREENLONG) !=
800 ResTable_config::SCREENLONG_ANY ||
801 config->density != ResTable_config::DENSITY_DEFAULT) {
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700802 min_sdk = SDK_DONUT;
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700803 }
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800804
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700805 if (min_sdk > config->sdkVersion) {
806 config->sdkVersion = min_sdk;
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700807 }
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800808}
809
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700810ConfigDescription ConfigDescription::CopyWithoutSdkVersion() const {
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700811 ConfigDescription copy = *this;
812 copy.sdkVersion = 0;
813 return copy;
Adam Lesinski87675ad2016-07-15 17:03:03 -0700814}
815
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700816bool ConfigDescription::Dominates(const ConfigDescription& o) const {
817 if (*this == DefaultConfig() || *this == o) {
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700818 return true;
819 }
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700820 return MatchWithDensity(o) && !o.MatchWithDensity(*this) &&
821 !isMoreSpecificThan(o) && !o.HasHigherPrecedenceThan(*this);
Alexandria Cornwall77788eb2016-09-06 15:16:49 -0700822}
823
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700824bool ConfigDescription::HasHigherPrecedenceThan(
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700825 const ConfigDescription& o) const {
826 // The order of the following tests defines the importance of one
827 // configuration parameter over another. Those tests first are more
828 // important, trumping any values in those following them.
829 // The ordering should be the same as ResTable_config#isBetterThan.
830 if (mcc || o.mcc) return (!o.mcc);
831 if (mnc || o.mnc) return (!o.mnc);
832 if (language[0] || o.language[0]) return (!o.language[0]);
833 if (country[0] || o.country[0]) return (!o.country[0]);
834 // Script and variant require either a language or country, both of which
835 // have higher precedence.
836 if ((screenLayout | o.screenLayout) & MASK_LAYOUTDIR) {
837 return !(o.screenLayout & MASK_LAYOUTDIR);
838 }
839 if (smallestScreenWidthDp || o.smallestScreenWidthDp)
840 return (!o.smallestScreenWidthDp);
841 if (screenWidthDp || o.screenWidthDp) return (!o.screenWidthDp);
842 if (screenHeightDp || o.screenHeightDp) return (!o.screenHeightDp);
843 if ((screenLayout | o.screenLayout) & MASK_SCREENSIZE) {
844 return !(o.screenLayout & MASK_SCREENSIZE);
845 }
846 if ((screenLayout | o.screenLayout) & MASK_SCREENLONG) {
847 return !(o.screenLayout & MASK_SCREENLONG);
848 }
849 if ((screenLayout2 | o.screenLayout2) & MASK_SCREENROUND) {
850 return !(o.screenLayout2 & MASK_SCREENROUND);
851 }
852 if (orientation || o.orientation) return (!o.orientation);
853 if ((uiMode | o.uiMode) & MASK_UI_MODE_TYPE) {
854 return !(o.uiMode & MASK_UI_MODE_TYPE);
855 }
856 if ((uiMode | o.uiMode) & MASK_UI_MODE_NIGHT) {
857 return !(o.uiMode & MASK_UI_MODE_NIGHT);
858 }
859 if (density || o.density) return (!o.density);
860 if (touchscreen || o.touchscreen) return (!o.touchscreen);
861 if ((inputFlags | o.inputFlags) & MASK_KEYSHIDDEN) {
862 return !(o.inputFlags & MASK_KEYSHIDDEN);
863 }
864 if ((inputFlags | o.inputFlags) & MASK_NAVHIDDEN) {
865 return !(o.inputFlags & MASK_NAVHIDDEN);
866 }
867 if (keyboard || o.keyboard) return (!o.keyboard);
868 if (navigation || o.navigation) return (!o.navigation);
869 if (screenWidth || o.screenWidth) return (!o.screenWidth);
870 if (screenHeight || o.screenHeight) return (!o.screenHeight);
871 if (sdkVersion || o.sdkVersion) return (!o.sdkVersion);
872 if (minorVersion || o.minorVersion) return (!o.minorVersion);
873 // Both configurations have nothing defined except some possible future
874 // value. Returning the comparison of the two configurations is a
875 // "best effort" at this point to protect against incorrect dominations.
876 return *this != o;
Alexandria Cornwall77788eb2016-09-06 15:16:49 -0700877}
878
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700879bool ConfigDescription::ConflictsWith(const ConfigDescription& o) const {
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700880 // This method should be updated as new configuration parameters are
881 // introduced (e.g. screenConfig2).
882 auto pred = [](const uint32_t a, const uint32_t b) -> bool {
883 return a == 0 || b == 0 || a == b;
884 };
885 // The values here can be found in ResTable_config#match. Density and range
886 // values can't lead to conflicts, and are ignored.
887 return !pred(mcc, o.mcc) || !pred(mnc, o.mnc) || !pred(locale, o.locale) ||
888 !pred(screenLayout & MASK_LAYOUTDIR,
889 o.screenLayout & MASK_LAYOUTDIR) ||
890 !pred(screenLayout & MASK_SCREENLONG,
891 o.screenLayout & MASK_SCREENLONG) ||
892 !pred(screenLayout & MASK_UI_MODE_TYPE,
893 o.screenLayout & MASK_UI_MODE_TYPE) ||
894 !pred(uiMode & MASK_UI_MODE_TYPE, o.uiMode & MASK_UI_MODE_TYPE) ||
895 !pred(uiMode & MASK_UI_MODE_NIGHT, o.uiMode & MASK_UI_MODE_NIGHT) ||
896 !pred(screenLayout2 & MASK_SCREENROUND,
897 o.screenLayout2 & MASK_SCREENROUND) ||
898 !pred(orientation, o.orientation) ||
899 !pred(touchscreen, o.touchscreen) ||
900 !pred(inputFlags & MASK_KEYSHIDDEN, o.inputFlags & MASK_KEYSHIDDEN) ||
901 !pred(inputFlags & MASK_NAVHIDDEN, o.inputFlags & MASK_NAVHIDDEN) ||
902 !pred(keyboard, o.keyboard) || !pred(navigation, o.navigation);
Alexandria Cornwall77788eb2016-09-06 15:16:49 -0700903}
904
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700905bool ConfigDescription::IsCompatibleWith(const ConfigDescription& o) const {
906 return !ConflictsWith(o) && !Dominates(o) && !o.Dominates(*this);
Alexandria Cornwall77788eb2016-09-06 15:16:49 -0700907}
908
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700909} // namespace aapt