static const char* kAssetDir = "assets";
static const char* kResourceDir = "res";
static const char* kInvalidChars = "/\\:";
-static const char* kExcludeExtension = ".EXCLUDE";
static const size_t kMaxAssetFileName = 100;
static const String8 kResString(kResourceDir);
return true;
}
-
+
// =========================================================================
// =========================================================================
// =========================================================================
*value = config.touchscreen;
return 0;
}
-
+
// keyboard hidden
if (getKeysHiddenName(part.string(), &config)) {
*axis = AXIS_KEYSHIDDEN;
*value = config.inputFlags;
return 0;
}
-
+
// keyboard
if (getKeyboardName(part.string(), &config)) {
*axis = AXIS_KEYBOARD;
*value = config.keyboard;
return 0;
}
-
+
// navigation
if (getNavigationName(part.string(), &config)) {
*axis = AXIS_NAVIGATION;
*value = config.navigation;
return 0;
}
-
+
// screen size
if (getScreenSizeName(part.string(), &config)) {
*axis = AXIS_SCREENSIZE;
// touchscreen
if (getTouchscreenName(part.string())) {
touch = part;
-
+
index++;
if (index == N) {
goto success;
} else {
//printf("not touchscreen: %s\n", part.string());
}
-
+
// keyboard hidden
if (getKeysHiddenName(part.string())) {
keysHidden = part;
-
+
index++;
if (index == N) {
goto success;
} else {
//printf("not keysHidden: %s\n", part.string());
}
-
+
// keyboard
if (getKeyboardName(part.string())) {
key = part;
-
+
index++;
if (index == N) {
goto success;
} else {
//printf("not keyboard: %s\n", part.string());
}
-
+
if (getNavigationName(part.string())) {
nav = part;
-
+
index++;
if (index == N) {
goto success;
} else {
//printf("not navigation: %s\n", part.string());
}
-
+
if (getScreenSizeName(part.string())) {
size = part;
-
+
index++;
if (index == N) {
goto success;
} else {
//printf("not screen size: %s\n", part.string());
}
-
+
if (getVersionName(part.string())) {
vers = part;
-
+
index++;
if (index == N) {
goto success;
} else {
//printf("not version: %s\n", part.string());
}
-
+
// if there are extra parts, it doesn't match
return false;
s += "-";
s += version;
}
-
+
return s;
}
c++;
if (tolower(*c) != 'c') return false;
c++;
-
+
const char* val = c;
-
+
while (*c >= '0' && *c <= '9') {
c++;
}
c++;
if (tolower(*c) != 'c') return false;
c++;
-
+
const char* val = c;
-
+
while (*c >= '0' && *c <= '9') {
c++;
}
if (out) out->orientation = out->ORIENTATION_SQUARE;
return true;
}
-
+
return false;
}
if (out) out->touchscreen = out->TOUCHSCREEN_FINGER;
return true;
}
-
+
return false;
}
mask = out->MASK_KEYSHIDDEN;
value = out->KEYSHIDDEN_SOFT;
}
-
+
if (mask != 0) {
if (out) out->inputFlags = (out->inputFlags&~mask) | value;
return true;
}
-
+
return false;
}
if (out) out->keyboard = out->KEYBOARD_12KEY;
return true;
}
-
+
return false;
}
if (out) out->navigation = out->NAVIGATION_WHEEL;
return true;
}
-
+
return false;
}
}
return true;
}
-
+
const char* x = name;
while (*x >= '0' && *x <= '9') x++;
if (x == name || *x != 'x') return false;
String8 xName(name, x-name);
x++;
-
+
const char* y = x;
while (*y >= '0' && *y <= '9') y++;
if (y == name || *y != 0) return false;
String8 yName(x, y-x);
-
+
uint16_t w = (uint16_t)atoi(xName.string());
uint16_t h = (uint16_t)atoi(yName.string());
if (w < h) {
return false;
}
-
+
if (out) {
out->screenWidth = w;
out->screenHeight = h;
}
-
+
return true;
}
}
return true;
}
-
+
if (*name != 'v') {
return false;
}
-
+
name++;
const char* s = name;
while (*s >= '0' && *s <= '9') s++;
if (s == name || *s != 0) return false;
String8 sdkName(name, s-name);
-
+
if (out) {
out->sdkVersion = (uint16_t)atoi(sdkName.string());
out->minorVersion = 0;
}
-
+
return true;
}
{
DIR* dir = NULL;
-
+
dir = opendir(srcDir.string());
if (dir == NULL) {
fprintf(stderr, "ERROR: opendir(%s): %s\n", srcDir.string(), strerror(errno));
return UNKNOWN_ERROR;
}
-
+
/*
* Slurp the filenames out of the directory.
*/
while (1) {
struct dirent* entry;
-
+
entry = readdir(dir);
if (entry == NULL)
break;
-
+
if (isHidden(srcDir.string(), entry->d_name))
continue;
fileNames.add(String8(entry->d_name));
}
-
+
closedir(dir);
}
sp<AaptDir> subdir = res->makeDir(dirname);
sp<AaptGroup> grr = new AaptGroup(leafName, path);
grr->addFile(file);
-
+
subdir->addFile(leafName, grr);
}
{
int count;
int totalCount = 0;
- int i;
- int arg = 0;
FileType type;
- const char* res;
+ const Vector<const char *>& resDirs = bundle->getResourceSourceDirs();
+ const size_t dirCount =resDirs.size();
+ sp<AaptAssets> current = this;
const int N = bundle->getFileSpecCount();
/*
* If a directory of resource-specific assets was supplied, slurp 'em up.
*/
- res = bundle->getResourceSourceDir();
- if (res) {
- type = getFileType(res);
- if (type == kFileTypeNonexistent) {
- fprintf(stderr, "ERROR: resource directory '%s' does not exist\n", res);
- return UNKNOWN_ERROR;
- }
- if (type == kFileTypeDirectory) {
- count = slurpResourceTree(bundle, String8(res));
+ for (size_t i=0; i<dirCount; i++) {
+ const char *res = resDirs[i];
+ if (res) {
+ type = getFileType(res);
+ if (type == kFileTypeNonexistent) {
+ fprintf(stderr, "ERROR: resource directory '%s' does not exist\n", res);
+ return UNKNOWN_ERROR;
+ }
+ if (type == kFileTypeDirectory) {
+ if (i>0) {
+ sp<AaptAssets> nextOverlay = new AaptAssets();
+ current->setOverlay(nextOverlay);
+ current = nextOverlay;
+ }
+ count = current->slurpResourceTree(bundle, String8(res));
- if (count < 0) {
- totalCount = count;
- goto bail;
+ if (count < 0) {
+ totalCount = count;
+ goto bail;
+ }
+ totalCount += count;
+ }
+ else {
+ fprintf(stderr, "ERROR: '%s' is not a directory\n", res);
+ return UNKNOWN_ERROR;
}
- totalCount += count;
- }
- else {
- fprintf(stderr, "ERROR: '%s' is not a directory\n", res);
- return UNKNOWN_ERROR;
}
+
}
-
/*
* Now do any additional raw files.
*/
AaptSymbolEntry mDefSymbol;
};
+class ResourceTypeSet;
+
/**
* Asset hierarchy being operated on.
*/
inline const Vector<sp<AaptDir> >& resDirs() { return mDirs; }
+ inline sp<AaptAssets> getOverlay() { return mOverlay; }
+ inline void setOverlay(sp<AaptAssets>& overlay) { mOverlay = overlay; }
+
+ inline KeyedVector<String8, sp<ResourceTypeSet> >* getResources() { return mRes; }
+ inline void
+ setResources(KeyedVector<String8, sp<ResourceTypeSet> >* res) { mRes = res; }
+
private:
String8 mPackage;
SortedVector<AaptGroupEntry> mGroupEntries;
bool mHaveIncludedAssets;
AssetManager mIncludedAssets;
+
+ sp<AaptAssets> mOverlay;
+ KeyedVector<String8, sp<ResourceTypeSet> >* mRes;
};
#endif // __AAPT_ASSETS_H
public:
Bundle(void)
: mCmd(kCommandUnknown), mVerbose(false), mAndroidList(false),
- mForce(false), mMakePackageDirs(false),
+ mForce(false), mGrayscaleTolerance(0), mMakePackageDirs(false),
mUpdate(false), mExtending(false),
mRequireLocalization(false), mPseudolocalize(false),
mCompressionMethod(0), mOutputAPKFile(NULL),
- mAssetSourceDir(NULL), mResourceSourceDir(NULL),
+ mAssetSourceDir(NULL),
mAndroidManifestFile(NULL), mPublicOutputFile(NULL),
mRClassDir(NULL), mResourceIntermediatesDir(NULL),
mArgc(0), mArgv(NULL)
void setAndroidList(bool val) { mAndroidList = val; }
bool getForce(void) const { return mForce; }
void setForce(bool val) { mForce = val; }
+ void setGrayscaleTolerance(int val) { mGrayscaleTolerance = val; }
+ int getGrayscaleTolerance() { return mGrayscaleTolerance; }
bool getMakePackageDirs(void) const { return mMakePackageDirs; }
void setMakePackageDirs(bool val) { mMakePackageDirs = val; }
bool getUpdate(void) const { return mUpdate; }
*/
const char* getAssetSourceDir() const { return mAssetSourceDir; }
void setAssetSourceDir(const char* dir) { mAssetSourceDir = dir; }
- const char* getResourceSourceDir() const { return mResourceSourceDir; }
- void setResourceSourceDir(const char* dir) { mResourceSourceDir = dir; }
+ const android::Vector<const char*>& getResourceSourceDirs() const { return mResourceSourceDirs; }
+ void addResourceSourceDir(const char* dir) { mResourceSourceDirs.insertAt(dir,0); }
const char* getAndroidManifestFile() const { return mAndroidManifestFile; }
void setAndroidManifestFile(const char* file) { mAndroidManifestFile = file; }
const char* getPublicOutputFile() const { return mPublicOutputFile; }
bool mVerbose;
bool mAndroidList;
bool mForce;
+ int mGrayscaleTolerance;
bool mMakePackageDirs;
bool mUpdate;
bool mExtending;
int mCompressionMethod;
const char* mOutputAPKFile;
const char* mAssetSourceDir;
- const char* mResourceSourceDir;
const char* mAndroidManifestFile;
const char* mPublicOutputFile;
const char* mRClassDir;
android::Vector<const char*> mPackageIncludes;
android::Vector<const char*> mJarFiles;
android::Vector<const char*> mNoCompressExtensions;
-
+ android::Vector<const char*> mResourceSourceDirs;
+
/* file specification */
int mArgc;
char* const* mArgv;
}
N = bundle->getFileSpecCount();
- if (N < 1 && bundle->getResourceSourceDir() == NULL && bundle->getJarFiles().size() == 0
+ if (N < 1 && bundle->getResourceSourceDirs().size() == 0 && bundle->getJarFiles().size() == 0
&& bundle->getAndroidManifestFile() == NULL && bundle->getAssetSourceDir() == NULL) {
fprintf(stderr, "ERROR: no input files\n");
goto bail;
}
// If they asked for any files that need to be compiled, do so.
- if (bundle->getResourceSourceDir() || bundle->getAndroidManifestFile()) {
+ if (bundle->getResourceSourceDirs().size() || bundle->getAndroidManifestFile()) {
err = buildResources(bundle, assets);
if (err != 0) {
goto bail;
// This holds an image as 8bpp RGBA.
struct image_info
{
- image_info() : rows(NULL), hasTransparency(true), is9Patch(false), allocRows(NULL) { }
+ image_info() : rows(NULL), is9Patch(false), allocRows(NULL) { }
~image_info() {
if (rows && rows != allocRows) {
free(rows);
png_uint_32 height;
png_bytepp rows;
- bool hasTransparency;
-
// 9-patch info.
bool is9Patch;
Res_png_9patch info9Patch;
return c;
}
-static void examine_image(image_info* image)
-{
- bool hasTrans = false;
- for (int i=0; i<(int)image->height && !hasTrans; i++) {
- png_bytep p = image->rows[i];
- for (int j=0; j<(int)image->width; j++) {
- if (p[(j*4)+3] != 0xFF) {
- hasTrans = true;
- break;
- }
- }
- }
-
- image->hasTransparency = hasTrans;
-}
-
static status_t do_9patch(const char* imageName, image_info* image)
{
image->is9Patch = true;
return true;
}
+static void dump_image(int w, int h, png_bytepp rows, int bpp)
+{
+ int i, j, rr, gg, bb, aa;
+
+ for (j = 0; j < h; j++) {
+ png_bytep row = rows[j];
+ for (i = 0; i < w; i++) {
+ rr = row[0];
+ gg = row[1];
+ bb = row[2];
+ aa = row[3];
+ row += bpp;
+
+ if (i == 0) {
+ printf("Row %d:", j);
+ }
+ switch (bpp) {
+ case 1:
+ printf(" (%d)", rr);
+ break;
+ case 2:
+ printf(" (%d %d", rr, gg);
+ break;
+ case 3:
+ printf(" (%d %d %d)", rr, gg, bb);
+ break;
+ case 4:
+ printf(" (%d %d %d %d)", rr, gg, bb, aa);
+ break;
+ }
+ if (i == (w - 1)) {
+ NOISY(printf("\n"));
+ }
+ }
+ }
+}
+
+#define MAX(a,b) ((a)>(b)?(a):(b))
+#define ABS(a) ((a)<0?-(a):(a))
-static void analyze_image(image_info &imageInfo, png_colorp rgbPalette, png_bytep alphaPalette,
+static void analyze_image(image_info &imageInfo, int grayscaleTolerance,
+ png_colorp rgbPalette, png_bytep alphaPalette,
int *paletteEntries, bool *hasTransparency, int *colorType,
png_bytepp outRows)
{
int w = imageInfo.width;
int h = imageInfo.height;
- bool trans = imageInfo.hasTransparency;
int i, j, rr, gg, bb, aa, idx;
uint32_t colors[256], col;
int num_colors = 0;
+ int maxGrayDeviation = 0;
bool isOpaque = true;
bool isPalette = true;
// 1. Every pixel has R == G == B (grayscale)
// 2. Every pixel has A == 255 (opaque)
// 3. There are no more than 256 distinct RGBA colors
+
+ // NOISY(printf("Initial image data:\n"));
+ // dump_image(w, h, imageInfo.rows, 4);
+
for (j = 0; j < h; j++) {
png_bytep row = imageInfo.rows[j];
png_bytep out = outRows[j];
gg = *row++;
bb = *row++;
aa = *row++;
- if (!trans) {
- // Ignore the actually byte and assume alpha == 255
- aa = 0xff;
+
+ int odev = maxGrayDeviation;
+ maxGrayDeviation = MAX(ABS(rr - gg), maxGrayDeviation);
+ maxGrayDeviation = MAX(ABS(gg - bb), maxGrayDeviation);
+ maxGrayDeviation = MAX(ABS(bb - rr), maxGrayDeviation);
+ if (maxGrayDeviation > odev) {
+ NOISY(printf("New max dev. = %d at pixel (%d, %d) = (%d %d %d %d)\n",
+ maxGrayDeviation, i, j, rr, gg, bb, aa));
}
// Check if image is really grayscale
if (isGrayscale) {
- if (rr != gg || rr != bb) {
- isGrayscale = false;
- }
+ if (rr != gg || rr != bb) {
+ NOISY(printf("Found a non-gray pixel at %d, %d = (%d %d %d %d)\n",
+ i, j, rr, gg, bb, aa));
+ isGrayscale = false;
+ }
}
// Check if image is really opaque
if (isOpaque) {
- if (aa != 0xff) {
- isOpaque = false;
- }
+ if (aa != 0xff) {
+ NOISY(printf("Found a non-opaque pixel at %d, %d = (%d %d %d %d)\n",
+ i, j, rr, gg, bb, aa));
+ isOpaque = false;
+ }
}
// Check if image is really <= 256 colors
*out++ = idx;
if (!match) {
if (num_colors == 256) {
+ NOISY(printf("Found 257th color at %d, %d\n", i, j));
isPalette = false;
} else {
colors[num_colors++] = col;
int bpp = isOpaque ? 3 : 4;
int paletteSize = w * h + bpp * num_colors;
+ NOISY(printf("isGrayscale = %s\n", isGrayscale ? "true" : "false"));
+ NOISY(printf("isOpaque = %s\n", isOpaque ? "true" : "false"));
+ NOISY(printf("isPalette = %s\n", isPalette ? "true" : "false"));
+ NOISY(printf("Size w/ palette = %d, gray+alpha = %d, rgb(a) = %d\n",
+ paletteSize, 2 * w * h, bpp * w * h));
+ NOISY(printf("Max gray deviation = %d, tolerance = %d\n", maxGrayDeviation, grayscaleTolerance));
+
// Choose the best color type for the image.
// 1. Opaque gray - use COLOR_TYPE_GRAY at 1 byte/pixel
// 2. Gray + alpha - use COLOR_TYPE_PALETTE if the number of distinct combinations
} else if (isPalette && (paletteSize < bpp * w * h)) {
*colorType = PNG_COLOR_TYPE_PALETTE;
} else {
- *colorType = isOpaque ? PNG_COLOR_TYPE_RGB : PNG_COLOR_TYPE_RGB_ALPHA;
+ if (maxGrayDeviation <= grayscaleTolerance) {
+ NOISY(printf("Forcing image to gray (max deviation = %d)\n", maxGrayDeviation));
+ *colorType = isOpaque ? PNG_COLOR_TYPE_GRAY : PNG_COLOR_TYPE_GRAY_ALPHA;
+ } else {
+ *colorType = isOpaque ? PNG_COLOR_TYPE_RGB : PNG_COLOR_TYPE_RGB_ALPHA;
+ }
}
// Perform postprocessing of the image or palette data based on the final
bb = *row++;
aa = *row++;
- *out++ = rr;
+ if (isGrayscale) {
+ *out++ = rr;
+ } else {
+ *out++ = (png_byte) (rr * 0.2126f + gg * 0.7152f + bb * 0.0722f);
+ }
if (!isOpaque) {
*out++ = aa;
}
- }
+ }
}
}
}
static void write_png(const char* imageName,
png_structp write_ptr, png_infop write_info,
- image_info& imageInfo)
+ image_info& imageInfo, int grayscaleTolerance)
{
bool optimize = true;
png_uint_32 width, height;
png_set_compression_level(write_ptr, Z_BEST_COMPRESSION);
- NOISY(printf("Writing image %s: w = %d, h = %d, trans = %s\n", imageName,
- (int) imageInfo.width, (int) imageInfo.height,
- imageInfo.hasTransparency ? "true" : "false"));
+ NOISY(printf("Writing image %s: w = %d, h = %d\n", imageName,
+ (int) imageInfo.width, (int) imageInfo.height));
png_color rgbPalette[256];
png_byte alphaPalette[256];
bool hasTransparency;
int paletteEntries;
- if (optimize) {
- analyze_image(imageInfo, rgbPalette, alphaPalette, &paletteEntries, &hasTransparency,
- &color_type, outRows);
- switch (color_type) {
- case PNG_COLOR_TYPE_PALETTE:
- NOISY(printf("Image %s has %d colors%s, using PNG_COLOR_TYPE_PALETTE\n",
- imageName, paletteEntries,
- hasTransparency ? " (with alpha)" : ""));
- break;
- case PNG_COLOR_TYPE_GRAY:
- NOISY(printf("Image %s is opaque gray, using PNG_COLOR_TYPE_GRAY\n", imageName));
- break;
- case PNG_COLOR_TYPE_GRAY_ALPHA:
- NOISY(printf("Image %s is gray + alpha, using PNG_COLOR_TYPE_GRAY_ALPHA\n", imageName));
- break;
- case PNG_COLOR_TYPE_RGB:
- NOISY(printf("Image %s is opaque RGB, using PNG_COLOR_TYPE_RGB\n", imageName));
- break;
- case PNG_COLOR_TYPE_RGB_ALPHA:
- NOISY(printf("Image %s is RGB + alpha, using PNG_COLOR_TYPE_RGB_ALPHA\n", imageName));
- break;
- }
- } else {
- // Force RGB or RGB_ALPHA color type, copy transparency from input
- paletteEntries = 0;
- hasTransparency = imageInfo.hasTransparency;
- color_type = hasTransparency ? PNG_COLOR_TYPE_RGB_ALPHA : PNG_COLOR_TYPE_RGB;
+ analyze_image(imageInfo, grayscaleTolerance, rgbPalette, alphaPalette,
+ &paletteEntries, &hasTransparency, &color_type, outRows);
+ switch (color_type) {
+ case PNG_COLOR_TYPE_PALETTE:
+ NOISY(printf("Image %s has %d colors%s, using PNG_COLOR_TYPE_PALETTE\n",
+ imageName, paletteEntries,
+ hasTransparency ? " (with alpha)" : ""));
+ break;
+ case PNG_COLOR_TYPE_GRAY:
+ NOISY(printf("Image %s is opaque gray, using PNG_COLOR_TYPE_GRAY\n", imageName));
+ break;
+ case PNG_COLOR_TYPE_GRAY_ALPHA:
+ NOISY(printf("Image %s is gray + alpha, using PNG_COLOR_TYPE_GRAY_ALPHA\n", imageName));
+ break;
+ case PNG_COLOR_TYPE_RGB:
+ NOISY(printf("Image %s is opaque RGB, using PNG_COLOR_TYPE_RGB\n", imageName));
+ break;
+ case PNG_COLOR_TYPE_RGB_ALPHA:
+ NOISY(printf("Image %s is RGB + alpha, using PNG_COLOR_TYPE_RGB_ALPHA\n", imageName));
+ break;
}
png_set_IHDR(write_ptr, write_info, imageInfo.width, imageInfo.height,
}
png_write_info(write_ptr, write_info);
-
- if (!imageInfo.hasTransparency) {
- png_set_filler(write_ptr, 0, PNG_FILLER_AFTER);
- }
+ png_bytepp rows;
if (color_type == PNG_COLOR_TYPE_RGB || color_type == PNG_COLOR_TYPE_RGB_ALPHA) {
- png_write_image(write_ptr, imageInfo.rows);
+ png_set_filler(write_ptr, 0, PNG_FILLER_AFTER);
+ rows = imageInfo.rows;
} else {
- png_write_image(write_ptr, outRows);
- }
+ rows = outRows;
+ }
+ png_write_image(write_ptr, rows);
+
+// int bpp;
+// if (color_type == PNG_COLOR_TYPE_PALETTE || color_type == PNG_COLOR_TYPE_GRAY) {
+// bpp = 1;
+// } else if (color_type == PNG_COLOR_TYPE_GRAY_ALPHA) {
+// bpp = 2;
+// } else if (color_type == PNG_COLOR_TYPE_RGB) {
+// bpp = 4;
+// } else if (color_type == PNG_COLOR_TYPE_RGB_ALPHA) {
+// bpp = 4;
+// } else {
+// printf("Uknknown color type %d, exiting.\n", color_type);
+// exit(1);
+// }
+// NOISY(printf("Final image data:\n"));
+// dump_image(imageInfo.width, imageInfo.height, rows, bpp);
png_write_end(write_ptr, write_info);
read_png(printableName.string(), read_ptr, read_info, &imageInfo);
- examine_image(&imageInfo);
-
if (nameLen > 6) {
const char* name = file->getPath().string();
if (name[nameLen-5] == '9' && name[nameLen-6] == '.') {
goto bail;
}
- write_png(printableName.string(), write_ptr, write_info, imageInfo);
+ write_png(printableName.string(), write_ptr, write_info, imageInfo,
+ bundle->getGrayscaleTolerance());
error = NO_ERROR;
" xmltree Print the compiled xmls in the given assets.\n"
" xmlstrings Print the strings of the given compiled xml assets.\n\n", gProgName);
fprintf(stderr,
- " %s p[ackage] [-f][-u][-m][-v][-x][-M AndroidManifest.xml] \\\n"
+ " %s p[ackage] [-d][-f][-m][-u][-v][-x][-z][-M AndroidManifest.xml] \\\n"
" [-0 extension [-0 extension ...]] \\\n"
+ " [-g tolerance] \\\n"
+ " [-j jarfile] \\\n"
" [-I base-package [-I base-package ...]] \\\n"
" [-A asset-source-dir] [-P public-definitions-file] \\\n"
- " [-S resource-sources] [-F apk-file] [-J R-file-dir] \\\n"
+ " [-S resource-sources [-S resource-sources ...]] "
+ " [-F apk-file] [-J R-file-dir] \\\n"
" [raw-files-dir [raw-files-dir] ...]\n"
"\n"
" Package the android resources. It will read assets and resources that are\n"
" port,land,zz_ZZ\n"
" -d one or more device assets to include, separated by commas\n"
" -f force overwrite of existing files\n"
+ " -g specify a pixel tolerance to force images to grayscale, default 0\n"
" -j specify a jar or zip file containing classes to include\n"
" -m make package directories under location specified by -J\n"
#if 0
" -J specify where to output R.java resource constant definitions\n"
" -M specify full path to AndroidManifest.xml to include in zip\n"
" -P specify where to output public resource definitions\n"
- " -S directory in which to find resources\n"
+ " -S directory in which to find resources. Multiple directories will be scanned"
+ " and the first match found (left to right) will take precedence."
" -0 specifies an additional extension for which such files will not\n"
" be stored compressed in the .apk. An empty string means to not\n"
" compress any files at all.\n");
case 'f':
bundle.setForce(true);
break;
+ case 'g':
+ argc--;
+ argv++;
+ if (!argc) {
+ fprintf(stderr, "ERROR: No argument supplied for '-g' option\n");
+ wantUsage = true;
+ goto bail;
+ }
+ bundle.setGrayscaleTolerance(atoi(argv[0]));
+ break;
case 'm':
bundle.setMakePackageDirs(true);
break;
goto bail;
}
convertPath(argv[0]);
- bundle.setResourceSourceDir(argv[0]);
+ bundle.addResourceSourceDir(argv[0]);
break;
case '0':
argc--;
}
}
+static void applyFileOverlay(const sp<AaptAssets>& assets,
+ const sp<ResourceTypeSet>& baseSet,
+ const char *resType)
+{
+ // Replace any base level files in this category with any found from the overlay
+ // Also add any found only in the overlay.
+ sp<AaptAssets> overlay = assets->getOverlay();
+ String8 resTypeString(resType);
+
+ // work through the linked list of overlays
+ while (overlay.get()) {
+ KeyedVector<String8, sp<ResourceTypeSet> >* overlayRes = overlay->getResources();
+
+ // get the overlay resources of the requested type
+ ssize_t index = overlayRes->indexOfKey(resTypeString);
+ if (index >= 0) {
+ sp<ResourceTypeSet> overlaySet = overlayRes->valueAt(index);
+
+ // for each of the resources, check for a match in the previously built
+ // non-overlay "baseset".
+ size_t overlayCount = overlaySet->size();
+ for (size_t overlayIndex=0; overlayIndex<overlayCount; overlayIndex++) {
+ size_t baseIndex = baseSet->indexOfKey(overlaySet->keyAt(overlayIndex));
+ if (baseIndex != UNKNOWN_ERROR) {
+ // look for same flavor. For a given file (strings.xml, for example)
+ // there may be a locale specific or other flavors - we want to match
+ // the same flavor.
+ sp<AaptGroup> overlayGroup = overlaySet->valueAt(overlayIndex);
+ sp<AaptGroup> baseGroup = baseSet->valueAt(baseIndex);
+
+ DefaultKeyedVector<AaptGroupEntry, sp<AaptFile> > baseFiles =
+ baseGroup->getFiles();
+ DefaultKeyedVector<AaptGroupEntry, sp<AaptFile> > overlayFiles =
+ overlayGroup->getFiles();
+ size_t overlayGroupSize = overlayFiles.size();
+ for (size_t overlayGroupIndex = 0;
+ overlayGroupIndex<overlayGroupSize;
+ overlayGroupIndex++) {
+ size_t baseFileIndex =
+ baseFiles.indexOfKey(overlayFiles.keyAt(overlayGroupIndex));
+ if(baseFileIndex < UNKNOWN_ERROR) {
+ baseGroup->removeFile(baseFileIndex);
+ } else {
+ // didn't find a match fall through and add it..
+ }
+ baseGroup->addFile(overlayFiles.valueAt(overlayGroupIndex));
+ }
+ } else {
+ // this group doesn't exist (a file that's only in the overlay)
+ // add it
+ baseSet->add(overlaySet->keyAt(overlayIndex),
+ overlaySet->valueAt(overlayIndex));
+ }
+ }
+ // this overlay didn't have resources for this type
+ }
+ // try next overlay
+ overlay = overlay->getOverlay();
+ }
+ return;
+}
+
#define ASSIGN_IT(n) \
do { \
- ssize_t index = resources.indexOfKey(String8(#n)); \
+ ssize_t index = resources->indexOfKey(String8(#n)); \
if (index >= 0) { \
- n ## s = resources.valueAt(index); \
+ n ## s = resources->valueAt(index); \
} \
} while (0)
NOISY(printf("Found %d included resource packages\n", (int)table.size()));
- sp<AaptDir> res = assets->getDirs().valueFor(String8("res"));
-
// --------------------------------------------------------------
// First, gather all resource information.
// --------------------------------------------------------------
// resType -> leafName -> group
- KeyedVector<String8, sp<ResourceTypeSet> > resources;
- collect_files(assets, &resources);
+ KeyedVector<String8, sp<ResourceTypeSet> > *resources =
+ new KeyedVector<String8, sp<ResourceTypeSet> >;
+ collect_files(assets, resources);
sp<ResourceTypeSet> drawables;
- sp<ResourceTypeSet> valuess;
sp<ResourceTypeSet> layouts;
sp<ResourceTypeSet> anims;
sp<ResourceTypeSet> xmls;
ASSIGN_IT(anim);
ASSIGN_IT(xml);
ASSIGN_IT(raw);
- ASSIGN_IT(values);
ASSIGN_IT(color);
ASSIGN_IT(menu);
+ assets->setResources(resources);
+ // now go through any resource overlays and collect their files
+ sp<AaptAssets> current = assets->getOverlay();
+ while(current.get()) {
+ KeyedVector<String8, sp<ResourceTypeSet> > *resources =
+ new KeyedVector<String8, sp<ResourceTypeSet> >;
+ current->setResources(resources);
+ collect_files(current, resources);
+ current = current->getOverlay();
+ }
+ // apply the overlay files to the base set
+ applyFileOverlay(assets, drawables, "drawable");
+ applyFileOverlay(assets, layouts, "layout");
+ applyFileOverlay(assets, anims, "anim");
+ applyFileOverlay(assets, xmls, "xml");
+ applyFileOverlay(assets, raws, "raw");
+ applyFileOverlay(assets, colors, "color");
+ applyFileOverlay(assets, menus, "menu");
+
bool hasErrors = false;
if (drawables != NULL) {
}
}
- if (valuess != NULL) {
- ResourceDirIterator it(valuess, String8("values"));
- ssize_t res;
- while ((res=it.next()) == NO_ERROR) {
- sp<AaptFile> file = it.getFile();
-
- res = compileResourceFile(bundle, assets, file, it.getParams(), &table);
- if (res != NO_ERROR) {
- hasErrors = true;
+ // compile resources
+ current = assets;
+ while(current.get()) {
+ KeyedVector<String8, sp<ResourceTypeSet> > *resources =
+ current->getResources();
+
+ ssize_t index = resources->indexOfKey(String8("values"));
+ if (index >= 0) {
+ ResourceDirIterator it(resources->valueAt(index), String8("values"));
+ ssize_t res;
+ while ((res=it.next()) == NO_ERROR) {
+ sp<AaptFile> file = it.getFile();
+ res = compileResourceFile(bundle, assets, file, it.getParams(),
+ (current!=assets), &table);
+ if (res != NO_ERROR) {
+ hasErrors = true;
+ }
}
}
+ current = current->getOverlay();
}
if (colors != NULL) {
const String16& itemIdent,
int32_t curFormat,
bool pseudolocalize,
+ const bool overwrite,
ResourceTable* outTable)
{
status_t err;
err = outTable->addBag(SourcePos(in->getPrintableSource(), block->getLineNumber()),
myPackage, curType, ident, parentIdent, itemIdent, str,
- &spans, &config, false, false, curFormat);
+ &spans, &config, overwrite, false, curFormat);
return err;
}
bool curIsStyled,
int32_t curFormat,
bool pseudolocalize,
+ const bool overwrite,
ResourceTable* outTable)
{
status_t err;
err = outTable->addEntry(SourcePos(in->getPrintableSource(), block->getLineNumber()),
myPackage, curType, ident, str, &spans, &config,
- false, curFormat);
+ false, curFormat, overwrite);
return err;
}
const sp<AaptAssets>& assets,
const sp<AaptFile>& in,
const ResTable_config& defParams,
+ const bool overwrite,
ResourceTable* outTable)
{
ResXMLTree block;
if (locale.size() > 0) {
fprintf(stderr, "aapt: warning: string '%s' in %s marked untranslatable but exists"
" in locale '%s'\n", String8(name).string(),
- bundle->getResourceSourceDir(),
+ bundle->getResourceSourceDirs()[0],
locale.string());
// hasErrors = localHasErrors = true;
} else {
block.getPosition(&parserPosition);
err = parseAndAddBag(bundle, in, &block, curParams, myPackage, curType,
- ident, parentIdent, itemIdent, curFormat, false, outTable);
+ ident, parentIdent, itemIdent, curFormat,
+ false, overwrite, outTable);
if (err == NO_ERROR) {
if (curIsPseudolocalizable && localeIsDefined(curParams)
&& bundle->getPseudolocalize()) {
block.setPosition(parserPosition);
err = parseAndAddBag(bundle, in, &block, pseudoParams, myPackage,
curType, ident, parentIdent, itemIdent, curFormat, true,
- outTable);
+ overwrite, outTable);
#endif
}
}
block.getPosition(&parserPosition);
err = parseAndAddEntry(bundle, in, &block, curParams, myPackage, curType, ident,
- *curTag, curIsStyled, curFormat, false, outTable);
+ *curTag, curIsStyled, curFormat, false, overwrite, outTable);
if (err < NO_ERROR) { // Why err < NO_ERROR instead of err != NO_ERROR?
hasErrors = localHasErrors = true;
// pseudolocalize here
block.setPosition(parserPosition);
err = parseAndAddEntry(bundle, in, &block, pseudoParams, myPackage, curType,
- ident, *curTag, curIsStyled, curFormat, true, outTable);
+ ident, *curTag, curIsStyled, curFormat, true, false, outTable);
if (err != NO_ERROR) {
hasErrors = localHasErrors = true;
}
const Vector<StringPool::entry_style_span>* style,
const ResTable_config* params,
const bool doSetIndex,
- const int32_t format)
+ const int32_t format,
+ const bool overwrite)
{
// Check for adding entries in other packages... for now we do
// nothing. We need to do the right thing here to support skinning.
if (e == NULL) {
return UNKNOWN_ERROR;
}
- status_t err = e->setItem(sourcePos, value, style, format);
+ status_t err = e->setItem(sourcePos, value, style, format, overwrite);
if (err == NO_ERROR) {
mNumLocal++;
}
// Look for strings with no default localization
if (configSet.count(defaultLocale) == 0) {
fprintf(stdout, "aapt: warning: string '%s' has no default translation in %s; found:",
- String8(nameIter->first).string(), mBundle->getResourceSourceDir());
+ String8(nameIter->first).string(), mBundle->getResourceSourceDirs()[0]);
for (set<String8>::iterator locales = configSet.begin();
locales != configSet.end();
locales++) {
"for '%s' in %s\n",
String8(nameIter->first).string(),
config.string(),
- mBundle->getResourceSourceDir());
+ mBundle->getResourceSourceDirs()[0]);
//err = UNKNOWN_ERROR;
}
}
status_t ResourceTable::Entry::setItem(const SourcePos& sourcePos,
const String16& value,
const Vector<StringPool::entry_style_span>* style,
- int32_t format)
+ int32_t format,
+ const bool overwrite)
{
Item item(sourcePos, false, value, style);
item.sourcePos.file.string(), item.sourcePos.line);
return UNKNOWN_ERROR;
}
- if (mType != TYPE_UNKNOWN) {
+ if ( (mType != TYPE_UNKNOWN) && (overwrite == false) ) {
sourcePos.error("Resource entry %s is already defined.\n"
"%s:%d: Originally defined here.\n",
String8(mName).string(),
const sp<AaptAssets>& assets,
const sp<AaptFile>& in,
const ResTable_config& defParams,
+ const bool overwrite,
ResourceTable* outTable);
struct AccessorCookie
const Vector<StringPool::entry_style_span>* style = NULL,
const ResTable_config* params = NULL,
const bool doSetIndex = false,
- const int32_t format = ResTable_map::TYPE_ANY);
+ const int32_t format = ResTable_map::TYPE_ANY,
+ const bool overwrite = false);
status_t startBag(const SourcePos& pos,
const String16& package,
status_t setItem(const SourcePos& pos,
const String16& value,
const Vector<StringPool::entry_style_span>* style = NULL,
- int32_t format = ResTable_map::TYPE_ANY);
+ int32_t format = ResTable_map::TYPE_ANY,
+ const bool overwrite = false);
status_t addToBag(const SourcePos& pos,
const String16& key, const String16& value,