blob: c1697e794c1e9085632a9e259e2b657d176c33d5 [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() {
34 static ConfigDescription config = {};
35 return config;
36}
37
Adam Lesinski6f6ceb72014-11-14 14:48:12 -080038static bool parseMcc(const char* name, ResTable_config* out) {
39 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') {
54 c++;
55 }
56 if (*c != 0) return false;
57 if (c-val != 3) return false;
58
59 int d = atoi(val);
60 if (d != 0) {
61 if (out) out->mcc = d;
62 return true;
63 }
64
65 return false;
66}
67
68static bool parseMnc(const char* name, ResTable_config* out) {
69 if (strcmp(name, kWildcardName) == 0) {
70 if (out) out->mcc = 0;
71 return true;
72 }
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;
97}
98
99static bool parseLayoutDirection(const char* name, ResTable_config* out) {
100 if (strcmp(name, kWildcardName) == 0) {
101 if (out) out->screenLayout =
102 (out->screenLayout&~ResTable_config::MASK_LAYOUTDIR)
103 | ResTable_config::LAYOUTDIR_ANY;
104 return true;
105 } else if (strcmp(name, "ldltr") == 0) {
106 if (out) out->screenLayout =
107 (out->screenLayout&~ResTable_config::MASK_LAYOUTDIR)
108 | ResTable_config::LAYOUTDIR_LTR;
109 return true;
110 } else if (strcmp(name, "ldrtl") == 0) {
111 if (out) out->screenLayout =
112 (out->screenLayout&~ResTable_config::MASK_LAYOUTDIR)
113 | ResTable_config::LAYOUTDIR_RTL;
114 return true;
115 }
116
117 return false;
118}
119
120static bool parseScreenLayoutSize(const char* name, ResTable_config* out) {
121 if (strcmp(name, kWildcardName) == 0) {
122 if (out) out->screenLayout =
123 (out->screenLayout&~ResTable_config::MASK_SCREENSIZE)
124 | ResTable_config::SCREENSIZE_ANY;
125 return true;
126 } else if (strcmp(name, "small") == 0) {
127 if (out) out->screenLayout =
128 (out->screenLayout&~ResTable_config::MASK_SCREENSIZE)
129 | ResTable_config::SCREENSIZE_SMALL;
130 return true;
131 } else if (strcmp(name, "normal") == 0) {
132 if (out) out->screenLayout =
133 (out->screenLayout&~ResTable_config::MASK_SCREENSIZE)
134 | ResTable_config::SCREENSIZE_NORMAL;
135 return true;
136 } else if (strcmp(name, "large") == 0) {
137 if (out) out->screenLayout =
138 (out->screenLayout&~ResTable_config::MASK_SCREENSIZE)
139 | ResTable_config::SCREENSIZE_LARGE;
140 return true;
141 } else if (strcmp(name, "xlarge") == 0) {
142 if (out) out->screenLayout =
143 (out->screenLayout&~ResTable_config::MASK_SCREENSIZE)
144 | ResTable_config::SCREENSIZE_XLARGE;
145 return true;
146 }
147
148 return false;
149}
150
151static bool parseScreenLayoutLong(const char* name, ResTable_config* out) {
152 if (strcmp(name, kWildcardName) == 0) {
153 if (out) out->screenLayout =
154 (out->screenLayout&~ResTable_config::MASK_SCREENLONG)
155 | ResTable_config::SCREENLONG_ANY;
156 return true;
157 } else if (strcmp(name, "long") == 0) {
158 if (out) out->screenLayout =
159 (out->screenLayout&~ResTable_config::MASK_SCREENLONG)
160 | ResTable_config::SCREENLONG_YES;
161 return true;
162 } else if (strcmp(name, "notlong") == 0) {
163 if (out) out->screenLayout =
164 (out->screenLayout&~ResTable_config::MASK_SCREENLONG)
165 | ResTable_config::SCREENLONG_NO;
166 return true;
167 }
168
169 return false;
170}
171
Adam Lesinski64254972015-11-03 16:16:17 -0800172static bool parseScreenRound(const char* name, ResTable_config* out) {
173 if (strcmp(name, kWildcardName) == 0) {
174 if (out) out->screenLayout2 =
175 (out->screenLayout2&~ResTable_config::MASK_SCREENROUND)
176 | ResTable_config::SCREENROUND_ANY;
177 return true;
178 } else if (strcmp(name, "round") == 0) {
179 if (out) out->screenLayout2 =
180 (out->screenLayout2&~ResTable_config::MASK_SCREENROUND)
181 | ResTable_config::SCREENROUND_YES;
182 return true;
183 } else if (strcmp(name, "notround") == 0) {
184 if (out) out->screenLayout2 =
185 (out->screenLayout2&~ResTable_config::MASK_SCREENROUND)
186 | ResTable_config::SCREENROUND_NO;
187 return true;
188 }
189 return false;
190}
191
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800192static bool parseOrientation(const char* name, ResTable_config* out) {
193 if (strcmp(name, kWildcardName) == 0) {
194 if (out) out->orientation = out->ORIENTATION_ANY;
195 return true;
196 } else if (strcmp(name, "port") == 0) {
197 if (out) out->orientation = out->ORIENTATION_PORT;
198 return true;
199 } else if (strcmp(name, "land") == 0) {
200 if (out) out->orientation = out->ORIENTATION_LAND;
201 return true;
202 } else if (strcmp(name, "square") == 0) {
203 if (out) out->orientation = out->ORIENTATION_SQUARE;
204 return true;
205 }
206
207 return false;
208}
209
210static bool parseUiModeType(const char* name, ResTable_config* out) {
211 if (strcmp(name, kWildcardName) == 0) {
212 if (out) out->uiMode =
213 (out->uiMode&~ResTable_config::MASK_UI_MODE_TYPE)
214 | ResTable_config::UI_MODE_TYPE_ANY;
215 return true;
216 } else if (strcmp(name, "desk") == 0) {
217 if (out) out->uiMode =
218 (out->uiMode&~ResTable_config::MASK_UI_MODE_TYPE)
219 | ResTable_config::UI_MODE_TYPE_DESK;
220 return true;
221 } else if (strcmp(name, "car") == 0) {
222 if (out) out->uiMode =
223 (out->uiMode&~ResTable_config::MASK_UI_MODE_TYPE)
224 | ResTable_config::UI_MODE_TYPE_CAR;
225 return true;
226 } else if (strcmp(name, "television") == 0) {
227 if (out) out->uiMode =
228 (out->uiMode&~ResTable_config::MASK_UI_MODE_TYPE)
229 | ResTable_config::UI_MODE_TYPE_TELEVISION;
230 return true;
231 } else if (strcmp(name, "appliance") == 0) {
232 if (out) out->uiMode =
233 (out->uiMode&~ResTable_config::MASK_UI_MODE_TYPE)
234 | ResTable_config::UI_MODE_TYPE_APPLIANCE;
235 return true;
236 } else if (strcmp(name, "watch") == 0) {
237 if (out) out->uiMode =
238 (out->uiMode&~ResTable_config::MASK_UI_MODE_TYPE)
239 | ResTable_config::UI_MODE_TYPE_WATCH;
240 return true;
241 }
242
243 return false;
244}
245
246static bool parseUiModeNight(const char* name, ResTable_config* out) {
247 if (strcmp(name, kWildcardName) == 0) {
248 if (out) out->uiMode =
249 (out->uiMode&~ResTable_config::MASK_UI_MODE_NIGHT)
250 | ResTable_config::UI_MODE_NIGHT_ANY;
251 return true;
252 } else if (strcmp(name, "night") == 0) {
253 if (out) out->uiMode =
254 (out->uiMode&~ResTable_config::MASK_UI_MODE_NIGHT)
255 | ResTable_config::UI_MODE_NIGHT_YES;
256 return true;
257 } else if (strcmp(name, "notnight") == 0) {
258 if (out) out->uiMode =
259 (out->uiMode&~ResTable_config::MASK_UI_MODE_NIGHT)
260 | ResTable_config::UI_MODE_NIGHT_NO;
261 return true;
262 }
263
264 return false;
265}
266
267static bool parseDensity(const char* name, ResTable_config* out) {
268 if (strcmp(name, kWildcardName) == 0) {
269 if (out) out->density = ResTable_config::DENSITY_DEFAULT;
270 return true;
271 }
272
273 if (strcmp(name, "anydpi") == 0) {
274 if (out) out->density = ResTable_config::DENSITY_ANY;
275 return true;
276 }
277
278 if (strcmp(name, "nodpi") == 0) {
279 if (out) out->density = ResTable_config::DENSITY_NONE;
280 return true;
281 }
282
283 if (strcmp(name, "ldpi") == 0) {
284 if (out) out->density = ResTable_config::DENSITY_LOW;
285 return true;
286 }
287
288 if (strcmp(name, "mdpi") == 0) {
289 if (out) out->density = ResTable_config::DENSITY_MEDIUM;
290 return true;
291 }
292
293 if (strcmp(name, "tvdpi") == 0) {
294 if (out) out->density = ResTable_config::DENSITY_TV;
295 return true;
296 }
297
298 if (strcmp(name, "hdpi") == 0) {
299 if (out) out->density = ResTable_config::DENSITY_HIGH;
300 return true;
301 }
302
303 if (strcmp(name, "xhdpi") == 0) {
304 if (out) out->density = ResTable_config::DENSITY_XHIGH;
305 return true;
306 }
307
308 if (strcmp(name, "xxhdpi") == 0) {
309 if (out) out->density = ResTable_config::DENSITY_XXHIGH;
310 return true;
311 }
312
313 if (strcmp(name, "xxxhdpi") == 0) {
314 if (out) out->density = ResTable_config::DENSITY_XXXHIGH;
315 return true;
316 }
317
318 char* c = (char*)name;
319 while (*c >= '0' && *c <= '9') {
320 c++;
321 }
322
323 // check that we have 'dpi' after the last digit.
324 if (toupper(c[0]) != 'D' ||
325 toupper(c[1]) != 'P' ||
326 toupper(c[2]) != 'I' ||
327 c[3] != 0) {
328 return false;
329 }
330
331 // temporarily replace the first letter with \0 to
332 // use atoi.
333 char tmp = c[0];
334 c[0] = '\0';
335
336 int d = atoi(name);
337 c[0] = tmp;
338
339 if (d != 0) {
340 if (out) out->density = d;
341 return true;
342 }
343
344 return false;
345}
346
347static bool parseTouchscreen(const char* name, ResTable_config* out) {
348 if (strcmp(name, kWildcardName) == 0) {
349 if (out) out->touchscreen = out->TOUCHSCREEN_ANY;
350 return true;
351 } else if (strcmp(name, "notouch") == 0) {
352 if (out) out->touchscreen = out->TOUCHSCREEN_NOTOUCH;
353 return true;
354 } else if (strcmp(name, "stylus") == 0) {
355 if (out) out->touchscreen = out->TOUCHSCREEN_STYLUS;
356 return true;
357 } else if (strcmp(name, "finger") == 0) {
358 if (out) out->touchscreen = out->TOUCHSCREEN_FINGER;
359 return true;
360 }
361
362 return false;
363}
364
365static bool parseKeysHidden(const char* name, ResTable_config* out) {
366 uint8_t mask = 0;
367 uint8_t value = 0;
368 if (strcmp(name, kWildcardName) == 0) {
369 mask = ResTable_config::MASK_KEYSHIDDEN;
370 value = ResTable_config::KEYSHIDDEN_ANY;
371 } else if (strcmp(name, "keysexposed") == 0) {
372 mask = ResTable_config::MASK_KEYSHIDDEN;
373 value = ResTable_config::KEYSHIDDEN_NO;
374 } else if (strcmp(name, "keyshidden") == 0) {
375 mask = ResTable_config::MASK_KEYSHIDDEN;
376 value = ResTable_config::KEYSHIDDEN_YES;
377 } else if (strcmp(name, "keyssoft") == 0) {
378 mask = ResTable_config::MASK_KEYSHIDDEN;
379 value = ResTable_config::KEYSHIDDEN_SOFT;
380 }
381
382 if (mask != 0) {
383 if (out) out->inputFlags = (out->inputFlags&~mask) | value;
384 return true;
385 }
386
387 return false;
388}
389
390static bool parseKeyboard(const char* name, ResTable_config* out) {
391 if (strcmp(name, kWildcardName) == 0) {
392 if (out) out->keyboard = out->KEYBOARD_ANY;
393 return true;
394 } else if (strcmp(name, "nokeys") == 0) {
395 if (out) out->keyboard = out->KEYBOARD_NOKEYS;
396 return true;
397 } else if (strcmp(name, "qwerty") == 0) {
398 if (out) out->keyboard = out->KEYBOARD_QWERTY;
399 return true;
400 } else if (strcmp(name, "12key") == 0) {
401 if (out) out->keyboard = out->KEYBOARD_12KEY;
402 return true;
403 }
404
405 return false;
406}
407
408static bool parseNavHidden(const char* name, ResTable_config* out) {
409 uint8_t mask = 0;
410 uint8_t value = 0;
411 if (strcmp(name, kWildcardName) == 0) {
412 mask = ResTable_config::MASK_NAVHIDDEN;
413 value = ResTable_config::NAVHIDDEN_ANY;
414 } else if (strcmp(name, "navexposed") == 0) {
415 mask = ResTable_config::MASK_NAVHIDDEN;
416 value = ResTable_config::NAVHIDDEN_NO;
417 } else if (strcmp(name, "navhidden") == 0) {
418 mask = ResTable_config::MASK_NAVHIDDEN;
419 value = ResTable_config::NAVHIDDEN_YES;
420 }
421
422 if (mask != 0) {
423 if (out) out->inputFlags = (out->inputFlags&~mask) | value;
424 return true;
425 }
426
427 return false;
428}
429
430static bool parseNavigation(const char* name, ResTable_config* out) {
431 if (strcmp(name, kWildcardName) == 0) {
432 if (out) out->navigation = out->NAVIGATION_ANY;
433 return true;
434 } else if (strcmp(name, "nonav") == 0) {
435 if (out) out->navigation = out->NAVIGATION_NONAV;
436 return true;
437 } else if (strcmp(name, "dpad") == 0) {
438 if (out) out->navigation = out->NAVIGATION_DPAD;
439 return true;
440 } else if (strcmp(name, "trackball") == 0) {
441 if (out) out->navigation = out->NAVIGATION_TRACKBALL;
442 return true;
443 } else if (strcmp(name, "wheel") == 0) {
444 if (out) out->navigation = out->NAVIGATION_WHEEL;
445 return true;
446 }
447
448 return false;
449}
450
451static bool parseScreenSize(const char* name, ResTable_config* out) {
452 if (strcmp(name, kWildcardName) == 0) {
453 if (out) {
454 out->screenWidth = out->SCREENWIDTH_ANY;
455 out->screenHeight = out->SCREENHEIGHT_ANY;
456 }
457 return true;
458 }
459
460 const char* x = name;
461 while (*x >= '0' && *x <= '9') x++;
462 if (x == name || *x != 'x') return false;
463 std::string xName(name, x-name);
464 x++;
465
466 const char* y = x;
467 while (*y >= '0' && *y <= '9') y++;
468 if (y == name || *y != 0) return false;
469 std::string yName(x, y-x);
470
471 uint16_t w = (uint16_t)atoi(xName.c_str());
472 uint16_t h = (uint16_t)atoi(yName.c_str());
473 if (w < h) {
474 return false;
475 }
476
477 if (out) {
478 out->screenWidth = w;
479 out->screenHeight = h;
480 }
481
482 return true;
483}
484
485static bool parseSmallestScreenWidthDp(const char* name, ResTable_config* out) {
486 if (strcmp(name, kWildcardName) == 0) {
487 if (out) {
488 out->smallestScreenWidthDp = out->SCREENWIDTH_ANY;
489 }
490 return true;
491 }
492
493 if (*name != 's') return false;
494 name++;
495 if (*name != 'w') return false;
496 name++;
497 const char* x = name;
498 while (*x >= '0' && *x <= '9') x++;
499 if (x == name || x[0] != 'd' || x[1] != 'p' || x[2] != 0) return false;
500 std::string xName(name, x-name);
501
502 if (out) {
503 out->smallestScreenWidthDp = (uint16_t)atoi(xName.c_str());
504 }
505
506 return true;
507}
508
509static bool parseScreenWidthDp(const char* name, ResTable_config* out) {
510 if (strcmp(name, kWildcardName) == 0) {
511 if (out) {
512 out->screenWidthDp = out->SCREENWIDTH_ANY;
513 }
514 return true;
515 }
516
517 if (*name != 'w') return false;
518 name++;
519 const char* x = name;
520 while (*x >= '0' && *x <= '9') x++;
521 if (x == name || x[0] != 'd' || x[1] != 'p' || x[2] != 0) return false;
522 std::string xName(name, x-name);
523
524 if (out) {
525 out->screenWidthDp = (uint16_t)atoi(xName.c_str());
526 }
527
528 return true;
529}
530
531static bool parseScreenHeightDp(const char* name, ResTable_config* out) {
532 if (strcmp(name, kWildcardName) == 0) {
533 if (out) {
534 out->screenHeightDp = out->SCREENWIDTH_ANY;
535 }
536 return true;
537 }
538
539 if (*name != 'h') return false;
540 name++;
541 const char* x = name;
542 while (*x >= '0' && *x <= '9') x++;
543 if (x == name || x[0] != 'd' || x[1] != 'p' || x[2] != 0) return false;
544 std::string xName(name, x-name);
545
546 if (out) {
547 out->screenHeightDp = (uint16_t)atoi(xName.c_str());
548 }
549
550 return true;
551}
552
553static bool parseVersion(const char* name, ResTable_config* out) {
554 if (strcmp(name, kWildcardName) == 0) {
555 if (out) {
556 out->sdkVersion = out->SDKVERSION_ANY;
557 out->minorVersion = out->MINORVERSION_ANY;
558 }
559 return true;
560 }
561
562 if (*name != 'v') {
563 return false;
564 }
565
566 name++;
567 const char* s = name;
568 while (*s >= '0' && *s <= '9') s++;
569 if (s == name || *s != 0) return false;
570 std::string sdkName(name, s-name);
571
572 if (out) {
573 out->sdkVersion = (uint16_t)atoi(sdkName.c_str());
574 out->minorVersion = 0;
575 }
576
577 return true;
578}
579
580bool ConfigDescription::parse(const StringPiece& str, ConfigDescription* out) {
581 std::vector<std::string> parts = util::splitAndLowercase(str, '-');
582
583 ConfigDescription config;
584 ssize_t partsConsumed = 0;
585 LocaleValue locale;
586
587 const auto partsEnd = parts.end();
588 auto partIter = parts.begin();
589
590 if (str.size() == 0) {
591 goto success;
592 }
593
594 if (parseMcc(partIter->c_str(), &config)) {
595 ++partIter;
596 if (partIter == partsEnd) {
597 goto success;
598 }
599 }
600
601 if (parseMnc(partIter->c_str(), &config)) {
602 ++partIter;
603 if (partIter == partsEnd) {
604 goto success;
605 }
606 }
607
608 // Locale spans a few '-' separators, so we let it
609 // control the index.
610 partsConsumed = locale.initFromParts(partIter, partsEnd);
611 if (partsConsumed < 0) {
612 return false;
613 } else {
614 locale.writeTo(&config);
615 partIter += partsConsumed;
616 if (partIter == partsEnd) {
617 goto success;
618 }
619 }
620
621 if (parseLayoutDirection(partIter->c_str(), &config)) {
622 ++partIter;
623 if (partIter == partsEnd) {
624 goto success;
625 }
626 }
627
628 if (parseSmallestScreenWidthDp(partIter->c_str(), &config)) {
629 ++partIter;
630 if (partIter == partsEnd) {
631 goto success;
632 }
633 }
634
635 if (parseScreenWidthDp(partIter->c_str(), &config)) {
636 ++partIter;
637 if (partIter == partsEnd) {
638 goto success;
639 }
640 }
641
642 if (parseScreenHeightDp(partIter->c_str(), &config)) {
643 ++partIter;
644 if (partIter == partsEnd) {
645 goto success;
646 }
647 }
648
649 if (parseScreenLayoutSize(partIter->c_str(), &config)) {
650 ++partIter;
651 if (partIter == partsEnd) {
652 goto success;
653 }
654 }
655
656 if (parseScreenLayoutLong(partIter->c_str(), &config)) {
657 ++partIter;
658 if (partIter == partsEnd) {
659 goto success;
660 }
661 }
662
Adam Lesinski64254972015-11-03 16:16:17 -0800663 if (parseScreenRound(partIter->c_str(), &config)) {
664 ++partIter;
665 if (partIter == partsEnd) {
666 goto success;
667 }
668 }
669
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800670 if (parseOrientation(partIter->c_str(), &config)) {
671 ++partIter;
672 if (partIter == partsEnd) {
673 goto success;
674 }
675 }
676
677 if (parseUiModeType(partIter->c_str(), &config)) {
678 ++partIter;
679 if (partIter == partsEnd) {
680 goto success;
681 }
682 }
683
684 if (parseUiModeNight(partIter->c_str(), &config)) {
685 ++partIter;
686 if (partIter == partsEnd) {
687 goto success;
688 }
689 }
690
691 if (parseDensity(partIter->c_str(), &config)) {
692 ++partIter;
693 if (partIter == partsEnd) {
694 goto success;
695 }
696 }
697
698 if (parseTouchscreen(partIter->c_str(), &config)) {
699 ++partIter;
700 if (partIter == partsEnd) {
701 goto success;
702 }
703 }
704
705 if (parseKeysHidden(partIter->c_str(), &config)) {
706 ++partIter;
707 if (partIter == partsEnd) {
708 goto success;
709 }
710 }
711
712 if (parseKeyboard(partIter->c_str(), &config)) {
713 ++partIter;
714 if (partIter == partsEnd) {
715 goto success;
716 }
717 }
718
719 if (parseNavHidden(partIter->c_str(), &config)) {
720 ++partIter;
721 if (partIter == partsEnd) {
722 goto success;
723 }
724 }
725
726 if (parseNavigation(partIter->c_str(), &config)) {
727 ++partIter;
728 if (partIter == partsEnd) {
729 goto success;
730 }
731 }
732
733 if (parseScreenSize(partIter->c_str(), &config)) {
734 ++partIter;
735 if (partIter == partsEnd) {
736 goto success;
737 }
738 }
739
740 if (parseVersion(partIter->c_str(), &config)) {
741 ++partIter;
742 if (partIter == partsEnd) {
743 goto success;
744 }
745 }
746
747 // Unrecognized.
748 return false;
749
750success:
751 if (out != NULL) {
752 applyVersionForCompatibility(&config);
753 *out = config;
754 }
755 return true;
756}
757
758void ConfigDescription::applyVersionForCompatibility(ConfigDescription* config) {
759 uint16_t minSdk = 0;
Adam Lesinski64254972015-11-03 16:16:17 -0800760 if (config->screenLayout2 & ResTable_config::MASK_SCREENROUND) {
761 minSdk = SDK_MARSHMALLOW;
762 } else if (config->density == ResTable_config::DENSITY_ANY) {
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800763 minSdk = SDK_LOLLIPOP;
764 } else if (config->smallestScreenWidthDp != ResTable_config::SCREENWIDTH_ANY
765 || config->screenWidthDp != ResTable_config::SCREENWIDTH_ANY
766 || config->screenHeightDp != ResTable_config::SCREENHEIGHT_ANY) {
767 minSdk = SDK_HONEYCOMB_MR2;
768 } else if ((config->uiMode & ResTable_config::MASK_UI_MODE_TYPE)
769 != ResTable_config::UI_MODE_TYPE_ANY
770 || (config->uiMode & ResTable_config::MASK_UI_MODE_NIGHT)
771 != ResTable_config::UI_MODE_NIGHT_ANY) {
772 minSdk = SDK_FROYO;
773 } else if ((config->screenLayout & ResTable_config::MASK_SCREENSIZE)
774 != ResTable_config::SCREENSIZE_ANY
775 || (config->screenLayout & ResTable_config::MASK_SCREENLONG)
776 != ResTable_config::SCREENLONG_ANY
777 || config->density != ResTable_config::DENSITY_DEFAULT) {
778 minSdk = SDK_DONUT;
779 }
780
781 if (minSdk > config->sdkVersion) {
782 config->sdkVersion = minSdk;
783 }
784}
785
Adam Lesinski87675ad2016-07-15 17:03:03 -0700786ConfigDescription ConfigDescription::copyWithoutSdkVersion() const {
787 ConfigDescription copy = *this;
788 copy.sdkVersion = 0;
789 return copy;
790}
791
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800792} // namespace aapt