Home | History | Annotate | Download | only in androidfw
      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 
     30 const ConfigDescription& ConfigDescription::DefaultConfig() {
     31   static ConfigDescription config = {};
     32   return config;
     33 }
     34 
     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 
     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 
     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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    867 ConfigDescription ConfigDescription::CopyWithoutSdkVersion() const {
    868   ConfigDescription copy = *this;
    869   copy.sdkVersion = 0;
    870   return copy;
    871 }
    872 
    873 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 
    879 std::string ConfigDescription::to_string() const {
    880   const String8 str = toString();
    881   return std::string(str.string(), str.size());
    882 }
    883 
    884 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 
    901 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 
    962 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 
    989 bool ConfigDescription::IsCompatibleWith(const ConfigDescription& o) const {
    990   return !ConflictsWith(o) && !Dominates(o) && !o.Dominates(*this);
    991 }
    992 
    993 }  // namespace android
    994