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