X-Git-Url: https://git.saurik.com/android/aapt.git/blobdiff_plain/12ab65f6432a84bd6a3ba3232471c9fcd50e0ba9..6e5d020e2e2975ebe0ebad5caf8047acfca8b6c4:/AaptAssets.cpp diff --git a/AaptAssets.cpp b/AaptAssets.cpp index c346b90..7900ab7 100644 --- a/AaptAssets.cpp +++ b/AaptAssets.cpp @@ -3,6 +3,7 @@ // #include "AaptAssets.h" +#include "ResourceFilter.h" #include "Main.h" #include @@ -16,6 +17,8 @@ static const char* kDefaultLocale = "default"; static const char* kWildcardName = "any"; static const char* kAssetDir = "assets"; static const char* kResourceDir = "res"; +static const char* kValuesDir = "values"; +static const char* kMipmapDir = "mipmap"; static const char* kInvalidChars = "/\\:"; static const size_t kMaxAssetFileName = 100; @@ -142,6 +145,27 @@ AaptGroupEntry::parseNamePart(const String8& part, int* axis, uint32_t* value) return 0; } + // smallest screen dp width + if (getSmallestScreenWidthDpName(part.string(), &config)) { + *axis = AXIS_SMALLESTSCREENWIDTHDP; + *value = config.smallestScreenWidthDp; + return 0; + } + + // screen dp width + if (getScreenWidthDpName(part.string(), &config)) { + *axis = AXIS_SCREENWIDTHDP; + *value = config.screenWidthDp; + return 0; + } + + // screen dp height + if (getScreenHeightDpName(part.string(), &config)) { + *axis = AXIS_SCREENHEIGHTDP; + *value = config.screenHeightDp; + return 0; + } + // screen layout size if (getScreenLayoutSizeName(part.string(), &config)) { *axis = AXIS_SCREENLAYOUTSIZE; @@ -163,6 +187,20 @@ AaptGroupEntry::parseNamePart(const String8& part, int* axis, uint32_t* value) return 0; } + // ui mode type + if (getUiModeTypeName(part.string(), &config)) { + *axis = AXIS_UIMODETYPE; + *value = (config.uiMode&ResTable_config::MASK_UI_MODE_TYPE); + return 0; + } + + // ui mode night + if (getUiModeNightName(part.string(), &config)) { + *axis = AXIS_UIMODENIGHT; + *value = (config.uiMode&ResTable_config::MASK_UI_MODE_NIGHT); + return 0; + } + // density if (getDensityName(part.string(), &config)) { *axis = AXIS_DENSITY; @@ -222,13 +260,74 @@ AaptGroupEntry::parseNamePart(const String8& part, int* axis, uint32_t* value) return 1; } +uint32_t +AaptGroupEntry::getConfigValueForAxis(const ResTable_config& config, int axis) +{ + switch (axis) { + case AXIS_MCC: + return config.mcc; + case AXIS_MNC: + return config.mnc; + case AXIS_LANGUAGE: + return (((uint32_t)config.country[1]) << 24) | (((uint32_t)config.country[0]) << 16) + | (((uint32_t)config.language[1]) << 8) | (config.language[0]); + case AXIS_SCREENLAYOUTSIZE: + return config.screenLayout&ResTable_config::MASK_SCREENSIZE; + case AXIS_ORIENTATION: + return config.orientation; + case AXIS_UIMODETYPE: + return (config.uiMode&ResTable_config::MASK_UI_MODE_TYPE); + case AXIS_UIMODENIGHT: + return (config.uiMode&ResTable_config::MASK_UI_MODE_NIGHT); + case AXIS_DENSITY: + return config.density; + case AXIS_TOUCHSCREEN: + return config.touchscreen; + case AXIS_KEYSHIDDEN: + return config.inputFlags; + case AXIS_KEYBOARD: + return config.keyboard; + case AXIS_NAVIGATION: + return config.navigation; + case AXIS_SCREENSIZE: + return config.screenSize; + case AXIS_SMALLESTSCREENWIDTHDP: + return config.smallestScreenWidthDp; + case AXIS_SCREENWIDTHDP: + return config.screenWidthDp; + case AXIS_SCREENHEIGHTDP: + return config.screenHeightDp; + case AXIS_VERSION: + return config.version; + } + return 0; +} + +bool +AaptGroupEntry::configSameExcept(const ResTable_config& config, + const ResTable_config& otherConfig, int axis) +{ + for (int i=AXIS_START; i<=AXIS_END; i++) { + if (i == axis) { + continue; + } + if (getConfigValueForAxis(config, i) != getConfigValueForAxis(otherConfig, i)) { + return false; + } + } + return true; +} + bool AaptGroupEntry::initFromDirName(const char* dir, String8* resType) { + mParamsChanged = true; + Vector parts; String8 mcc, mnc, loc, layoutsize, layoutlong, orient, den; String8 touch, key, keysHidden, nav, navHidden, size, vers; + String8 uiModeType, uiModeNight, smallestwidthdp, widthdp, heightdp; const char *p = dir; const char *q; @@ -315,6 +414,42 @@ AaptGroupEntry::initFromDirName(const char* dir, String8* resType) //printf("not region: %s\n", part.string()); } + if (getSmallestScreenWidthDpName(part.string())) { + smallestwidthdp = part; + + index++; + if (index == N) { + goto success; + } + part = parts[index]; + } else { + //printf("not smallest screen width dp: %s\n", part.string()); + } + + if (getScreenWidthDpName(part.string())) { + widthdp = part; + + index++; + if (index == N) { + goto success; + } + part = parts[index]; + } else { + //printf("not screen width dp: %s\n", part.string()); + } + + if (getScreenHeightDpName(part.string())) { + heightdp = part; + + index++; + if (index == N) { + goto success; + } + part = parts[index]; + } else { + //printf("not screen height dp: %s\n", part.string()); + } + if (getScreenLayoutSizeName(part.string())) { layoutsize = part; @@ -352,6 +487,32 @@ AaptGroupEntry::initFromDirName(const char* dir, String8* resType) //printf("not orientation: %s\n", part.string()); } + // ui mode type + if (getUiModeTypeName(part.string())) { + uiModeType = part; + + index++; + if (index == N) { + goto success; + } + part = parts[index]; + } else { + //printf("not ui mode type: %s\n", part.string()); + } + + // ui mode night + if (getUiModeNightName(part.string())) { + uiModeNight = part; + + index++; + if (index == N) { + goto success; + } + part = parts[index]; + } else { + //printf("not ui mode night: %s\n", part.string()); + } + // density if (getDensityName(part.string())) { den = part; @@ -462,7 +623,12 @@ success: this->locale = loc; this->screenLayoutSize = layoutsize; this->screenLayoutLong = layoutlong; + this->smallestScreenWidthDp = smallestwidthdp; + this->screenWidthDp = widthdp; + this->screenHeightDp = heightdp; this->orientation = orient; + this->uiModeType = uiModeType; + this->uiModeNight = uiModeNight; this->density = den; this->touchscreen = touch; this->keysHidden = keysHidden; @@ -487,12 +653,22 @@ AaptGroupEntry::toString() const s += ","; s += this->locale; s += ","; + s += smallestScreenWidthDp; + s += ","; + s += screenWidthDp; + s += ","; + s += screenHeightDp; + s += ","; s += screenLayoutSize; s += ","; s += screenLayoutLong; s += ","; s += this->orientation; s += ","; + s += uiModeType; + s += ","; + s += uiModeNight; + s += ","; s += density; s += ","; s += touchscreen; @@ -516,59 +692,117 @@ AaptGroupEntry::toDirName(const String8& resType) const { String8 s = resType; if (this->mcc != "") { - s += "-"; + if (s.length() > 0) { + s += "-"; + } s += mcc; } if (this->mnc != "") { - s += "-"; + if (s.length() > 0) { + s += "-"; + } s += mnc; } if (this->locale != "") { - s += "-"; + if (s.length() > 0) { + s += "-"; + } s += locale; } + if (this->smallestScreenWidthDp != "") { + if (s.length() > 0) { + s += "-"; + } + s += smallestScreenWidthDp; + } + if (this->screenWidthDp != "") { + if (s.length() > 0) { + s += "-"; + } + s += screenWidthDp; + } + if (this->screenHeightDp != "") { + if (s.length() > 0) { + s += "-"; + } + s += screenHeightDp; + } if (this->screenLayoutSize != "") { - s += "-"; + if (s.length() > 0) { + s += "-"; + } s += screenLayoutSize; } if (this->screenLayoutLong != "") { - s += "-"; + if (s.length() > 0) { + s += "-"; + } s += screenLayoutLong; } if (this->orientation != "") { - s += "-"; + if (s.length() > 0) { + s += "-"; + } s += orientation; } + if (this->uiModeType != "") { + if (s.length() > 0) { + s += "-"; + } + s += uiModeType; + } + if (this->uiModeNight != "") { + if (s.length() > 0) { + s += "-"; + } + s += uiModeNight; + } if (this->density != "") { - s += "-"; + if (s.length() > 0) { + s += "-"; + } s += density; } if (this->touchscreen != "") { - s += "-"; + if (s.length() > 0) { + s += "-"; + } s += touchscreen; } if (this->keysHidden != "") { - s += "-"; + if (s.length() > 0) { + s += "-"; + } s += keysHidden; } if (this->keyboard != "") { - s += "-"; + if (s.length() > 0) { + s += "-"; + } s += keyboard; } if (this->navHidden != "") { - s += "-"; + if (s.length() > 0) { + s += "-"; + } s += navHidden; } if (this->navigation != "") { - s += "-"; + if (s.length() > 0) { + s += "-"; + } s += navigation; } if (this->screenSize != "") { - s += "-"; + if (s.length() > 0) { + s += "-"; + } s += screenSize; } if (this->version != "") { - s += "-"; + if (s.length() > 0) { + s += "-"; + } s += version; } @@ -630,13 +864,11 @@ bool AaptGroupEntry::getMncName(const char* name, if (*c != 0) return false; if (c-val == 0 || c-val > 3) return false; - int d = atoi(val); - if (d != 0) { - if (out) out->mnc = d; - return true; + if (out) { + out->mnc = atoi(val); } - return false; + return true; } /* @@ -711,6 +943,11 @@ bool AaptGroupEntry::getScreenLayoutSizeName(const char* name, (out->screenLayout&~ResTable_config::MASK_SCREENSIZE) | ResTable_config::SCREENSIZE_LARGE; return true; + } else if (strcmp(name, "xlarge") == 0) { + if (out) out->screenLayout = + (out->screenLayout&~ResTable_config::MASK_SCREENSIZE) + | ResTable_config::SCREENSIZE_XLARGE; + return true; } return false; @@ -759,6 +996,57 @@ bool AaptGroupEntry::getOrientationName(const char* name, return false; } +bool AaptGroupEntry::getUiModeTypeName(const char* name, + ResTable_config* out) +{ + if (strcmp(name, kWildcardName) == 0) { + if (out) out->uiMode = + (out->uiMode&~ResTable_config::MASK_UI_MODE_TYPE) + | ResTable_config::UI_MODE_TYPE_ANY; + return true; + } else if (strcmp(name, "desk") == 0) { + if (out) out->uiMode = + (out->uiMode&~ResTable_config::MASK_UI_MODE_TYPE) + | ResTable_config::UI_MODE_TYPE_DESK; + return true; + } else if (strcmp(name, "car") == 0) { + if (out) out->uiMode = + (out->uiMode&~ResTable_config::MASK_UI_MODE_TYPE) + | ResTable_config::UI_MODE_TYPE_CAR; + return true; + } else if (strcmp(name, "television") == 0) { + if (out) out->uiMode = + (out->uiMode&~ResTable_config::MASK_UI_MODE_TYPE) + | ResTable_config::UI_MODE_TYPE_TELEVISION; + return true; + } + + return false; +} + +bool AaptGroupEntry::getUiModeNightName(const char* name, + ResTable_config* out) +{ + if (strcmp(name, kWildcardName) == 0) { + if (out) out->uiMode = + (out->uiMode&~ResTable_config::MASK_UI_MODE_NIGHT) + | ResTable_config::UI_MODE_NIGHT_ANY; + return true; + } else if (strcmp(name, "night") == 0) { + if (out) out->uiMode = + (out->uiMode&~ResTable_config::MASK_UI_MODE_NIGHT) + | ResTable_config::UI_MODE_NIGHT_YES; + return true; + } else if (strcmp(name, "notnight") == 0) { + if (out) out->uiMode = + (out->uiMode&~ResTable_config::MASK_UI_MODE_NIGHT) + | ResTable_config::UI_MODE_NIGHT_NO; + return true; + } + + return false; +} + bool AaptGroupEntry::getDensityName(const char* name, ResTable_config* out) { @@ -782,11 +1070,26 @@ bool AaptGroupEntry::getDensityName(const char* name, return true; } + if (strcmp(name, "tvdpi") == 0) { + if (out) out->density = ResTable_config::DENSITY_TV; + return true; + } + if (strcmp(name, "hdpi") == 0) { if (out) out->density = ResTable_config::DENSITY_HIGH; return true; } - + + if (strcmp(name, "xhdpi") == 0) { + if (out) out->density = ResTable_config::DENSITY_XHIGH; + return true; + } + + if (strcmp(name, "xxhdpi") == 0) { + if (out) out->density = ResTable_config::DENSITY_XXHIGH; + return true; + } + char* c = (char*)name; while (*c >= '0' && *c <= '9') { c++; @@ -842,17 +1145,17 @@ bool AaptGroupEntry::getKeysHiddenName(const char* name, uint8_t mask = 0; uint8_t value = 0; if (strcmp(name, kWildcardName) == 0) { - mask = out->MASK_KEYSHIDDEN; - value = out->KEYSHIDDEN_ANY; + mask = ResTable_config::MASK_KEYSHIDDEN; + value = ResTable_config::KEYSHIDDEN_ANY; } else if (strcmp(name, "keysexposed") == 0) { - mask = out->MASK_KEYSHIDDEN; - value = out->KEYSHIDDEN_NO; + mask = ResTable_config::MASK_KEYSHIDDEN; + value = ResTable_config::KEYSHIDDEN_NO; } else if (strcmp(name, "keyshidden") == 0) { - mask = out->MASK_KEYSHIDDEN; - value = out->KEYSHIDDEN_YES; + mask = ResTable_config::MASK_KEYSHIDDEN; + value = ResTable_config::KEYSHIDDEN_YES; } else if (strcmp(name, "keyssoft") == 0) { - mask = out->MASK_KEYSHIDDEN; - value = out->KEYSHIDDEN_SOFT; + mask = ResTable_config::MASK_KEYSHIDDEN; + value = ResTable_config::KEYSHIDDEN_SOFT; } if (mask != 0) { @@ -889,14 +1192,14 @@ bool AaptGroupEntry::getNavHiddenName(const char* name, uint8_t mask = 0; uint8_t value = 0; if (strcmp(name, kWildcardName) == 0) { - mask = out->MASK_NAVHIDDEN; - value = out->NAVHIDDEN_ANY; + mask = ResTable_config::MASK_NAVHIDDEN; + value = ResTable_config::NAVHIDDEN_ANY; } else if (strcmp(name, "navexposed") == 0) { - mask = out->MASK_NAVHIDDEN; - value = out->NAVHIDDEN_NO; + mask = ResTable_config::MASK_NAVHIDDEN; + value = ResTable_config::NAVHIDDEN_NO; } else if (strcmp(name, "navhidden") == 0) { - mask = out->MASK_NAVHIDDEN; - value = out->NAVHIDDEN_YES; + mask = ResTable_config::MASK_NAVHIDDEN; + value = ResTable_config::NAVHIDDEN_YES; } if (mask != 0) { @@ -930,8 +1233,7 @@ bool AaptGroupEntry::getNavigationName(const char* name, return false; } -bool AaptGroupEntry::getScreenSizeName(const char* name, - ResTable_config* out) +bool AaptGroupEntry::getScreenSizeName(const char* name, ResTable_config* out) { if (strcmp(name, kWildcardName) == 0) { if (out) { @@ -966,8 +1268,78 @@ bool AaptGroupEntry::getScreenSizeName(const char* name, return true; } -bool AaptGroupEntry::getVersionName(const char* name, - ResTable_config* out) +bool AaptGroupEntry::getSmallestScreenWidthDpName(const char* name, ResTable_config* out) +{ + if (strcmp(name, kWildcardName) == 0) { + if (out) { + out->smallestScreenWidthDp = out->SCREENWIDTH_ANY; + } + return true; + } + + if (*name != 's') return false; + name++; + if (*name != 'w') return false; + name++; + const char* x = name; + while (*x >= '0' && *x <= '9') x++; + if (x == name || x[0] != 'd' || x[1] != 'p' || x[2] != 0) return false; + String8 xName(name, x-name); + + if (out) { + out->smallestScreenWidthDp = (uint16_t)atoi(xName.string()); + } + + return true; +} + +bool AaptGroupEntry::getScreenWidthDpName(const char* name, ResTable_config* out) +{ + if (strcmp(name, kWildcardName) == 0) { + if (out) { + out->screenWidthDp = out->SCREENWIDTH_ANY; + } + return true; + } + + if (*name != 'w') return false; + name++; + const char* x = name; + while (*x >= '0' && *x <= '9') x++; + if (x == name || x[0] != 'd' || x[1] != 'p' || x[2] != 0) return false; + String8 xName(name, x-name); + + if (out) { + out->screenWidthDp = (uint16_t)atoi(xName.string()); + } + + return true; +} + +bool AaptGroupEntry::getScreenHeightDpName(const char* name, ResTable_config* out) +{ + if (strcmp(name, kWildcardName) == 0) { + if (out) { + out->screenHeightDp = out->SCREENWIDTH_ANY; + } + return true; + } + + if (*name != 'h') return false; + name++; + const char* x = name; + while (*x >= '0' && *x <= '9') x++; + if (x == name || x[0] != 'd' || x[1] != 'p' || x[2] != 0) return false; + String8 xName(name, x-name); + + if (out) { + out->screenHeightDp = (uint16_t)atoi(xName.string()); + } + + return true; +} + +bool AaptGroupEntry::getVersionName(const char* name, ResTable_config* out) { if (strcmp(name, kWildcardName) == 0) { if (out) { @@ -1001,9 +1373,14 @@ int AaptGroupEntry::compare(const AaptGroupEntry& o) const if (v == 0) v = mnc.compare(o.mnc); if (v == 0) v = locale.compare(o.locale); if (v == 0) v = vendor.compare(o.vendor); + if (v == 0) v = smallestScreenWidthDp.compare(o.smallestScreenWidthDp); + if (v == 0) v = screenWidthDp.compare(o.screenWidthDp); + if (v == 0) v = screenHeightDp.compare(o.screenHeightDp); if (v == 0) v = screenLayoutSize.compare(o.screenLayoutSize); if (v == 0) v = screenLayoutLong.compare(o.screenLayoutLong); if (v == 0) v = orientation.compare(o.orientation); + if (v == 0) v = uiModeType.compare(o.uiModeType); + if (v == 0) v = uiModeNight.compare(o.uiModeNight); if (v == 0) v = density.compare(o.density); if (v == 0) v = touchscreen.compare(o.touchscreen); if (v == 0) v = keysHidden.compare(o.keysHidden); @@ -1015,16 +1392,26 @@ int AaptGroupEntry::compare(const AaptGroupEntry& o) const return v; } -ResTable_config AaptGroupEntry::toParams() const +const ResTable_config& AaptGroupEntry::toParams() const { - ResTable_config params; + if (!mParamsChanged) { + return mParams; + } + + mParamsChanged = false; + ResTable_config& params(mParams); memset(¶ms, 0, sizeof(params)); getMccName(mcc.string(), ¶ms); getMncName(mnc.string(), ¶ms); getLocaleName(locale.string(), ¶ms); + getSmallestScreenWidthDpName(smallestScreenWidthDp.string(), ¶ms); + getScreenWidthDpName(screenWidthDp.string(), ¶ms); + getScreenHeightDpName(screenHeightDp.string(), ¶ms); getScreenLayoutSizeName(screenLayoutSize.string(), ¶ms); getScreenLayoutLongName(screenLayoutLong.string(), ¶ms); getOrientationName(orientation.string(), ¶ms); + getUiModeTypeName(uiModeType.string(), ¶ms); + getUiModeNightName(uiModeNight.string(), ¶ms); getDensityName(density.string(), ¶ms); getTouchscreenName(touchscreen.string(), ¶ms); getKeysHiddenName(keysHidden.string(), ¶ms); @@ -1033,6 +1420,30 @@ ResTable_config AaptGroupEntry::toParams() const getNavigationName(navigation.string(), ¶ms); getScreenSizeName(screenSize.string(), ¶ms); getVersionName(version.string(), ¶ms); + + // Fix up version number based on specified parameters. + int minSdk = 0; + if (params.smallestScreenWidthDp != ResTable_config::SCREENWIDTH_ANY + || params.screenWidthDp != ResTable_config::SCREENWIDTH_ANY + || params.screenHeightDp != ResTable_config::SCREENHEIGHT_ANY) { + minSdk = SDK_HONEYCOMB_MR2; + } else if ((params.uiMode&ResTable_config::MASK_UI_MODE_TYPE) + != ResTable_config::UI_MODE_TYPE_ANY + || (params.uiMode&ResTable_config::MASK_UI_MODE_NIGHT) + != ResTable_config::UI_MODE_NIGHT_ANY) { + minSdk = SDK_FROYO; + } else if ((params.screenLayout&ResTable_config::MASK_SCREENSIZE) + != ResTable_config::SCREENSIZE_ANY + || (params.screenLayout&ResTable_config::MASK_SCREENLONG) + != ResTable_config::SCREENLONG_ANY + || params.density != ResTable_config::DENSITY_DEFAULT) { + minSdk = SDK_DONUT; + } + + if (minSdk > params.sdkVersion) { + params.sdkVersion = minSdk; + } + return params; } @@ -1103,8 +1514,7 @@ void AaptFile::clearData() String8 AaptFile::getPrintableSource() const { if (hasData()) { - String8 name(mGroupEntry.locale.string()); - name.appendPath(mGroupEntry.vendor.string()); + String8 name(mGroupEntry.toDirName(String8())); name.appendPath(mPath); name.append(" #generated"); return name; @@ -1124,6 +1534,13 @@ status_t AaptGroup::addFile(const sp& file) return NO_ERROR; } +#if 0 + printf("Error adding file %s: group %s already exists in leaf=%s path=%s\n", + file->getSourceFile().string(), + file->getGroupEntry().toDirName(String8()).string(), + mLeaf.string(), mPath.string()); +#endif + SourcePos(file->getSourceFile(), -1).error("Duplicate file.\n%s: Original is here.", getPrintableSource().string()); return UNKNOWN_ERROR; @@ -1134,20 +1551,23 @@ void AaptGroup::removeFile(size_t index) mFiles.removeItemsAt(index); } -void AaptGroup::print() const +void AaptGroup::print(const String8& prefix) const { - printf(" %s\n", getPath().string()); + printf("%s%s\n", prefix.string(), getPath().string()); const size_t N=mFiles.size(); size_t i; for (i=0; i file = mFiles.valueAt(i); const AaptGroupEntry& e = file->getGroupEntry(); if (file->hasData()) { - printf(" Gen: (%s) %d bytes\n", e.toString().string(), + printf("%s Gen: (%s) %d bytes\n", prefix.string(), e.toDirName(String8()).string(), (int)file->getSize()); } else { - printf(" Src: %s\n", file->getPrintableSource().string()); + printf("%s Src: (%s) %s\n", prefix.string(), e.toDirName(String8()).string(), + file->getPrintableSource().string()); } + //printf("%s File Group Entry: %s\n", prefix.string(), + // file->getGroupEntry().toDirName(String8()).string()); } } @@ -1214,38 +1634,6 @@ void AaptDir::removeDir(const String8& name) mDirs.removeItem(name); } -status_t AaptDir::renameFile(const sp& file, const String8& newName) -{ - sp origGroup; - - // Find and remove the given file with shear, brute force! - const size_t NG = mFiles.size(); - size_t i; - for (i=0; origGroup == NULL && i g = mFiles.valueAt(i); - const size_t NF = g->getFiles().size(); - for (size_t j=0; jgetFiles().valueAt(j) == file) { - origGroup = g; - g->removeFile(j); - if (NF == 1) { - mFiles.removeItemsAt(i); - } - break; - } - } - } - - //printf("Renaming %s to %s\n", file->getPath().getPathName(), newName.string()); - - // Place the file under its new name. - if (origGroup != NULL) { - return addLeafFile(newName, file); - } - - return NO_ERROR; -} - status_t AaptDir::addLeafFile(const String8& leafName, const sp& file) { sp group; @@ -1260,10 +1648,10 @@ status_t AaptDir::addLeafFile(const String8& leafName, const sp& file) } ssize_t AaptDir::slurpFullTree(Bundle* bundle, const String8& srcDir, - const AaptGroupEntry& kind, const String8& resType) + const AaptGroupEntry& kind, const String8& resType, + sp& fullResPaths) { Vector fileNames; - { DIR* dir = NULL; @@ -1286,9 +1674,14 @@ ssize_t AaptDir::slurpFullTree(Bundle* bundle, const String8& srcDir, if (isHidden(srcDir.string(), entry->d_name)) continue; - fileNames.add(String8(entry->d_name)); + String8 name(entry->d_name); + fileNames.add(name); + // Add fully qualified path for dependency purposes + // if we're collecting them + if (fullResPaths != NULL) { + fullResPaths->add(srcDir.appendPathCopy(name)); + } } - closedir(dir); } @@ -1315,7 +1708,7 @@ ssize_t AaptDir::slurpFullTree(Bundle* bundle, const String8& srcDir, notAdded = true; } ssize_t res = subdir->slurpFullTree(bundle, pathName, kind, - resType); + resType, fullResPaths); if (res < NO_ERROR) { return res; } @@ -1405,17 +1798,17 @@ status_t AaptDir::validate() const return NO_ERROR; } -void AaptDir::print() const +void AaptDir::print(const String8& prefix) const { const size_t ND=getDirs().size(); size_t i; for (i=0; iprint(); + getDirs().valueAt(i)->print(prefix); } const size_t NF=getFiles().size(); for (i=0; iprint(); + getFiles().valueAt(i)->print(prefix); } } @@ -1439,6 +1832,24 @@ String8 AaptDir::getPrintableSource() const // ========================================================================= // ========================================================================= +AaptAssets::AaptAssets() + : AaptDir(String8(), String8()), + mChanged(false), mHaveIncludedAssets(false), mRes(NULL) +{ +} + +const SortedVector& AaptAssets::getGroupEntries() const { + if (mChanged) { + } + return mGroupEntries; +} + +status_t AaptAssets::addFile(const String8& name, const sp& file) +{ + mChanged = true; + return AaptDir::addFile(name, file); +} + sp AaptAssets::addFile( const String8& filePath, const AaptGroupEntry& entry, const String8& srcDir, sp* outGroup, @@ -1547,7 +1958,7 @@ ssize_t AaptAssets::slurpFromArgs(Bundle* bundle) sp assetAaptDir = makeDir(String8(kAssetDir)); AaptGroupEntry group; count = assetAaptDir->slurpFullTree(bundle, assetRoot, group, - String8()); + String8(), mFullAssetPaths); if (count < 0) { totalCount = count; goto bail; @@ -1578,6 +1989,7 @@ ssize_t AaptAssets::slurpFromArgs(Bundle* bundle) sp nextOverlay = new AaptAssets(); current->setOverlay(nextOverlay); current = nextOverlay; + current->setFullResPaths(mFullResPaths); } count = current->slurpResourceTree(bundle, String8(res)); @@ -1620,7 +2032,7 @@ ssize_t AaptAssets::slurpFromArgs(Bundle* bundle) * guarantees about ordering, so we're okay with an inorder search * using whatever order the OS happens to hand back to us. */ - count = slurpFullTree(bundle, assetRoot, AaptGroupEntry(), String8()); + count = slurpFullTree(bundle, assetRoot, AaptGroupEntry(), String8(), mFullAssetPaths); if (count < 0) { /* failure; report error and remove archive */ totalCount = count; @@ -1639,6 +2051,11 @@ ssize_t AaptAssets::slurpFromArgs(Bundle* bundle) goto bail; } + count = filter(bundle); + if (count != NO_ERROR) { + totalCount = count; + goto bail; + } bail: return totalCount; @@ -1646,9 +2063,10 @@ bail: ssize_t AaptAssets::slurpFullTree(Bundle* bundle, const String8& srcDir, const AaptGroupEntry& kind, - const String8& resType) + const String8& resType, + sp& fullResPaths) { - ssize_t res = AaptDir::slurpFullTree(bundle, srcDir, kind, resType); + ssize_t res = AaptDir::slurpFullTree(bundle, srcDir, kind, resType, fullResPaths); if (res > 0) { mGroupEntries.add(kind); } @@ -1695,12 +2113,22 @@ ssize_t AaptAssets::slurpResourceTree(Bundle* bundle, const String8& srcDir) continue; } + if (bundle->getMaxResVersion() != NULL && group.getVersionString().length() != 0) { + int maxResInt = atoi(bundle->getMaxResVersion()); + const char *verString = group.getVersionString().string(); + int dirVersionInt = atoi(verString + 1); // skip 'v' in version name + if (dirVersionInt > maxResInt) { + fprintf(stderr, "max res %d, skipping %s\n", maxResInt, entry->d_name); + continue; + } + } + FileType type = getFileType(subdirName.string()); if (type == kFileTypeDirectory) { - sp dir = makeDir(String8(entry->d_name)); + sp dir = makeDir(resType); ssize_t res = dir->slurpFullTree(bundle, subdirName, group, - resType); + resType, mFullResPaths); if (res < 0) { count = res; goto bail; @@ -1710,7 +2138,13 @@ ssize_t AaptAssets::slurpResourceTree(Bundle* bundle, const String8& srcDir) count += res; } - mDirs.add(dir); + // Only add this directory if we don't already have a resource dir + // for the current type. This ensures that we only add the dir once + // for all configs. + sp rdir = resDir(resType); + if (rdir == NULL) { + mResDirs.add(dir); + } } else { if (bundle->getVerbose()) { fprintf(stderr, " (ignoring file '%s')\n", subdirName.string()); @@ -1819,6 +2253,142 @@ bail: return count; } +status_t AaptAssets::filter(Bundle* bundle) +{ + ResourceFilter reqFilter; + status_t err = reqFilter.parse(bundle->getConfigurations()); + if (err != NO_ERROR) { + return err; + } + + ResourceFilter prefFilter; + err = prefFilter.parse(bundle->getPreferredConfigurations()); + if (err != NO_ERROR) { + return err; + } + + if (reqFilter.isEmpty() && prefFilter.isEmpty()) { + return NO_ERROR; + } + + if (bundle->getVerbose()) { + if (!reqFilter.isEmpty()) { + printf("Applying required filter: %s\n", + bundle->getConfigurations()); + } + if (!prefFilter.isEmpty()) { + printf("Applying preferred filter: %s\n", + bundle->getPreferredConfigurations()); + } + } + + const Vector >& resdirs = mResDirs; + const size_t ND = resdirs.size(); + for (size_t i=0; i& dir = resdirs.itemAt(i); + if (dir->getLeaf() == kValuesDir) { + // The "value" dir is special since a single file defines + // multiple resources, so we can not do filtering on the + // files themselves. + continue; + } + if (dir->getLeaf() == kMipmapDir) { + // We also skip the "mipmap" directory, since the point of this + // is to include all densities without stripping. If you put + // other configurations in here as well they won't be stripped + // either... So don't do that. Seriously. What is wrong with you? + continue; + } + + const size_t NG = dir->getFiles().size(); + for (size_t j=0; j grp = dir->getFiles().valueAt(j); + + // First remove any configurations we know we don't need. + for (size_t k=0; kgetFiles().size(); k++) { + sp file = grp->getFiles().valueAt(k); + if (k == 0 && grp->getFiles().size() == 1) { + // If this is the only file left, we need to keep it. + // Otherwise the resource IDs we are using will be inconsistent + // with what we get when not stripping. Sucky, but at least + // for now we can rely on the back-end doing another filtering + // pass to take this out and leave us with this resource name + // containing no entries. + continue; + } + if (file->getPath().getPathExtension() == ".xml") { + // We can't remove .xml files at this point, because when + // we parse them they may add identifier resources, so + // removing them can cause our resource identifiers to + // become inconsistent. + continue; + } + const ResTable_config& config(file->getGroupEntry().toParams()); + if (!reqFilter.match(config)) { + if (bundle->getVerbose()) { + printf("Pruning unneeded resource: %s\n", + file->getPrintableSource().string()); + } + grp->removeFile(k); + k--; + } + } + + // Quick check: no preferred filters, nothing more to do. + if (prefFilter.isEmpty()) { + continue; + } + + // Now deal with preferred configurations. + for (int axis=AXIS_START; axis<=AXIS_END; axis++) { + for (size_t k=0; kgetFiles().size(); k++) { + sp file = grp->getFiles().valueAt(k); + if (k == 0 && grp->getFiles().size() == 1) { + // If this is the only file left, we need to keep it. + // Otherwise the resource IDs we are using will be inconsistent + // with what we get when not stripping. Sucky, but at least + // for now we can rely on the back-end doing another filtering + // pass to take this out and leave us with this resource name + // containing no entries. + continue; + } + if (file->getPath().getPathExtension() == ".xml") { + // We can't remove .xml files at this point, because when + // we parse them they may add identifier resources, so + // removing them can cause our resource identifiers to + // become inconsistent. + continue; + } + const ResTable_config& config(file->getGroupEntry().toParams()); + if (!prefFilter.match(axis, config)) { + // This is a resource we would prefer not to have. Check + // to see if have a similar variation that we would like + // to have and, if so, we can drop it. + for (size_t m=0; mgetFiles().size(); m++) { + if (m == k) continue; + sp mfile = grp->getFiles().valueAt(m); + const ResTable_config& mconfig(mfile->getGroupEntry().toParams()); + if (AaptGroupEntry::configSameExcept(config, mconfig, axis)) { + if (prefFilter.match(axis, mconfig)) { + if (bundle->getVerbose()) { + printf("Pruning unneeded resource: %s\n", + file->getPrintableSource().string()); + } + grp->removeFile(k); + k--; + break; + } + } + } + } + } + } + } + } + + return NO_ERROR; +} + sp AaptAssets::getSymbolsFor(const String8& name) { sp sym = mSymbols.valueFor(name); @@ -1862,26 +2432,39 @@ const ResTable& AaptAssets::getIncludedResources() const return mIncludedAssets.getResources(false); } -void AaptAssets::print() const +void AaptAssets::print(const String8& prefix) const { - printf("Locale/Vendor pairs:\n"); + String8 innerPrefix(prefix); + innerPrefix.append(" "); + String8 innerInnerPrefix(innerPrefix); + innerInnerPrefix.append(" "); + printf("%sConfigurations:\n", prefix.string()); const size_t N=mGroupEntries.size(); for (size_t i=0; i >& resdirs = mResDirs; + const size_t NR = resdirs.size(); + for (size_t i=0; i& d = resdirs.itemAt(i); + printf("%s Type %s\n", prefix.string(), d->getLeaf().string()); + d->print(innerInnerPrefix); + } } -sp AaptAssets::resDir(const String8& name) +sp AaptAssets::resDir(const String8& name) const { - const Vector >& dirs = mDirs; - const size_t N = dirs.size(); + const Vector >& resdirs = mResDirs; + const size_t N = resdirs.size(); for (size_t i=0; i& d = dirs.itemAt(i); + const sp& d = resdirs.itemAt(i); if (d->getLeaf() == name) { return d; }