• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
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 
19 #include <string>
20 #include <vector>
21 
22 #include "androidfw/ResourceTypes.h"
23 #include "androidfw/StringPiece.h"
24 
25 #include "Locale.h"
26 #include "SdkConstants.h"
27 #include "util/Util.h"
28 
29 using android::ResTable_config;
30 using android::StringPiece;
31 
32 namespace aapt {
33 
34 static const char* kWildcardName = "any";
35 
DefaultConfig()36 const ConfigDescription& ConfigDescription::DefaultConfig() {
37   static ConfigDescription config = {};
38   return config;
39 }
40 
parseMcc(const char * name,ResTable_config * out)41 static bool parseMcc(const char* name, ResTable_config* out) {
42   if (strcmp(name, kWildcardName) == 0) {
43     if (out) out->mcc = 0;
44     return true;
45   }
46   const char* c = name;
47   if (tolower(*c) != 'm') return false;
48   c++;
49   if (tolower(*c) != 'c') return false;
50   c++;
51   if (tolower(*c) != 'c') return false;
52   c++;
53 
54   const char* val = c;
55 
56   while (*c >= '0' && *c <= '9') {
57     c++;
58   }
59   if (*c != 0) return false;
60   if (c - val != 3) return false;
61 
62   int d = atoi(val);
63   if (d != 0) {
64     if (out) out->mcc = d;
65     return true;
66   }
67 
68   return false;
69 }
70 
parseMnc(const char * name,ResTable_config * out)71 static bool parseMnc(const char* name, ResTable_config* out) {
72   if (strcmp(name, kWildcardName) == 0) {
73     if (out) out->mnc = 0;
74     return true;
75   }
76   const char* c = name;
77   if (tolower(*c) != 'm') return false;
78   c++;
79   if (tolower(*c) != 'n') return false;
80   c++;
81   if (tolower(*c) != 'c') return false;
82   c++;
83 
84   const char* val = c;
85 
86   while (*c >= '0' && *c <= '9') {
87     c++;
88   }
89   if (*c != 0) return false;
90   if (c - val == 0 || c - val > 3) return false;
91 
92   if (out) {
93     out->mnc = atoi(val);
94     if (out->mnc == 0) {
95       out->mnc = ACONFIGURATION_MNC_ZERO;
96     }
97   }
98 
99   return true;
100 }
101 
parseLayoutDirection(const char * name,ResTable_config * out)102 static bool parseLayoutDirection(const char* name, ResTable_config* out) {
103   if (strcmp(name, kWildcardName) == 0) {
104     if (out)
105       out->screenLayout =
106           (out->screenLayout & ~ResTable_config::MASK_LAYOUTDIR) |
107           ResTable_config::LAYOUTDIR_ANY;
108     return true;
109   } else if (strcmp(name, "ldltr") == 0) {
110     if (out)
111       out->screenLayout =
112           (out->screenLayout & ~ResTable_config::MASK_LAYOUTDIR) |
113           ResTable_config::LAYOUTDIR_LTR;
114     return true;
115   } else if (strcmp(name, "ldrtl") == 0) {
116     if (out)
117       out->screenLayout =
118           (out->screenLayout & ~ResTable_config::MASK_LAYOUTDIR) |
119           ResTable_config::LAYOUTDIR_RTL;
120     return true;
121   }
122 
123   return false;
124 }
125 
parseScreenLayoutSize(const char * name,ResTable_config * out)126 static bool parseScreenLayoutSize(const char* name, ResTable_config* out) {
127   if (strcmp(name, kWildcardName) == 0) {
128     if (out)
129       out->screenLayout =
130           (out->screenLayout & ~ResTable_config::MASK_SCREENSIZE) |
131           ResTable_config::SCREENSIZE_ANY;
132     return true;
133   } else if (strcmp(name, "small") == 0) {
134     if (out)
135       out->screenLayout =
136           (out->screenLayout & ~ResTable_config::MASK_SCREENSIZE) |
137           ResTable_config::SCREENSIZE_SMALL;
138     return true;
139   } else if (strcmp(name, "normal") == 0) {
140     if (out)
141       out->screenLayout =
142           (out->screenLayout & ~ResTable_config::MASK_SCREENSIZE) |
143           ResTable_config::SCREENSIZE_NORMAL;
144     return true;
145   } else if (strcmp(name, "large") == 0) {
146     if (out)
147       out->screenLayout =
148           (out->screenLayout & ~ResTable_config::MASK_SCREENSIZE) |
149           ResTable_config::SCREENSIZE_LARGE;
150     return true;
151   } else if (strcmp(name, "xlarge") == 0) {
152     if (out)
153       out->screenLayout =
154           (out->screenLayout & ~ResTable_config::MASK_SCREENSIZE) |
155           ResTable_config::SCREENSIZE_XLARGE;
156     return true;
157   }
158 
159   return false;
160 }
161 
parseScreenLayoutLong(const char * name,ResTable_config * out)162 static bool parseScreenLayoutLong(const char* name, ResTable_config* out) {
163   if (strcmp(name, kWildcardName) == 0) {
164     if (out)
165       out->screenLayout =
166           (out->screenLayout & ~ResTable_config::MASK_SCREENLONG) |
167           ResTable_config::SCREENLONG_ANY;
168     return true;
169   } else if (strcmp(name, "long") == 0) {
170     if (out)
171       out->screenLayout =
172           (out->screenLayout & ~ResTable_config::MASK_SCREENLONG) |
173           ResTable_config::SCREENLONG_YES;
174     return true;
175   } else if (strcmp(name, "notlong") == 0) {
176     if (out)
177       out->screenLayout =
178           (out->screenLayout & ~ResTable_config::MASK_SCREENLONG) |
179           ResTable_config::SCREENLONG_NO;
180     return true;
181   }
182 
183   return false;
184 }
185 
parseScreenRound(const char * name,ResTable_config * out)186 static bool parseScreenRound(const char* name, ResTable_config* out) {
187   if (strcmp(name, kWildcardName) == 0) {
188     if (out)
189       out->screenLayout2 =
190           (out->screenLayout2 & ~ResTable_config::MASK_SCREENROUND) |
191           ResTable_config::SCREENROUND_ANY;
192     return true;
193   } else if (strcmp(name, "round") == 0) {
194     if (out)
195       out->screenLayout2 =
196           (out->screenLayout2 & ~ResTable_config::MASK_SCREENROUND) |
197           ResTable_config::SCREENROUND_YES;
198     return true;
199   } else if (strcmp(name, "notround") == 0) {
200     if (out)
201       out->screenLayout2 =
202           (out->screenLayout2 & ~ResTable_config::MASK_SCREENROUND) |
203           ResTable_config::SCREENROUND_NO;
204     return true;
205   }
206   return false;
207 }
208 
parseWideColorGamut(const char * name,ResTable_config * out)209 static bool parseWideColorGamut(const char* name, ResTable_config* out) {
210   if (strcmp(name, kWildcardName) == 0) {
211     if (out)
212       out->colorMode =
213           (out->colorMode & ~ResTable_config::MASK_WIDE_COLOR_GAMUT) |
214           ResTable_config::WIDE_COLOR_GAMUT_ANY;
215     return true;
216   } else if (strcmp(name, "widecg") == 0) {
217     if (out)
218       out->colorMode =
219           (out->colorMode & ~ResTable_config::MASK_WIDE_COLOR_GAMUT) |
220           ResTable_config::WIDE_COLOR_GAMUT_YES;
221     return true;
222   } else if (strcmp(name, "nowidecg") == 0) {
223     if (out)
224       out->colorMode =
225           (out->colorMode & ~ResTable_config::MASK_WIDE_COLOR_GAMUT) |
226           ResTable_config::WIDE_COLOR_GAMUT_NO;
227     return true;
228   }
229   return false;
230 }
231 
parseHdr(const char * name,ResTable_config * out)232 static bool parseHdr(const char* name, ResTable_config* out) {
233   if (strcmp(name, kWildcardName) == 0) {
234     if (out)
235       out->colorMode =
236           (out->colorMode & ~ResTable_config::MASK_HDR) |
237           ResTable_config::HDR_ANY;
238     return true;
239   } else if (strcmp(name, "highdr") == 0) {
240     if (out)
241       out->colorMode =
242           (out->colorMode & ~ResTable_config::MASK_HDR) |
243           ResTable_config::HDR_YES;
244     return true;
245   } else if (strcmp(name, "lowdr") == 0) {
246     if (out)
247       out->colorMode =
248           (out->colorMode & ~ResTable_config::MASK_HDR) |
249           ResTable_config::HDR_NO;
250     return true;
251   }
252   return false;
253 }
254 
parseOrientation(const char * name,ResTable_config * out)255 static bool parseOrientation(const char* name, ResTable_config* out) {
256   if (strcmp(name, kWildcardName) == 0) {
257     if (out) out->orientation = out->ORIENTATION_ANY;
258     return true;
259   } else if (strcmp(name, "port") == 0) {
260     if (out) out->orientation = out->ORIENTATION_PORT;
261     return true;
262   } else if (strcmp(name, "land") == 0) {
263     if (out) out->orientation = out->ORIENTATION_LAND;
264     return true;
265   } else if (strcmp(name, "square") == 0) {
266     if (out) out->orientation = out->ORIENTATION_SQUARE;
267     return true;
268   }
269 
270   return false;
271 }
272 
parseUiModeType(const char * name,ResTable_config * out)273 static bool parseUiModeType(const char* name, ResTable_config* out) {
274   if (strcmp(name, kWildcardName) == 0) {
275     if (out)
276       out->uiMode = (out->uiMode & ~ResTable_config::MASK_UI_MODE_TYPE) |
277                     ResTable_config::UI_MODE_TYPE_ANY;
278     return true;
279   } else if (strcmp(name, "desk") == 0) {
280     if (out)
281       out->uiMode = (out->uiMode & ~ResTable_config::MASK_UI_MODE_TYPE) |
282                     ResTable_config::UI_MODE_TYPE_DESK;
283     return true;
284   } else if (strcmp(name, "car") == 0) {
285     if (out)
286       out->uiMode = (out->uiMode & ~ResTable_config::MASK_UI_MODE_TYPE) |
287                     ResTable_config::UI_MODE_TYPE_CAR;
288     return true;
289   } else if (strcmp(name, "television") == 0) {
290     if (out)
291       out->uiMode = (out->uiMode & ~ResTable_config::MASK_UI_MODE_TYPE) |
292                     ResTable_config::UI_MODE_TYPE_TELEVISION;
293     return true;
294   } else if (strcmp(name, "appliance") == 0) {
295     if (out)
296       out->uiMode = (out->uiMode & ~ResTable_config::MASK_UI_MODE_TYPE) |
297                     ResTable_config::UI_MODE_TYPE_APPLIANCE;
298     return true;
299   } else if (strcmp(name, "watch") == 0) {
300     if (out)
301       out->uiMode = (out->uiMode & ~ResTable_config::MASK_UI_MODE_TYPE) |
302                     ResTable_config::UI_MODE_TYPE_WATCH;
303     return true;
304   } else if (strcmp(name, "vrheadset") == 0) {
305     if (out)
306       out->uiMode = (out->uiMode & ~ResTable_config::MASK_UI_MODE_TYPE) |
307                     ResTable_config::UI_MODE_TYPE_VR_HEADSET;
308     return true;
309   }
310 
311   return false;
312 }
313 
parseUiModeNight(const char * name,ResTable_config * out)314 static bool parseUiModeNight(const char* name, ResTable_config* out) {
315   if (strcmp(name, kWildcardName) == 0) {
316     if (out)
317       out->uiMode = (out->uiMode & ~ResTable_config::MASK_UI_MODE_NIGHT) |
318                     ResTable_config::UI_MODE_NIGHT_ANY;
319     return true;
320   } else if (strcmp(name, "night") == 0) {
321     if (out)
322       out->uiMode = (out->uiMode & ~ResTable_config::MASK_UI_MODE_NIGHT) |
323                     ResTable_config::UI_MODE_NIGHT_YES;
324     return true;
325   } else if (strcmp(name, "notnight") == 0) {
326     if (out)
327       out->uiMode = (out->uiMode & ~ResTable_config::MASK_UI_MODE_NIGHT) |
328                     ResTable_config::UI_MODE_NIGHT_NO;
329     return true;
330   }
331 
332   return false;
333 }
334 
parseDensity(const char * name,ResTable_config * out)335 static bool parseDensity(const char* name, ResTable_config* out) {
336   if (strcmp(name, kWildcardName) == 0) {
337     if (out) out->density = ResTable_config::DENSITY_DEFAULT;
338     return true;
339   }
340 
341   if (strcmp(name, "anydpi") == 0) {
342     if (out) out->density = ResTable_config::DENSITY_ANY;
343     return true;
344   }
345 
346   if (strcmp(name, "nodpi") == 0) {
347     if (out) out->density = ResTable_config::DENSITY_NONE;
348     return true;
349   }
350 
351   if (strcmp(name, "ldpi") == 0) {
352     if (out) out->density = ResTable_config::DENSITY_LOW;
353     return true;
354   }
355 
356   if (strcmp(name, "mdpi") == 0) {
357     if (out) out->density = ResTable_config::DENSITY_MEDIUM;
358     return true;
359   }
360 
361   if (strcmp(name, "tvdpi") == 0) {
362     if (out) out->density = ResTable_config::DENSITY_TV;
363     return true;
364   }
365 
366   if (strcmp(name, "hdpi") == 0) {
367     if (out) out->density = ResTable_config::DENSITY_HIGH;
368     return true;
369   }
370 
371   if (strcmp(name, "xhdpi") == 0) {
372     if (out) out->density = ResTable_config::DENSITY_XHIGH;
373     return true;
374   }
375 
376   if (strcmp(name, "xxhdpi") == 0) {
377     if (out) out->density = ResTable_config::DENSITY_XXHIGH;
378     return true;
379   }
380 
381   if (strcmp(name, "xxxhdpi") == 0) {
382     if (out) out->density = ResTable_config::DENSITY_XXXHIGH;
383     return true;
384   }
385 
386   char* c = (char*)name;
387   while (*c >= '0' && *c <= '9') {
388     c++;
389   }
390 
391   // check that we have 'dpi' after the last digit.
392   if (toupper(c[0]) != 'D' || toupper(c[1]) != 'P' || toupper(c[2]) != 'I' ||
393       c[3] != 0) {
394     return false;
395   }
396 
397   // temporarily replace the first letter with \0 to
398   // use atoi.
399   char tmp = c[0];
400   c[0] = '\0';
401 
402   int d = atoi(name);
403   c[0] = tmp;
404 
405   if (d != 0) {
406     if (out) out->density = d;
407     return true;
408   }
409 
410   return false;
411 }
412 
parseTouchscreen(const char * name,ResTable_config * out)413 static bool parseTouchscreen(const char* name, ResTable_config* out) {
414   if (strcmp(name, kWildcardName) == 0) {
415     if (out) out->touchscreen = out->TOUCHSCREEN_ANY;
416     return true;
417   } else if (strcmp(name, "notouch") == 0) {
418     if (out) out->touchscreen = out->TOUCHSCREEN_NOTOUCH;
419     return true;
420   } else if (strcmp(name, "stylus") == 0) {
421     if (out) out->touchscreen = out->TOUCHSCREEN_STYLUS;
422     return true;
423   } else if (strcmp(name, "finger") == 0) {
424     if (out) out->touchscreen = out->TOUCHSCREEN_FINGER;
425     return true;
426   }
427 
428   return false;
429 }
430 
parseKeysHidden(const char * name,ResTable_config * out)431 static bool parseKeysHidden(const char* name, ResTable_config* out) {
432   uint8_t mask = 0;
433   uint8_t value = 0;
434   if (strcmp(name, kWildcardName) == 0) {
435     mask = ResTable_config::MASK_KEYSHIDDEN;
436     value = ResTable_config::KEYSHIDDEN_ANY;
437   } else if (strcmp(name, "keysexposed") == 0) {
438     mask = ResTable_config::MASK_KEYSHIDDEN;
439     value = ResTable_config::KEYSHIDDEN_NO;
440   } else if (strcmp(name, "keyshidden") == 0) {
441     mask = ResTable_config::MASK_KEYSHIDDEN;
442     value = ResTable_config::KEYSHIDDEN_YES;
443   } else if (strcmp(name, "keyssoft") == 0) {
444     mask = ResTable_config::MASK_KEYSHIDDEN;
445     value = ResTable_config::KEYSHIDDEN_SOFT;
446   }
447 
448   if (mask != 0) {
449     if (out) out->inputFlags = (out->inputFlags & ~mask) | value;
450     return true;
451   }
452 
453   return false;
454 }
455 
parseKeyboard(const char * name,ResTable_config * out)456 static bool parseKeyboard(const char* name, ResTable_config* out) {
457   if (strcmp(name, kWildcardName) == 0) {
458     if (out) out->keyboard = out->KEYBOARD_ANY;
459     return true;
460   } else if (strcmp(name, "nokeys") == 0) {
461     if (out) out->keyboard = out->KEYBOARD_NOKEYS;
462     return true;
463   } else if (strcmp(name, "qwerty") == 0) {
464     if (out) out->keyboard = out->KEYBOARD_QWERTY;
465     return true;
466   } else if (strcmp(name, "12key") == 0) {
467     if (out) out->keyboard = out->KEYBOARD_12KEY;
468     return true;
469   }
470 
471   return false;
472 }
473 
parseNavHidden(const char * name,ResTable_config * out)474 static bool parseNavHidden(const char* name, ResTable_config* out) {
475   uint8_t mask = 0;
476   uint8_t value = 0;
477   if (strcmp(name, kWildcardName) == 0) {
478     mask = ResTable_config::MASK_NAVHIDDEN;
479     value = ResTable_config::NAVHIDDEN_ANY;
480   } else if (strcmp(name, "navexposed") == 0) {
481     mask = ResTable_config::MASK_NAVHIDDEN;
482     value = ResTable_config::NAVHIDDEN_NO;
483   } else if (strcmp(name, "navhidden") == 0) {
484     mask = ResTable_config::MASK_NAVHIDDEN;
485     value = ResTable_config::NAVHIDDEN_YES;
486   }
487 
488   if (mask != 0) {
489     if (out) out->inputFlags = (out->inputFlags & ~mask) | value;
490     return true;
491   }
492 
493   return false;
494 }
495 
parseNavigation(const char * name,ResTable_config * out)496 static bool parseNavigation(const char* name, ResTable_config* out) {
497   if (strcmp(name, kWildcardName) == 0) {
498     if (out) out->navigation = out->NAVIGATION_ANY;
499     return true;
500   } else if (strcmp(name, "nonav") == 0) {
501     if (out) out->navigation = out->NAVIGATION_NONAV;
502     return true;
503   } else if (strcmp(name, "dpad") == 0) {
504     if (out) out->navigation = out->NAVIGATION_DPAD;
505     return true;
506   } else if (strcmp(name, "trackball") == 0) {
507     if (out) out->navigation = out->NAVIGATION_TRACKBALL;
508     return true;
509   } else if (strcmp(name, "wheel") == 0) {
510     if (out) out->navigation = out->NAVIGATION_WHEEL;
511     return true;
512   }
513 
514   return false;
515 }
516 
parseScreenSize(const char * name,ResTable_config * out)517 static bool parseScreenSize(const char* name, ResTable_config* out) {
518   if (strcmp(name, kWildcardName) == 0) {
519     if (out) {
520       out->screenWidth = out->SCREENWIDTH_ANY;
521       out->screenHeight = out->SCREENHEIGHT_ANY;
522     }
523     return true;
524   }
525 
526   const char* x = name;
527   while (*x >= '0' && *x <= '9') x++;
528   if (x == name || *x != 'x') return false;
529   std::string xName(name, x - name);
530   x++;
531 
532   const char* y = x;
533   while (*y >= '0' && *y <= '9') y++;
534   if (y == name || *y != 0) return false;
535   std::string yName(x, y - x);
536 
537   uint16_t w = (uint16_t)atoi(xName.c_str());
538   uint16_t h = (uint16_t)atoi(yName.c_str());
539   if (w < h) {
540     return false;
541   }
542 
543   if (out) {
544     out->screenWidth = w;
545     out->screenHeight = h;
546   }
547 
548   return true;
549 }
550 
parseSmallestScreenWidthDp(const char * name,ResTable_config * out)551 static bool parseSmallestScreenWidthDp(const char* name, ResTable_config* out) {
552   if (strcmp(name, kWildcardName) == 0) {
553     if (out) {
554       out->smallestScreenWidthDp = out->SCREENWIDTH_ANY;
555     }
556     return true;
557   }
558 
559   if (*name != 's') return false;
560   name++;
561   if (*name != 'w') return false;
562   name++;
563   const char* x = name;
564   while (*x >= '0' && *x <= '9') x++;
565   if (x == name || x[0] != 'd' || x[1] != 'p' || x[2] != 0) return false;
566   std::string xName(name, x - name);
567 
568   if (out) {
569     out->smallestScreenWidthDp = (uint16_t)atoi(xName.c_str());
570   }
571 
572   return true;
573 }
574 
parseScreenWidthDp(const char * name,ResTable_config * out)575 static bool parseScreenWidthDp(const char* name, ResTable_config* out) {
576   if (strcmp(name, kWildcardName) == 0) {
577     if (out) {
578       out->screenWidthDp = out->SCREENWIDTH_ANY;
579     }
580     return true;
581   }
582 
583   if (*name != 'w') return false;
584   name++;
585   const char* x = name;
586   while (*x >= '0' && *x <= '9') x++;
587   if (x == name || x[0] != 'd' || x[1] != 'p' || x[2] != 0) return false;
588   std::string xName(name, x - name);
589 
590   if (out) {
591     out->screenWidthDp = (uint16_t)atoi(xName.c_str());
592   }
593 
594   return true;
595 }
596 
parseScreenHeightDp(const char * name,ResTable_config * out)597 static bool parseScreenHeightDp(const char* name, ResTable_config* out) {
598   if (strcmp(name, kWildcardName) == 0) {
599     if (out) {
600       out->screenHeightDp = out->SCREENWIDTH_ANY;
601     }
602     return true;
603   }
604 
605   if (*name != 'h') return false;
606   name++;
607   const char* x = name;
608   while (*x >= '0' && *x <= '9') x++;
609   if (x == name || x[0] != 'd' || x[1] != 'p' || x[2] != 0) return false;
610   std::string xName(name, x - name);
611 
612   if (out) {
613     out->screenHeightDp = (uint16_t)atoi(xName.c_str());
614   }
615 
616   return true;
617 }
618 
parseVersion(const char * name,ResTable_config * out)619 static bool parseVersion(const char* name, ResTable_config* out) {
620   if (strcmp(name, kWildcardName) == 0) {
621     if (out) {
622       out->sdkVersion = out->SDKVERSION_ANY;
623       out->minorVersion = out->MINORVERSION_ANY;
624     }
625     return true;
626   }
627 
628   if (*name != 'v') {
629     return false;
630   }
631 
632   name++;
633   const char* s = name;
634   while (*s >= '0' && *s <= '9') s++;
635   if (s == name || *s != 0) return false;
636   std::string sdkName(name, s - name);
637 
638   if (out) {
639     out->sdkVersion = (uint16_t)atoi(sdkName.c_str());
640     out->minorVersion = 0;
641   }
642 
643   return true;
644 }
645 
Parse(const StringPiece & str,ConfigDescription * out)646 bool ConfigDescription::Parse(const StringPiece& str, ConfigDescription* out) {
647   std::vector<std::string> parts = util::SplitAndLowercase(str, '-');
648 
649   ConfigDescription config;
650   ssize_t parts_consumed = 0;
651   LocaleValue locale;
652 
653   const auto parts_end = parts.end();
654   auto part_iter = parts.begin();
655 
656   if (str.size() == 0) {
657     goto success;
658   }
659 
660   if (parseMcc(part_iter->c_str(), &config)) {
661     ++part_iter;
662     if (part_iter == parts_end) {
663       goto success;
664     }
665   }
666 
667   if (parseMnc(part_iter->c_str(), &config)) {
668     ++part_iter;
669     if (part_iter == parts_end) {
670       goto success;
671     }
672   }
673 
674   // Locale spans a few '-' separators, so we let it
675   // control the index.
676   parts_consumed = locale.InitFromParts(part_iter, parts_end);
677   if (parts_consumed < 0) {
678     return false;
679   } else {
680     locale.WriteTo(&config);
681     part_iter += parts_consumed;
682     if (part_iter == parts_end) {
683       goto success;
684     }
685   }
686 
687   if (parseLayoutDirection(part_iter->c_str(), &config)) {
688     ++part_iter;
689     if (part_iter == parts_end) {
690       goto success;
691     }
692   }
693 
694   if (parseSmallestScreenWidthDp(part_iter->c_str(), &config)) {
695     ++part_iter;
696     if (part_iter == parts_end) {
697       goto success;
698     }
699   }
700 
701   if (parseScreenWidthDp(part_iter->c_str(), &config)) {
702     ++part_iter;
703     if (part_iter == parts_end) {
704       goto success;
705     }
706   }
707 
708   if (parseScreenHeightDp(part_iter->c_str(), &config)) {
709     ++part_iter;
710     if (part_iter == parts_end) {
711       goto success;
712     }
713   }
714 
715   if (parseScreenLayoutSize(part_iter->c_str(), &config)) {
716     ++part_iter;
717     if (part_iter == parts_end) {
718       goto success;
719     }
720   }
721 
722   if (parseScreenLayoutLong(part_iter->c_str(), &config)) {
723     ++part_iter;
724     if (part_iter == parts_end) {
725       goto success;
726     }
727   }
728 
729   if (parseScreenRound(part_iter->c_str(), &config)) {
730     ++part_iter;
731     if (part_iter == parts_end) {
732       goto success;
733     }
734   }
735 
736   if (parseWideColorGamut(part_iter->c_str(), &config)) {
737     ++part_iter;
738     if (part_iter == parts_end) {
739       goto success;
740     }
741   }
742 
743   if (parseHdr(part_iter->c_str(), &config)) {
744     ++part_iter;
745     if (part_iter == parts_end) {
746       goto success;
747     }
748   }
749 
750   if (parseOrientation(part_iter->c_str(), &config)) {
751     ++part_iter;
752     if (part_iter == parts_end) {
753       goto success;
754     }
755   }
756 
757   if (parseUiModeType(part_iter->c_str(), &config)) {
758     ++part_iter;
759     if (part_iter == parts_end) {
760       goto success;
761     }
762   }
763 
764   if (parseUiModeNight(part_iter->c_str(), &config)) {
765     ++part_iter;
766     if (part_iter == parts_end) {
767       goto success;
768     }
769   }
770 
771   if (parseDensity(part_iter->c_str(), &config)) {
772     ++part_iter;
773     if (part_iter == parts_end) {
774       goto success;
775     }
776   }
777 
778   if (parseTouchscreen(part_iter->c_str(), &config)) {
779     ++part_iter;
780     if (part_iter == parts_end) {
781       goto success;
782     }
783   }
784 
785   if (parseKeysHidden(part_iter->c_str(), &config)) {
786     ++part_iter;
787     if (part_iter == parts_end) {
788       goto success;
789     }
790   }
791 
792   if (parseKeyboard(part_iter->c_str(), &config)) {
793     ++part_iter;
794     if (part_iter == parts_end) {
795       goto success;
796     }
797   }
798 
799   if (parseNavHidden(part_iter->c_str(), &config)) {
800     ++part_iter;
801     if (part_iter == parts_end) {
802       goto success;
803     }
804   }
805 
806   if (parseNavigation(part_iter->c_str(), &config)) {
807     ++part_iter;
808     if (part_iter == parts_end) {
809       goto success;
810     }
811   }
812 
813   if (parseScreenSize(part_iter->c_str(), &config)) {
814     ++part_iter;
815     if (part_iter == parts_end) {
816       goto success;
817     }
818   }
819 
820   if (parseVersion(part_iter->c_str(), &config)) {
821     ++part_iter;
822     if (part_iter == parts_end) {
823       goto success;
824     }
825   }
826 
827   // Unrecognized.
828   return false;
829 
830 success:
831   if (out != NULL) {
832     ApplyVersionForCompatibility(&config);
833     *out = config;
834   }
835   return true;
836 }
837 
ApplyVersionForCompatibility(ConfigDescription * config)838 void ConfigDescription::ApplyVersionForCompatibility(
839     ConfigDescription* config) {
840   uint16_t min_sdk = 0;
841   if ((config->uiMode & ResTable_config::MASK_UI_MODE_TYPE)
842                 == ResTable_config::UI_MODE_TYPE_VR_HEADSET ||
843             config->colorMode & ResTable_config::MASK_WIDE_COLOR_GAMUT ||
844             config->colorMode & ResTable_config::MASK_HDR) {
845         min_sdk = SDK_O;
846   } else if (config->screenLayout2 & ResTable_config::MASK_SCREENROUND) {
847     min_sdk = SDK_MARSHMALLOW;
848   } else if (config->density == ResTable_config::DENSITY_ANY) {
849     min_sdk = SDK_LOLLIPOP;
850   } else if (config->smallestScreenWidthDp !=
851                  ResTable_config::SCREENWIDTH_ANY ||
852              config->screenWidthDp != ResTable_config::SCREENWIDTH_ANY ||
853              config->screenHeightDp != ResTable_config::SCREENHEIGHT_ANY) {
854     min_sdk = SDK_HONEYCOMB_MR2;
855   } else if ((config->uiMode & ResTable_config::MASK_UI_MODE_TYPE) !=
856                  ResTable_config::UI_MODE_TYPE_ANY ||
857              (config->uiMode & ResTable_config::MASK_UI_MODE_NIGHT) !=
858                  ResTable_config::UI_MODE_NIGHT_ANY) {
859     min_sdk = SDK_FROYO;
860   } else if ((config->screenLayout & ResTable_config::MASK_SCREENSIZE) !=
861                  ResTable_config::SCREENSIZE_ANY ||
862              (config->screenLayout & ResTable_config::MASK_SCREENLONG) !=
863                  ResTable_config::SCREENLONG_ANY ||
864              config->density != ResTable_config::DENSITY_DEFAULT) {
865     min_sdk = SDK_DONUT;
866   }
867 
868   if (min_sdk > config->sdkVersion) {
869     config->sdkVersion = min_sdk;
870   }
871 }
872 
CopyWithoutSdkVersion() const873 ConfigDescription ConfigDescription::CopyWithoutSdkVersion() const {
874   ConfigDescription copy = *this;
875   copy.sdkVersion = 0;
876   return copy;
877 }
878 
Dominates(const ConfigDescription & o) const879 bool ConfigDescription::Dominates(const ConfigDescription& o) const {
880   if (*this == o) {
881     return true;
882   }
883 
884   // Locale de-duping is not-trivial, disable for now (b/62409213).
885   if (diff(o) & CONFIG_LOCALE) {
886     return false;
887   }
888 
889   if (*this == DefaultConfig()) {
890     return true;
891   }
892   return MatchWithDensity(o) && !o.MatchWithDensity(*this) &&
893          !isMoreSpecificThan(o) && !o.HasHigherPrecedenceThan(*this);
894 }
895 
HasHigherPrecedenceThan(const ConfigDescription & o) const896 bool ConfigDescription::HasHigherPrecedenceThan(
897     const ConfigDescription& o) const {
898   // The order of the following tests defines the importance of one
899   // configuration parameter over another. Those tests first are more
900   // important, trumping any values in those following them.
901   // The ordering should be the same as ResTable_config#isBetterThan.
902   if (mcc || o.mcc) return (!o.mcc);
903   if (mnc || o.mnc) return (!o.mnc);
904   if (language[0] || o.language[0]) return (!o.language[0]);
905   if (country[0] || o.country[0]) return (!o.country[0]);
906   // Script and variant require either a language or country, both of which
907   // have higher precedence.
908   if ((screenLayout | o.screenLayout) & MASK_LAYOUTDIR) {
909     return !(o.screenLayout & MASK_LAYOUTDIR);
910   }
911   if (smallestScreenWidthDp || o.smallestScreenWidthDp)
912     return (!o.smallestScreenWidthDp);
913   if (screenWidthDp || o.screenWidthDp) return (!o.screenWidthDp);
914   if (screenHeightDp || o.screenHeightDp) return (!o.screenHeightDp);
915   if ((screenLayout | o.screenLayout) & MASK_SCREENSIZE) {
916     return !(o.screenLayout & MASK_SCREENSIZE);
917   }
918   if ((screenLayout | o.screenLayout) & MASK_SCREENLONG) {
919     return !(o.screenLayout & MASK_SCREENLONG);
920   }
921   if ((screenLayout2 | o.screenLayout2) & MASK_SCREENROUND) {
922     return !(o.screenLayout2 & MASK_SCREENROUND);
923   }
924   if ((colorMode | o.colorMode) & MASK_HDR) {
925     return !(o.colorMode & MASK_HDR);
926   }
927   if ((colorMode | o.colorMode) & MASK_WIDE_COLOR_GAMUT) {
928     return !(o.colorMode & MASK_WIDE_COLOR_GAMUT);
929   }
930   if (orientation || o.orientation) return (!o.orientation);
931   if ((uiMode | o.uiMode) & MASK_UI_MODE_TYPE) {
932     return !(o.uiMode & MASK_UI_MODE_TYPE);
933   }
934   if ((uiMode | o.uiMode) & MASK_UI_MODE_NIGHT) {
935     return !(o.uiMode & MASK_UI_MODE_NIGHT);
936   }
937   if (density || o.density) return (!o.density);
938   if (touchscreen || o.touchscreen) return (!o.touchscreen);
939   if ((inputFlags | o.inputFlags) & MASK_KEYSHIDDEN) {
940     return !(o.inputFlags & MASK_KEYSHIDDEN);
941   }
942   if ((inputFlags | o.inputFlags) & MASK_NAVHIDDEN) {
943     return !(o.inputFlags & MASK_NAVHIDDEN);
944   }
945   if (keyboard || o.keyboard) return (!o.keyboard);
946   if (navigation || o.navigation) return (!o.navigation);
947   if (screenWidth || o.screenWidth) return (!o.screenWidth);
948   if (screenHeight || o.screenHeight) return (!o.screenHeight);
949   if (sdkVersion || o.sdkVersion) return (!o.sdkVersion);
950   if (minorVersion || o.minorVersion) return (!o.minorVersion);
951   // Both configurations have nothing defined except some possible future
952   // value. Returning the comparison of the two configurations is a
953   // "best effort" at this point to protect against incorrect dominations.
954   return *this != o;
955 }
956 
ConflictsWith(const ConfigDescription & o) const957 bool ConfigDescription::ConflictsWith(const ConfigDescription& o) const {
958   // This method should be updated as new configuration parameters are
959   // introduced (e.g. screenConfig2).
960   auto pred = [](const uint32_t a, const uint32_t b) -> bool {
961     return a == 0 || b == 0 || a == b;
962   };
963   // The values here can be found in ResTable_config#match. Density and range
964   // values can't lead to conflicts, and are ignored.
965   return !pred(mcc, o.mcc) || !pred(mnc, o.mnc) || !pred(locale, o.locale) ||
966          !pred(screenLayout & MASK_LAYOUTDIR,
967                o.screenLayout & MASK_LAYOUTDIR) ||
968          !pred(screenLayout & MASK_SCREENLONG,
969                o.screenLayout & MASK_SCREENLONG) ||
970          !pred(uiMode & MASK_UI_MODE_TYPE, o.uiMode & MASK_UI_MODE_TYPE) ||
971          !pred(uiMode & MASK_UI_MODE_NIGHT, o.uiMode & MASK_UI_MODE_NIGHT) ||
972          !pred(screenLayout2 & MASK_SCREENROUND,
973                o.screenLayout2 & MASK_SCREENROUND) ||
974          !pred(colorMode & MASK_HDR, o.colorMode & MASK_HDR) ||
975          !pred(colorMode & MASK_WIDE_COLOR_GAMUT,
976                o.colorMode & MASK_WIDE_COLOR_GAMUT) ||
977          !pred(orientation, o.orientation) ||
978          !pred(touchscreen, o.touchscreen) ||
979          !pred(inputFlags & MASK_KEYSHIDDEN, o.inputFlags & MASK_KEYSHIDDEN) ||
980          !pred(inputFlags & MASK_NAVHIDDEN, o.inputFlags & MASK_NAVHIDDEN) ||
981          !pred(keyboard, o.keyboard) || !pred(navigation, o.navigation);
982 }
983 
IsCompatibleWith(const ConfigDescription & o) const984 bool ConfigDescription::IsCompatibleWith(const ConfigDescription& o) const {
985   return !ConflictsWith(o) && !Dominates(o) && !o.Dominates(*this);
986 }
987 
988 }  // namespace aapt
989