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