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