]> git.saurik.com Git - android/aapt.git/commitdiff
auto import from //branches/cupcake/...@126645
authorThe Android Open Source Project <initial-contribution@android.com>
Fri, 16 Jan 2009 00:12:10 +0000 (16:12 -0800)
committerThe Android Open Source Project <initial-contribution@android.com>
Fri, 16 Jan 2009 00:12:10 +0000 (16:12 -0800)
AaptAssets.cpp
AaptAssets.h
Bundle.h
Command.cpp
Images.cpp
Main.cpp
Resource.cpp
ResourceTable.cpp
ResourceTable.h

index 027662d84d26ef4caba55a4e09c1192311719c86..6bc1ee6cbfbc5bd67197fefbec19deeca3b4d6e3 100644 (file)
@@ -17,7 +17,6 @@ static const char* kWildcardName = "any";
 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);
@@ -100,7 +99,7 @@ static bool isHidden(const char *root, const char *path)
 
     return true;
 }
+
 // =========================================================================
 // =========================================================================
 // =========================================================================
@@ -159,28 +158,28 @@ AaptGroupEntry::parseNamePart(const String8& part, int* axis, uint32_t* value)
         *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;
@@ -319,7 +318,7 @@ AaptGroupEntry::initFromDirName(const char* dir, String8* resType)
     // touchscreen
     if (getTouchscreenName(part.string())) {
         touch = part;
-        
+
         index++;
         if (index == N) {
             goto success;
@@ -328,11 +327,11 @@ AaptGroupEntry::initFromDirName(const char* dir, String8* resType)
     } else {
         //printf("not touchscreen: %s\n", part.string());
     }
-    
+
     // keyboard hidden
     if (getKeysHiddenName(part.string())) {
         keysHidden = part;
-        
+
         index++;
         if (index == N) {
             goto success;
@@ -341,11 +340,11 @@ AaptGroupEntry::initFromDirName(const char* dir, String8* resType)
     } else {
         //printf("not keysHidden: %s\n", part.string());
     }
-    
+
     // keyboard
     if (getKeyboardName(part.string())) {
         key = part;
-        
+
         index++;
         if (index == N) {
             goto success;
@@ -354,10 +353,10 @@ AaptGroupEntry::initFromDirName(const char* dir, String8* resType)
     } else {
         //printf("not keyboard: %s\n", part.string());
     }
-    
+
     if (getNavigationName(part.string())) {
         nav = part;
-        
+
         index++;
         if (index == N) {
             goto success;
@@ -366,10 +365,10 @@ AaptGroupEntry::initFromDirName(const char* dir, String8* resType)
     } else {
         //printf("not navigation: %s\n", part.string());
     }
-    
+
     if (getScreenSizeName(part.string())) {
         size = part;
-        
+
         index++;
         if (index == N) {
             goto success;
@@ -378,10 +377,10 @@ AaptGroupEntry::initFromDirName(const char* dir, String8* resType)
     } else {
         //printf("not screen size: %s\n", part.string());
     }
-    
+
     if (getVersionName(part.string())) {
         vers = part;
-        
+
         index++;
         if (index == N) {
             goto success;
@@ -390,7 +389,7 @@ AaptGroupEntry::initFromDirName(const char* dir, String8* resType)
     } else {
         //printf("not version: %s\n", part.string());
     }
-    
+
     // if there are extra parts, it doesn't match
     return false;
 
@@ -488,7 +487,7 @@ AaptGroupEntry::toDirName(const String8& resType) const
         s += "-";
         s += version;
     }
-    
+
     return s;
 }
 
@@ -506,9 +505,9 @@ bool AaptGroupEntry::getMccName(const char* name,
     c++;
     if (tolower(*c) != 'c') return false;
     c++;
-    
+
     const char* val = c;
-    
+
     while (*c >= '0' && *c <= '9') {
         c++;
     }
@@ -538,9 +537,9 @@ bool AaptGroupEntry::getMncName(const char* name,
     c++;
     if (tolower(*c) != 'c') return false;
     c++;
-    
+
     const char* val = c;
-    
+
     while (*c >= '0' && *c <= '9') {
         c++;
     }
@@ -621,7 +620,7 @@ bool AaptGroupEntry::getOrientationName(const char* name,
         if (out) out->orientation = out->ORIENTATION_SQUARE;
         return true;
     }
-    
+
     return false;
 }
 
@@ -677,7 +676,7 @@ bool AaptGroupEntry::getTouchscreenName(const char* name,
         if (out) out->touchscreen = out->TOUCHSCREEN_FINGER;
         return true;
     }
-    
+
     return false;
 }
 
@@ -699,12 +698,12 @@ bool AaptGroupEntry::getKeysHiddenName(const char* name,
         mask = out->MASK_KEYSHIDDEN;
         value = out->KEYSHIDDEN_SOFT;
     }
-    
+
     if (mask != 0) {
         if (out) out->inputFlags = (out->inputFlags&~mask) | value;
         return true;
     }
-    
+
     return false;
 }
 
@@ -724,7 +723,7 @@ bool AaptGroupEntry::getKeyboardName(const char* name,
         if (out) out->keyboard = out->KEYBOARD_12KEY;
         return true;
     }
-    
+
     return false;
 }
 
@@ -747,7 +746,7 @@ bool AaptGroupEntry::getNavigationName(const char* name,
         if (out) out->navigation = out->NAVIGATION_WHEEL;
         return true;
     }
-    
+
     return false;
 }
 
@@ -761,29 +760,29 @@ bool AaptGroupEntry::getScreenSizeName(const char* name,
         }
         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;
 }
 
@@ -797,22 +796,22 @@ bool AaptGroupEntry::getVersionName(const char* name,
         }
         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;
 }
 
@@ -1081,29 +1080,29 @@ ssize_t AaptDir::slurpFullTree(Bundle* bundle, const String8& srcDir,
 
     {
         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);
     }
 
@@ -1315,7 +1314,7 @@ void AaptAssets::addResource(const String8& leafName, const String8& path,
     sp<AaptDir> subdir = res->makeDir(dirname);
     sp<AaptGroup> grr = new AaptGroup(leafName, path);
     grr->addFile(file);
-    
+
     subdir->addFile(leafName, grr);
 }
 
@@ -1324,10 +1323,10 @@ ssize_t AaptAssets::slurpFromArgs(Bundle* bundle)
 {
     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();
 
@@ -1380,28 +1379,35 @@ ssize_t AaptAssets::slurpFromArgs(Bundle* bundle)
     /*
      * 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.
      */
index 6ab0ae542defdc3f5630d4952c09592854ee2e9d..01c8140b25ce09683d917df04e61ab3efc290fc7 100644 (file)
@@ -441,6 +441,8 @@ private:
     AaptSymbolEntry                                 mDefSymbol;
 };
 
+class ResourceTypeSet;
+
 /**
  * Asset hierarchy being operated on.
  */
@@ -491,6 +493,13 @@ public:
 
     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;
@@ -501,6 +510,9 @@ private:
 
     bool mHaveIncludedAssets;
     AssetManager mIncludedAssets;
+
+    sp<AaptAssets> mOverlay;
+    KeyedVector<String8, sp<ResourceTypeSet> >* mRes;
 };
 
 #endif // __AAPT_ASSETS_H
index 99fac2fa23892b5755b379dac45f17dee8d0308a..2d8471bb5cc64f686594983c0cd06f327c218657 100644 (file)
--- a/Bundle.h
+++ b/Bundle.h
@@ -31,11 +31,11 @@ class Bundle {
 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)
@@ -58,6 +58,8 @@ public:
     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; }
@@ -78,8 +80,8 @@ public:
      */
     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; }
@@ -130,6 +132,7 @@ private:
     bool        mVerbose;
     bool        mAndroidList;
     bool        mForce;
+    int         mGrayscaleTolerance;
     bool        mMakePackageDirs;
     bool        mUpdate;
     bool        mExtending;
@@ -138,7 +141,6 @@ private:
     int         mCompressionMethod;
     const char* mOutputAPKFile;
     const char* mAssetSourceDir;
-    const char* mResourceSourceDir;
     const char* mAndroidManifestFile;
     const char* mPublicOutputFile;
     const char* mRClassDir;
@@ -147,7 +149,8 @@ private:
     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;
index 9f75d4bec4ad98d7ac8c4209aa420f787b5959e9..bff0423c45c5fd5f50b84ed3b3dd0a643e1e4372 100644 (file)
@@ -761,7 +761,7 @@ int doPackage(Bundle* bundle)
     }
 
     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;
@@ -793,7 +793,7 @@ int doPackage(Bundle* bundle)
     }
 
     // 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;
index 7c4963fb6ec82c45dcff77b33a0b445b9a59e7b6..a516a5a632984f96f1d00e63935c90f3e7c2ae50 100644 (file)
@@ -33,7 +33,7 @@ png_flush_aapt_file(png_structp png_ptr)
 // 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);
@@ -50,8 +50,6 @@ struct image_info
     png_uint_32 height;
     png_bytepp rows;
 
-    bool hasTransparency;
-
     // 9-patch info.
     bool is9Patch;
     Res_png_9patch info9Patch;
@@ -326,22 +324,6 @@ static uint32_t get_color(image_info* image, int hpatch, int vpatch)
     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;
@@ -618,17 +600,57 @@ static bool patch_equals(Res_png_9patch& patch1, Res_png_9patch& patch2) {
     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;
@@ -638,6 +660,10 @@ static void analyze_image(image_info &imageInfo, png_colorp rgbPalette, png_byte
     // 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];
@@ -646,23 +672,32 @@ static void analyze_image(image_info &imageInfo, png_colorp rgbPalette, png_byte
             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
@@ -682,6 +717,7 @@ static void analyze_image(image_info &imageInfo, png_colorp rgbPalette, png_byte
                 *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;
@@ -696,6 +732,13 @@ static void analyze_image(image_info &imageInfo, png_colorp rgbPalette, png_byte
     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
@@ -719,7 +762,12 @@ static void analyze_image(image_info &imageInfo, png_colorp rgbPalette, png_byte
     } 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
@@ -748,11 +796,15 @@ static void analyze_image(image_info &imageInfo, png_colorp rgbPalette, png_byte
                 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;
                 }
-            }
+           }
         }
     }
 }
@@ -760,7 +812,7 @@ static void analyze_image(image_info &imageInfo, png_colorp rgbPalette, png_byte
 
 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;
@@ -785,42 +837,34 @@ static void write_png(const char* imageName,
 
     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,
@@ -856,16 +900,31 @@ static void write_png(const char* imageName,
     }
 
     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);
 
@@ -937,8 +996,6 @@ status_t preProcessImage(Bundle* bundle, const sp<AaptAssets>& assets,
 
     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] == '.') {
@@ -969,7 +1026,8 @@ status_t preProcessImage(Bundle* bundle, const sp<AaptAssets>& assets,
         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;
 
index a1978da37f366fabd68c7421c12728fb3827838b..ee0dbad49a6d5916e6262a3adcc3d7ad58594fb9 100644 (file)
--- a/Main.cpp
+++ b/Main.cpp
@@ -53,11 +53,14 @@ void usage(void)
         "   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"
@@ -91,6 +94,7 @@ void usage(void)
         "            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
@@ -107,7 +111,8 @@ void usage(void)
         "   -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");
@@ -201,6 +206,16 @@ int main(int argc, char* const argv[])
             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;
@@ -304,7 +319,7 @@ int main(int argc, char* const argv[])
                     goto bail;
                 }
                 convertPath(argv[0]);
-                bundle.setResourceSourceDir(argv[0]);
+                bundle.addResourceSourceDir(argv[0]);
                 break;
             case '0':
                 argc--;
index fd6ddb5796ae80734709da2e25ae4bb93a47040f..b2bd9ffc35eca9628acec0b2919766908a735e88 100644 (file)
@@ -433,11 +433,73 @@ static void checkForIds(const String8& path, ResXMLParser& parser)
     }
 }
 
+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)
 
@@ -468,18 +530,16 @@ status_t buildResources(Bundle* bundle, const sp<AaptAssets>& assets)
 
     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;
@@ -492,10 +552,28 @@ status_t buildResources(Bundle* bundle, const sp<AaptAssets>& assets)
     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) {
@@ -538,17 +616,26 @@ status_t buildResources(Bundle* bundle, const sp<AaptAssets>& assets)
         }
     }
 
-    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) {
index 33f8f721bd6227f5e2cd1a3a8894384b2e76988f..877763dd4777d6decfff8b912798c0effde8a21c 100644 (file)
@@ -546,6 +546,7 @@ status_t parseAndAddBag(Bundle* bundle,
                         const String16& itemIdent,
                         int32_t curFormat,
                         bool pseudolocalize,
+                        const bool overwrite,
                         ResourceTable* outTable)
 {
     status_t err;
@@ -572,7 +573,7 @@ status_t parseAndAddBag(Bundle* bundle,
 
     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;
 }
 
@@ -588,6 +589,7 @@ status_t parseAndAddEntry(Bundle* bundle,
                         bool curIsStyled,
                         int32_t curFormat,
                         bool pseudolocalize,
+                        const bool overwrite,
                         ResourceTable* outTable)
 {
     status_t err;
@@ -610,7 +612,7 @@ status_t parseAndAddEntry(Bundle* bundle,
 
     err = outTable->addEntry(SourcePos(in->getPrintableSource(), block->getLineNumber()),
                              myPackage, curType, ident, str, &spans, &config,
-                             false, curFormat);
+                             false, curFormat, overwrite);
 
     return err;
 }
@@ -619,6 +621,7 @@ status_t compileResourceFile(Bundle* bundle,
                              const sp<AaptAssets>& assets,
                              const sp<AaptFile>& in,
                              const ResTable_config& defParams,
+                             const bool overwrite,
                              ResourceTable* outTable)
 {
     ResXMLTree block;
@@ -979,7 +982,7 @@ status_t compileResourceFile(Bundle* bundle,
                         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 {
@@ -1172,7 +1175,8 @@ status_t compileResourceFile(Bundle* bundle,
                         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()) {
@@ -1181,7 +1185,7 @@ status_t compileResourceFile(Bundle* bundle,
                                 block.setPosition(parserPosition);
                                 err = parseAndAddBag(bundle, in, &block, pseudoParams, myPackage,
                                         curType, ident, parentIdent, itemIdent, curFormat, true,
-                                        outTable);
+                                        overwrite, outTable);
 #endif
                             }
                         } 
@@ -1204,7 +1208,7 @@ status_t compileResourceFile(Bundle* bundle,
                 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;
@@ -1215,7 +1219,7 @@ status_t compileResourceFile(Bundle* bundle,
                         // 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;
                         }
@@ -1360,7 +1364,8 @@ status_t ResourceTable::addEntry(const SourcePos& sourcePos,
                                  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.
@@ -1384,7 +1389,7 @@ status_t ResourceTable::addEntry(const SourcePos& sourcePos,
     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++;
     }
@@ -2125,7 +2130,7 @@ ResourceTable::validateLocalizations(void)
         // 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++) {
@@ -2167,7 +2172,7 @@ ResourceTable::validateLocalizations(void)
                                         "for '%s' in %s\n",
                                         String8(nameIter->first).string(),
                                         config.string(),
-                                        mBundle->getResourceSourceDir());
+                                        mBundle->getResourceSourceDirs()[0]);
                                 //err = UNKNOWN_ERROR;
                             }
                         }
@@ -2728,7 +2733,8 @@ status_t ResourceTable::Entry::makeItABag(const SourcePos& sourcePos)
 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);
 
@@ -2740,7 +2746,7 @@ status_t ResourceTable::Entry::setItem(const SourcePos& sourcePos,
                         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(),
index fff4f49795b0105361cde03322eab897dbfe68ec..e8fbd9b7b7c75538e9d9f13d3e6cf8bdaaeb43c1 100644 (file)
@@ -38,6 +38,7 @@ status_t compileResourceFile(Bundle* bundle,
                              const sp<AaptAssets>& assets,
                              const sp<AaptFile>& in,
                              const ResTable_config& defParams,
+                             const bool overwrite,
                              ResourceTable* outTable);
 
 struct AccessorCookie
@@ -79,7 +80,8 @@ public:
                       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,
@@ -256,7 +258,8 @@ public:
         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,