blob: c97d6d4876fdfa54e166fec227183bfdaa5828f8 [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"
Adam Lesinskid5083f62017-01-16 15:07:21 -080023#include "androidfw/StringPiece.h"
Adam Lesinskice5e56e2016-10-21 17:56:45 -070024
Adam Lesinski6f6ceb72014-11-14 14:48:12 -080025#include "Locale.h"
26#include "SdkConstants.h"
Adam Lesinski1ab598f2015-08-14 14:26:04 -070027#include "util/Util.h"
Adam Lesinski6f6ceb72014-11-14 14:48:12 -080028
Adam Lesinski6f6ceb72014-11-14 14:48:12 -080029using android::ResTable_config;
Adam Lesinskid5083f62017-01-16 15:07:21 -080030using android::StringPiece;
31
32namespace aapt {
Adam Lesinski6f6ceb72014-11-14 14:48:12 -080033
34static const char* kWildcardName = "any";
35
Adam Lesinskice5e56e2016-10-21 17:56:45 -070036const ConfigDescription& ConfigDescription::DefaultConfig() {
Adam Lesinskicacb28f2016-10-19 12:18:14 -070037 static ConfigDescription config = {};
38 return config;
Adam Lesinski52364f72016-01-11 13:10:24 -080039}
40
Adam Lesinski6f6ceb72014-11-14 14:48:12 -080041static bool parseMcc(const char* name, ResTable_config* out) {
Adam Lesinskicacb28f2016-10-19 12:18:14 -070042 if (strcmp(name, kWildcardName) == 0) {
43 if (out) out->mcc = 0;
44 return true;
45 }
46 const char* c = name;
47 if (tolower(*c) != 'm') return false;
48 c++;
49 if (tolower(*c) != 'c') return false;
50 c++;
51 if (tolower(*c) != 'c') return false;
52 c++;
53
54 const char* val = c;
55
56 while (*c >= '0' && *c <= '9') {
Adam Lesinski6f6ceb72014-11-14 14:48:12 -080057 c++;
Adam Lesinskicacb28f2016-10-19 12:18:14 -070058 }
59 if (*c != 0) return false;
60 if (c - val != 3) return false;
Adam Lesinski6f6ceb72014-11-14 14:48:12 -080061
Adam Lesinskicacb28f2016-10-19 12:18:14 -070062 int d = atoi(val);
63 if (d != 0) {
64 if (out) out->mcc = d;
65 return true;
66 }
Adam Lesinski6f6ceb72014-11-14 14:48:12 -080067
Adam Lesinskicacb28f2016-10-19 12:18:14 -070068 return false;
Adam Lesinski6f6ceb72014-11-14 14:48:12 -080069}
70
71static bool parseMnc(const char* name, ResTable_config* out) {
Adam Lesinskicacb28f2016-10-19 12:18:14 -070072 if (strcmp(name, kWildcardName) == 0) {
73 if (out) out->mcc = 0;
Adam Lesinski6f6ceb72014-11-14 14:48:12 -080074 return true;
Adam Lesinskicacb28f2016-10-19 12:18:14 -070075 }
76 const char* c = name;
77 if (tolower(*c) != 'm') return false;
78 c++;
79 if (tolower(*c) != 'n') return false;
80 c++;
81 if (tolower(*c) != 'c') return false;
82 c++;
83
84 const char* val = c;
85
86 while (*c >= '0' && *c <= '9') {
87 c++;
88 }
89 if (*c != 0) return false;
90 if (c - val == 0 || c - val > 3) return false;
91
92 if (out) {
93 out->mnc = atoi(val);
94 if (out->mnc == 0) {
95 out->mnc = ACONFIGURATION_MNC_ZERO;
96 }
97 }
98
99 return true;
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800100}
101
102static bool parseLayoutDirection(const char* name, ResTable_config* out) {
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700103 if (strcmp(name, kWildcardName) == 0) {
104 if (out)
105 out->screenLayout =
106 (out->screenLayout & ~ResTable_config::MASK_LAYOUTDIR) |
107 ResTable_config::LAYOUTDIR_ANY;
108 return true;
109 } else if (strcmp(name, "ldltr") == 0) {
110 if (out)
111 out->screenLayout =
112 (out->screenLayout & ~ResTable_config::MASK_LAYOUTDIR) |
113 ResTable_config::LAYOUTDIR_LTR;
114 return true;
115 } else if (strcmp(name, "ldrtl") == 0) {
116 if (out)
117 out->screenLayout =
118 (out->screenLayout & ~ResTable_config::MASK_LAYOUTDIR) |
119 ResTable_config::LAYOUTDIR_RTL;
120 return true;
121 }
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800122
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700123 return false;
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800124}
125
126static bool parseScreenLayoutSize(const char* name, ResTable_config* out) {
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700127 if (strcmp(name, kWildcardName) == 0) {
128 if (out)
129 out->screenLayout =
130 (out->screenLayout & ~ResTable_config::MASK_SCREENSIZE) |
131 ResTable_config::SCREENSIZE_ANY;
132 return true;
133 } else if (strcmp(name, "small") == 0) {
134 if (out)
135 out->screenLayout =
136 (out->screenLayout & ~ResTable_config::MASK_SCREENSIZE) |
137 ResTable_config::SCREENSIZE_SMALL;
138 return true;
139 } else if (strcmp(name, "normal") == 0) {
140 if (out)
141 out->screenLayout =
142 (out->screenLayout & ~ResTable_config::MASK_SCREENSIZE) |
143 ResTable_config::SCREENSIZE_NORMAL;
144 return true;
145 } else if (strcmp(name, "large") == 0) {
146 if (out)
147 out->screenLayout =
148 (out->screenLayout & ~ResTable_config::MASK_SCREENSIZE) |
149 ResTable_config::SCREENSIZE_LARGE;
150 return true;
151 } else if (strcmp(name, "xlarge") == 0) {
152 if (out)
153 out->screenLayout =
154 (out->screenLayout & ~ResTable_config::MASK_SCREENSIZE) |
155 ResTable_config::SCREENSIZE_XLARGE;
156 return true;
157 }
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800158
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700159 return false;
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800160}
161
162static bool parseScreenLayoutLong(const char* name, ResTable_config* out) {
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700163 if (strcmp(name, kWildcardName) == 0) {
164 if (out)
165 out->screenLayout =
166 (out->screenLayout & ~ResTable_config::MASK_SCREENLONG) |
167 ResTable_config::SCREENLONG_ANY;
168 return true;
169 } else if (strcmp(name, "long") == 0) {
170 if (out)
171 out->screenLayout =
172 (out->screenLayout & ~ResTable_config::MASK_SCREENLONG) |
173 ResTable_config::SCREENLONG_YES;
174 return true;
175 } else if (strcmp(name, "notlong") == 0) {
176 if (out)
177 out->screenLayout =
178 (out->screenLayout & ~ResTable_config::MASK_SCREENLONG) |
179 ResTable_config::SCREENLONG_NO;
180 return true;
181 }
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800182
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700183 return false;
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800184}
185
Adam Lesinski64254972015-11-03 16:16:17 -0800186static bool parseScreenRound(const char* name, ResTable_config* out) {
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700187 if (strcmp(name, kWildcardName) == 0) {
188 if (out)
189 out->screenLayout2 =
190 (out->screenLayout2 & ~ResTable_config::MASK_SCREENROUND) |
191 ResTable_config::SCREENROUND_ANY;
192 return true;
193 } else if (strcmp(name, "round") == 0) {
194 if (out)
195 out->screenLayout2 =
196 (out->screenLayout2 & ~ResTable_config::MASK_SCREENROUND) |
197 ResTable_config::SCREENROUND_YES;
198 return true;
199 } else if (strcmp(name, "notround") == 0) {
200 if (out)
201 out->screenLayout2 =
202 (out->screenLayout2 & ~ResTable_config::MASK_SCREENROUND) |
203 ResTable_config::SCREENROUND_NO;
204 return true;
205 }
206 return false;
Adam Lesinski64254972015-11-03 16:16:17 -0800207}
208
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800209static bool parseOrientation(const char* name, ResTable_config* out) {
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700210 if (strcmp(name, kWildcardName) == 0) {
211 if (out) out->orientation = out->ORIENTATION_ANY;
212 return true;
213 } else if (strcmp(name, "port") == 0) {
214 if (out) out->orientation = out->ORIENTATION_PORT;
215 return true;
216 } else if (strcmp(name, "land") == 0) {
217 if (out) out->orientation = out->ORIENTATION_LAND;
218 return true;
219 } else if (strcmp(name, "square") == 0) {
220 if (out) out->orientation = out->ORIENTATION_SQUARE;
221 return true;
222 }
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800223
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700224 return false;
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800225}
226
227static bool parseUiModeType(const char* name, ResTable_config* out) {
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700228 if (strcmp(name, kWildcardName) == 0) {
229 if (out)
230 out->uiMode = (out->uiMode & ~ResTable_config::MASK_UI_MODE_TYPE) |
231 ResTable_config::UI_MODE_TYPE_ANY;
232 return true;
233 } else if (strcmp(name, "desk") == 0) {
234 if (out)
235 out->uiMode = (out->uiMode & ~ResTable_config::MASK_UI_MODE_TYPE) |
236 ResTable_config::UI_MODE_TYPE_DESK;
237 return true;
238 } else if (strcmp(name, "car") == 0) {
239 if (out)
240 out->uiMode = (out->uiMode & ~ResTable_config::MASK_UI_MODE_TYPE) |
241 ResTable_config::UI_MODE_TYPE_CAR;
242 return true;
243 } else if (strcmp(name, "television") == 0) {
244 if (out)
245 out->uiMode = (out->uiMode & ~ResTable_config::MASK_UI_MODE_TYPE) |
246 ResTable_config::UI_MODE_TYPE_TELEVISION;
247 return true;
248 } else if (strcmp(name, "appliance") == 0) {
249 if (out)
250 out->uiMode = (out->uiMode & ~ResTable_config::MASK_UI_MODE_TYPE) |
251 ResTable_config::UI_MODE_TYPE_APPLIANCE;
252 return true;
253 } else if (strcmp(name, "watch") == 0) {
254 if (out)
255 out->uiMode = (out->uiMode & ~ResTable_config::MASK_UI_MODE_TYPE) |
256 ResTable_config::UI_MODE_TYPE_WATCH;
257 return true;
Zak Cohen1a6acdb2016-12-12 15:21:21 -0800258 } else if (strcmp(name, "vrheadset") == 0) {
259 if (out)
260 out->uiMode = (out->uiMode & ~ResTable_config::MASK_UI_MODE_TYPE) |
261 ResTable_config::UI_MODE_TYPE_VR_HEADSET;
262 return true;
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700263 }
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800264
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700265 return false;
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800266}
267
268static bool parseUiModeNight(const char* name, ResTable_config* out) {
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700269 if (strcmp(name, kWildcardName) == 0) {
270 if (out)
271 out->uiMode = (out->uiMode & ~ResTable_config::MASK_UI_MODE_NIGHT) |
272 ResTable_config::UI_MODE_NIGHT_ANY;
273 return true;
274 } else if (strcmp(name, "night") == 0) {
275 if (out)
276 out->uiMode = (out->uiMode & ~ResTable_config::MASK_UI_MODE_NIGHT) |
277 ResTable_config::UI_MODE_NIGHT_YES;
278 return true;
279 } else if (strcmp(name, "notnight") == 0) {
280 if (out)
281 out->uiMode = (out->uiMode & ~ResTable_config::MASK_UI_MODE_NIGHT) |
282 ResTable_config::UI_MODE_NIGHT_NO;
283 return true;
284 }
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800285
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700286 return false;
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800287}
288
289static bool parseDensity(const char* name, ResTable_config* out) {
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700290 if (strcmp(name, kWildcardName) == 0) {
291 if (out) out->density = ResTable_config::DENSITY_DEFAULT;
292 return true;
293 }
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800294
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700295 if (strcmp(name, "anydpi") == 0) {
296 if (out) out->density = ResTable_config::DENSITY_ANY;
297 return true;
298 }
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800299
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700300 if (strcmp(name, "nodpi") == 0) {
301 if (out) out->density = ResTable_config::DENSITY_NONE;
302 return true;
303 }
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800304
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700305 if (strcmp(name, "ldpi") == 0) {
306 if (out) out->density = ResTable_config::DENSITY_LOW;
307 return true;
308 }
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800309
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700310 if (strcmp(name, "mdpi") == 0) {
311 if (out) out->density = ResTable_config::DENSITY_MEDIUM;
312 return true;
313 }
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800314
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700315 if (strcmp(name, "tvdpi") == 0) {
316 if (out) out->density = ResTable_config::DENSITY_TV;
317 return true;
318 }
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800319
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700320 if (strcmp(name, "hdpi") == 0) {
321 if (out) out->density = ResTable_config::DENSITY_HIGH;
322 return true;
323 }
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800324
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700325 if (strcmp(name, "xhdpi") == 0) {
326 if (out) out->density = ResTable_config::DENSITY_XHIGH;
327 return true;
328 }
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800329
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700330 if (strcmp(name, "xxhdpi") == 0) {
331 if (out) out->density = ResTable_config::DENSITY_XXHIGH;
332 return true;
333 }
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800334
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700335 if (strcmp(name, "xxxhdpi") == 0) {
336 if (out) out->density = ResTable_config::DENSITY_XXXHIGH;
337 return true;
338 }
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800339
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700340 char* c = (char*)name;
341 while (*c >= '0' && *c <= '9') {
342 c++;
343 }
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800344
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700345 // check that we have 'dpi' after the last digit.
346 if (toupper(c[0]) != 'D' || toupper(c[1]) != 'P' || toupper(c[2]) != 'I' ||
347 c[3] != 0) {
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800348 return false;
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700349 }
350
351 // temporarily replace the first letter with \0 to
352 // use atoi.
353 char tmp = c[0];
354 c[0] = '\0';
355
356 int d = atoi(name);
357 c[0] = tmp;
358
359 if (d != 0) {
360 if (out) out->density = d;
361 return true;
362 }
363
364 return false;
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800365}
366
367static bool parseTouchscreen(const char* name, ResTable_config* out) {
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700368 if (strcmp(name, kWildcardName) == 0) {
369 if (out) out->touchscreen = out->TOUCHSCREEN_ANY;
370 return true;
371 } else if (strcmp(name, "notouch") == 0) {
372 if (out) out->touchscreen = out->TOUCHSCREEN_NOTOUCH;
373 return true;
374 } else if (strcmp(name, "stylus") == 0) {
375 if (out) out->touchscreen = out->TOUCHSCREEN_STYLUS;
376 return true;
377 } else if (strcmp(name, "finger") == 0) {
378 if (out) out->touchscreen = out->TOUCHSCREEN_FINGER;
379 return true;
380 }
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800381
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700382 return false;
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800383}
384
385static bool parseKeysHidden(const char* name, ResTable_config* out) {
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700386 uint8_t mask = 0;
387 uint8_t value = 0;
388 if (strcmp(name, kWildcardName) == 0) {
389 mask = ResTable_config::MASK_KEYSHIDDEN;
390 value = ResTable_config::KEYSHIDDEN_ANY;
391 } else if (strcmp(name, "keysexposed") == 0) {
392 mask = ResTable_config::MASK_KEYSHIDDEN;
393 value = ResTable_config::KEYSHIDDEN_NO;
394 } else if (strcmp(name, "keyshidden") == 0) {
395 mask = ResTable_config::MASK_KEYSHIDDEN;
396 value = ResTable_config::KEYSHIDDEN_YES;
397 } else if (strcmp(name, "keyssoft") == 0) {
398 mask = ResTable_config::MASK_KEYSHIDDEN;
399 value = ResTable_config::KEYSHIDDEN_SOFT;
400 }
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800401
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700402 if (mask != 0) {
403 if (out) out->inputFlags = (out->inputFlags & ~mask) | value;
404 return true;
405 }
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800406
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700407 return false;
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800408}
409
410static bool parseKeyboard(const char* name, ResTable_config* out) {
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700411 if (strcmp(name, kWildcardName) == 0) {
412 if (out) out->keyboard = out->KEYBOARD_ANY;
413 return true;
414 } else if (strcmp(name, "nokeys") == 0) {
415 if (out) out->keyboard = out->KEYBOARD_NOKEYS;
416 return true;
417 } else if (strcmp(name, "qwerty") == 0) {
418 if (out) out->keyboard = out->KEYBOARD_QWERTY;
419 return true;
420 } else if (strcmp(name, "12key") == 0) {
421 if (out) out->keyboard = out->KEYBOARD_12KEY;
422 return true;
423 }
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800424
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700425 return false;
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800426}
427
428static bool parseNavHidden(const char* name, ResTable_config* out) {
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700429 uint8_t mask = 0;
430 uint8_t value = 0;
431 if (strcmp(name, kWildcardName) == 0) {
432 mask = ResTable_config::MASK_NAVHIDDEN;
433 value = ResTable_config::NAVHIDDEN_ANY;
434 } else if (strcmp(name, "navexposed") == 0) {
435 mask = ResTable_config::MASK_NAVHIDDEN;
436 value = ResTable_config::NAVHIDDEN_NO;
437 } else if (strcmp(name, "navhidden") == 0) {
438 mask = ResTable_config::MASK_NAVHIDDEN;
439 value = ResTable_config::NAVHIDDEN_YES;
440 }
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800441
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700442 if (mask != 0) {
443 if (out) out->inputFlags = (out->inputFlags & ~mask) | value;
444 return true;
445 }
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800446
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700447 return false;
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800448}
449
450static bool parseNavigation(const char* name, ResTable_config* out) {
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700451 if (strcmp(name, kWildcardName) == 0) {
452 if (out) out->navigation = out->NAVIGATION_ANY;
453 return true;
454 } else if (strcmp(name, "nonav") == 0) {
455 if (out) out->navigation = out->NAVIGATION_NONAV;
456 return true;
457 } else if (strcmp(name, "dpad") == 0) {
458 if (out) out->navigation = out->NAVIGATION_DPAD;
459 return true;
460 } else if (strcmp(name, "trackball") == 0) {
461 if (out) out->navigation = out->NAVIGATION_TRACKBALL;
462 return true;
463 } else if (strcmp(name, "wheel") == 0) {
464 if (out) out->navigation = out->NAVIGATION_WHEEL;
465 return true;
466 }
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800467
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700468 return false;
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800469}
470
471static bool parseScreenSize(const char* name, ResTable_config* out) {
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700472 if (strcmp(name, kWildcardName) == 0) {
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800473 if (out) {
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700474 out->screenWidth = out->SCREENWIDTH_ANY;
475 out->screenHeight = out->SCREENHEIGHT_ANY;
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800476 }
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800477 return true;
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700478 }
479
480 const char* x = name;
481 while (*x >= '0' && *x <= '9') x++;
482 if (x == name || *x != 'x') return false;
483 std::string xName(name, x - name);
484 x++;
485
486 const char* y = x;
487 while (*y >= '0' && *y <= '9') y++;
488 if (y == name || *y != 0) return false;
489 std::string yName(x, y - x);
490
491 uint16_t w = (uint16_t)atoi(xName.c_str());
492 uint16_t h = (uint16_t)atoi(yName.c_str());
493 if (w < h) {
494 return false;
495 }
496
497 if (out) {
498 out->screenWidth = w;
499 out->screenHeight = h;
500 }
501
502 return true;
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800503}
504
505static bool parseSmallestScreenWidthDp(const char* name, ResTable_config* out) {
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700506 if (strcmp(name, kWildcardName) == 0) {
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800507 if (out) {
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700508 out->smallestScreenWidthDp = out->SCREENWIDTH_ANY;
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800509 }
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800510 return true;
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700511 }
512
513 if (*name != 's') return false;
514 name++;
515 if (*name != 'w') return false;
516 name++;
517 const char* x = name;
518 while (*x >= '0' && *x <= '9') x++;
519 if (x == name || x[0] != 'd' || x[1] != 'p' || x[2] != 0) return false;
520 std::string xName(name, x - name);
521
522 if (out) {
523 out->smallestScreenWidthDp = (uint16_t)atoi(xName.c_str());
524 }
525
526 return true;
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800527}
528
529static bool parseScreenWidthDp(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->screenWidthDp = out->SCREENWIDTH_ANY;
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800533 }
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800534 return true;
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700535 }
536
537 if (*name != 'w') return false;
538 name++;
539 const char* x = name;
540 while (*x >= '0' && *x <= '9') x++;
541 if (x == name || x[0] != 'd' || x[1] != 'p' || x[2] != 0) return false;
542 std::string xName(name, x - name);
543
544 if (out) {
545 out->screenWidthDp = (uint16_t)atoi(xName.c_str());
546 }
547
548 return true;
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800549}
550
551static bool parseScreenHeightDp(const char* name, ResTable_config* out) {
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700552 if (strcmp(name, kWildcardName) == 0) {
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800553 if (out) {
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700554 out->screenHeightDp = out->SCREENWIDTH_ANY;
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800555 }
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800556 return true;
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700557 }
558
559 if (*name != 'h') return false;
560 name++;
561 const char* x = name;
562 while (*x >= '0' && *x <= '9') x++;
563 if (x == name || x[0] != 'd' || x[1] != 'p' || x[2] != 0) return false;
564 std::string xName(name, x - name);
565
566 if (out) {
567 out->screenHeightDp = (uint16_t)atoi(xName.c_str());
568 }
569
570 return true;
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800571}
572
573static bool parseVersion(const char* name, ResTable_config* out) {
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700574 if (strcmp(name, kWildcardName) == 0) {
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800575 if (out) {
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700576 out->sdkVersion = out->SDKVERSION_ANY;
577 out->minorVersion = out->MINORVERSION_ANY;
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800578 }
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800579 return true;
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700580 }
581
582 if (*name != 'v') {
583 return false;
584 }
585
586 name++;
587 const char* s = name;
588 while (*s >= '0' && *s <= '9') s++;
589 if (s == name || *s != 0) return false;
590 std::string sdkName(name, s - name);
591
592 if (out) {
593 out->sdkVersion = (uint16_t)atoi(sdkName.c_str());
594 out->minorVersion = 0;
595 }
596
597 return true;
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800598}
599
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700600bool ConfigDescription::Parse(const StringPiece& str, ConfigDescription* out) {
601 std::vector<std::string> parts = util::SplitAndLowercase(str, '-');
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800602
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700603 ConfigDescription config;
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700604 ssize_t parts_consumed = 0;
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700605 LocaleValue locale;
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800606
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700607 const auto parts_end = parts.end();
608 auto part_iter = parts.begin();
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800609
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700610 if (str.size() == 0) {
611 goto success;
612 }
613
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700614 if (parseMcc(part_iter->c_str(), &config)) {
615 ++part_iter;
616 if (part_iter == parts_end) {
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700617 goto success;
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800618 }
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700619 }
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800620
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700621 if (parseMnc(part_iter->c_str(), &config)) {
622 ++part_iter;
623 if (part_iter == parts_end) {
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700624 goto success;
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800625 }
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700626 }
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800627
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700628 // Locale spans a few '-' separators, so we let it
629 // control the index.
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700630 parts_consumed = locale.InitFromParts(part_iter, parts_end);
631 if (parts_consumed < 0) {
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800632 return false;
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700633 } else {
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700634 locale.WriteTo(&config);
635 part_iter += parts_consumed;
636 if (part_iter == parts_end) {
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700637 goto success;
638 }
639 }
640
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700641 if (parseLayoutDirection(part_iter->c_str(), &config)) {
642 ++part_iter;
643 if (part_iter == parts_end) {
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700644 goto success;
645 }
646 }
647
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700648 if (parseSmallestScreenWidthDp(part_iter->c_str(), &config)) {
649 ++part_iter;
650 if (part_iter == parts_end) {
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700651 goto success;
652 }
653 }
654
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700655 if (parseScreenWidthDp(part_iter->c_str(), &config)) {
656 ++part_iter;
657 if (part_iter == parts_end) {
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700658 goto success;
659 }
660 }
661
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700662 if (parseScreenHeightDp(part_iter->c_str(), &config)) {
663 ++part_iter;
664 if (part_iter == parts_end) {
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700665 goto success;
666 }
667 }
668
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700669 if (parseScreenLayoutSize(part_iter->c_str(), &config)) {
670 ++part_iter;
671 if (part_iter == parts_end) {
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700672 goto success;
673 }
674 }
675
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700676 if (parseScreenLayoutLong(part_iter->c_str(), &config)) {
677 ++part_iter;
678 if (part_iter == parts_end) {
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700679 goto success;
680 }
681 }
682
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700683 if (parseScreenRound(part_iter->c_str(), &config)) {
684 ++part_iter;
685 if (part_iter == parts_end) {
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700686 goto success;
687 }
688 }
689
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700690 if (parseOrientation(part_iter->c_str(), &config)) {
691 ++part_iter;
692 if (part_iter == parts_end) {
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700693 goto success;
694 }
695 }
696
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700697 if (parseUiModeType(part_iter->c_str(), &config)) {
698 ++part_iter;
699 if (part_iter == parts_end) {
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700700 goto success;
701 }
702 }
703
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700704 if (parseUiModeNight(part_iter->c_str(), &config)) {
705 ++part_iter;
706 if (part_iter == parts_end) {
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700707 goto success;
708 }
709 }
710
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700711 if (parseDensity(part_iter->c_str(), &config)) {
712 ++part_iter;
713 if (part_iter == parts_end) {
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700714 goto success;
715 }
716 }
717
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700718 if (parseTouchscreen(part_iter->c_str(), &config)) {
719 ++part_iter;
720 if (part_iter == parts_end) {
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700721 goto success;
722 }
723 }
724
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700725 if (parseKeysHidden(part_iter->c_str(), &config)) {
726 ++part_iter;
727 if (part_iter == parts_end) {
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700728 goto success;
729 }
730 }
731
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700732 if (parseKeyboard(part_iter->c_str(), &config)) {
733 ++part_iter;
734 if (part_iter == parts_end) {
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700735 goto success;
736 }
737 }
738
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700739 if (parseNavHidden(part_iter->c_str(), &config)) {
740 ++part_iter;
741 if (part_iter == parts_end) {
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700742 goto success;
743 }
744 }
745
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700746 if (parseNavigation(part_iter->c_str(), &config)) {
747 ++part_iter;
748 if (part_iter == parts_end) {
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700749 goto success;
750 }
751 }
752
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700753 if (parseScreenSize(part_iter->c_str(), &config)) {
754 ++part_iter;
755 if (part_iter == parts_end) {
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700756 goto success;
757 }
758 }
759
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700760 if (parseVersion(part_iter->c_str(), &config)) {
761 ++part_iter;
762 if (part_iter == parts_end) {
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700763 goto success;
764 }
765 }
766
767 // Unrecognized.
768 return false;
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800769
770success:
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700771 if (out != NULL) {
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700772 ApplyVersionForCompatibility(&config);
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700773 *out = config;
774 }
775 return true;
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800776}
777
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700778void ConfigDescription::ApplyVersionForCompatibility(
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700779 ConfigDescription* config) {
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700780 uint16_t min_sdk = 0;
Zak Cohen1a6acdb2016-12-12 15:21:21 -0800781 if ((config->uiMode & ResTable_config::MASK_UI_MODE_TYPE)
782 == ResTable_config::UI_MODE_TYPE_VR_HEADSET) {
783 min_sdk = SDK_O;
784 } else if (config->screenLayout2 & ResTable_config::MASK_SCREENROUND) {
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700785 min_sdk = SDK_MARSHMALLOW;
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700786 } else if (config->density == ResTable_config::DENSITY_ANY) {
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700787 min_sdk = SDK_LOLLIPOP;
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700788 } else if (config->smallestScreenWidthDp !=
789 ResTable_config::SCREENWIDTH_ANY ||
790 config->screenWidthDp != ResTable_config::SCREENWIDTH_ANY ||
791 config->screenHeightDp != ResTable_config::SCREENHEIGHT_ANY) {
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700792 min_sdk = SDK_HONEYCOMB_MR2;
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700793 } else if ((config->uiMode & ResTable_config::MASK_UI_MODE_TYPE) !=
794 ResTable_config::UI_MODE_TYPE_ANY ||
795 (config->uiMode & ResTable_config::MASK_UI_MODE_NIGHT) !=
796 ResTable_config::UI_MODE_NIGHT_ANY) {
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700797 min_sdk = SDK_FROYO;
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700798 } else if ((config->screenLayout & ResTable_config::MASK_SCREENSIZE) !=
799 ResTable_config::SCREENSIZE_ANY ||
800 (config->screenLayout & ResTable_config::MASK_SCREENLONG) !=
801 ResTable_config::SCREENLONG_ANY ||
802 config->density != ResTable_config::DENSITY_DEFAULT) {
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700803 min_sdk = SDK_DONUT;
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700804 }
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800805
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700806 if (min_sdk > config->sdkVersion) {
807 config->sdkVersion = min_sdk;
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700808 }
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800809}
810
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700811ConfigDescription ConfigDescription::CopyWithoutSdkVersion() const {
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700812 ConfigDescription copy = *this;
813 copy.sdkVersion = 0;
814 return copy;
Adam Lesinski87675ad2016-07-15 17:03:03 -0700815}
816
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700817bool ConfigDescription::Dominates(const ConfigDescription& o) const {
818 if (*this == DefaultConfig() || *this == o) {
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700819 return true;
820 }
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700821 return MatchWithDensity(o) && !o.MatchWithDensity(*this) &&
822 !isMoreSpecificThan(o) && !o.HasHigherPrecedenceThan(*this);
Alexandria Cornwall77788eb2016-09-06 15:16:49 -0700823}
824
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700825bool ConfigDescription::HasHigherPrecedenceThan(
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700826 const ConfigDescription& o) const {
827 // The order of the following tests defines the importance of one
828 // configuration parameter over another. Those tests first are more
829 // important, trumping any values in those following them.
830 // The ordering should be the same as ResTable_config#isBetterThan.
831 if (mcc || o.mcc) return (!o.mcc);
832 if (mnc || o.mnc) return (!o.mnc);
833 if (language[0] || o.language[0]) return (!o.language[0]);
834 if (country[0] || o.country[0]) return (!o.country[0]);
835 // Script and variant require either a language or country, both of which
836 // have higher precedence.
837 if ((screenLayout | o.screenLayout) & MASK_LAYOUTDIR) {
838 return !(o.screenLayout & MASK_LAYOUTDIR);
839 }
840 if (smallestScreenWidthDp || o.smallestScreenWidthDp)
841 return (!o.smallestScreenWidthDp);
842 if (screenWidthDp || o.screenWidthDp) return (!o.screenWidthDp);
843 if (screenHeightDp || o.screenHeightDp) return (!o.screenHeightDp);
844 if ((screenLayout | o.screenLayout) & MASK_SCREENSIZE) {
845 return !(o.screenLayout & MASK_SCREENSIZE);
846 }
847 if ((screenLayout | o.screenLayout) & MASK_SCREENLONG) {
848 return !(o.screenLayout & MASK_SCREENLONG);
849 }
850 if ((screenLayout2 | o.screenLayout2) & MASK_SCREENROUND) {
851 return !(o.screenLayout2 & MASK_SCREENROUND);
852 }
853 if (orientation || o.orientation) return (!o.orientation);
854 if ((uiMode | o.uiMode) & MASK_UI_MODE_TYPE) {
855 return !(o.uiMode & MASK_UI_MODE_TYPE);
856 }
857 if ((uiMode | o.uiMode) & MASK_UI_MODE_NIGHT) {
858 return !(o.uiMode & MASK_UI_MODE_NIGHT);
859 }
860 if (density || o.density) return (!o.density);
861 if (touchscreen || o.touchscreen) return (!o.touchscreen);
862 if ((inputFlags | o.inputFlags) & MASK_KEYSHIDDEN) {
863 return !(o.inputFlags & MASK_KEYSHIDDEN);
864 }
865 if ((inputFlags | o.inputFlags) & MASK_NAVHIDDEN) {
866 return !(o.inputFlags & MASK_NAVHIDDEN);
867 }
868 if (keyboard || o.keyboard) return (!o.keyboard);
869 if (navigation || o.navigation) return (!o.navigation);
870 if (screenWidth || o.screenWidth) return (!o.screenWidth);
871 if (screenHeight || o.screenHeight) return (!o.screenHeight);
872 if (sdkVersion || o.sdkVersion) return (!o.sdkVersion);
873 if (minorVersion || o.minorVersion) return (!o.minorVersion);
874 // Both configurations have nothing defined except some possible future
875 // value. Returning the comparison of the two configurations is a
876 // "best effort" at this point to protect against incorrect dominations.
877 return *this != o;
Alexandria Cornwall77788eb2016-09-06 15:16:49 -0700878}
879
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700880bool ConfigDescription::ConflictsWith(const ConfigDescription& o) const {
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700881 // This method should be updated as new configuration parameters are
882 // introduced (e.g. screenConfig2).
883 auto pred = [](const uint32_t a, const uint32_t b) -> bool {
884 return a == 0 || b == 0 || a == b;
885 };
886 // The values here can be found in ResTable_config#match. Density and range
887 // values can't lead to conflicts, and are ignored.
888 return !pred(mcc, o.mcc) || !pred(mnc, o.mnc) || !pred(locale, o.locale) ||
889 !pred(screenLayout & MASK_LAYOUTDIR,
890 o.screenLayout & MASK_LAYOUTDIR) ||
891 !pred(screenLayout & MASK_SCREENLONG,
892 o.screenLayout & MASK_SCREENLONG) ||
893 !pred(screenLayout & MASK_UI_MODE_TYPE,
894 o.screenLayout & MASK_UI_MODE_TYPE) ||
895 !pred(uiMode & MASK_UI_MODE_TYPE, o.uiMode & MASK_UI_MODE_TYPE) ||
896 !pred(uiMode & MASK_UI_MODE_NIGHT, o.uiMode & MASK_UI_MODE_NIGHT) ||
897 !pred(screenLayout2 & MASK_SCREENROUND,
898 o.screenLayout2 & MASK_SCREENROUND) ||
899 !pred(orientation, o.orientation) ||
900 !pred(touchscreen, o.touchscreen) ||
901 !pred(inputFlags & MASK_KEYSHIDDEN, o.inputFlags & MASK_KEYSHIDDEN) ||
902 !pred(inputFlags & MASK_NAVHIDDEN, o.inputFlags & MASK_NAVHIDDEN) ||
903 !pred(keyboard, o.keyboard) || !pred(navigation, o.navigation);
Alexandria Cornwall77788eb2016-09-06 15:16:49 -0700904}
905
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700906bool ConfigDescription::IsCompatibleWith(const ConfigDescription& o) const {
907 return !ConflictsWith(o) && !Dominates(o) && !o.Dominates(*this);
Alexandria Cornwall77788eb2016-09-06 15:16:49 -0700908}
909
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700910} // namespace aapt