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