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