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) out->screenLayout = 102 (out->screenLayout&~ResTable_config::MASK_LAYOUTDIR) 103 | ResTable_config::LAYOUTDIR_ANY; 104 return true; 105 } else if (strcmp(name, "ldltr") == 0) { 106 if (out) out->screenLayout = 107 (out->screenLayout&~ResTable_config::MASK_LAYOUTDIR) 108 | ResTable_config::LAYOUTDIR_LTR; 109 return true; 110 } else if (strcmp(name, "ldrtl") == 0) { 111 if (out) out->screenLayout = 112 (out->screenLayout&~ResTable_config::MASK_LAYOUTDIR) 113 | ResTable_config::LAYOUTDIR_RTL; 114 return true; 115 } 116 117 return false; 118} 119 120static bool parseScreenLayoutSize(const char* name, ResTable_config* out) { 121 if (strcmp(name, kWildcardName) == 0) { 122 if (out) out->screenLayout = 123 (out->screenLayout&~ResTable_config::MASK_SCREENSIZE) 124 | ResTable_config::SCREENSIZE_ANY; 125 return true; 126 } else if (strcmp(name, "small") == 0) { 127 if (out) out->screenLayout = 128 (out->screenLayout&~ResTable_config::MASK_SCREENSIZE) 129 | ResTable_config::SCREENSIZE_SMALL; 130 return true; 131 } else if (strcmp(name, "normal") == 0) { 132 if (out) out->screenLayout = 133 (out->screenLayout&~ResTable_config::MASK_SCREENSIZE) 134 | ResTable_config::SCREENSIZE_NORMAL; 135 return true; 136 } else if (strcmp(name, "large") == 0) { 137 if (out) out->screenLayout = 138 (out->screenLayout&~ResTable_config::MASK_SCREENSIZE) 139 | ResTable_config::SCREENSIZE_LARGE; 140 return true; 141 } else if (strcmp(name, "xlarge") == 0) { 142 if (out) out->screenLayout = 143 (out->screenLayout&~ResTable_config::MASK_SCREENSIZE) 144 | ResTable_config::SCREENSIZE_XLARGE; 145 return true; 146 } 147 148 return false; 149} 150 151static bool parseScreenLayoutLong(const char* name, ResTable_config* out) { 152 if (strcmp(name, kWildcardName) == 0) { 153 if (out) out->screenLayout = 154 (out->screenLayout&~ResTable_config::MASK_SCREENLONG) 155 | ResTable_config::SCREENLONG_ANY; 156 return true; 157 } else if (strcmp(name, "long") == 0) { 158 if (out) out->screenLayout = 159 (out->screenLayout&~ResTable_config::MASK_SCREENLONG) 160 | ResTable_config::SCREENLONG_YES; 161 return true; 162 } else if (strcmp(name, "notlong") == 0) { 163 if (out) out->screenLayout = 164 (out->screenLayout&~ResTable_config::MASK_SCREENLONG) 165 | ResTable_config::SCREENLONG_NO; 166 return true; 167 } 168 169 return false; 170} 171 172static bool parseScreenRound(const char* name, ResTable_config* out) { 173 if (strcmp(name, kWildcardName) == 0) { 174 if (out) out->screenLayout2 = 175 (out->screenLayout2&~ResTable_config::MASK_SCREENROUND) 176 | ResTable_config::SCREENROUND_ANY; 177 return true; 178 } else if (strcmp(name, "round") == 0) { 179 if (out) out->screenLayout2 = 180 (out->screenLayout2&~ResTable_config::MASK_SCREENROUND) 181 | ResTable_config::SCREENROUND_YES; 182 return true; 183 } else if (strcmp(name, "notround") == 0) { 184 if (out) out->screenLayout2 = 185 (out->screenLayout2&~ResTable_config::MASK_SCREENROUND) 186 | ResTable_config::SCREENROUND_NO; 187 return true; 188 } 189 return false; 190} 191 192static bool parseOrientation(const char* name, ResTable_config* out) { 193 if (strcmp(name, kWildcardName) == 0) { 194 if (out) out->orientation = out->ORIENTATION_ANY; 195 return true; 196 } else if (strcmp(name, "port") == 0) { 197 if (out) out->orientation = out->ORIENTATION_PORT; 198 return true; 199 } else if (strcmp(name, "land") == 0) { 200 if (out) out->orientation = out->ORIENTATION_LAND; 201 return true; 202 } else if (strcmp(name, "square") == 0) { 203 if (out) out->orientation = out->ORIENTATION_SQUARE; 204 return true; 205 } 206 207 return false; 208} 209 210static bool parseUiModeType(const char* name, ResTable_config* out) { 211 if (strcmp(name, kWildcardName) == 0) { 212 if (out) out->uiMode = 213 (out->uiMode&~ResTable_config::MASK_UI_MODE_TYPE) 214 | ResTable_config::UI_MODE_TYPE_ANY; 215 return true; 216 } else if (strcmp(name, "desk") == 0) { 217 if (out) out->uiMode = 218 (out->uiMode&~ResTable_config::MASK_UI_MODE_TYPE) 219 | ResTable_config::UI_MODE_TYPE_DESK; 220 return true; 221 } else if (strcmp(name, "car") == 0) { 222 if (out) out->uiMode = 223 (out->uiMode&~ResTable_config::MASK_UI_MODE_TYPE) 224 | ResTable_config::UI_MODE_TYPE_CAR; 225 return true; 226 } else if (strcmp(name, "television") == 0) { 227 if (out) out->uiMode = 228 (out->uiMode&~ResTable_config::MASK_UI_MODE_TYPE) 229 | ResTable_config::UI_MODE_TYPE_TELEVISION; 230 return true; 231 } else if (strcmp(name, "appliance") == 0) { 232 if (out) out->uiMode = 233 (out->uiMode&~ResTable_config::MASK_UI_MODE_TYPE) 234 | ResTable_config::UI_MODE_TYPE_APPLIANCE; 235 return true; 236 } else if (strcmp(name, "watch") == 0) { 237 if (out) out->uiMode = 238 (out->uiMode&~ResTable_config::MASK_UI_MODE_TYPE) 239 | ResTable_config::UI_MODE_TYPE_WATCH; 240 return true; 241 } 242 243 return false; 244} 245 246static bool parseUiModeNight(const char* name, ResTable_config* out) { 247 if (strcmp(name, kWildcardName) == 0) { 248 if (out) out->uiMode = 249 (out->uiMode&~ResTable_config::MASK_UI_MODE_NIGHT) 250 | ResTable_config::UI_MODE_NIGHT_ANY; 251 return true; 252 } else if (strcmp(name, "night") == 0) { 253 if (out) out->uiMode = 254 (out->uiMode&~ResTable_config::MASK_UI_MODE_NIGHT) 255 | ResTable_config::UI_MODE_NIGHT_YES; 256 return true; 257 } else if (strcmp(name, "notnight") == 0) { 258 if (out) out->uiMode = 259 (out->uiMode&~ResTable_config::MASK_UI_MODE_NIGHT) 260 | ResTable_config::UI_MODE_NIGHT_NO; 261 return true; 262 } 263 264 return false; 265} 266 267static bool parseDensity(const char* name, ResTable_config* out) { 268 if (strcmp(name, kWildcardName) == 0) { 269 if (out) out->density = ResTable_config::DENSITY_DEFAULT; 270 return true; 271 } 272 273 if (strcmp(name, "anydpi") == 0) { 274 if (out) out->density = ResTable_config::DENSITY_ANY; 275 return true; 276 } 277 278 if (strcmp(name, "nodpi") == 0) { 279 if (out) out->density = ResTable_config::DENSITY_NONE; 280 return true; 281 } 282 283 if (strcmp(name, "ldpi") == 0) { 284 if (out) out->density = ResTable_config::DENSITY_LOW; 285 return true; 286 } 287 288 if (strcmp(name, "mdpi") == 0) { 289 if (out) out->density = ResTable_config::DENSITY_MEDIUM; 290 return true; 291 } 292 293 if (strcmp(name, "tvdpi") == 0) { 294 if (out) out->density = ResTable_config::DENSITY_TV; 295 return true; 296 } 297 298 if (strcmp(name, "hdpi") == 0) { 299 if (out) out->density = ResTable_config::DENSITY_HIGH; 300 return true; 301 } 302 303 if (strcmp(name, "xhdpi") == 0) { 304 if (out) out->density = ResTable_config::DENSITY_XHIGH; 305 return true; 306 } 307 308 if (strcmp(name, "xxhdpi") == 0) { 309 if (out) out->density = ResTable_config::DENSITY_XXHIGH; 310 return true; 311 } 312 313 if (strcmp(name, "xxxhdpi") == 0) { 314 if (out) out->density = ResTable_config::DENSITY_XXXHIGH; 315 return true; 316 } 317 318 char* c = (char*)name; 319 while (*c >= '0' && *c <= '9') { 320 c++; 321 } 322 323 // check that we have 'dpi' after the last digit. 324 if (toupper(c[0]) != 'D' || 325 toupper(c[1]) != 'P' || 326 toupper(c[2]) != 'I' || 327 c[3] != 0) { 328 return false; 329 } 330 331 // temporarily replace the first letter with \0 to 332 // use atoi. 333 char tmp = c[0]; 334 c[0] = '\0'; 335 336 int d = atoi(name); 337 c[0] = tmp; 338 339 if (d != 0) { 340 if (out) out->density = d; 341 return true; 342 } 343 344 return false; 345} 346 347static bool parseTouchscreen(const char* name, ResTable_config* out) { 348 if (strcmp(name, kWildcardName) == 0) { 349 if (out) out->touchscreen = out->TOUCHSCREEN_ANY; 350 return true; 351 } else if (strcmp(name, "notouch") == 0) { 352 if (out) out->touchscreen = out->TOUCHSCREEN_NOTOUCH; 353 return true; 354 } else if (strcmp(name, "stylus") == 0) { 355 if (out) out->touchscreen = out->TOUCHSCREEN_STYLUS; 356 return true; 357 } else if (strcmp(name, "finger") == 0) { 358 if (out) out->touchscreen = out->TOUCHSCREEN_FINGER; 359 return true; 360 } 361 362 return false; 363} 364 365static bool parseKeysHidden(const char* name, ResTable_config* out) { 366 uint8_t mask = 0; 367 uint8_t value = 0; 368 if (strcmp(name, kWildcardName) == 0) { 369 mask = ResTable_config::MASK_KEYSHIDDEN; 370 value = ResTable_config::KEYSHIDDEN_ANY; 371 } else if (strcmp(name, "keysexposed") == 0) { 372 mask = ResTable_config::MASK_KEYSHIDDEN; 373 value = ResTable_config::KEYSHIDDEN_NO; 374 } else if (strcmp(name, "keyshidden") == 0) { 375 mask = ResTable_config::MASK_KEYSHIDDEN; 376 value = ResTable_config::KEYSHIDDEN_YES; 377 } else if (strcmp(name, "keyssoft") == 0) { 378 mask = ResTable_config::MASK_KEYSHIDDEN; 379 value = ResTable_config::KEYSHIDDEN_SOFT; 380 } 381 382 if (mask != 0) { 383 if (out) out->inputFlags = (out->inputFlags&~mask) | value; 384 return true; 385 } 386 387 return false; 388} 389 390static bool parseKeyboard(const char* name, ResTable_config* out) { 391 if (strcmp(name, kWildcardName) == 0) { 392 if (out) out->keyboard = out->KEYBOARD_ANY; 393 return true; 394 } else if (strcmp(name, "nokeys") == 0) { 395 if (out) out->keyboard = out->KEYBOARD_NOKEYS; 396 return true; 397 } else if (strcmp(name, "qwerty") == 0) { 398 if (out) out->keyboard = out->KEYBOARD_QWERTY; 399 return true; 400 } else if (strcmp(name, "12key") == 0) { 401 if (out) out->keyboard = out->KEYBOARD_12KEY; 402 return true; 403 } 404 405 return false; 406} 407 408static bool parseNavHidden(const char* name, ResTable_config* out) { 409 uint8_t mask = 0; 410 uint8_t value = 0; 411 if (strcmp(name, kWildcardName) == 0) { 412 mask = ResTable_config::MASK_NAVHIDDEN; 413 value = ResTable_config::NAVHIDDEN_ANY; 414 } else if (strcmp(name, "navexposed") == 0) { 415 mask = ResTable_config::MASK_NAVHIDDEN; 416 value = ResTable_config::NAVHIDDEN_NO; 417 } else if (strcmp(name, "navhidden") == 0) { 418 mask = ResTable_config::MASK_NAVHIDDEN; 419 value = ResTable_config::NAVHIDDEN_YES; 420 } 421 422 if (mask != 0) { 423 if (out) out->inputFlags = (out->inputFlags&~mask) | value; 424 return true; 425 } 426 427 return false; 428} 429 430static bool parseNavigation(const char* name, ResTable_config* out) { 431 if (strcmp(name, kWildcardName) == 0) { 432 if (out) out->navigation = out->NAVIGATION_ANY; 433 return true; 434 } else if (strcmp(name, "nonav") == 0) { 435 if (out) out->navigation = out->NAVIGATION_NONAV; 436 return true; 437 } else if (strcmp(name, "dpad") == 0) { 438 if (out) out->navigation = out->NAVIGATION_DPAD; 439 return true; 440 } else if (strcmp(name, "trackball") == 0) { 441 if (out) out->navigation = out->NAVIGATION_TRACKBALL; 442 return true; 443 } else if (strcmp(name, "wheel") == 0) { 444 if (out) out->navigation = out->NAVIGATION_WHEEL; 445 return true; 446 } 447 448 return false; 449} 450 451static bool parseScreenSize(const char* name, ResTable_config* out) { 452 if (strcmp(name, kWildcardName) == 0) { 453 if (out) { 454 out->screenWidth = out->SCREENWIDTH_ANY; 455 out->screenHeight = out->SCREENHEIGHT_ANY; 456 } 457 return true; 458 } 459 460 const char* x = name; 461 while (*x >= '0' && *x <= '9') x++; 462 if (x == name || *x != 'x') return false; 463 std::string xName(name, x-name); 464 x++; 465 466 const char* y = x; 467 while (*y >= '0' && *y <= '9') y++; 468 if (y == name || *y != 0) return false; 469 std::string yName(x, y-x); 470 471 uint16_t w = (uint16_t)atoi(xName.c_str()); 472 uint16_t h = (uint16_t)atoi(yName.c_str()); 473 if (w < h) { 474 return false; 475 } 476 477 if (out) { 478 out->screenWidth = w; 479 out->screenHeight = h; 480 } 481 482 return true; 483} 484 485static bool parseSmallestScreenWidthDp(const char* name, ResTable_config* out) { 486 if (strcmp(name, kWildcardName) == 0) { 487 if (out) { 488 out->smallestScreenWidthDp = out->SCREENWIDTH_ANY; 489 } 490 return true; 491 } 492 493 if (*name != 's') return false; 494 name++; 495 if (*name != 'w') return false; 496 name++; 497 const char* x = name; 498 while (*x >= '0' && *x <= '9') x++; 499 if (x == name || x[0] != 'd' || x[1] != 'p' || x[2] != 0) return false; 500 std::string xName(name, x-name); 501 502 if (out) { 503 out->smallestScreenWidthDp = (uint16_t)atoi(xName.c_str()); 504 } 505 506 return true; 507} 508 509static bool parseScreenWidthDp(const char* name, ResTable_config* out) { 510 if (strcmp(name, kWildcardName) == 0) { 511 if (out) { 512 out->screenWidthDp = out->SCREENWIDTH_ANY; 513 } 514 return true; 515 } 516 517 if (*name != 'w') return false; 518 name++; 519 const char* x = name; 520 while (*x >= '0' && *x <= '9') x++; 521 if (x == name || x[0] != 'd' || x[1] != 'p' || x[2] != 0) return false; 522 std::string xName(name, x-name); 523 524 if (out) { 525 out->screenWidthDp = (uint16_t)atoi(xName.c_str()); 526 } 527 528 return true; 529} 530 531static bool parseScreenHeightDp(const char* name, ResTable_config* out) { 532 if (strcmp(name, kWildcardName) == 0) { 533 if (out) { 534 out->screenHeightDp = out->SCREENWIDTH_ANY; 535 } 536 return true; 537 } 538 539 if (*name != 'h') return false; 540 name++; 541 const char* x = name; 542 while (*x >= '0' && *x <= '9') x++; 543 if (x == name || x[0] != 'd' || x[1] != 'p' || x[2] != 0) return false; 544 std::string xName(name, x-name); 545 546 if (out) { 547 out->screenHeightDp = (uint16_t)atoi(xName.c_str()); 548 } 549 550 return true; 551} 552 553static bool parseVersion(const char* name, ResTable_config* out) { 554 if (strcmp(name, kWildcardName) == 0) { 555 if (out) { 556 out->sdkVersion = out->SDKVERSION_ANY; 557 out->minorVersion = out->MINORVERSION_ANY; 558 } 559 return true; 560 } 561 562 if (*name != 'v') { 563 return false; 564 } 565 566 name++; 567 const char* s = name; 568 while (*s >= '0' && *s <= '9') s++; 569 if (s == name || *s != 0) return false; 570 std::string sdkName(name, s-name); 571 572 if (out) { 573 out->sdkVersion = (uint16_t)atoi(sdkName.c_str()); 574 out->minorVersion = 0; 575 } 576 577 return true; 578} 579 580bool ConfigDescription::parse(const StringPiece& str, ConfigDescription* out) { 581 std::vector<std::string> parts = util::splitAndLowercase(str, '-'); 582 583 ConfigDescription config; 584 ssize_t partsConsumed = 0; 585 LocaleValue locale; 586 587 const auto partsEnd = parts.end(); 588 auto partIter = parts.begin(); 589 590 if (str.size() == 0) { 591 goto success; 592 } 593 594 if (parseMcc(partIter->c_str(), &config)) { 595 ++partIter; 596 if (partIter == partsEnd) { 597 goto success; 598 } 599 } 600 601 if (parseMnc(partIter->c_str(), &config)) { 602 ++partIter; 603 if (partIter == partsEnd) { 604 goto success; 605 } 606 } 607 608 // Locale spans a few '-' separators, so we let it 609 // control the index. 610 partsConsumed = locale.initFromParts(partIter, partsEnd); 611 if (partsConsumed < 0) { 612 return false; 613 } else { 614 locale.writeTo(&config); 615 partIter += partsConsumed; 616 if (partIter == partsEnd) { 617 goto success; 618 } 619 } 620 621 if (parseLayoutDirection(partIter->c_str(), &config)) { 622 ++partIter; 623 if (partIter == partsEnd) { 624 goto success; 625 } 626 } 627 628 if (parseSmallestScreenWidthDp(partIter->c_str(), &config)) { 629 ++partIter; 630 if (partIter == partsEnd) { 631 goto success; 632 } 633 } 634 635 if (parseScreenWidthDp(partIter->c_str(), &config)) { 636 ++partIter; 637 if (partIter == partsEnd) { 638 goto success; 639 } 640 } 641 642 if (parseScreenHeightDp(partIter->c_str(), &config)) { 643 ++partIter; 644 if (partIter == partsEnd) { 645 goto success; 646 } 647 } 648 649 if (parseScreenLayoutSize(partIter->c_str(), &config)) { 650 ++partIter; 651 if (partIter == partsEnd) { 652 goto success; 653 } 654 } 655 656 if (parseScreenLayoutLong(partIter->c_str(), &config)) { 657 ++partIter; 658 if (partIter == partsEnd) { 659 goto success; 660 } 661 } 662 663 if (parseScreenRound(partIter->c_str(), &config)) { 664 ++partIter; 665 if (partIter == partsEnd) { 666 goto success; 667 } 668 } 669 670 if (parseOrientation(partIter->c_str(), &config)) { 671 ++partIter; 672 if (partIter == partsEnd) { 673 goto success; 674 } 675 } 676 677 if (parseUiModeType(partIter->c_str(), &config)) { 678 ++partIter; 679 if (partIter == partsEnd) { 680 goto success; 681 } 682 } 683 684 if (parseUiModeNight(partIter->c_str(), &config)) { 685 ++partIter; 686 if (partIter == partsEnd) { 687 goto success; 688 } 689 } 690 691 if (parseDensity(partIter->c_str(), &config)) { 692 ++partIter; 693 if (partIter == partsEnd) { 694 goto success; 695 } 696 } 697 698 if (parseTouchscreen(partIter->c_str(), &config)) { 699 ++partIter; 700 if (partIter == partsEnd) { 701 goto success; 702 } 703 } 704 705 if (parseKeysHidden(partIter->c_str(), &config)) { 706 ++partIter; 707 if (partIter == partsEnd) { 708 goto success; 709 } 710 } 711 712 if (parseKeyboard(partIter->c_str(), &config)) { 713 ++partIter; 714 if (partIter == partsEnd) { 715 goto success; 716 } 717 } 718 719 if (parseNavHidden(partIter->c_str(), &config)) { 720 ++partIter; 721 if (partIter == partsEnd) { 722 goto success; 723 } 724 } 725 726 if (parseNavigation(partIter->c_str(), &config)) { 727 ++partIter; 728 if (partIter == partsEnd) { 729 goto success; 730 } 731 } 732 733 if (parseScreenSize(partIter->c_str(), &config)) { 734 ++partIter; 735 if (partIter == partsEnd) { 736 goto success; 737 } 738 } 739 740 if (parseVersion(partIter->c_str(), &config)) { 741 ++partIter; 742 if (partIter == partsEnd) { 743 goto success; 744 } 745 } 746 747 // Unrecognized. 748 return false; 749 750success: 751 if (out != NULL) { 752 applyVersionForCompatibility(&config); 753 *out = config; 754 } 755 return true; 756} 757 758void ConfigDescription::applyVersionForCompatibility(ConfigDescription* config) { 759 uint16_t minSdk = 0; 760 if (config->screenLayout2 & ResTable_config::MASK_SCREENROUND) { 761 minSdk = SDK_MARSHMALLOW; 762 } else if (config->density == ResTable_config::DENSITY_ANY) { 763 minSdk = SDK_LOLLIPOP; 764 } else if (config->smallestScreenWidthDp != ResTable_config::SCREENWIDTH_ANY 765 || config->screenWidthDp != ResTable_config::SCREENWIDTH_ANY 766 || config->screenHeightDp != ResTable_config::SCREENHEIGHT_ANY) { 767 minSdk = SDK_HONEYCOMB_MR2; 768 } else if ((config->uiMode & ResTable_config::MASK_UI_MODE_TYPE) 769 != ResTable_config::UI_MODE_TYPE_ANY 770 || (config->uiMode & ResTable_config::MASK_UI_MODE_NIGHT) 771 != ResTable_config::UI_MODE_NIGHT_ANY) { 772 minSdk = SDK_FROYO; 773 } else if ((config->screenLayout & ResTable_config::MASK_SCREENSIZE) 774 != ResTable_config::SCREENSIZE_ANY 775 || (config->screenLayout & ResTable_config::MASK_SCREENLONG) 776 != ResTable_config::SCREENLONG_ANY 777 || config->density != ResTable_config::DENSITY_DEFAULT) { 778 minSdk = SDK_DONUT; 779 } 780 781 if (minSdk > config->sdkVersion) { 782 config->sdkVersion = minSdk; 783 } 784} 785 786} // namespace aapt 787