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