1 /*
2 * Copyright (C) 2014 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 <androidfw/ResourceTypes.h>
18 #include <ctype.h>
19
20 #include "AaptConfig.h"
21 #include "AaptAssets.h"
22 #include "AaptUtil.h"
23 #include "ResourceFilter.h"
24 #include "SdkConstants.h"
25
26 using android::String8;
27 using android::Vector;
28 using android::ResTable_config;
29
30 namespace AaptConfig {
31
32 static const char* kWildcardName = "any";
33
parse(const String8 & str,ConfigDescription * out)34 bool parse(const String8& str, ConfigDescription* out) {
35 Vector<String8> parts = AaptUtil::splitAndLowerCase(str, '-');
36
37 ConfigDescription config;
38 AaptLocaleValue locale;
39 ssize_t index = 0;
40 ssize_t localeIndex = 0;
41 const ssize_t N = parts.size();
42 const char* part = parts[index].c_str();
43
44 if (str.length() == 0) {
45 goto success;
46 }
47
48 if (parseMcc(part, &config)) {
49 index++;
50 if (index == N) {
51 goto success;
52 }
53 part = parts[index].c_str();
54 }
55
56 if (parseMnc(part, &config)) {
57 index++;
58 if (index == N) {
59 goto success;
60 }
61 part = parts[index].c_str();
62 }
63
64 // Locale spans a few '-' separators, so we let it
65 // control the index.
66 localeIndex = locale.initFromDirName(parts, index);
67 if (localeIndex < 0) {
68 return false;
69 } else if (localeIndex > index) {
70 locale.writeTo(&config);
71 index = localeIndex;
72 if (index >= N) {
73 goto success;
74 }
75 part = parts[index].c_str();
76 }
77
78 if (parseLayoutDirection(part, &config)) {
79 index++;
80 if (index == N) {
81 goto success;
82 }
83 part = parts[index].c_str();
84 }
85
86 if (parseSmallestScreenWidthDp(part, &config)) {
87 index++;
88 if (index == N) {
89 goto success;
90 }
91 part = parts[index].c_str();
92 }
93
94 if (parseScreenWidthDp(part, &config)) {
95 index++;
96 if (index == N) {
97 goto success;
98 }
99 part = parts[index].c_str();
100 }
101
102 if (parseScreenHeightDp(part, &config)) {
103 index++;
104 if (index == N) {
105 goto success;
106 }
107 part = parts[index].c_str();
108 }
109
110 if (parseScreenLayoutSize(part, &config)) {
111 index++;
112 if (index == N) {
113 goto success;
114 }
115 part = parts[index].c_str();
116 }
117
118 if (parseScreenLayoutLong(part, &config)) {
119 index++;
120 if (index == N) {
121 goto success;
122 }
123 part = parts[index].c_str();
124 }
125
126 if (parseScreenRound(part, &config)) {
127 index++;
128 if (index == N) {
129 goto success;
130 }
131 part = parts[index].c_str();
132 }
133
134 if (parseWideColorGamut(part, &config)) {
135 index++;
136 if (index == N) {
137 goto success;
138 }
139 part = parts[index].c_str();
140 }
141
142 if (parseHdr(part, &config)) {
143 index++;
144 if (index == N) {
145 goto success;
146 }
147 part = parts[index].c_str();
148 }
149
150 if (parseOrientation(part, &config)) {
151 index++;
152 if (index == N) {
153 goto success;
154 }
155 part = parts[index].c_str();
156 }
157
158 if (parseUiModeType(part, &config)) {
159 index++;
160 if (index == N) {
161 goto success;
162 }
163 part = parts[index].c_str();
164 }
165
166 if (parseUiModeNight(part, &config)) {
167 index++;
168 if (index == N) {
169 goto success;
170 }
171 part = parts[index].c_str();
172 }
173
174 if (parseDensity(part, &config)) {
175 index++;
176 if (index == N) {
177 goto success;
178 }
179 part = parts[index].c_str();
180 }
181
182 if (parseTouchscreen(part, &config)) {
183 index++;
184 if (index == N) {
185 goto success;
186 }
187 part = parts[index].c_str();
188 }
189
190 if (parseKeysHidden(part, &config)) {
191 index++;
192 if (index == N) {
193 goto success;
194 }
195 part = parts[index].c_str();
196 }
197
198 if (parseKeyboard(part, &config)) {
199 index++;
200 if (index == N) {
201 goto success;
202 }
203 part = parts[index].c_str();
204 }
205
206 if (parseNavHidden(part, &config)) {
207 index++;
208 if (index == N) {
209 goto success;
210 }
211 part = parts[index].c_str();
212 }
213
214 if (parseNavigation(part, &config)) {
215 index++;
216 if (index == N) {
217 goto success;
218 }
219 part = parts[index].c_str();
220 }
221
222 if (parseScreenSize(part, &config)) {
223 index++;
224 if (index == N) {
225 goto success;
226 }
227 part = parts[index].c_str();
228 }
229
230 if (parseVersion(part, &config)) {
231 index++;
232 if (index == N) {
233 goto success;
234 }
235 part = parts[index].c_str();
236 }
237
238 // Unrecognized.
239 return false;
240
241 success:
242 if (out != NULL) {
243 applyVersionForCompatibility(&config);
244 *out = config;
245 }
246 return true;
247 }
248
parseCommaSeparatedList(const String8 & str,std::set<ConfigDescription> * outSet)249 bool parseCommaSeparatedList(const String8& str, std::set<ConfigDescription>* outSet) {
250 Vector<String8> parts = AaptUtil::splitAndLowerCase(str, ',');
251 const size_t N = parts.size();
252 for (size_t i = 0; i < N; i++) {
253 ConfigDescription config;
254 if (!parse(parts[i], &config)) {
255 return false;
256 }
257 outSet->insert(config);
258 }
259 return true;
260 }
261
applyVersionForCompatibility(ConfigDescription * config)262 void applyVersionForCompatibility(ConfigDescription* config) {
263 if (config == NULL) {
264 return;
265 }
266
267 uint16_t minSdk = 0;
268 if ((config->uiMode & ResTable_config::MASK_UI_MODE_TYPE)
269 == ResTable_config::UI_MODE_TYPE_VR_HEADSET
270 || config->colorMode & ResTable_config::MASK_WIDE_COLOR_GAMUT
271 || config->colorMode & ResTable_config::MASK_HDR) {
272 minSdk = SDK_O;
273 } else if (config->screenLayout2 & ResTable_config::MASK_SCREENROUND) {
274 minSdk = SDK_MNC;
275 } else if (config->density == ResTable_config::DENSITY_ANY) {
276 minSdk = SDK_LOLLIPOP;
277 } else if (config->smallestScreenWidthDp != ResTable_config::SCREENWIDTH_ANY
278 || config->screenWidthDp != ResTable_config::SCREENWIDTH_ANY
279 || config->screenHeightDp != ResTable_config::SCREENHEIGHT_ANY) {
280 minSdk = SDK_HONEYCOMB_MR2;
281 } else if ((config->uiMode & ResTable_config::MASK_UI_MODE_TYPE)
282 != ResTable_config::UI_MODE_TYPE_ANY
283 || (config->uiMode & ResTable_config::MASK_UI_MODE_NIGHT)
284 != ResTable_config::UI_MODE_NIGHT_ANY) {
285 minSdk = SDK_FROYO;
286 } else if ((config->screenLayout & ResTable_config::MASK_SCREENSIZE)
287 != ResTable_config::SCREENSIZE_ANY
288 || (config->screenLayout & ResTable_config::MASK_SCREENLONG)
289 != ResTable_config::SCREENLONG_ANY
290 || config->density != ResTable_config::DENSITY_DEFAULT) {
291 minSdk = SDK_DONUT;
292 }
293
294 if (minSdk > config->sdkVersion) {
295 config->sdkVersion = minSdk;
296 }
297 }
298
parseMcc(const char * name,ResTable_config * out)299 bool parseMcc(const char* name, ResTable_config* out) {
300 if (strcmp(name, kWildcardName) == 0) {
301 if (out) out->mcc = 0;
302 return true;
303 }
304 const char* c = name;
305 if (tolower(*c) != 'm') return false;
306 c++;
307 if (tolower(*c) != 'c') return false;
308 c++;
309 if (tolower(*c) != 'c') return false;
310 c++;
311
312 const char* val = c;
313
314 while (*c >= '0' && *c <= '9') {
315 c++;
316 }
317 if (*c != 0) return false;
318 if (c-val != 3) return false;
319
320 int d = atoi(val);
321 if (d != 0) {
322 if (out) out->mcc = d;
323 return true;
324 }
325
326 return false;
327 }
328
parseMnc(const char * name,ResTable_config * out)329 bool parseMnc(const char* name, ResTable_config* out) {
330 if (strcmp(name, kWildcardName) == 0) {
331 if (out) out->mcc = 0;
332 return true;
333 }
334 const char* c = name;
335 if (tolower(*c) != 'm') return false;
336 c++;
337 if (tolower(*c) != 'n') return false;
338 c++;
339 if (tolower(*c) != 'c') return false;
340 c++;
341
342 const char* val = c;
343
344 while (*c >= '0' && *c <= '9') {
345 c++;
346 }
347 if (*c != 0) return false;
348 if (c-val == 0 || c-val > 3) return false;
349
350 if (out) {
351 out->mnc = atoi(val);
352 if (out->mnc == 0) {
353 out->mnc = ACONFIGURATION_MNC_ZERO;
354 }
355 }
356
357 return true;
358 }
359
parseLayoutDirection(const char * name,ResTable_config * out)360 bool parseLayoutDirection(const char* name, ResTable_config* out) {
361 if (strcmp(name, kWildcardName) == 0) {
362 if (out) out->screenLayout =
363 (out->screenLayout&~ResTable_config::MASK_LAYOUTDIR)
364 | ResTable_config::LAYOUTDIR_ANY;
365 return true;
366 } else if (strcmp(name, "ldltr") == 0) {
367 if (out) out->screenLayout =
368 (out->screenLayout&~ResTable_config::MASK_LAYOUTDIR)
369 | ResTable_config::LAYOUTDIR_LTR;
370 return true;
371 } else if (strcmp(name, "ldrtl") == 0) {
372 if (out) out->screenLayout =
373 (out->screenLayout&~ResTable_config::MASK_LAYOUTDIR)
374 | ResTable_config::LAYOUTDIR_RTL;
375 return true;
376 }
377
378 return false;
379 }
380
parseScreenLayoutSize(const char * name,ResTable_config * out)381 bool parseScreenLayoutSize(const char* name, ResTable_config* out) {
382 if (strcmp(name, kWildcardName) == 0) {
383 if (out) out->screenLayout =
384 (out->screenLayout&~ResTable_config::MASK_SCREENSIZE)
385 | ResTable_config::SCREENSIZE_ANY;
386 return true;
387 } else if (strcmp(name, "small") == 0) {
388 if (out) out->screenLayout =
389 (out->screenLayout&~ResTable_config::MASK_SCREENSIZE)
390 | ResTable_config::SCREENSIZE_SMALL;
391 return true;
392 } else if (strcmp(name, "normal") == 0) {
393 if (out) out->screenLayout =
394 (out->screenLayout&~ResTable_config::MASK_SCREENSIZE)
395 | ResTable_config::SCREENSIZE_NORMAL;
396 return true;
397 } else if (strcmp(name, "large") == 0) {
398 if (out) out->screenLayout =
399 (out->screenLayout&~ResTable_config::MASK_SCREENSIZE)
400 | ResTable_config::SCREENSIZE_LARGE;
401 return true;
402 } else if (strcmp(name, "xlarge") == 0) {
403 if (out) out->screenLayout =
404 (out->screenLayout&~ResTable_config::MASK_SCREENSIZE)
405 | ResTable_config::SCREENSIZE_XLARGE;
406 return true;
407 }
408
409 return false;
410 }
411
parseScreenLayoutLong(const char * name,ResTable_config * out)412 bool parseScreenLayoutLong(const char* name, ResTable_config* out) {
413 if (strcmp(name, kWildcardName) == 0) {
414 if (out) out->screenLayout =
415 (out->screenLayout&~ResTable_config::MASK_SCREENLONG)
416 | ResTable_config::SCREENLONG_ANY;
417 return true;
418 } else if (strcmp(name, "long") == 0) {
419 if (out) out->screenLayout =
420 (out->screenLayout&~ResTable_config::MASK_SCREENLONG)
421 | ResTable_config::SCREENLONG_YES;
422 return true;
423 } else if (strcmp(name, "notlong") == 0) {
424 if (out) out->screenLayout =
425 (out->screenLayout&~ResTable_config::MASK_SCREENLONG)
426 | ResTable_config::SCREENLONG_NO;
427 return true;
428 }
429 return false;
430 }
431
parseScreenRound(const char * name,ResTable_config * out)432 bool parseScreenRound(const char* name, ResTable_config* out) {
433 if (strcmp(name, kWildcardName) == 0) {
434 if (out) out->screenLayout2 =
435 (out->screenLayout2&~ResTable_config::MASK_SCREENROUND)
436 | ResTable_config::SCREENROUND_ANY;
437 return true;
438 } else if (strcmp(name, "round") == 0) {
439 if (out) out->screenLayout2 =
440 (out->screenLayout2&~ResTable_config::MASK_SCREENROUND)
441 | ResTable_config::SCREENROUND_YES;
442 return true;
443 } else if (strcmp(name, "notround") == 0) {
444 if (out) out->screenLayout2 =
445 (out->screenLayout2&~ResTable_config::MASK_SCREENROUND)
446 | ResTable_config::SCREENROUND_NO;
447 return true;
448 }
449 return false;
450 }
451
parseWideColorGamut(const char * name,ResTable_config * out)452 bool parseWideColorGamut(const char* name, ResTable_config* out) {
453 if (strcmp(name, kWildcardName) == 0) {
454 if (out) out->colorMode =
455 (out->colorMode&~ResTable_config::MASK_WIDE_COLOR_GAMUT)
456 | ResTable_config::WIDE_COLOR_GAMUT_ANY;
457 return true;
458 } else if (strcmp(name, "widecg") == 0) {
459 if (out) out->colorMode =
460 (out->colorMode&~ResTable_config::MASK_WIDE_COLOR_GAMUT)
461 | ResTable_config::WIDE_COLOR_GAMUT_YES;
462 return true;
463 } else if (strcmp(name, "nowidecg") == 0) {
464 if (out) out->colorMode =
465 (out->colorMode&~ResTable_config::MASK_WIDE_COLOR_GAMUT)
466 | ResTable_config::WIDE_COLOR_GAMUT_NO;
467 return true;
468 }
469 return false;
470 }
471
parseHdr(const char * name,ResTable_config * out)472 bool parseHdr(const char* name, ResTable_config* out) {
473 if (strcmp(name, kWildcardName) == 0) {
474 if (out) out->colorMode =
475 (out->colorMode&~ResTable_config::MASK_HDR)
476 | ResTable_config::HDR_ANY;
477 return true;
478 } else if (strcmp(name, "highdr") == 0) {
479 if (out) out->colorMode =
480 (out->colorMode&~ResTable_config::MASK_HDR)
481 | ResTable_config::HDR_YES;
482 return true;
483 } else if (strcmp(name, "lowdr") == 0) {
484 if (out) out->colorMode =
485 (out->colorMode&~ResTable_config::MASK_HDR)
486 | ResTable_config::HDR_NO;
487 return true;
488 }
489 return false;
490 }
491
parseOrientation(const char * name,ResTable_config * out)492 bool parseOrientation(const char* name, ResTable_config* out) {
493 if (strcmp(name, kWildcardName) == 0) {
494 if (out) out->orientation = out->ORIENTATION_ANY;
495 return true;
496 } else if (strcmp(name, "port") == 0) {
497 if (out) out->orientation = out->ORIENTATION_PORT;
498 return true;
499 } else if (strcmp(name, "land") == 0) {
500 if (out) out->orientation = out->ORIENTATION_LAND;
501 return true;
502 } else if (strcmp(name, "square") == 0) {
503 if (out) out->orientation = out->ORIENTATION_SQUARE;
504 return true;
505 }
506
507 return false;
508 }
509
parseUiModeType(const char * name,ResTable_config * out)510 bool parseUiModeType(const char* name, ResTable_config* out) {
511 if (strcmp(name, kWildcardName) == 0) {
512 if (out) out->uiMode =
513 (out->uiMode&~ResTable_config::MASK_UI_MODE_TYPE)
514 | ResTable_config::UI_MODE_TYPE_ANY;
515 return true;
516 } else if (strcmp(name, "desk") == 0) {
517 if (out) out->uiMode =
518 (out->uiMode&~ResTable_config::MASK_UI_MODE_TYPE)
519 | ResTable_config::UI_MODE_TYPE_DESK;
520 return true;
521 } else if (strcmp(name, "car") == 0) {
522 if (out) out->uiMode =
523 (out->uiMode&~ResTable_config::MASK_UI_MODE_TYPE)
524 | ResTable_config::UI_MODE_TYPE_CAR;
525 return true;
526 } else if (strcmp(name, "television") == 0) {
527 if (out) out->uiMode =
528 (out->uiMode&~ResTable_config::MASK_UI_MODE_TYPE)
529 | ResTable_config::UI_MODE_TYPE_TELEVISION;
530 return true;
531 } else if (strcmp(name, "appliance") == 0) {
532 if (out) out->uiMode =
533 (out->uiMode&~ResTable_config::MASK_UI_MODE_TYPE)
534 | ResTable_config::UI_MODE_TYPE_APPLIANCE;
535 return true;
536 } else if (strcmp(name, "watch") == 0) {
537 if (out) out->uiMode =
538 (out->uiMode&~ResTable_config::MASK_UI_MODE_TYPE)
539 | ResTable_config::UI_MODE_TYPE_WATCH;
540 return true;
541 } else if (strcmp(name, "vrheadset") == 0) {
542 if (out) out->uiMode =
543 (out->uiMode&~ResTable_config::MASK_UI_MODE_TYPE)
544 | ResTable_config::UI_MODE_TYPE_VR_HEADSET;
545 return true;
546 }
547
548 return false;
549 }
550
parseUiModeNight(const char * name,ResTable_config * out)551 bool parseUiModeNight(const char* name, ResTable_config* out) {
552 if (strcmp(name, kWildcardName) == 0) {
553 if (out) out->uiMode =
554 (out->uiMode&~ResTable_config::MASK_UI_MODE_NIGHT)
555 | ResTable_config::UI_MODE_NIGHT_ANY;
556 return true;
557 } else if (strcmp(name, "night") == 0) {
558 if (out) out->uiMode =
559 (out->uiMode&~ResTable_config::MASK_UI_MODE_NIGHT)
560 | ResTable_config::UI_MODE_NIGHT_YES;
561 return true;
562 } else if (strcmp(name, "notnight") == 0) {
563 if (out) out->uiMode =
564 (out->uiMode&~ResTable_config::MASK_UI_MODE_NIGHT)
565 | ResTable_config::UI_MODE_NIGHT_NO;
566 return true;
567 }
568
569 return false;
570 }
571
parseDensity(const char * name,ResTable_config * out)572 bool parseDensity(const char* name, ResTable_config* out) {
573 if (strcmp(name, kWildcardName) == 0) {
574 if (out) out->density = ResTable_config::DENSITY_DEFAULT;
575 return true;
576 }
577
578 if (strcmp(name, "anydpi") == 0) {
579 if (out) out->density = ResTable_config::DENSITY_ANY;
580 return true;
581 }
582
583 if (strcmp(name, "nodpi") == 0) {
584 if (out) out->density = ResTable_config::DENSITY_NONE;
585 return true;
586 }
587
588 if (strcmp(name, "ldpi") == 0) {
589 if (out) out->density = ResTable_config::DENSITY_LOW;
590 return true;
591 }
592
593 if (strcmp(name, "mdpi") == 0) {
594 if (out) out->density = ResTable_config::DENSITY_MEDIUM;
595 return true;
596 }
597
598 if (strcmp(name, "tvdpi") == 0) {
599 if (out) out->density = ResTable_config::DENSITY_TV;
600 return true;
601 }
602
603 if (strcmp(name, "hdpi") == 0) {
604 if (out) out->density = ResTable_config::DENSITY_HIGH;
605 return true;
606 }
607
608 if (strcmp(name, "xhdpi") == 0) {
609 if (out) out->density = ResTable_config::DENSITY_XHIGH;
610 return true;
611 }
612
613 if (strcmp(name, "xxhdpi") == 0) {
614 if (out) out->density = ResTable_config::DENSITY_XXHIGH;
615 return true;
616 }
617
618 if (strcmp(name, "xxxhdpi") == 0) {
619 if (out) out->density = ResTable_config::DENSITY_XXXHIGH;
620 return true;
621 }
622
623 char* c = (char*)name;
624 while (*c >= '0' && *c <= '9') {
625 c++;
626 }
627
628 // check that we have 'dpi' after the last digit.
629 if (toupper(c[0]) != 'D' ||
630 toupper(c[1]) != 'P' ||
631 toupper(c[2]) != 'I' ||
632 c[3] != 0) {
633 return false;
634 }
635
636 // temporarily replace the first letter with \0 to
637 // use atoi.
638 char tmp = c[0];
639 c[0] = '\0';
640
641 int d = atoi(name);
642 c[0] = tmp;
643
644 if (d != 0) {
645 if (out) out->density = d;
646 return true;
647 }
648
649 return false;
650 }
651
parseTouchscreen(const char * name,ResTable_config * out)652 bool parseTouchscreen(const char* name, ResTable_config* out) {
653 if (strcmp(name, kWildcardName) == 0) {
654 if (out) out->touchscreen = out->TOUCHSCREEN_ANY;
655 return true;
656 } else if (strcmp(name, "notouch") == 0) {
657 if (out) out->touchscreen = out->TOUCHSCREEN_NOTOUCH;
658 return true;
659 } else if (strcmp(name, "stylus") == 0) {
660 if (out) out->touchscreen = out->TOUCHSCREEN_STYLUS;
661 return true;
662 } else if (strcmp(name, "finger") == 0) {
663 if (out) out->touchscreen = out->TOUCHSCREEN_FINGER;
664 return true;
665 }
666
667 return false;
668 }
669
parseKeysHidden(const char * name,ResTable_config * out)670 bool parseKeysHidden(const char* name, ResTable_config* out) {
671 uint8_t mask = 0;
672 uint8_t value = 0;
673 if (strcmp(name, kWildcardName) == 0) {
674 mask = ResTable_config::MASK_KEYSHIDDEN;
675 value = ResTable_config::KEYSHIDDEN_ANY;
676 } else if (strcmp(name, "keysexposed") == 0) {
677 mask = ResTable_config::MASK_KEYSHIDDEN;
678 value = ResTable_config::KEYSHIDDEN_NO;
679 } else if (strcmp(name, "keyshidden") == 0) {
680 mask = ResTable_config::MASK_KEYSHIDDEN;
681 value = ResTable_config::KEYSHIDDEN_YES;
682 } else if (strcmp(name, "keyssoft") == 0) {
683 mask = ResTable_config::MASK_KEYSHIDDEN;
684 value = ResTable_config::KEYSHIDDEN_SOFT;
685 }
686
687 if (mask != 0) {
688 if (out) out->inputFlags = (out->inputFlags&~mask) | value;
689 return true;
690 }
691
692 return false;
693 }
694
parseKeyboard(const char * name,ResTable_config * out)695 bool parseKeyboard(const char* name, ResTable_config* out) {
696 if (strcmp(name, kWildcardName) == 0) {
697 if (out) out->keyboard = out->KEYBOARD_ANY;
698 return true;
699 } else if (strcmp(name, "nokeys") == 0) {
700 if (out) out->keyboard = out->KEYBOARD_NOKEYS;
701 return true;
702 } else if (strcmp(name, "qwerty") == 0) {
703 if (out) out->keyboard = out->KEYBOARD_QWERTY;
704 return true;
705 } else if (strcmp(name, "12key") == 0) {
706 if (out) out->keyboard = out->KEYBOARD_12KEY;
707 return true;
708 }
709
710 return false;
711 }
712
parseNavHidden(const char * name,ResTable_config * out)713 bool parseNavHidden(const char* name, ResTable_config* out) {
714 uint8_t mask = 0;
715 uint8_t value = 0;
716 if (strcmp(name, kWildcardName) == 0) {
717 mask = ResTable_config::MASK_NAVHIDDEN;
718 value = ResTable_config::NAVHIDDEN_ANY;
719 } else if (strcmp(name, "navexposed") == 0) {
720 mask = ResTable_config::MASK_NAVHIDDEN;
721 value = ResTable_config::NAVHIDDEN_NO;
722 } else if (strcmp(name, "navhidden") == 0) {
723 mask = ResTable_config::MASK_NAVHIDDEN;
724 value = ResTable_config::NAVHIDDEN_YES;
725 }
726
727 if (mask != 0) {
728 if (out) out->inputFlags = (out->inputFlags&~mask) | value;
729 return true;
730 }
731
732 return false;
733 }
734
parseNavigation(const char * name,ResTable_config * out)735 bool parseNavigation(const char* name, ResTable_config* out) {
736 if (strcmp(name, kWildcardName) == 0) {
737 if (out) out->navigation = out->NAVIGATION_ANY;
738 return true;
739 } else if (strcmp(name, "nonav") == 0) {
740 if (out) out->navigation = out->NAVIGATION_NONAV;
741 return true;
742 } else if (strcmp(name, "dpad") == 0) {
743 if (out) out->navigation = out->NAVIGATION_DPAD;
744 return true;
745 } else if (strcmp(name, "trackball") == 0) {
746 if (out) out->navigation = out->NAVIGATION_TRACKBALL;
747 return true;
748 } else if (strcmp(name, "wheel") == 0) {
749 if (out) out->navigation = out->NAVIGATION_WHEEL;
750 return true;
751 }
752
753 return false;
754 }
755
parseScreenSize(const char * name,ResTable_config * out)756 bool parseScreenSize(const char* name, ResTable_config* out) {
757 if (strcmp(name, kWildcardName) == 0) {
758 if (out) {
759 out->screenWidth = out->SCREENWIDTH_ANY;
760 out->screenHeight = out->SCREENHEIGHT_ANY;
761 }
762 return true;
763 }
764
765 const char* x = name;
766 while (*x >= '0' && *x <= '9') x++;
767 if (x == name || *x != 'x') return false;
768 String8 xName(name, x-name);
769 x++;
770
771 const char* y = x;
772 while (*y >= '0' && *y <= '9') y++;
773 if (y == name || *y != 0) return false;
774 String8 yName(x, y-x);
775
776 uint16_t w = (uint16_t)atoi(xName.c_str());
777 uint16_t h = (uint16_t)atoi(yName.c_str());
778 if (w < h) {
779 return false;
780 }
781
782 if (out) {
783 out->screenWidth = w;
784 out->screenHeight = h;
785 }
786
787 return true;
788 }
789
parseSmallestScreenWidthDp(const char * name,ResTable_config * out)790 bool parseSmallestScreenWidthDp(const char* name, ResTable_config* out) {
791 if (strcmp(name, kWildcardName) == 0) {
792 if (out) {
793 out->smallestScreenWidthDp = out->SCREENWIDTH_ANY;
794 }
795 return true;
796 }
797
798 if (*name != 's') return false;
799 name++;
800 if (*name != 'w') return false;
801 name++;
802 const char* x = name;
803 while (*x >= '0' && *x <= '9') x++;
804 if (x == name || x[0] != 'd' || x[1] != 'p' || x[2] != 0) return false;
805 String8 xName(name, x-name);
806
807 if (out) {
808 out->smallestScreenWidthDp = (uint16_t)atoi(xName.c_str());
809 }
810
811 return true;
812 }
813
parseScreenWidthDp(const char * name,ResTable_config * out)814 bool parseScreenWidthDp(const char* name, ResTable_config* out) {
815 if (strcmp(name, kWildcardName) == 0) {
816 if (out) {
817 out->screenWidthDp = out->SCREENWIDTH_ANY;
818 }
819 return true;
820 }
821
822 if (*name != 'w') return false;
823 name++;
824 const char* x = name;
825 while (*x >= '0' && *x <= '9') x++;
826 if (x == name || x[0] != 'd' || x[1] != 'p' || x[2] != 0) return false;
827 String8 xName(name, x-name);
828
829 if (out) {
830 out->screenWidthDp = (uint16_t)atoi(xName.c_str());
831 }
832
833 return true;
834 }
835
parseScreenHeightDp(const char * name,ResTable_config * out)836 bool parseScreenHeightDp(const char* name, ResTable_config* out) {
837 if (strcmp(name, kWildcardName) == 0) {
838 if (out) {
839 out->screenHeightDp = out->SCREENWIDTH_ANY;
840 }
841 return true;
842 }
843
844 if (*name != 'h') return false;
845 name++;
846 const char* x = name;
847 while (*x >= '0' && *x <= '9') x++;
848 if (x == name || x[0] != 'd' || x[1] != 'p' || x[2] != 0) return false;
849 String8 xName(name, x-name);
850
851 if (out) {
852 out->screenHeightDp = (uint16_t)atoi(xName.c_str());
853 }
854
855 return true;
856 }
857
parseVersion(const char * name,ResTable_config * out)858 bool parseVersion(const char* name, ResTable_config* out) {
859 if (strcmp(name, kWildcardName) == 0) {
860 if (out) {
861 out->sdkVersion = out->SDKVERSION_ANY;
862 out->minorVersion = out->MINORVERSION_ANY;
863 }
864 return true;
865 }
866
867 if (*name != 'v') {
868 return false;
869 }
870
871 name++;
872 const char* s = name;
873 while (*s >= '0' && *s <= '9') s++;
874 if (s == name || *s != 0) return false;
875 String8 sdkName(name, s-name);
876
877 if (out) {
878 out->sdkVersion = (uint16_t)atoi(sdkName.c_str());
879 out->minorVersion = 0;
880 }
881
882 return true;
883 }
884
getVersion(const ResTable_config & config)885 String8 getVersion(const ResTable_config& config) {
886 return String8::format("v%u", config.sdkVersion);
887 }
888
isSameExcept(const ResTable_config & a,const ResTable_config & b,int axisMask)889 bool isSameExcept(const ResTable_config& a, const ResTable_config& b, int axisMask) {
890 return a.diff(b) == axisMask;
891 }
892
isDensityOnly(const ResTable_config & config)893 bool isDensityOnly(const ResTable_config& config) {
894 if (config.density == ResTable_config::DENSITY_DEFAULT) {
895 return false;
896 }
897
898 if (config.density == ResTable_config::DENSITY_ANY) {
899 if (config.sdkVersion != SDK_LOLLIPOP) {
900 // Someone modified the sdkVersion from the default, this is not safe to assume.
901 return false;
902 }
903 } else if (config.sdkVersion != SDK_DONUT) {
904 return false;
905 }
906
907 const uint32_t mask = ResTable_config::CONFIG_DENSITY | ResTable_config::CONFIG_VERSION;
908 const ConfigDescription nullConfig;
909 return (nullConfig.diff(config) & ~mask) == 0;
910 }
911
912 } // namespace AaptConfig
913