• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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