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