New aapt feature to do smarter filtering of configurations.
This adds a --preferred-configurations flag that specifies the specific configurations you would like to have. It is smarter than "-c" because it will avoid stripping a configuration if that would result in there being no value for the resource. It is dumber than "-c" because it can't process as many kinds of resources. It is really only intended for bitmaps and use with density configs. This required re-arranging AaptAssets to group files together by config again, like they used to be. I think this hasn't broken anything. Hopefully. Change-Id: I4e9d12ff6e6dbd1abb8fd4cb1814c6674b19d0e5
This commit is contained in:
@@ -3,6 +3,7 @@
|
||||
//
|
||||
|
||||
#include "AaptAssets.h"
|
||||
#include "ResourceFilter.h"
|
||||
#include "Main.h"
|
||||
|
||||
#include <utils/misc.h>
|
||||
@@ -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;
|
||||
|
||||
@@ -257,9 +260,69 @@ 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<String8> parts;
|
||||
|
||||
String8 mcc, mnc, loc, layoutsize, layoutlong, orient, den;
|
||||
@@ -629,79 +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 != "") {
|
||||
s += "-";
|
||||
if (s.length() > 0) {
|
||||
s += "-";
|
||||
}
|
||||
s += smallestScreenWidthDp;
|
||||
}
|
||||
if (this->screenWidthDp != "") {
|
||||
s += "-";
|
||||
if (s.length() > 0) {
|
||||
s += "-";
|
||||
}
|
||||
s += screenWidthDp;
|
||||
}
|
||||
if (this->screenHeightDp != "") {
|
||||
s += "-";
|
||||
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 != "") {
|
||||
s += "-";
|
||||
if (s.length() > 0) {
|
||||
s += "-";
|
||||
}
|
||||
s += uiModeType;
|
||||
}
|
||||
if (this->uiModeNight != "") {
|
||||
s += "-";
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -1286,9 +1387,14 @@ 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);
|
||||
@@ -1403,8 +1509,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;
|
||||
@@ -1424,6 +1529,13 @@ status_t AaptGroup::addFile(const sp<AaptFile>& 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;
|
||||
@@ -1434,20 +1546,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<N; i++) {
|
||||
sp<AaptFile> 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());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1514,38 +1629,6 @@ void AaptDir::removeDir(const String8& name)
|
||||
mDirs.removeItem(name);
|
||||
}
|
||||
|
||||
status_t AaptDir::renameFile(const sp<AaptFile>& file, const String8& newName)
|
||||
{
|
||||
sp<AaptGroup> 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<NG; i++) {
|
||||
sp<AaptGroup> g = mFiles.valueAt(i);
|
||||
const size_t NF = g->getFiles().size();
|
||||
for (size_t j=0; j<NF; j++) {
|
||||
if (g->getFiles().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<AaptFile>& file)
|
||||
{
|
||||
sp<AaptGroup> group;
|
||||
@@ -1710,17 +1793,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; i<ND; i++) {
|
||||
getDirs().valueAt(i)->print();
|
||||
getDirs().valueAt(i)->print(prefix);
|
||||
}
|
||||
|
||||
const size_t NF=getFiles().size();
|
||||
for (i=0; i<NF; i++) {
|
||||
getFiles().valueAt(i)->print();
|
||||
getFiles().valueAt(i)->print(prefix);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1744,6 +1827,24 @@ String8 AaptDir::getPrintableSource() const
|
||||
// =========================================================================
|
||||
// =========================================================================
|
||||
|
||||
AaptAssets::AaptAssets()
|
||||
: AaptDir(String8(), String8()),
|
||||
mChanged(false), mHaveIncludedAssets(false), mRes(NULL)
|
||||
{
|
||||
}
|
||||
|
||||
const SortedVector<AaptGroupEntry>& AaptAssets::getGroupEntries() const {
|
||||
if (mChanged) {
|
||||
}
|
||||
return mGroupEntries;
|
||||
}
|
||||
|
||||
status_t AaptAssets::addFile(const String8& name, const sp<AaptGroup>& file)
|
||||
{
|
||||
mChanged = true;
|
||||
return AaptDir::addFile(name, file);
|
||||
}
|
||||
|
||||
sp<AaptFile> AaptAssets::addFile(
|
||||
const String8& filePath, const AaptGroupEntry& entry,
|
||||
const String8& srcDir, sp<AaptGroup>* outGroup,
|
||||
@@ -1945,6 +2046,11 @@ ssize_t AaptAssets::slurpFromArgs(Bundle* bundle)
|
||||
goto bail;
|
||||
}
|
||||
|
||||
count = filter(bundle);
|
||||
if (count != NO_ERROR) {
|
||||
totalCount = count;
|
||||
goto bail;
|
||||
}
|
||||
|
||||
bail:
|
||||
return totalCount;
|
||||
@@ -2002,9 +2108,9 @@ ssize_t AaptAssets::slurpResourceTree(Bundle* bundle, const String8& srcDir)
|
||||
continue;
|
||||
}
|
||||
|
||||
if (bundle->getMaxResVersion() != NULL && group.version.length() != 0) {
|
||||
if (bundle->getMaxResVersion() != NULL && group.getVersionString().length() != 0) {
|
||||
int maxResInt = atoi(bundle->getMaxResVersion());
|
||||
const char *verString = group.version.string();
|
||||
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);
|
||||
@@ -2015,7 +2121,7 @@ ssize_t AaptAssets::slurpResourceTree(Bundle* bundle, const String8& srcDir)
|
||||
FileType type = getFileType(subdirName.string());
|
||||
|
||||
if (type == kFileTypeDirectory) {
|
||||
sp<AaptDir> dir = makeDir(String8(entry->d_name));
|
||||
sp<AaptDir> dir = makeDir(resType);
|
||||
ssize_t res = dir->slurpFullTree(bundle, subdirName, group,
|
||||
resType, mFullResPaths);
|
||||
if (res < 0) {
|
||||
@@ -2027,7 +2133,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<AaptDir> rdir = resDir(resType);
|
||||
if (rdir == NULL) {
|
||||
mResDirs.add(dir);
|
||||
}
|
||||
} else {
|
||||
if (bundle->getVerbose()) {
|
||||
fprintf(stderr, " (ignoring file '%s')\n", subdirName.string());
|
||||
@@ -2136,6 +2248,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 (true || 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<sp<AaptDir> >& resdirs = mResDirs;
|
||||
const size_t ND = resdirs.size();
|
||||
for (size_t i=0; i<ND; i++) {
|
||||
const sp<AaptDir>& 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<NG; j++) {
|
||||
sp<AaptGroup> grp = dir->getFiles().valueAt(j);
|
||||
|
||||
// First remove any configurations we know we don't need.
|
||||
for (size_t k=0; k<grp->getFiles().size(); k++) {
|
||||
sp<AaptFile> 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; k<grp->getFiles().size(); k++) {
|
||||
sp<AaptFile> 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; m<grp->getFiles().size(); m++) {
|
||||
if (m == k) continue;
|
||||
sp<AaptFile> 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<AaptSymbols> AaptAssets::getSymbolsFor(const String8& name)
|
||||
{
|
||||
sp<AaptSymbols> sym = mSymbols.valueFor(name);
|
||||
@@ -2179,26 +2427,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<N; i++) {
|
||||
printf(" %s/%s\n",
|
||||
mGroupEntries.itemAt(i).locale.string(),
|
||||
mGroupEntries.itemAt(i).vendor.string());
|
||||
String8 cname = mGroupEntries.itemAt(i).toDirName(String8());
|
||||
printf("%s %s\n", prefix.string(),
|
||||
cname != "" ? cname.string() : "(default)");
|
||||
}
|
||||
|
||||
printf("\nFiles:\n");
|
||||
AaptDir::print();
|
||||
printf("\n%sFiles:\n", prefix.string());
|
||||
AaptDir::print(innerPrefix);
|
||||
|
||||
printf("\n%sResource Dirs:\n", prefix.string());
|
||||
const Vector<sp<AaptDir> >& resdirs = mResDirs;
|
||||
const size_t NR = resdirs.size();
|
||||
for (size_t i=0; i<NR; i++) {
|
||||
const sp<AaptDir>& d = resdirs.itemAt(i);
|
||||
printf("%s Type %s\n", prefix.string(), d->getLeaf().string());
|
||||
d->print(innerInnerPrefix);
|
||||
}
|
||||
}
|
||||
|
||||
sp<AaptDir> AaptAssets::resDir(const String8& name)
|
||||
sp<AaptDir> AaptAssets::resDir(const String8& name) const
|
||||
{
|
||||
const Vector<sp<AaptDir> >& dirs = mDirs;
|
||||
const size_t N = dirs.size();
|
||||
const Vector<sp<AaptDir> >& resdirs = mResDirs;
|
||||
const size_t N = resdirs.size();
|
||||
for (size_t i=0; i<N; i++) {
|
||||
const sp<AaptDir>& d = dirs.itemAt(i);
|
||||
const sp<AaptDir>& d = resdirs.itemAt(i);
|
||||
if (d->getLeaf() == name) {
|
||||
return d;
|
||||
}
|
||||
|
||||
@@ -24,6 +24,8 @@ using namespace android;
|
||||
|
||||
bool valid_symbol_name(const String8& str);
|
||||
|
||||
class AaptAssets;
|
||||
|
||||
enum {
|
||||
AXIS_NONE = 0,
|
||||
AXIS_MCC = 1,
|
||||
@@ -45,7 +47,10 @@ enum {
|
||||
AXIS_SMALLESTSCREENWIDTHDP,
|
||||
AXIS_SCREENWIDTHDP,
|
||||
AXIS_SCREENHEIGHTDP,
|
||||
AXIS_VERSION
|
||||
AXIS_VERSION,
|
||||
|
||||
AXIS_START = AXIS_MCC,
|
||||
AXIS_END = AXIS_VERSION,
|
||||
};
|
||||
|
||||
enum {
|
||||
@@ -56,6 +61,7 @@ enum {
|
||||
SDK_MR1 = 7,
|
||||
SDK_FROYO = 8,
|
||||
SDK_HONEYCOMB_MR2 = 13,
|
||||
SDK_ICE_CREAM_SANDWICH = 14,
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -65,35 +71,19 @@ enum {
|
||||
struct AaptGroupEntry
|
||||
{
|
||||
public:
|
||||
AaptGroupEntry() { }
|
||||
AaptGroupEntry() : mParamsChanged(true) { }
|
||||
AaptGroupEntry(const String8& _locale, const String8& _vendor)
|
||||
: locale(_locale), vendor(_vendor) { }
|
||||
|
||||
String8 mcc;
|
||||
String8 mnc;
|
||||
String8 locale;
|
||||
String8 vendor;
|
||||
String8 smallestScreenWidthDp;
|
||||
String8 screenWidthDp;
|
||||
String8 screenHeightDp;
|
||||
String8 screenLayoutSize;
|
||||
String8 screenLayoutLong;
|
||||
String8 orientation;
|
||||
String8 uiModeType;
|
||||
String8 uiModeNight;
|
||||
String8 density;
|
||||
String8 touchscreen;
|
||||
String8 keysHidden;
|
||||
String8 keyboard;
|
||||
String8 navHidden;
|
||||
String8 navigation;
|
||||
String8 screenSize;
|
||||
String8 version;
|
||||
: locale(_locale), vendor(_vendor), mParamsChanged(true) { }
|
||||
|
||||
bool initFromDirName(const char* dir, String8* resType);
|
||||
|
||||
static status_t parseNamePart(const String8& part, int* axis, uint32_t* value);
|
||||
|
||||
|
||||
static uint32_t getConfigValueForAxis(const ResTable_config& config, int axis);
|
||||
|
||||
static bool configSameExcept(const ResTable_config& config,
|
||||
const ResTable_config& otherConfig, int axis);
|
||||
|
||||
static bool getMccName(const char* name, ResTable_config* out = NULL);
|
||||
static bool getMncName(const char* name, ResTable_config* out = NULL);
|
||||
static bool getLocaleName(const char* name, ResTable_config* out = NULL);
|
||||
@@ -116,7 +106,7 @@ public:
|
||||
|
||||
int compare(const AaptGroupEntry& o) const;
|
||||
|
||||
ResTable_config toParams() const;
|
||||
const ResTable_config& toParams() const;
|
||||
|
||||
inline bool operator<(const AaptGroupEntry& o) const { return compare(o) < 0; }
|
||||
inline bool operator<=(const AaptGroupEntry& o) const { return compare(o) <= 0; }
|
||||
@@ -127,6 +117,33 @@ public:
|
||||
|
||||
String8 toString() const;
|
||||
String8 toDirName(const String8& resType) const;
|
||||
|
||||
const String8& getVersionString() const { return version; }
|
||||
|
||||
private:
|
||||
String8 mcc;
|
||||
String8 mnc;
|
||||
String8 locale;
|
||||
String8 vendor;
|
||||
String8 smallestScreenWidthDp;
|
||||
String8 screenWidthDp;
|
||||
String8 screenHeightDp;
|
||||
String8 screenLayoutSize;
|
||||
String8 screenLayoutLong;
|
||||
String8 orientation;
|
||||
String8 uiModeType;
|
||||
String8 uiModeNight;
|
||||
String8 density;
|
||||
String8 touchscreen;
|
||||
String8 keysHidden;
|
||||
String8 keyboard;
|
||||
String8 navHidden;
|
||||
String8 navigation;
|
||||
String8 screenSize;
|
||||
String8 version;
|
||||
|
||||
mutable bool mParamsChanged;
|
||||
mutable ResTable_config mParams;
|
||||
};
|
||||
|
||||
inline int compare_type(const AaptGroupEntry& lhs, const AaptGroupEntry& rhs)
|
||||
@@ -225,7 +242,7 @@ public:
|
||||
status_t addFile(const sp<AaptFile>& file);
|
||||
void removeFile(size_t index);
|
||||
|
||||
void print() const;
|
||||
void print(const String8& prefix) const;
|
||||
|
||||
String8 getPrintableSource() const;
|
||||
|
||||
@@ -237,7 +254,7 @@ private:
|
||||
};
|
||||
|
||||
/**
|
||||
* A single directory of assets, which can contain for files and other
|
||||
* A single directory of assets, which can contain files and other
|
||||
* sub-directories.
|
||||
*/
|
||||
class AaptDir : public RefBase
|
||||
@@ -254,25 +271,11 @@ public:
|
||||
const DefaultKeyedVector<String8, sp<AaptGroup> >& getFiles() const { return mFiles; }
|
||||
const DefaultKeyedVector<String8, sp<AaptDir> >& getDirs() const { return mDirs; }
|
||||
|
||||
status_t addFile(const String8& name, const sp<AaptGroup>& file);
|
||||
status_t addDir(const String8& name, const sp<AaptDir>& dir);
|
||||
|
||||
sp<AaptDir> makeDir(const String8& name);
|
||||
virtual status_t addFile(const String8& name, const sp<AaptGroup>& file);
|
||||
|
||||
void removeFile(const String8& name);
|
||||
void removeDir(const String8& name);
|
||||
|
||||
status_t renameFile(const sp<AaptFile>& file, const String8& newName);
|
||||
|
||||
status_t addLeafFile(const String8& leafName,
|
||||
const sp<AaptFile>& file);
|
||||
|
||||
virtual ssize_t slurpFullTree(Bundle* bundle,
|
||||
const String8& srcDir,
|
||||
const AaptGroupEntry& kind,
|
||||
const String8& resType,
|
||||
sp<FilePathStore>& fullResPaths);
|
||||
|
||||
/*
|
||||
* Perform some sanity checks on the names of files and directories here.
|
||||
* In particular:
|
||||
@@ -292,11 +295,23 @@ public:
|
||||
*/
|
||||
status_t validate() const;
|
||||
|
||||
void print() const;
|
||||
void print(const String8& prefix) const;
|
||||
|
||||
String8 getPrintableSource() const;
|
||||
|
||||
private:
|
||||
friend class AaptAssets;
|
||||
|
||||
status_t addDir(const String8& name, const sp<AaptDir>& dir);
|
||||
sp<AaptDir> makeDir(const String8& name);
|
||||
status_t addLeafFile(const String8& leafName,
|
||||
const sp<AaptFile>& file);
|
||||
virtual ssize_t slurpFullTree(Bundle* bundle,
|
||||
const String8& srcDir,
|
||||
const AaptGroupEntry& kind,
|
||||
const String8& resType,
|
||||
sp<FilePathStore>& fullResPaths);
|
||||
|
||||
String8 mLeaf;
|
||||
String8 mPath;
|
||||
|
||||
@@ -501,13 +516,15 @@ public:
|
||||
class AaptAssets : public AaptDir
|
||||
{
|
||||
public:
|
||||
AaptAssets() : AaptDir(String8(), String8()), mHaveIncludedAssets(false), mRes(NULL) { }
|
||||
AaptAssets();
|
||||
virtual ~AaptAssets() { delete mRes; }
|
||||
|
||||
const String8& getPackage() const { return mPackage; }
|
||||
void setPackage(const String8& package) { mPackage = package; mSymbolsPrivatePackage = package; }
|
||||
|
||||
const SortedVector<AaptGroupEntry>& getGroupEntries() const { return mGroupEntries; }
|
||||
const SortedVector<AaptGroupEntry>& getGroupEntries() const;
|
||||
|
||||
virtual status_t addFile(const String8& name, const sp<AaptGroup>& file);
|
||||
|
||||
sp<AaptFile> addFile(const String8& filePath,
|
||||
const AaptGroupEntry& entry,
|
||||
@@ -524,15 +541,6 @@ public:
|
||||
|
||||
ssize_t slurpFromArgs(Bundle* bundle);
|
||||
|
||||
virtual ssize_t slurpFullTree(Bundle* bundle,
|
||||
const String8& srcDir,
|
||||
const AaptGroupEntry& kind,
|
||||
const String8& resType,
|
||||
sp<FilePathStore>& fullResPaths);
|
||||
|
||||
ssize_t slurpResourceTree(Bundle* bundle, const String8& srcDir);
|
||||
ssize_t slurpResourceZip(Bundle* bundle, const char* filename);
|
||||
|
||||
sp<AaptSymbols> getSymbolsFor(const String8& name);
|
||||
|
||||
const DefaultKeyedVector<String8, sp<AaptSymbols> >& getSymbols() const { return mSymbols; }
|
||||
@@ -544,10 +552,10 @@ public:
|
||||
status_t addIncludedResources(const sp<AaptFile>& file);
|
||||
const ResTable& getIncludedResources() const;
|
||||
|
||||
void print() const;
|
||||
void print(const String8& prefix) const;
|
||||
|
||||
inline const Vector<sp<AaptDir> >& resDirs() { return mDirs; }
|
||||
sp<AaptDir> resDir(const String8& name);
|
||||
inline const Vector<sp<AaptDir> >& resDirs() const { return mResDirs; }
|
||||
sp<AaptDir> resDir(const String8& name) const;
|
||||
|
||||
inline sp<AaptAssets> getOverlay() { return mOverlay; }
|
||||
inline void setOverlay(sp<AaptAssets>& overlay) { mOverlay = overlay; }
|
||||
@@ -565,12 +573,25 @@ public:
|
||||
setFullAssetPaths(sp<FilePathStore>& res) { mFullAssetPaths = res; }
|
||||
|
||||
private:
|
||||
virtual ssize_t slurpFullTree(Bundle* bundle,
|
||||
const String8& srcDir,
|
||||
const AaptGroupEntry& kind,
|
||||
const String8& resType,
|
||||
sp<FilePathStore>& fullResPaths);
|
||||
|
||||
ssize_t slurpResourceTree(Bundle* bundle, const String8& srcDir);
|
||||
ssize_t slurpResourceZip(Bundle* bundle, const char* filename);
|
||||
|
||||
status_t filter(Bundle* bundle);
|
||||
|
||||
String8 mPackage;
|
||||
SortedVector<AaptGroupEntry> mGroupEntries;
|
||||
DefaultKeyedVector<String8, sp<AaptSymbols> > mSymbols;
|
||||
String8 mSymbolsPrivatePackage;
|
||||
|
||||
Vector<sp<AaptDir> > mDirs;
|
||||
Vector<sp<AaptDir> > mResDirs;
|
||||
|
||||
bool mChanged;
|
||||
|
||||
bool mHaveIncludedAssets;
|
||||
AssetManager mIncludedAssets;
|
||||
|
||||
@@ -19,6 +19,7 @@ LOCAL_SRC_FILES := \
|
||||
Package.cpp \
|
||||
StringPool.cpp \
|
||||
XMLNode.cpp \
|
||||
ResourceFilter.cpp \
|
||||
ResourceTable.cpp \
|
||||
Images.cpp \
|
||||
Resource.cpp \
|
||||
|
||||
@@ -122,6 +122,8 @@ public:
|
||||
void setRClassDir(const char* dir) { mRClassDir = dir; }
|
||||
const char* getConfigurations() const { return mConfigurations.size() > 0 ? mConfigurations.string() : NULL; }
|
||||
void addConfigurations(const char* val) { if (mConfigurations.size() > 0) { mConfigurations.append(","); mConfigurations.append(val); } else { mConfigurations = val; } }
|
||||
const char* getPreferredConfigurations() const { return mPreferredConfigurations.size() > 0 ? mPreferredConfigurations.string() : NULL; }
|
||||
void addPreferredConfigurations(const char* val) { if (mPreferredConfigurations.size() > 0) { mPreferredConfigurations.append(","); mPreferredConfigurations.append(val); } else { mPreferredConfigurations = val; } }
|
||||
const char* getResourceIntermediatesDir() const { return mResourceIntermediatesDir; }
|
||||
void setResourceIntermediatesDir(const char* dir) { mResourceIntermediatesDir = dir; }
|
||||
const android::Vector<const char*>& getPackageIncludes() const { return mPackageIncludes; }
|
||||
@@ -244,6 +246,7 @@ private:
|
||||
const char* mRClassDir;
|
||||
const char* mResourceIntermediatesDir;
|
||||
android::String8 mConfigurations;
|
||||
android::String8 mPreferredConfigurations;
|
||||
android::Vector<const char*> mPackageIncludes;
|
||||
android::Vector<const char*> mJarFiles;
|
||||
android::Vector<const char*> mNoCompressExtensions;
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
//
|
||||
#include "Main.h"
|
||||
#include "Bundle.h"
|
||||
#include "ResourceFilter.h"
|
||||
#include "ResourceTable.h"
|
||||
#include "XMLNode.h"
|
||||
|
||||
@@ -1572,7 +1573,7 @@ int doPackage(Bundle* bundle)
|
||||
}
|
||||
|
||||
if (bundle->getVerbose()) {
|
||||
assets->print();
|
||||
assets->print(String8());
|
||||
}
|
||||
|
||||
// If they asked for any fileAs that need to be compiled, do so.
|
||||
|
||||
@@ -980,6 +980,10 @@ status_t preProcessImage(Bundle* bundle, const sp<AaptAssets>& assets,
|
||||
|
||||
String8 printableName(file->getPrintableSource());
|
||||
|
||||
if (bundle->getVerbose()) {
|
||||
printf("Processing image: %s\n", printableName.string());
|
||||
}
|
||||
|
||||
png_structp read_ptr = NULL;
|
||||
png_infop read_info = NULL;
|
||||
FILE* fp;
|
||||
@@ -1094,6 +1098,10 @@ status_t preProcessImageToCache(Bundle* bundle, String8 source, String8 dest)
|
||||
|
||||
status_t error = UNKNOWN_ERROR;
|
||||
|
||||
if (bundle->getVerbose()) {
|
||||
printf("Processing image to cache: %s => %s\n", source.string(), dest.string());
|
||||
}
|
||||
|
||||
// Get a file handler to read from
|
||||
fp = fopen(source.string(),"rb");
|
||||
if (fp == NULL) {
|
||||
|
||||
@@ -65,9 +65,10 @@ void usage(void)
|
||||
" [--max-res-version VAL] \\\n"
|
||||
" [-I base-package [-I base-package ...]] \\\n"
|
||||
" [-A asset-source-dir] [-G class-list-file] [-P public-definitions-file] \\\n"
|
||||
" [-S resource-sources [-S resource-sources ...]] "
|
||||
" [-S resource-sources [-S resource-sources ...]] \\\n"
|
||||
" [-F apk-file] [-J R-file-dir] \\\n"
|
||||
" [--product product1,product2,...] \\\n"
|
||||
" [-c CONFIGS] [--preferred-configurations CONFIGS] \\\n"
|
||||
" [-o] \\\n"
|
||||
" [raw-files-dir [raw-files-dir] ...]\n"
|
||||
"\n"
|
||||
@@ -154,6 +155,10 @@ void usage(void)
|
||||
" generate dependency files in the same directories for R.java and resource package\n"
|
||||
" --auto-add-overlay\n"
|
||||
" Automatically add resources that are only in overlays.\n"
|
||||
" --preferred-configurations\n"
|
||||
" Like the -c option for filtering out unneeded configurations, but\n"
|
||||
" only expresses a preference. If there is no resource available with\n"
|
||||
" the preferred configuration then it will not be stripped.\n"
|
||||
" --rename-manifest-package\n"
|
||||
" Rewrite the manifest so that its package name is the package name\n"
|
||||
" given here. Relative class names (for example .Foo) will be\n"
|
||||
@@ -509,6 +514,15 @@ int main(int argc, char* const argv[])
|
||||
bundle.setGenDependencies(true);
|
||||
} else if (strcmp(cp, "-utf16") == 0) {
|
||||
bundle.setWantUTF16(true);
|
||||
} else if (strcmp(cp, "-preferred-configurations") == 0) {
|
||||
argc--;
|
||||
argv++;
|
||||
if (!argc) {
|
||||
fprintf(stderr, "ERROR: No argument supplied for '--preferred-configurations' option\n");
|
||||
wantUsage = true;
|
||||
goto bail;
|
||||
}
|
||||
bundle.addPreferredConfigurations(argv[0]);
|
||||
} else if (strcmp(cp, "-rename-manifest-package") == 0) {
|
||||
argc--;
|
||||
argv++;
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
#include "Main.h"
|
||||
#include "AaptAssets.h"
|
||||
#include "ResourceTable.h"
|
||||
#include "ResourceFilter.h"
|
||||
|
||||
#include <utils/Log.h>
|
||||
#include <utils/threads.h>
|
||||
|
||||
@@ -352,18 +352,27 @@ static void collect_files(const sp<AaptDir>& dir,
|
||||
|
||||
if (index < 0) {
|
||||
sp<ResourceTypeSet> set = new ResourceTypeSet();
|
||||
NOISY(printf("Creating new resource type set for leaf %s with group %s (%p)\n",
|
||||
leafName.string(), group->getPath().string(), group.get()));
|
||||
set->add(leafName, group);
|
||||
resources->add(resType, set);
|
||||
} else {
|
||||
sp<ResourceTypeSet> set = resources->valueAt(index);
|
||||
index = set->indexOfKey(leafName);
|
||||
if (index < 0) {
|
||||
NOISY(printf("Adding to resource type set for leaf %s group %s (%p)\n",
|
||||
leafName.string(), group->getPath().string(), group.get()));
|
||||
set->add(leafName, group);
|
||||
} else {
|
||||
sp<AaptGroup> existingGroup = set->valueAt(index);
|
||||
int M = files.size();
|
||||
for (int j=0; j<M; j++) {
|
||||
existingGroup->addFile(files.valueAt(j));
|
||||
NOISY(printf("Extending to resource type set for leaf %s group %s (%p)\n",
|
||||
leafName.string(), group->getPath().string(), group.get()));
|
||||
for (size_t j=0; j<files.size(); j++) {
|
||||
NOISY(printf("Adding file %s in group %s resType %s\n",
|
||||
files.valueAt(j)->getSourceFile().string(),
|
||||
files.keyAt(j).toDirName(String8()).string(),
|
||||
resType.string()));
|
||||
status_t err = existingGroup->addFile(files.valueAt(j));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -378,9 +387,12 @@ static void collect_files(const sp<AaptAssets>& ass,
|
||||
|
||||
for (int i=0; i<N; i++) {
|
||||
sp<AaptDir> d = dirs.itemAt(i);
|
||||
NOISY(printf("Collecting dir #%d %p: %s, leaf %s\n", i, d.get(), d->getPath().string(),
|
||||
d->getLeaf().string()));
|
||||
collect_files(d, resources);
|
||||
|
||||
// don't try to include the res dir
|
||||
NOISY(printf("Removing dir leaf %s\n", d->getLeaf().string()));
|
||||
ass->removeDir(d->getLeaf());
|
||||
}
|
||||
}
|
||||
@@ -570,7 +582,7 @@ static bool applyFileOverlay(Bundle *bundle,
|
||||
size_t baseFileIndex =
|
||||
baseGroup->getFiles().indexOfKey(overlayFiles.
|
||||
keyAt(overlayGroupIndex));
|
||||
if(baseFileIndex < UNKNOWN_ERROR) {
|
||||
if (baseFileIndex < UNKNOWN_ERROR) {
|
||||
if (bundle->getVerbose()) {
|
||||
printf("found a match (%zd) for overlay file %s, for flavor %s\n",
|
||||
baseFileIndex,
|
||||
@@ -580,6 +592,11 @@ static bool applyFileOverlay(Bundle *bundle,
|
||||
baseGroup->removeFile(baseFileIndex);
|
||||
} else {
|
||||
// didn't find a match fall through and add it..
|
||||
if (true || bundle->getVerbose()) {
|
||||
printf("nothing matches overlay file %s, for flavor %s\n",
|
||||
overlayGroup->getLeaf().string(),
|
||||
overlayFiles.keyAt(overlayGroupIndex).toString().string());
|
||||
}
|
||||
}
|
||||
baseGroup->addFile(overlayFiles.valueAt(overlayGroupIndex));
|
||||
assets->addGroupEntry(overlayFiles.keyAt(overlayGroupIndex));
|
||||
|
||||
112
tools/aapt/ResourceFilter.cpp
Normal file
112
tools/aapt/ResourceFilter.cpp
Normal file
@@ -0,0 +1,112 @@
|
||||
//
|
||||
// Copyright 2011 The Android Open Source Project
|
||||
//
|
||||
// Build resource files from raw assets.
|
||||
//
|
||||
|
||||
#include "ResourceFilter.h"
|
||||
|
||||
status_t
|
||||
ResourceFilter::parse(const char* arg)
|
||||
{
|
||||
if (arg == NULL) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
const char* p = arg;
|
||||
const char* q;
|
||||
|
||||
while (true) {
|
||||
q = strchr(p, ',');
|
||||
if (q == NULL) {
|
||||
q = p + strlen(p);
|
||||
}
|
||||
|
||||
String8 part(p, q-p);
|
||||
|
||||
if (part == "zz_ZZ") {
|
||||
mContainsPseudo = true;
|
||||
}
|
||||
int axis;
|
||||
uint32_t value;
|
||||
if (AaptGroupEntry::parseNamePart(part, &axis, &value)) {
|
||||
fprintf(stderr, "Invalid configuration: %s\n", arg);
|
||||
fprintf(stderr, " ");
|
||||
for (int i=0; i<p-arg; i++) {
|
||||
fprintf(stderr, " ");
|
||||
}
|
||||
for (int i=0; i<q-p; i++) {
|
||||
fprintf(stderr, "^");
|
||||
}
|
||||
fprintf(stderr, "\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
ssize_t index = mData.indexOfKey(axis);
|
||||
if (index < 0) {
|
||||
mData.add(axis, SortedVector<uint32_t>());
|
||||
}
|
||||
SortedVector<uint32_t>& sv = mData.editValueFor(axis);
|
||||
sv.add(value);
|
||||
// if it's a locale with a region, also match an unmodified locale of the
|
||||
// same language
|
||||
if (axis == AXIS_LANGUAGE) {
|
||||
if (value & 0xffff0000) {
|
||||
sv.add(value & 0x0000ffff);
|
||||
}
|
||||
}
|
||||
p = q;
|
||||
if (!*p) break;
|
||||
p++;
|
||||
}
|
||||
|
||||
return NO_ERROR;
|
||||
}
|
||||
|
||||
bool
|
||||
ResourceFilter::isEmpty() const
|
||||
{
|
||||
return mData.size() == 0;
|
||||
}
|
||||
|
||||
bool
|
||||
ResourceFilter::match(int axis, uint32_t value) const
|
||||
{
|
||||
if (value == 0) {
|
||||
// they didn't specify anything so take everything
|
||||
return true;
|
||||
}
|
||||
ssize_t index = mData.indexOfKey(axis);
|
||||
if (index < 0) {
|
||||
// we didn't request anything on this axis so take everything
|
||||
return true;
|
||||
}
|
||||
const SortedVector<uint32_t>& sv = mData.valueAt(index);
|
||||
return sv.indexOf(value) >= 0;
|
||||
}
|
||||
|
||||
bool
|
||||
ResourceFilter::match(int axis, const ResTable_config& config) const
|
||||
{
|
||||
return match(axis, AaptGroupEntry::getConfigValueForAxis(config, axis));
|
||||
}
|
||||
|
||||
bool
|
||||
ResourceFilter::match(const ResTable_config& config) const
|
||||
{
|
||||
for (int i=AXIS_START; i<=AXIS_END; i++) {
|
||||
if (!match(i, AaptGroupEntry::getConfigValueForAxis(config, i))) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
const SortedVector<uint32_t>* ResourceFilter::configsForAxis(int axis) const
|
||||
{
|
||||
ssize_t index = mData.indexOfKey(axis);
|
||||
if (index < 0) {
|
||||
return NULL;
|
||||
}
|
||||
return &mData.valueAt(index);
|
||||
}
|
||||
33
tools/aapt/ResourceFilter.h
Normal file
33
tools/aapt/ResourceFilter.h
Normal file
@@ -0,0 +1,33 @@
|
||||
//
|
||||
// Copyright 2011 The Android Open Source Project
|
||||
//
|
||||
// Build resource files from raw assets.
|
||||
//
|
||||
|
||||
#ifndef RESOURCE_FILTER_H
|
||||
#define RESOURCE_FILTER_H
|
||||
|
||||
#include "AaptAssets.h"
|
||||
|
||||
/**
|
||||
* Implements logic for parsing and handling "-c" and "--preferred-configurations"
|
||||
* options.
|
||||
*/
|
||||
class ResourceFilter
|
||||
{
|
||||
public:
|
||||
ResourceFilter() : mData(), mContainsPseudo(false) {}
|
||||
status_t parse(const char* arg);
|
||||
bool isEmpty() const;
|
||||
bool match(int axis, uint32_t value) const;
|
||||
bool match(int axis, const ResTable_config& config) const;
|
||||
bool match(const ResTable_config& config) const;
|
||||
const SortedVector<uint32_t>* configsForAxis(int axis) const;
|
||||
inline bool containsPseudo() const { return mContainsPseudo; }
|
||||
|
||||
private:
|
||||
KeyedVector<int,SortedVector<uint32_t> > mData;
|
||||
bool mContainsPseudo;
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -7,6 +7,7 @@
|
||||
#include "ResourceTable.h"
|
||||
|
||||
#include "XMLNode.h"
|
||||
#include "ResourceFilter.h"
|
||||
|
||||
#include <utils/ByteOrder.h>
|
||||
#include <utils/ResourceTypes.h>
|
||||
@@ -2528,135 +2529,6 @@ ResourceTable::validateLocalizations(void)
|
||||
return err;
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
ResourceFilter::parse(const char* arg)
|
||||
{
|
||||
if (arg == NULL) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
const char* p = arg;
|
||||
const char* q;
|
||||
|
||||
while (true) {
|
||||
q = strchr(p, ',');
|
||||
if (q == NULL) {
|
||||
q = p + strlen(p);
|
||||
}
|
||||
|
||||
String8 part(p, q-p);
|
||||
|
||||
if (part == "zz_ZZ") {
|
||||
mContainsPseudo = true;
|
||||
}
|
||||
int axis;
|
||||
uint32_t value;
|
||||
if (AaptGroupEntry::parseNamePart(part, &axis, &value)) {
|
||||
fprintf(stderr, "Invalid configuration: %s\n", arg);
|
||||
fprintf(stderr, " ");
|
||||
for (int i=0; i<p-arg; i++) {
|
||||
fprintf(stderr, " ");
|
||||
}
|
||||
for (int i=0; i<q-p; i++) {
|
||||
fprintf(stderr, "^");
|
||||
}
|
||||
fprintf(stderr, "\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
ssize_t index = mData.indexOfKey(axis);
|
||||
if (index < 0) {
|
||||
mData.add(axis, SortedVector<uint32_t>());
|
||||
}
|
||||
SortedVector<uint32_t>& sv = mData.editValueFor(axis);
|
||||
sv.add(value);
|
||||
// if it's a locale with a region, also match an unmodified locale of the
|
||||
// same language
|
||||
if (axis == AXIS_LANGUAGE) {
|
||||
if (value & 0xffff0000) {
|
||||
sv.add(value & 0x0000ffff);
|
||||
}
|
||||
}
|
||||
p = q;
|
||||
if (!*p) break;
|
||||
p++;
|
||||
}
|
||||
|
||||
return NO_ERROR;
|
||||
}
|
||||
|
||||
bool
|
||||
ResourceFilter::match(int axis, uint32_t value) const
|
||||
{
|
||||
if (value == 0) {
|
||||
// they didn't specify anything so take everything
|
||||
return true;
|
||||
}
|
||||
ssize_t index = mData.indexOfKey(axis);
|
||||
if (index < 0) {
|
||||
// we didn't request anything on this axis so take everything
|
||||
return true;
|
||||
}
|
||||
const SortedVector<uint32_t>& sv = mData.valueAt(index);
|
||||
return sv.indexOf(value) >= 0;
|
||||
}
|
||||
|
||||
bool
|
||||
ResourceFilter::match(const ResTable_config& config) const
|
||||
{
|
||||
if (config.locale) {
|
||||
uint32_t locale = (config.country[1] << 24) | (config.country[0] << 16)
|
||||
| (config.language[1] << 8) | (config.language[0]);
|
||||
if (!match(AXIS_LANGUAGE, locale)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if (!match(AXIS_ORIENTATION, config.orientation)) {
|
||||
return false;
|
||||
}
|
||||
if (!match(AXIS_UIMODETYPE, (config.uiMode&ResTable_config::MASK_UI_MODE_TYPE))) {
|
||||
return false;
|
||||
}
|
||||
if (!match(AXIS_UIMODENIGHT, (config.uiMode&ResTable_config::MASK_UI_MODE_NIGHT))) {
|
||||
return false;
|
||||
}
|
||||
if (!match(AXIS_DENSITY, config.density)) {
|
||||
return false;
|
||||
}
|
||||
if (!match(AXIS_TOUCHSCREEN, config.touchscreen)) {
|
||||
return false;
|
||||
}
|
||||
if (!match(AXIS_KEYSHIDDEN, config.inputFlags)) {
|
||||
return false;
|
||||
}
|
||||
if (!match(AXIS_KEYBOARD, config.keyboard)) {
|
||||
return false;
|
||||
}
|
||||
if (!match(AXIS_NAVIGATION, config.navigation)) {
|
||||
return false;
|
||||
}
|
||||
if (!match(AXIS_SCREENSIZE, config.screenSize)) {
|
||||
return false;
|
||||
}
|
||||
if (!match(AXIS_SMALLESTSCREENWIDTHDP, config.smallestScreenWidthDp)) {
|
||||
return false;
|
||||
}
|
||||
if (!match(AXIS_SCREENWIDTHDP, config.screenWidthDp)) {
|
||||
return false;
|
||||
}
|
||||
if (!match(AXIS_SCREENHEIGHTDP, config.screenHeightDp)) {
|
||||
return false;
|
||||
}
|
||||
if (!match(AXIS_SCREENLAYOUTSIZE, config.screenLayout&ResTable_config::MASK_SCREENSIZE)) {
|
||||
return false;
|
||||
}
|
||||
if (!match(AXIS_VERSION, config.version)) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
status_t ResourceTable::flatten(Bundle* bundle, const sp<AaptFile>& dest)
|
||||
{
|
||||
ResourceFilter filter;
|
||||
|
||||
@@ -549,19 +549,4 @@ private:
|
||||
map<String16, set<String8> > mLocalizations;
|
||||
};
|
||||
|
||||
class ResourceFilter
|
||||
{
|
||||
public:
|
||||
ResourceFilter() : mData(), mContainsPseudo(false) {}
|
||||
status_t parse(const char* arg);
|
||||
bool match(int axis, uint32_t value) const;
|
||||
bool match(const ResTable_config& config) const;
|
||||
inline bool containsPseudo() const { return mContainsPseudo; }
|
||||
|
||||
private:
|
||||
KeyedVector<int,SortedVector<uint32_t> > mData;
|
||||
bool mContainsPseudo;
|
||||
};
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
Reference in New Issue
Block a user