blob: 6598d63882001189f933d91c58415053583cd860 [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"
18#include "Locale.h"
19#include "SdkConstants.h"
Adam Lesinski1ab598f2015-08-14 14:26:04 -070020#include "util/StringPiece.h"
21#include "util/Util.h"
Adam Lesinski6f6ceb72014-11-14 14:48:12 -080022
23#include <androidfw/ResourceTypes.h>
24#include <string>
25#include <vector>
26
27namespace aapt {
28
29using android::ResTable_config;
30
31static const char* kWildcardName = "any";
32
Adam Lesinski52364f72016-01-11 13:10:24 -080033const ConfigDescription& ConfigDescription::defaultConfig() {
Adam Lesinskicacb28f2016-10-19 12:18:14 -070034 static ConfigDescription config = {};
35 return config;
Adam Lesinski52364f72016-01-11 13:10:24 -080036}
37
Adam Lesinski6f6ceb72014-11-14 14:48:12 -080038static bool parseMcc(const char* name, ResTable_config* out) {
Adam Lesinskicacb28f2016-10-19 12:18:14 -070039 if (strcmp(name, kWildcardName) == 0) {
40 if (out) out->mcc = 0;
41 return true;
42 }
43 const char* c = name;
44 if (tolower(*c) != 'm') return false;
45 c++;
46 if (tolower(*c) != 'c') return false;
47 c++;
48 if (tolower(*c) != 'c') return false;
49 c++;
50
51 const char* val = c;
52
53 while (*c >= '0' && *c <= '9') {
Adam Lesinski6f6ceb72014-11-14 14:48:12 -080054 c++;
Adam Lesinskicacb28f2016-10-19 12:18:14 -070055 }
56 if (*c != 0) return false;
57 if (c - val != 3) return false;
Adam Lesinski6f6ceb72014-11-14 14:48:12 -080058
Adam Lesinskicacb28f2016-10-19 12:18:14 -070059 int d = atoi(val);
60 if (d != 0) {
61 if (out) out->mcc = d;
62 return true;
63 }
Adam Lesinski6f6ceb72014-11-14 14:48:12 -080064
Adam Lesinskicacb28f2016-10-19 12:18:14 -070065 return false;
Adam Lesinski6f6ceb72014-11-14 14:48:12 -080066}
67
68static bool parseMnc(const char* name, ResTable_config* out) {
Adam Lesinskicacb28f2016-10-19 12:18:14 -070069 if (strcmp(name, kWildcardName) == 0) {
70 if (out) out->mcc = 0;
Adam Lesinski6f6ceb72014-11-14 14:48:12 -080071 return true;
Adam Lesinskicacb28f2016-10-19 12:18:14 -070072 }
73 const char* c = name;
74 if (tolower(*c) != 'm') return false;
75 c++;
76 if (tolower(*c) != 'n') return false;
77 c++;
78 if (tolower(*c) != 'c') return false;
79 c++;
80
81 const char* val = c;
82
83 while (*c >= '0' && *c <= '9') {
84 c++;
85 }
86 if (*c != 0) return false;
87 if (c - val == 0 || c - val > 3) return false;
88
89 if (out) {
90 out->mnc = atoi(val);
91 if (out->mnc == 0) {
92 out->mnc = ACONFIGURATION_MNC_ZERO;
93 }
94 }
95
96 return true;
Adam Lesinski6f6ceb72014-11-14 14:48:12 -080097}
98
99static bool parseLayoutDirection(const char* name, ResTable_config* out) {
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700100 if (strcmp(name, kWildcardName) == 0) {
101 if (out)
102 out->screenLayout =
103 (out->screenLayout & ~ResTable_config::MASK_LAYOUTDIR) |
104 ResTable_config::LAYOUTDIR_ANY;
105 return true;
106 } else if (strcmp(name, "ldltr") == 0) {
107 if (out)
108 out->screenLayout =
109 (out->screenLayout & ~ResTable_config::MASK_LAYOUTDIR) |
110 ResTable_config::LAYOUTDIR_LTR;
111 return true;
112 } else if (strcmp(name, "ldrtl") == 0) {
113 if (out)
114 out->screenLayout =
115 (out->screenLayout & ~ResTable_config::MASK_LAYOUTDIR) |
116 ResTable_config::LAYOUTDIR_RTL;
117 return true;
118 }
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800119
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700120 return false;
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800121}
122
123static bool parseScreenLayoutSize(const char* name, ResTable_config* out) {
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700124 if (strcmp(name, kWildcardName) == 0) {
125 if (out)
126 out->screenLayout =
127 (out->screenLayout & ~ResTable_config::MASK_SCREENSIZE) |
128 ResTable_config::SCREENSIZE_ANY;
129 return true;
130 } else if (strcmp(name, "small") == 0) {
131 if (out)
132 out->screenLayout =
133 (out->screenLayout & ~ResTable_config::MASK_SCREENSIZE) |
134 ResTable_config::SCREENSIZE_SMALL;
135 return true;
136 } else if (strcmp(name, "normal") == 0) {
137 if (out)
138 out->screenLayout =
139 (out->screenLayout & ~ResTable_config::MASK_SCREENSIZE) |
140 ResTable_config::SCREENSIZE_NORMAL;
141 return true;
142 } else if (strcmp(name, "large") == 0) {
143 if (out)
144 out->screenLayout =
145 (out->screenLayout & ~ResTable_config::MASK_SCREENSIZE) |
146 ResTable_config::SCREENSIZE_LARGE;
147 return true;
148 } else if (strcmp(name, "xlarge") == 0) {
149 if (out)
150 out->screenLayout =
151 (out->screenLayout & ~ResTable_config::MASK_SCREENSIZE) |
152 ResTable_config::SCREENSIZE_XLARGE;
153 return true;
154 }
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800155
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700156 return false;
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800157}
158
159static bool parseScreenLayoutLong(const char* name, ResTable_config* out) {
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700160 if (strcmp(name, kWildcardName) == 0) {
161 if (out)
162 out->screenLayout =
163 (out->screenLayout & ~ResTable_config::MASK_SCREENLONG) |
164 ResTable_config::SCREENLONG_ANY;
165 return true;
166 } else if (strcmp(name, "long") == 0) {
167 if (out)
168 out->screenLayout =
169 (out->screenLayout & ~ResTable_config::MASK_SCREENLONG) |
170 ResTable_config::SCREENLONG_YES;
171 return true;
172 } else if (strcmp(name, "notlong") == 0) {
173 if (out)
174 out->screenLayout =
175 (out->screenLayout & ~ResTable_config::MASK_SCREENLONG) |
176 ResTable_config::SCREENLONG_NO;
177 return true;
178 }
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800179
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700180 return false;
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800181}
182
Adam Lesinski64254972015-11-03 16:16:17 -0800183static bool parseScreenRound(const char* name, ResTable_config* out) {
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700184 if (strcmp(name, kWildcardName) == 0) {
185 if (out)
186 out->screenLayout2 =
187 (out->screenLayout2 & ~ResTable_config::MASK_SCREENROUND) |
188 ResTable_config::SCREENROUND_ANY;
189 return true;
190 } else if (strcmp(name, "round") == 0) {
191 if (out)
192 out->screenLayout2 =
193 (out->screenLayout2 & ~ResTable_config::MASK_SCREENROUND) |
194 ResTable_config::SCREENROUND_YES;
195 return true;
196 } else if (strcmp(name, "notround") == 0) {
197 if (out)
198 out->screenLayout2 =
199 (out->screenLayout2 & ~ResTable_config::MASK_SCREENROUND) |
200 ResTable_config::SCREENROUND_NO;
201 return true;
202 }
203 return false;
Adam Lesinski64254972015-11-03 16:16:17 -0800204}
205
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800206static bool parseOrientation(const char* name, ResTable_config* out) {
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700207 if (strcmp(name, kWildcardName) == 0) {
208 if (out) out->orientation = out->ORIENTATION_ANY;
209 return true;
210 } else if (strcmp(name, "port") == 0) {
211 if (out) out->orientation = out->ORIENTATION_PORT;
212 return true;
213 } else if (strcmp(name, "land") == 0) {
214 if (out) out->orientation = out->ORIENTATION_LAND;
215 return true;
216 } else if (strcmp(name, "square") == 0) {
217 if (out) out->orientation = out->ORIENTATION_SQUARE;
218 return true;
219 }
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800220
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700221 return false;
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800222}
223
224static bool parseUiModeType(const char* name, ResTable_config* out) {
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700225 if (strcmp(name, kWildcardName) == 0) {
226 if (out)
227 out->uiMode = (out->uiMode & ~ResTable_config::MASK_UI_MODE_TYPE) |
228 ResTable_config::UI_MODE_TYPE_ANY;
229 return true;
230 } else if (strcmp(name, "desk") == 0) {
231 if (out)
232 out->uiMode = (out->uiMode & ~ResTable_config::MASK_UI_MODE_TYPE) |
233 ResTable_config::UI_MODE_TYPE_DESK;
234 return true;
235 } else if (strcmp(name, "car") == 0) {
236 if (out)
237 out->uiMode = (out->uiMode & ~ResTable_config::MASK_UI_MODE_TYPE) |
238 ResTable_config::UI_MODE_TYPE_CAR;
239 return true;
240 } else if (strcmp(name, "television") == 0) {
241 if (out)
242 out->uiMode = (out->uiMode & ~ResTable_config::MASK_UI_MODE_TYPE) |
243 ResTable_config::UI_MODE_TYPE_TELEVISION;
244 return true;
245 } else if (strcmp(name, "appliance") == 0) {
246 if (out)
247 out->uiMode = (out->uiMode & ~ResTable_config::MASK_UI_MODE_TYPE) |
248 ResTable_config::UI_MODE_TYPE_APPLIANCE;
249 return true;
250 } else if (strcmp(name, "watch") == 0) {
251 if (out)
252 out->uiMode = (out->uiMode & ~ResTable_config::MASK_UI_MODE_TYPE) |
253 ResTable_config::UI_MODE_TYPE_WATCH;
254 return true;
255 }
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800256
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700257 return false;
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800258}
259
260static bool parseUiModeNight(const char* name, ResTable_config* out) {
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700261 if (strcmp(name, kWildcardName) == 0) {
262 if (out)
263 out->uiMode = (out->uiMode & ~ResTable_config::MASK_UI_MODE_NIGHT) |
264 ResTable_config::UI_MODE_NIGHT_ANY;
265 return true;
266 } else if (strcmp(name, "night") == 0) {
267 if (out)
268 out->uiMode = (out->uiMode & ~ResTable_config::MASK_UI_MODE_NIGHT) |
269 ResTable_config::UI_MODE_NIGHT_YES;
270 return true;
271 } else if (strcmp(name, "notnight") == 0) {
272 if (out)
273 out->uiMode = (out->uiMode & ~ResTable_config::MASK_UI_MODE_NIGHT) |
274 ResTable_config::UI_MODE_NIGHT_NO;
275 return true;
276 }
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800277
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700278 return false;
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800279}
280
281static bool parseDensity(const char* name, ResTable_config* out) {
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700282 if (strcmp(name, kWildcardName) == 0) {
283 if (out) out->density = ResTable_config::DENSITY_DEFAULT;
284 return true;
285 }
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800286
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700287 if (strcmp(name, "anydpi") == 0) {
288 if (out) out->density = ResTable_config::DENSITY_ANY;
289 return true;
290 }
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800291
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700292 if (strcmp(name, "nodpi") == 0) {
293 if (out) out->density = ResTable_config::DENSITY_NONE;
294 return true;
295 }
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800296
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700297 if (strcmp(name, "ldpi") == 0) {
298 if (out) out->density = ResTable_config::DENSITY_LOW;
299 return true;
300 }
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800301
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700302 if (strcmp(name, "mdpi") == 0) {
303 if (out) out->density = ResTable_config::DENSITY_MEDIUM;
304 return true;
305 }
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800306
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700307 if (strcmp(name, "tvdpi") == 0) {
308 if (out) out->density = ResTable_config::DENSITY_TV;
309 return true;
310 }
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800311
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700312 if (strcmp(name, "hdpi") == 0) {
313 if (out) out->density = ResTable_config::DENSITY_HIGH;
314 return true;
315 }
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800316
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700317 if (strcmp(name, "xhdpi") == 0) {
318 if (out) out->density = ResTable_config::DENSITY_XHIGH;
319 return true;
320 }
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800321
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700322 if (strcmp(name, "xxhdpi") == 0) {
323 if (out) out->density = ResTable_config::DENSITY_XXHIGH;
324 return true;
325 }
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800326
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700327 if (strcmp(name, "xxxhdpi") == 0) {
328 if (out) out->density = ResTable_config::DENSITY_XXXHIGH;
329 return true;
330 }
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800331
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700332 char* c = (char*)name;
333 while (*c >= '0' && *c <= '9') {
334 c++;
335 }
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800336
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700337 // check that we have 'dpi' after the last digit.
338 if (toupper(c[0]) != 'D' || toupper(c[1]) != 'P' || toupper(c[2]) != 'I' ||
339 c[3] != 0) {
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800340 return false;
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700341 }
342
343 // temporarily replace the first letter with \0 to
344 // use atoi.
345 char tmp = c[0];
346 c[0] = '\0';
347
348 int d = atoi(name);
349 c[0] = tmp;
350
351 if (d != 0) {
352 if (out) out->density = d;
353 return true;
354 }
355
356 return false;
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800357}
358
359static bool parseTouchscreen(const char* name, ResTable_config* out) {
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700360 if (strcmp(name, kWildcardName) == 0) {
361 if (out) out->touchscreen = out->TOUCHSCREEN_ANY;
362 return true;
363 } else if (strcmp(name, "notouch") == 0) {
364 if (out) out->touchscreen = out->TOUCHSCREEN_NOTOUCH;
365 return true;
366 } else if (strcmp(name, "stylus") == 0) {
367 if (out) out->touchscreen = out->TOUCHSCREEN_STYLUS;
368 return true;
369 } else if (strcmp(name, "finger") == 0) {
370 if (out) out->touchscreen = out->TOUCHSCREEN_FINGER;
371 return true;
372 }
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800373
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700374 return false;
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800375}
376
377static bool parseKeysHidden(const char* name, ResTable_config* out) {
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700378 uint8_t mask = 0;
379 uint8_t value = 0;
380 if (strcmp(name, kWildcardName) == 0) {
381 mask = ResTable_config::MASK_KEYSHIDDEN;
382 value = ResTable_config::KEYSHIDDEN_ANY;
383 } else if (strcmp(name, "keysexposed") == 0) {
384 mask = ResTable_config::MASK_KEYSHIDDEN;
385 value = ResTable_config::KEYSHIDDEN_NO;
386 } else if (strcmp(name, "keyshidden") == 0) {
387 mask = ResTable_config::MASK_KEYSHIDDEN;
388 value = ResTable_config::KEYSHIDDEN_YES;
389 } else if (strcmp(name, "keyssoft") == 0) {
390 mask = ResTable_config::MASK_KEYSHIDDEN;
391 value = ResTable_config::KEYSHIDDEN_SOFT;
392 }
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800393
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700394 if (mask != 0) {
395 if (out) out->inputFlags = (out->inputFlags & ~mask) | value;
396 return true;
397 }
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800398
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700399 return false;
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800400}
401
402static bool parseKeyboard(const char* name, ResTable_config* out) {
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700403 if (strcmp(name, kWildcardName) == 0) {
404 if (out) out->keyboard = out->KEYBOARD_ANY;
405 return true;
406 } else if (strcmp(name, "nokeys") == 0) {
407 if (out) out->keyboard = out->KEYBOARD_NOKEYS;
408 return true;
409 } else if (strcmp(name, "qwerty") == 0) {
410 if (out) out->keyboard = out->KEYBOARD_QWERTY;
411 return true;
412 } else if (strcmp(name, "12key") == 0) {
413 if (out) out->keyboard = out->KEYBOARD_12KEY;
414 return true;
415 }
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800416
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700417 return false;
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800418}
419
420static bool parseNavHidden(const char* name, ResTable_config* out) {
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700421 uint8_t mask = 0;
422 uint8_t value = 0;
423 if (strcmp(name, kWildcardName) == 0) {
424 mask = ResTable_config::MASK_NAVHIDDEN;
425 value = ResTable_config::NAVHIDDEN_ANY;
426 } else if (strcmp(name, "navexposed") == 0) {
427 mask = ResTable_config::MASK_NAVHIDDEN;
428 value = ResTable_config::NAVHIDDEN_NO;
429 } else if (strcmp(name, "navhidden") == 0) {
430 mask = ResTable_config::MASK_NAVHIDDEN;
431 value = ResTable_config::NAVHIDDEN_YES;
432 }
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800433
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700434 if (mask != 0) {
435 if (out) out->inputFlags = (out->inputFlags & ~mask) | value;
436 return true;
437 }
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800438
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700439 return false;
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800440}
441
442static bool parseNavigation(const char* name, ResTable_config* out) {
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700443 if (strcmp(name, kWildcardName) == 0) {
444 if (out) out->navigation = out->NAVIGATION_ANY;
445 return true;
446 } else if (strcmp(name, "nonav") == 0) {
447 if (out) out->navigation = out->NAVIGATION_NONAV;
448 return true;
449 } else if (strcmp(name, "dpad") == 0) {
450 if (out) out->navigation = out->NAVIGATION_DPAD;
451 return true;
452 } else if (strcmp(name, "trackball") == 0) {
453 if (out) out->navigation = out->NAVIGATION_TRACKBALL;
454 return true;
455 } else if (strcmp(name, "wheel") == 0) {
456 if (out) out->navigation = out->NAVIGATION_WHEEL;
457 return true;
458 }
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800459
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700460 return false;
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800461}
462
463static bool parseScreenSize(const char* name, ResTable_config* out) {
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700464 if (strcmp(name, kWildcardName) == 0) {
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800465 if (out) {
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700466 out->screenWidth = out->SCREENWIDTH_ANY;
467 out->screenHeight = out->SCREENHEIGHT_ANY;
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800468 }
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800469 return true;
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700470 }
471
472 const char* x = name;
473 while (*x >= '0' && *x <= '9') x++;
474 if (x == name || *x != 'x') return false;
475 std::string xName(name, x - name);
476 x++;
477
478 const char* y = x;
479 while (*y >= '0' && *y <= '9') y++;
480 if (y == name || *y != 0) return false;
481 std::string yName(x, y - x);
482
483 uint16_t w = (uint16_t)atoi(xName.c_str());
484 uint16_t h = (uint16_t)atoi(yName.c_str());
485 if (w < h) {
486 return false;
487 }
488
489 if (out) {
490 out->screenWidth = w;
491 out->screenHeight = h;
492 }
493
494 return true;
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800495}
496
497static bool parseSmallestScreenWidthDp(const char* name, ResTable_config* out) {
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700498 if (strcmp(name, kWildcardName) == 0) {
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800499 if (out) {
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700500 out->smallestScreenWidthDp = out->SCREENWIDTH_ANY;
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800501 }
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800502 return true;
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700503 }
504
505 if (*name != 's') return false;
506 name++;
507 if (*name != 'w') return false;
508 name++;
509 const char* x = name;
510 while (*x >= '0' && *x <= '9') x++;
511 if (x == name || x[0] != 'd' || x[1] != 'p' || x[2] != 0) return false;
512 std::string xName(name, x - name);
513
514 if (out) {
515 out->smallestScreenWidthDp = (uint16_t)atoi(xName.c_str());
516 }
517
518 return true;
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800519}
520
521static bool parseScreenWidthDp(const char* name, ResTable_config* out) {
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700522 if (strcmp(name, kWildcardName) == 0) {
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800523 if (out) {
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700524 out->screenWidthDp = out->SCREENWIDTH_ANY;
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800525 }
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800526 return true;
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700527 }
528
529 if (*name != 'w') return false;
530 name++;
531 const char* x = name;
532 while (*x >= '0' && *x <= '9') x++;
533 if (x == name || x[0] != 'd' || x[1] != 'p' || x[2] != 0) return false;
534 std::string xName(name, x - name);
535
536 if (out) {
537 out->screenWidthDp = (uint16_t)atoi(xName.c_str());
538 }
539
540 return true;
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800541}
542
543static bool parseScreenHeightDp(const char* name, ResTable_config* out) {
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700544 if (strcmp(name, kWildcardName) == 0) {
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800545 if (out) {
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700546 out->screenHeightDp = out->SCREENWIDTH_ANY;
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800547 }
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800548 return true;
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700549 }
550
551 if (*name != 'h') return false;
552 name++;
553 const char* x = name;
554 while (*x >= '0' && *x <= '9') x++;
555 if (x == name || x[0] != 'd' || x[1] != 'p' || x[2] != 0) return false;
556 std::string xName(name, x - name);
557
558 if (out) {
559 out->screenHeightDp = (uint16_t)atoi(xName.c_str());
560 }
561
562 return true;
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800563}
564
565static bool parseVersion(const char* name, ResTable_config* out) {
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700566 if (strcmp(name, kWildcardName) == 0) {
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800567 if (out) {
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700568 out->sdkVersion = out->SDKVERSION_ANY;
569 out->minorVersion = out->MINORVERSION_ANY;
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800570 }
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800571 return true;
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700572 }
573
574 if (*name != 'v') {
575 return false;
576 }
577
578 name++;
579 const char* s = name;
580 while (*s >= '0' && *s <= '9') s++;
581 if (s == name || *s != 0) return false;
582 std::string sdkName(name, s - name);
583
584 if (out) {
585 out->sdkVersion = (uint16_t)atoi(sdkName.c_str());
586 out->minorVersion = 0;
587 }
588
589 return true;
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800590}
591
592bool ConfigDescription::parse(const StringPiece& str, ConfigDescription* out) {
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700593 std::vector<std::string> parts = util::splitAndLowercase(str, '-');
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800594
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700595 ConfigDescription config;
596 ssize_t partsConsumed = 0;
597 LocaleValue locale;
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800598
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700599 const auto partsEnd = parts.end();
600 auto partIter = parts.begin();
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800601
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700602 if (str.size() == 0) {
603 goto success;
604 }
605
606 if (parseMcc(partIter->c_str(), &config)) {
607 ++partIter;
608 if (partIter == partsEnd) {
609 goto success;
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800610 }
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700611 }
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800612
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700613 if (parseMnc(partIter->c_str(), &config)) {
614 ++partIter;
615 if (partIter == partsEnd) {
616 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 Lesinskicacb28f2016-10-19 12:18:14 -0700620 // Locale spans a few '-' separators, so we let it
621 // control the index.
622 partsConsumed = locale.initFromParts(partIter, partsEnd);
623 if (partsConsumed < 0) {
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800624 return false;
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700625 } else {
626 locale.writeTo(&config);
627 partIter += partsConsumed;
628 if (partIter == partsEnd) {
629 goto success;
630 }
631 }
632
633 if (parseLayoutDirection(partIter->c_str(), &config)) {
634 ++partIter;
635 if (partIter == partsEnd) {
636 goto success;
637 }
638 }
639
640 if (parseSmallestScreenWidthDp(partIter->c_str(), &config)) {
641 ++partIter;
642 if (partIter == partsEnd) {
643 goto success;
644 }
645 }
646
647 if (parseScreenWidthDp(partIter->c_str(), &config)) {
648 ++partIter;
649 if (partIter == partsEnd) {
650 goto success;
651 }
652 }
653
654 if (parseScreenHeightDp(partIter->c_str(), &config)) {
655 ++partIter;
656 if (partIter == partsEnd) {
657 goto success;
658 }
659 }
660
661 if (parseScreenLayoutSize(partIter->c_str(), &config)) {
662 ++partIter;
663 if (partIter == partsEnd) {
664 goto success;
665 }
666 }
667
668 if (parseScreenLayoutLong(partIter->c_str(), &config)) {
669 ++partIter;
670 if (partIter == partsEnd) {
671 goto success;
672 }
673 }
674
675 if (parseScreenRound(partIter->c_str(), &config)) {
676 ++partIter;
677 if (partIter == partsEnd) {
678 goto success;
679 }
680 }
681
682 if (parseOrientation(partIter->c_str(), &config)) {
683 ++partIter;
684 if (partIter == partsEnd) {
685 goto success;
686 }
687 }
688
689 if (parseUiModeType(partIter->c_str(), &config)) {
690 ++partIter;
691 if (partIter == partsEnd) {
692 goto success;
693 }
694 }
695
696 if (parseUiModeNight(partIter->c_str(), &config)) {
697 ++partIter;
698 if (partIter == partsEnd) {
699 goto success;
700 }
701 }
702
703 if (parseDensity(partIter->c_str(), &config)) {
704 ++partIter;
705 if (partIter == partsEnd) {
706 goto success;
707 }
708 }
709
710 if (parseTouchscreen(partIter->c_str(), &config)) {
711 ++partIter;
712 if (partIter == partsEnd) {
713 goto success;
714 }
715 }
716
717 if (parseKeysHidden(partIter->c_str(), &config)) {
718 ++partIter;
719 if (partIter == partsEnd) {
720 goto success;
721 }
722 }
723
724 if (parseKeyboard(partIter->c_str(), &config)) {
725 ++partIter;
726 if (partIter == partsEnd) {
727 goto success;
728 }
729 }
730
731 if (parseNavHidden(partIter->c_str(), &config)) {
732 ++partIter;
733 if (partIter == partsEnd) {
734 goto success;
735 }
736 }
737
738 if (parseNavigation(partIter->c_str(), &config)) {
739 ++partIter;
740 if (partIter == partsEnd) {
741 goto success;
742 }
743 }
744
745 if (parseScreenSize(partIter->c_str(), &config)) {
746 ++partIter;
747 if (partIter == partsEnd) {
748 goto success;
749 }
750 }
751
752 if (parseVersion(partIter->c_str(), &config)) {
753 ++partIter;
754 if (partIter == partsEnd) {
755 goto success;
756 }
757 }
758
759 // Unrecognized.
760 return false;
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800761
762success:
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700763 if (out != NULL) {
764 applyVersionForCompatibility(&config);
765 *out = config;
766 }
767 return true;
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800768}
769
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700770void ConfigDescription::applyVersionForCompatibility(
771 ConfigDescription* config) {
772 uint16_t minSdk = 0;
773 if (config->screenLayout2 & ResTable_config::MASK_SCREENROUND) {
774 minSdk = SDK_MARSHMALLOW;
775 } else if (config->density == ResTable_config::DENSITY_ANY) {
776 minSdk = SDK_LOLLIPOP;
777 } else if (config->smallestScreenWidthDp !=
778 ResTable_config::SCREENWIDTH_ANY ||
779 config->screenWidthDp != ResTable_config::SCREENWIDTH_ANY ||
780 config->screenHeightDp != ResTable_config::SCREENHEIGHT_ANY) {
781 minSdk = SDK_HONEYCOMB_MR2;
782 } else if ((config->uiMode & ResTable_config::MASK_UI_MODE_TYPE) !=
783 ResTable_config::UI_MODE_TYPE_ANY ||
784 (config->uiMode & ResTable_config::MASK_UI_MODE_NIGHT) !=
785 ResTable_config::UI_MODE_NIGHT_ANY) {
786 minSdk = SDK_FROYO;
787 } else if ((config->screenLayout & ResTable_config::MASK_SCREENSIZE) !=
788 ResTable_config::SCREENSIZE_ANY ||
789 (config->screenLayout & ResTable_config::MASK_SCREENLONG) !=
790 ResTable_config::SCREENLONG_ANY ||
791 config->density != ResTable_config::DENSITY_DEFAULT) {
792 minSdk = SDK_DONUT;
793 }
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800794
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700795 if (minSdk > config->sdkVersion) {
796 config->sdkVersion = minSdk;
797 }
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800798}
799
Adam Lesinski87675ad2016-07-15 17:03:03 -0700800ConfigDescription ConfigDescription::copyWithoutSdkVersion() const {
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700801 ConfigDescription copy = *this;
802 copy.sdkVersion = 0;
803 return copy;
Adam Lesinski87675ad2016-07-15 17:03:03 -0700804}
805
Alexandria Cornwall77788eb2016-09-06 15:16:49 -0700806bool ConfigDescription::dominates(const ConfigDescription& o) const {
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700807 if (*this == defaultConfig() || *this == o) {
808 return true;
809 }
810 return matchWithDensity(o) && !o.matchWithDensity(*this) &&
811 !isMoreSpecificThan(o) && !o.hasHigherPrecedenceThan(*this);
Alexandria Cornwall77788eb2016-09-06 15:16:49 -0700812}
813
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700814bool ConfigDescription::hasHigherPrecedenceThan(
815 const ConfigDescription& o) const {
816 // The order of the following tests defines the importance of one
817 // configuration parameter over another. Those tests first are more
818 // important, trumping any values in those following them.
819 // The ordering should be the same as ResTable_config#isBetterThan.
820 if (mcc || o.mcc) return (!o.mcc);
821 if (mnc || o.mnc) return (!o.mnc);
822 if (language[0] || o.language[0]) return (!o.language[0]);
823 if (country[0] || o.country[0]) return (!o.country[0]);
824 // Script and variant require either a language or country, both of which
825 // have higher precedence.
826 if ((screenLayout | o.screenLayout) & MASK_LAYOUTDIR) {
827 return !(o.screenLayout & MASK_LAYOUTDIR);
828 }
829 if (smallestScreenWidthDp || o.smallestScreenWidthDp)
830 return (!o.smallestScreenWidthDp);
831 if (screenWidthDp || o.screenWidthDp) return (!o.screenWidthDp);
832 if (screenHeightDp || o.screenHeightDp) return (!o.screenHeightDp);
833 if ((screenLayout | o.screenLayout) & MASK_SCREENSIZE) {
834 return !(o.screenLayout & MASK_SCREENSIZE);
835 }
836 if ((screenLayout | o.screenLayout) & MASK_SCREENLONG) {
837 return !(o.screenLayout & MASK_SCREENLONG);
838 }
839 if ((screenLayout2 | o.screenLayout2) & MASK_SCREENROUND) {
840 return !(o.screenLayout2 & MASK_SCREENROUND);
841 }
842 if (orientation || o.orientation) return (!o.orientation);
843 if ((uiMode | o.uiMode) & MASK_UI_MODE_TYPE) {
844 return !(o.uiMode & MASK_UI_MODE_TYPE);
845 }
846 if ((uiMode | o.uiMode) & MASK_UI_MODE_NIGHT) {
847 return !(o.uiMode & MASK_UI_MODE_NIGHT);
848 }
849 if (density || o.density) return (!o.density);
850 if (touchscreen || o.touchscreen) return (!o.touchscreen);
851 if ((inputFlags | o.inputFlags) & MASK_KEYSHIDDEN) {
852 return !(o.inputFlags & MASK_KEYSHIDDEN);
853 }
854 if ((inputFlags | o.inputFlags) & MASK_NAVHIDDEN) {
855 return !(o.inputFlags & MASK_NAVHIDDEN);
856 }
857 if (keyboard || o.keyboard) return (!o.keyboard);
858 if (navigation || o.navigation) return (!o.navigation);
859 if (screenWidth || o.screenWidth) return (!o.screenWidth);
860 if (screenHeight || o.screenHeight) return (!o.screenHeight);
861 if (sdkVersion || o.sdkVersion) return (!o.sdkVersion);
862 if (minorVersion || o.minorVersion) return (!o.minorVersion);
863 // Both configurations have nothing defined except some possible future
864 // value. Returning the comparison of the two configurations is a
865 // "best effort" at this point to protect against incorrect dominations.
866 return *this != o;
Alexandria Cornwall77788eb2016-09-06 15:16:49 -0700867}
868
869bool ConfigDescription::conflictsWith(const ConfigDescription& o) const {
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700870 // This method should be updated as new configuration parameters are
871 // introduced (e.g. screenConfig2).
872 auto pred = [](const uint32_t a, const uint32_t b) -> bool {
873 return a == 0 || b == 0 || a == b;
874 };
875 // The values here can be found in ResTable_config#match. Density and range
876 // values can't lead to conflicts, and are ignored.
877 return !pred(mcc, o.mcc) || !pred(mnc, o.mnc) || !pred(locale, o.locale) ||
878 !pred(screenLayout & MASK_LAYOUTDIR,
879 o.screenLayout & MASK_LAYOUTDIR) ||
880 !pred(screenLayout & MASK_SCREENLONG,
881 o.screenLayout & MASK_SCREENLONG) ||
882 !pred(screenLayout & MASK_UI_MODE_TYPE,
883 o.screenLayout & MASK_UI_MODE_TYPE) ||
884 !pred(uiMode & MASK_UI_MODE_TYPE, o.uiMode & MASK_UI_MODE_TYPE) ||
885 !pred(uiMode & MASK_UI_MODE_NIGHT, o.uiMode & MASK_UI_MODE_NIGHT) ||
886 !pred(screenLayout2 & MASK_SCREENROUND,
887 o.screenLayout2 & MASK_SCREENROUND) ||
888 !pred(orientation, o.orientation) ||
889 !pred(touchscreen, o.touchscreen) ||
890 !pred(inputFlags & MASK_KEYSHIDDEN, o.inputFlags & MASK_KEYSHIDDEN) ||
891 !pred(inputFlags & MASK_NAVHIDDEN, o.inputFlags & MASK_NAVHIDDEN) ||
892 !pred(keyboard, o.keyboard) || !pred(navigation, o.navigation);
Alexandria Cornwall77788eb2016-09-06 15:16:49 -0700893}
894
895bool ConfigDescription::isCompatibleWith(const ConfigDescription& o) const {
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700896 return !conflictsWith(o) && !dominates(o) && !o.dominates(*this);
Alexandria Cornwall77788eb2016-09-06 15:16:49 -0700897}
898
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700899} // namespace aapt