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