Home | History | Annotate | Download | only in aapt2
      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 
     36 const ConfigDescription& ConfigDescription::DefaultConfig() {
     37   static ConfigDescription config = {};
     38   return config;
     39 }
     40 
     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 
     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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    873 ConfigDescription ConfigDescription::CopyWithoutSdkVersion() const {
    874   ConfigDescription copy = *this;
    875   copy.sdkVersion = 0;
    876   return copy;
    877 }
    878 
    879 std::string ConfigDescription::GetBcp47LanguageTag(bool canonicalize) const {
    880   char locale[RESTABLE_MAX_LOCALE_LEN];
    881   getBcp47Locale(locale, canonicalize);
    882   return std::string(locale);
    883 }
    884 
    885 std::string ConfigDescription::to_string() const {
    886   const android::String8 str = toString();
    887   return std::string(str.string(), str.size());
    888 }
    889 
    890 bool ConfigDescription::Dominates(const ConfigDescription& o) const {
    891   if (*this == o) {
    892     return true;
    893   }
    894 
    895   // Locale de-duping is not-trivial, disable for now (b/62409213).
    896   if (diff(o) & CONFIG_LOCALE) {
    897     return false;
    898   }
    899 
    900   if (*this == DefaultConfig()) {
    901     return true;
    902   }
    903   return MatchWithDensity(o) && !o.MatchWithDensity(*this) &&
    904          !isMoreSpecificThan(o) && !o.HasHigherPrecedenceThan(*this);
    905 }
    906 
    907 bool ConfigDescription::HasHigherPrecedenceThan(
    908     const ConfigDescription& o) const {
    909   // The order of the following tests defines the importance of one
    910   // configuration parameter over another. Those tests first are more
    911   // important, trumping any values in those following them.
    912   // The ordering should be the same as ResTable_config#isBetterThan.
    913   if (mcc || o.mcc) return (!o.mcc);
    914   if (mnc || o.mnc) return (!o.mnc);
    915   if (language[0] || o.language[0]) return (!o.language[0]);
    916   if (country[0] || o.country[0]) return (!o.country[0]);
    917   // Script and variant require either a language or country, both of which
    918   // have higher precedence.
    919   if ((screenLayout | o.screenLayout) & MASK_LAYOUTDIR) {
    920     return !(o.screenLayout & MASK_LAYOUTDIR);
    921   }
    922   if (smallestScreenWidthDp || o.smallestScreenWidthDp)
    923     return (!o.smallestScreenWidthDp);
    924   if (screenWidthDp || o.screenWidthDp) return (!o.screenWidthDp);
    925   if (screenHeightDp || o.screenHeightDp) return (!o.screenHeightDp);
    926   if ((screenLayout | o.screenLayout) & MASK_SCREENSIZE) {
    927     return !(o.screenLayout & MASK_SCREENSIZE);
    928   }
    929   if ((screenLayout | o.screenLayout) & MASK_SCREENLONG) {
    930     return !(o.screenLayout & MASK_SCREENLONG);
    931   }
    932   if ((screenLayout2 | o.screenLayout2) & MASK_SCREENROUND) {
    933     return !(o.screenLayout2 & MASK_SCREENROUND);
    934   }
    935   if ((colorMode | o.colorMode) & MASK_HDR) {
    936     return !(o.colorMode & MASK_HDR);
    937   }
    938   if ((colorMode | o.colorMode) & MASK_WIDE_COLOR_GAMUT) {
    939     return !(o.colorMode & MASK_WIDE_COLOR_GAMUT);
    940   }
    941   if (orientation || o.orientation) return (!o.orientation);
    942   if ((uiMode | o.uiMode) & MASK_UI_MODE_TYPE) {
    943     return !(o.uiMode & MASK_UI_MODE_TYPE);
    944   }
    945   if ((uiMode | o.uiMode) & MASK_UI_MODE_NIGHT) {
    946     return !(o.uiMode & MASK_UI_MODE_NIGHT);
    947   }
    948   if (density || o.density) return (!o.density);
    949   if (touchscreen || o.touchscreen) return (!o.touchscreen);
    950   if ((inputFlags | o.inputFlags) & MASK_KEYSHIDDEN) {
    951     return !(o.inputFlags & MASK_KEYSHIDDEN);
    952   }
    953   if ((inputFlags | o.inputFlags) & MASK_NAVHIDDEN) {
    954     return !(o.inputFlags & MASK_NAVHIDDEN);
    955   }
    956   if (keyboard || o.keyboard) return (!o.keyboard);
    957   if (navigation || o.navigation) return (!o.navigation);
    958   if (screenWidth || o.screenWidth) return (!o.screenWidth);
    959   if (screenHeight || o.screenHeight) return (!o.screenHeight);
    960   if (sdkVersion || o.sdkVersion) return (!o.sdkVersion);
    961   if (minorVersion || o.minorVersion) return (!o.minorVersion);
    962   // Both configurations have nothing defined except some possible future
    963   // value. Returning the comparison of the two configurations is a
    964   // "best effort" at this point to protect against incorrect dominations.
    965   return *this != o;
    966 }
    967 
    968 bool ConfigDescription::ConflictsWith(const ConfigDescription& o) const {
    969   // This method should be updated as new configuration parameters are
    970   // introduced (e.g. screenConfig2).
    971   auto pred = [](const uint32_t a, const uint32_t b) -> bool {
    972     return a == 0 || b == 0 || a == b;
    973   };
    974   // The values here can be found in ResTable_config#match. Density and range
    975   // values can't lead to conflicts, and are ignored.
    976   return !pred(mcc, o.mcc) || !pred(mnc, o.mnc) || !pred(locale, o.locale) ||
    977          !pred(screenLayout & MASK_LAYOUTDIR,
    978                o.screenLayout & MASK_LAYOUTDIR) ||
    979          !pred(screenLayout & MASK_SCREENLONG,
    980                o.screenLayout & MASK_SCREENLONG) ||
    981          !pred(uiMode & MASK_UI_MODE_TYPE, o.uiMode & MASK_UI_MODE_TYPE) ||
    982          !pred(uiMode & MASK_UI_MODE_NIGHT, o.uiMode & MASK_UI_MODE_NIGHT) ||
    983          !pred(screenLayout2 & MASK_SCREENROUND,
    984                o.screenLayout2 & MASK_SCREENROUND) ||
    985          !pred(colorMode & MASK_HDR, o.colorMode & MASK_HDR) ||
    986          !pred(colorMode & MASK_WIDE_COLOR_GAMUT,
    987                o.colorMode & MASK_WIDE_COLOR_GAMUT) ||
    988          !pred(orientation, o.orientation) ||
    989          !pred(touchscreen, o.touchscreen) ||
    990          !pred(inputFlags & MASK_KEYSHIDDEN, o.inputFlags & MASK_KEYSHIDDEN) ||
    991          !pred(inputFlags & MASK_NAVHIDDEN, o.inputFlags & MASK_NAVHIDDEN) ||
    992          !pred(keyboard, o.keyboard) || !pred(navigation, o.navigation);
    993 }
    994 
    995 bool ConfigDescription::IsCompatibleWith(const ConfigDescription& o) const {
    996   return !ConflictsWith(o) && !Dominates(o) && !o.Dominates(*this);
    997 }
    998 
    999 }  // namespace aapt
   1000