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