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