]> git.saurik.com Git - android/aapt.git/blobdiff - Resource.cpp
merge from open-source master
[android/aapt.git] / Resource.cpp
index fd6ddb5796ae80734709da2e25ae4bb93a47040f..41ee88b4451c1bc90162a62f4b5883262c32cd25 100644 (file)
@@ -45,13 +45,6 @@ static String8 parseResourceName(const String8& leaf)
     }
 }
 
-class ResourceTypeSet : public RefBase,
-                        public KeyedVector<String8,sp<AaptGroup> >
-{
-public:
-    ResourceTypeSet();
-};
-
 ResourceTypeSet::ResourceTypeSet()
     :RefBase(),
      KeyedVector<String8,sp<AaptGroup> >()
@@ -181,7 +174,7 @@ static sp<AaptFile> getResourceFile(const sp<AaptAssets>& assets, bool makeIfNec
 static status_t parsePackage(const sp<AaptAssets>& assets, const sp<AaptGroup>& grp)
 {
     if (grp->getFiles().size() != 1) {
-        fprintf(stderr, "WARNING: Multiple AndroidManifest.xml files found, using %s\n",
+        fprintf(stderr, "warning: Multiple AndroidManifest.xml files found, using %s\n",
                 grp->getFiles().valueAt(0)->getPrintableSource().string());
     }
 
@@ -426,18 +419,133 @@ static void checkForIds(const String8& path, ResXMLParser& parser)
         if (code == ResXMLTree::START_TAG) {
             ssize_t index = parser.indexOfAttribute(NULL, "id");
             if (index >= 0) {
-                fprintf(stderr, "%s:%d: WARNING: found plain 'id' attribute; did you mean the new 'android:id' name?\n",
+                fprintf(stderr, "%s:%d: warning: found plain 'id' attribute; did you mean the new 'android:id' name?\n",
                         path.string(), parser.getLineNumber());
             }
         }
     }
 }
 
+static bool 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)
+                    fprintf(stderr, "aapt: error: "
+                            "*** Resource file '%s' exists only in an overlay\n",
+                            overlaySet->keyAt(overlayIndex).string());
+                    return false;
+                }
+            }
+            // this overlay didn't have resources for this type
+        }
+        // try next overlay
+        overlay = overlay->getOverlay();
+    }
+    return true;
+}
+
+void addTagAttribute(const sp<XMLNode>& node, const char* ns8,
+        const char* attr8, const char* value)
+{
+    if (value == NULL) {
+        return;
+    }
+    
+    const String16 ns(ns8);
+    const String16 attr(attr8);
+    
+    if (node->getAttribute(ns, attr) != NULL) {
+        fprintf(stderr, "Warning: AndroidManifest.xml already defines %s (in %s)\n",
+                String8(attr).string(), String8(ns).string());
+        return;
+    }
+    
+    node->addAttribute(ns, attr, String16(value));
+}
+
+status_t massageManifest(Bundle* bundle, sp<XMLNode> root)
+{
+    root = root->searchElement(String16(), String16("manifest"));
+    if (root == NULL) {
+        fprintf(stderr, "No <manifest> tag.\n");
+        return UNKNOWN_ERROR;
+    }
+    
+    addTagAttribute(root, RESOURCES_ANDROID_NAMESPACE, "versionCode",
+            bundle->getVersionCode());
+    addTagAttribute(root, RESOURCES_ANDROID_NAMESPACE, "versionName",
+            bundle->getVersionName());
+    
+    if (bundle->getMinSdkVersion() != NULL
+            || bundle->getTargetSdkVersion() != NULL
+            || bundle->getMaxSdkVersion() != NULL) {
+        sp<XMLNode> vers = root->getChildElement(String16(), String16("uses-sdk"));
+        if (vers == NULL) {
+            vers = XMLNode::newElement(root->getFilename(), String16(), String16("uses-sdk"));
+            root->insertChildAt(vers, 0);
+        }
+        
+        addTagAttribute(vers, RESOURCES_ANDROID_NAMESPACE, "minSdkVersion",
+                bundle->getMinSdkVersion());
+        addTagAttribute(vers, RESOURCES_ANDROID_NAMESPACE, "targetSdkVersion",
+                bundle->getTargetSdkVersion());
+        addTagAttribute(vers, RESOURCES_ANDROID_NAMESPACE, "maxSdkVersion",
+                bundle->getMaxSdkVersion());
+    }
+    
+    return NO_ERROR;
+}
+
 #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 +576,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 +598,30 @@ 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
+    if (!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")) {
+        return UNKNOWN_ERROR;
+    }
+
     bool hasErrors = false;
 
     if (drawables != NULL) {
@@ -538,17 +664,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) {
@@ -926,7 +1061,15 @@ status_t buildResources(Bundle* bundle, const sp<AaptAssets>& assets)
 
     // Generate final compiled manifest file.
     manifestFile->clearData();
-    err = compileXmlFile(assets, manifestFile, &table);
+    sp<XMLNode> manifestTree = XMLNode::parse(manifestFile);
+    if (manifestTree == NULL) {
+        return UNKNOWN_ERROR;
+    }
+    err = massageManifest(bundle, manifestTree);
+    if (err < NO_ERROR) {
+        return err;
+    }
+    err = compileXmlFile(assets, manifestTree, manifestFile, &table);
     if (err < NO_ERROR) {
         return err;
     }
@@ -968,6 +1111,7 @@ status_t buildResources(Bundle* bundle, const sp<AaptAssets>& assets)
                 printf("  Writing public definitions to %s.\n", bundle->getPublicOutputFile());
             }
             table.writePublicDefinitions(String16(assets->getPackage()), fp);
+            fclose(fp);
         }
 
         NOISY(
@@ -985,7 +1129,6 @@ status_t buildResources(Bundle* bundle, const sp<AaptAssets>& assets)
             return err;
         }
     }
-
     return err;
 }