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