X-Git-Url: https://git.saurik.com/android/aapt.git/blobdiff_plain/e2b8897082298875339f82d006c3742086cd83dd..af945cf38e6121bb5066e4591493f78d09cba4e3:/Resource.cpp diff --git a/Resource.cpp b/Resource.cpp index 81db323..7142b1c 100644 --- a/Resource.cpp +++ b/Resource.cpp @@ -101,13 +101,13 @@ public: String8 leaf(group->getLeaf()); mLeafName = String8(leaf); mParams = file->getGroupEntry().toParams(); - NOISY(printf("Dir %s: mcc=%d mnc=%d lang=%c%c cnt=%c%c orient=%d density=%d touch=%d key=%d inp=%d nav=%d\n", + NOISY(printf("Dir %s: mcc=%d mnc=%d lang=%c%c cnt=%c%c orient=%d ui=%d density=%d touch=%d key=%d inp=%d nav=%d\n", group->getPath().string(), mParams.mcc, mParams.mnc, mParams.language[0] ? mParams.language[0] : '-', mParams.language[1] ? mParams.language[1] : '-', mParams.country[0] ? mParams.country[0] : '-', mParams.country[1] ? mParams.country[1] : '-', - mParams.orientation, + mParams.orientation, mParams.uiMode, mParams.density, mParams.touchscreen, mParams.keyboard, mParams.inputFlags, mParams.navigation)); mPath = "res"; @@ -171,10 +171,11 @@ static sp getResourceFile(const sp& assets, bool makeIfNec NULL, String8()); } -static status_t parsePackage(const sp& assets, const sp& grp) +static status_t parsePackage(Bundle* bundle, const sp& assets, + const sp& 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()); } @@ -215,6 +216,22 @@ static status_t parsePackage(const sp& assets, const sp& assets->setPackage(String8(block.getAttributeStringValue(nameIndex, &len))); + String16 uses_sdk16("uses-sdk"); + while ((code=block.next()) != ResXMLTree::END_DOCUMENT + && code != ResXMLTree::BAD_DOCUMENT) { + if (code == ResXMLTree::START_TAG) { + if (strcmp16(block.getElementName(&len), uses_sdk16.string()) == 0) { + ssize_t minSdkIndex = block.indexOfAttribute(RESOURCES_ANDROID_NAMESPACE, + "minSdkVersion"); + if (minSdkIndex >= 0) { + const uint16_t* minSdk16 = block.getAttributeStringValue(minSdkIndex, &len); + const char* minSdk8 = strdup(String8(minSdk16).string()); + bundle->setMinSdkVersion(minSdk8); + } + } + } + } + return NO_ERROR; } @@ -272,15 +289,16 @@ static status_t preProcessImages(Bundle* bundle, const sp& assets, ResourceDirIterator it(set, String8("drawable")); Vector > newNameFiles; Vector newNamePaths; + bool hasErrors = false; ssize_t res; while ((res=it.next()) == NO_ERROR) { res = preProcessImage(bundle, assets, it.getFile(), NULL); - if (res != NO_ERROR) { - return res; + if (res < NO_ERROR) { + hasErrors = true; } } - return NO_ERROR; + return (hasErrors || (res < NO_ERROR)) ? UNKNOWN_ERROR : NO_ERROR; } status_t postProcessImages(const sp& assets, @@ -288,15 +306,16 @@ status_t postProcessImages(const sp& assets, const sp& set) { ResourceDirIterator it(set, String8("drawable")); + bool hasErrors = false; ssize_t res; while ((res=it.next()) == NO_ERROR) { res = postProcessImage(assets, table, it.getFile()); - if (res != NO_ERROR) { - return res; + if (res < NO_ERROR) { + hasErrors = true; } } - return res < NO_ERROR ? res : (status_t)NO_ERROR; + return (hasErrors || (res < NO_ERROR)) ? UNKNOWN_ERROR : NO_ERROR; } static void collect_files(const sp& dir, @@ -419,17 +438,22 @@ 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& assets, +static bool applyFileOverlay(Bundle *bundle, + const sp& assets, const sp& baseSet, const char *resType) { + if (bundle->getVerbose()) { + printf("applyFileOverlay for %s\n", resType); + } + // Replace any base level files in this category with any found from the overlay // Also add any found only in the overlay. sp overlay = assets->getOverlay(); @@ -448,6 +472,9 @@ static bool applyFileOverlay(const sp& assets, // non-overlay "baseset". size_t overlayCount = overlaySet->size(); for (size_t overlayIndex=0; overlayIndexgetVerbose()) { + printf("trying overlaySet Key=%s\n",overlaySet->keyAt(overlayIndex).string()); + } size_t baseIndex = baseSet->indexOfKey(overlaySet->keyAt(overlayIndex)); if (baseIndex < UNKNOWN_ERROR) { // look for same flavor. For a given file (strings.xml, for example) @@ -455,30 +482,57 @@ static bool applyFileOverlay(const sp& assets, // the same flavor. sp overlayGroup = overlaySet->valueAt(overlayIndex); sp baseGroup = baseSet->valueAt(baseIndex); - - DefaultKeyedVector > baseFiles = - baseGroup->getFiles(); - DefaultKeyedVector > overlayFiles = + + DefaultKeyedVector > overlayFiles = overlayGroup->getFiles(); + if (bundle->getVerbose()) { + DefaultKeyedVector > baseFiles = + baseGroup->getFiles(); + for (size_t i=0; i < baseFiles.size(); i++) { + printf("baseFile %ld has flavor %s\n", i, + baseFiles.keyAt(i).toString().string()); + } + for (size_t i=0; i < overlayFiles.size(); i++) { + printf("overlayFile %ld has flavor %s\n", i, + overlayFiles.keyAt(i).toString().string()); + } + } + size_t overlayGroupSize = overlayFiles.size(); - for (size_t overlayGroupIndex = 0; - overlayGroupIndexgetFiles().indexOfKey(overlayFiles. + keyAt(overlayGroupIndex)); if(baseFileIndex < UNKNOWN_ERROR) { + if (bundle->getVerbose()) { + printf("found a match (%ld) for overlay file %s, for flavor %s\n", + baseFileIndex, + overlayGroup->getLeaf().string(), + overlayFiles.keyAt(overlayGroupIndex).toString().string()); + } baseGroup->removeFile(baseFileIndex); } else { // didn't find a match fall through and add it.. } baseGroup->addFile(overlayFiles.valueAt(overlayGroupIndex)); + assets->addGroupEntry(overlayFiles.keyAt(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; + baseSet->add(overlaySet->keyAt(overlayIndex), + overlaySet->valueAt(overlayIndex)); + // make sure all flavors are defined in the resources. + sp overlayGroup = overlaySet->valueAt(overlayIndex); + DefaultKeyedVector > overlayFiles = + overlayGroup->getFiles(); + size_t overlayGroupSize = overlayFiles.size(); + for (size_t overlayGroupIndex = 0; + overlayGroupIndexaddGroupEntry(overlayFiles.keyAt(overlayGroupIndex)); + } } } // this overlay didn't have resources for this type @@ -508,6 +562,34 @@ void addTagAttribute(const sp& node, const char* ns8, node->addAttribute(ns, attr, String16(value)); } +static void fullyQualifyClassName(const String8& package, sp node, + const String16& attrName) { + XMLNode::attribute_entry* attr = node->editAttribute( + String16("http://schemas.android.com/apk/res/android"), attrName); + if (attr != NULL) { + String8 name(attr->string); + + // asdf --> package.asdf + // .asdf .a.b --> package.asdf package.a.b + // asdf.adsf --> asdf.asdf + String8 className; + const char* p = name.string(); + const char* q = strchr(p, '.'); + if (p == q) { + className += package; + className += name; + } else if (q == NULL) { + className += package; + className += "."; + className += name; + } else { + className += name; + } + NOISY(printf("Qualifying class '%s' to '%s'", name.string(), className.string())); + attr->string.setTo(String16(className)); + } +} + status_t massageManifest(Bundle* bundle, sp root) { root = root->searchElement(String16(), String16("manifest")); @@ -537,6 +619,56 @@ status_t massageManifest(Bundle* bundle, sp root) addTagAttribute(vers, RESOURCES_ANDROID_NAMESPACE, "maxSdkVersion", bundle->getMaxSdkVersion()); } + + // Deal with manifest package name overrides + const char* manifestPackageNameOverride = bundle->getManifestPackageNameOverride(); + if (manifestPackageNameOverride != NULL) { + // Update the actual package name + XMLNode::attribute_entry* attr = root->editAttribute(String16(), String16("package")); + if (attr == NULL) { + fprintf(stderr, "package name is required with --rename-manifest-package.\n"); + return UNKNOWN_ERROR; + } + String8 origPackage(attr->string); + attr->string.setTo(String16(manifestPackageNameOverride)); + NOISY(printf("Overriding package '%s' to be '%s'\n", origPackage.string(), manifestPackageNameOverride)); + + // Make class names fully qualified + sp application = root->getChildElement(String16(), String16("application")); + if (application != NULL) { + fullyQualifyClassName(origPackage, application, String16("name")); + + Vector >& children = const_cast >&>(application->getChildren()); + for (size_t i = 0; i < children.size(); i++) { + sp child = children.editItemAt(i); + String8 tag(child->getElementName()); + if (tag == "activity" || tag == "service" || tag == "receiver" || tag == "provider") { + fullyQualifyClassName(origPackage, child, String16("name")); + } else if (tag == "activity-alias") { + fullyQualifyClassName(origPackage, child, String16("name")); + fullyQualifyClassName(origPackage, child, String16("targetActivity")); + } + } + } + } + + // Deal with manifest package name overrides + const char* instrumentationPackageNameOverride = bundle->getInstrumentationPackageNameOverride(); + if (instrumentationPackageNameOverride != NULL) { + // Fix up instrumentation targets. + Vector >& children = const_cast >&>(root->getChildren()); + for (size_t i = 0; i < children.size(); i++) { + sp child = children.editItemAt(i); + String8 tag(child->getElementName()); + if (tag == "instrumentation") { + XMLNode::attribute_entry* attr = child->editAttribute( + String16("http://schemas.android.com/apk/res/android"), String16("targetPackage")); + if (attr != NULL) { + attr->string.setTo(String16(instrumentationPackageNameOverride)); + } + } + } + } return NO_ERROR; } @@ -560,7 +692,7 @@ status_t buildResources(Bundle* bundle, const sp& assets) return UNKNOWN_ERROR; } - status_t err = parsePackage(assets, androidManifestFile); + status_t err = parsePackage(bundle, assets, androidManifestFile); if (err != NO_ERROR) { return err; } @@ -576,6 +708,12 @@ status_t buildResources(Bundle* bundle, const sp& assets) NOISY(printf("Found %d included resource packages\n", (int)table.size())); + // Standard flags for compiled XML and optional UTF-8 encoding + int xmlFlags = XML_COMPILE_STANDARD_RESOURCE; + if (bundle->getUTF8()) { + xmlFlags |= XML_COMPILE_UTF8; + } + // -------------------------------------------------------------- // First, gather all resource information. // -------------------------------------------------------------- @@ -612,13 +750,13 @@ status_t buildResources(Bundle* bundle, const sp& assets) 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")) { + if (!applyFileOverlay(bundle, assets, drawables, "drawable") || + !applyFileOverlay(bundle, assets, layouts, "layout") || + !applyFileOverlay(bundle, assets, anims, "anim") || + !applyFileOverlay(bundle, assets, xmls, "xml") || + !applyFileOverlay(bundle, assets, raws, "raw") || + !applyFileOverlay(bundle, assets, colors, "color") || + !applyFileOverlay(bundle, assets, menus, "menu")) { return UNKNOWN_ERROR; } @@ -726,7 +864,7 @@ status_t buildResources(Bundle* bundle, const sp& assets) ResourceDirIterator it(layouts, String8("layout")); while ((err=it.next()) == NO_ERROR) { String8 src = it.getFile()->getPrintableSource(); - err = compileXmlFile(assets, it.getFile(), &table); + err = compileXmlFile(assets, it.getFile(), &table, xmlFlags); if (err == NO_ERROR) { ResXMLTree block; block.setTo(it.getFile()->getData(), it.getFile()->getSize(), true); @@ -745,7 +883,7 @@ status_t buildResources(Bundle* bundle, const sp& assets) if (anims != NULL) { ResourceDirIterator it(anims, String8("anim")); while ((err=it.next()) == NO_ERROR) { - err = compileXmlFile(assets, it.getFile(), &table); + err = compileXmlFile(assets, it.getFile(), &table, xmlFlags); if (err != NO_ERROR) { hasErrors = true; } @@ -760,7 +898,7 @@ status_t buildResources(Bundle* bundle, const sp& assets) if (xmls != NULL) { ResourceDirIterator it(xmls, String8("xml")); while ((err=it.next()) == NO_ERROR) { - err = compileXmlFile(assets, it.getFile(), &table); + err = compileXmlFile(assets, it.getFile(), &table, xmlFlags); if (err != NO_ERROR) { hasErrors = true; } @@ -782,7 +920,7 @@ status_t buildResources(Bundle* bundle, const sp& assets) if (colors != NULL) { ResourceDirIterator it(colors, String8("color")); while ((err=it.next()) == NO_ERROR) { - err = compileXmlFile(assets, it.getFile(), &table); + err = compileXmlFile(assets, it.getFile(), &table, xmlFlags); if (err != NO_ERROR) { hasErrors = true; } @@ -798,7 +936,7 @@ status_t buildResources(Bundle* bundle, const sp& assets) ResourceDirIterator it(menus, String8("menu")); while ((err=it.next()) == NO_ERROR) { String8 src = it.getFile()->getPrintableSource(); - err = compileXmlFile(assets, it.getFile(), &table); + err = compileXmlFile(assets, it.getFile(), &table, xmlFlags); if (err != NO_ERROR) { hasErrors = true; } @@ -1113,14 +1251,14 @@ status_t buildResources(Bundle* bundle, const sp& assets) table.writePublicDefinitions(String16(assets->getPackage()), fp); fclose(fp); } - +#if 0 NOISY( ResTable rt; rt.add(resFile->getData(), resFile->getSize(), NULL); printf("Generated resources:\n"); rt.print(); ) - +#endif // These resources are now considered to be a part of the included // resources, for others to reference. err = assets->addIncludedResources(resFile); @@ -1227,10 +1365,16 @@ static status_t writeLayoutClasses( NA = idents.size(); + bool deprecated = false; + String16 comment = symbols->getComment(realClassName); fprintf(fp, "%s/** ", indentStr); if (comment.size() > 0) { - fprintf(fp, "%s\n", String8(comment).string()); + String8 cmt(comment); + fprintf(fp, "%s\n", cmt.string()); + if (strstr(cmt.string(), "@deprecated") != NULL) { + deprecated = true; + } } else { fprintf(fp, "Attributes that can be used with a %s.\n", nclassName.string()); } @@ -1242,10 +1386,10 @@ static status_t writeLayoutClasses( hasTable = true; fprintf(fp, "%s

Includes the following attributes:

\n" - "%s \n" + "%s
\n" "%s \n" "%s \n" - "%s \n", + "%s \n", indentStr, indentStr, indentStr, @@ -1279,7 +1423,7 @@ static status_t writeLayoutClasses( } String16 name(name8); fixupSymbol(&name); - fprintf(fp, "%s \n", + fprintf(fp, "%s \n", indentStr, nclassName.string(), String8(name).string(), assets->getPackage().string(), @@ -1306,6 +1450,10 @@ static status_t writeLayoutClasses( } fprintf(fp, "%s */\n", getIndentSpace(indent)); + if (deprecated) { + fprintf(fp, "%s@Deprecated\n", indentStr); + } + fprintf(fp, "%spublic static final int[] %s = {\n" "%s", @@ -1354,11 +1502,17 @@ static status_t writeLayoutClasses( //printf("%s:%s/%s: 0x%08x\n", String8(package16).string(), // String8(attr16).string(), String8(name16).string(), typeSpecFlags); const bool pub = (typeSpecFlags&ResTable_typeSpec::SPEC_PUBLIC) != 0; - + + bool deprecated = false; + fprintf(fp, "%s/**\n", indentStr); if (comment.size() > 0) { + String8 cmt(comment); fprintf(fp, "%s

\n%s @attr description\n", indentStr, indentStr); - fprintf(fp, "%s %s\n", indentStr, String8(comment).string()); + fprintf(fp, "%s %s\n", indentStr, cmt.string()); + if (strstr(cmt.string(), "@deprecated") != NULL) { + deprecated = true; + } } else { fprintf(fp, "%s

This symbol is the offset where the {@link %s.R.attr#%s}\n" @@ -1370,7 +1524,11 @@ static status_t writeLayoutClasses( indentStr, nclassName.string()); } if (typeComment.size() > 0) { - fprintf(fp, "\n\n%s %s\n", indentStr, String8(typeComment).string()); + String8 cmt(typeComment); + fprintf(fp, "\n\n%s %s\n", indentStr, cmt.string()); + if (strstr(cmt.string(), "@deprecated") != NULL) { + deprecated = true; + } } if (comment.size() > 0) { if (pub) { @@ -1388,6 +1546,9 @@ static status_t writeLayoutClasses( fprintf(fp, "%s @attr name %s:%s\n", indentStr, "android", String8(name).string()); fprintf(fp, "%s*/\n", indentStr); + if (deprecated) { + fprintf(fp, "%s@Deprecated\n", indentStr); + } fprintf(fp, "%spublic static final int %s_%s = %d;\n", indentStr, nclassName.string(), @@ -1429,11 +1590,16 @@ static status_t writeSymbolClass( } String16 comment(sym.comment); bool haveComment = false; + bool deprecated = false; if (comment.size() > 0) { haveComment = true; + String8 cmt(comment); fprintf(fp, "%s/** %s\n", - getIndentSpace(indent), String8(comment).string()); + getIndentSpace(indent), cmt.string()); + if (strstr(cmt.string(), "@deprecated") != NULL) { + deprecated = true; + } } else if (sym.isPublic && !includePrivate) { sym.sourcePos.warning("No comment for public symbol %s:%s/%s", assets->getPackage().string(), className.string(), @@ -1441,20 +1607,25 @@ static status_t writeSymbolClass( } String16 typeComment(sym.typeComment); if (typeComment.size() > 0) { + String8 cmt(typeComment); if (!haveComment) { haveComment = true; fprintf(fp, - "%s/** %s\n", - getIndentSpace(indent), String8(typeComment).string()); + "%s/** %s\n", getIndentSpace(indent), cmt.string()); } else { fprintf(fp, - "%s %s\n", - getIndentSpace(indent), String8(typeComment).string()); + "%s %s\n", getIndentSpace(indent), cmt.string()); + } + if (strstr(cmt.string(), "@deprecated") != NULL) { + deprecated = true; } } if (haveComment) { fprintf(fp,"%s */\n", getIndentSpace(indent)); } + if (deprecated) { + fprintf(fp, "%s@Deprecated\n", getIndentSpace(indent)); + } fprintf(fp, "%spublic static final int %s=0x%08x;\n", getIndentSpace(indent), String8(name).string(), (int)sym.int32Val); @@ -1473,17 +1644,25 @@ static status_t writeSymbolClass( return UNKNOWN_ERROR; } String16 comment(sym.comment); + bool deprecated = false; if (comment.size() > 0) { + String8 cmt(comment); fprintf(fp, "%s/** %s\n" "%s */\n", - getIndentSpace(indent), String8(comment).string(), + getIndentSpace(indent), cmt.string(), getIndentSpace(indent)); + if (strstr(cmt.string(), "@deprecated") != NULL) { + deprecated = true; + } } else if (sym.isPublic && !includePrivate) { sym.sourcePos.warning("No comment for public symbol %s:%s/%s", assets->getPackage().string(), className.string(), String8(sym.name).string()); } + if (deprecated) { + fprintf(fp, "%s@Deprecated\n", getIndentSpace(indent)); + } fprintf(fp, "%spublic static final String %s=\"%s\";\n", getIndentSpace(indent), String8(name).string(), sym.stringVal.string()); @@ -1578,3 +1757,246 @@ status_t writeResourceSymbols(Bundle* bundle, const sp& assets, return NO_ERROR; } + + + +class ProguardKeepSet +{ +public: + // { rule --> { file locations } } + KeyedVector > rules; + + void add(const String8& rule, const String8& where); +}; + +void ProguardKeepSet::add(const String8& rule, const String8& where) +{ + ssize_t index = rules.indexOfKey(rule); + if (index < 0) { + index = rules.add(rule, SortedVector()); + } + rules.editValueAt(index).add(where); +} + +status_t +writeProguardForAndroidManifest(ProguardKeepSet* keep, const sp& assets) +{ + status_t err; + ResXMLTree tree; + size_t len; + ResXMLTree::event_code_t code; + int depth = 0; + bool inApplication = false; + String8 error; + sp assGroup; + sp assFile; + String8 pkg; + + // First, look for a package file to parse. This is required to + // be able to generate the resource information. + assGroup = assets->getFiles().valueFor(String8("AndroidManifest.xml")); + if (assGroup == NULL) { + fprintf(stderr, "ERROR: No AndroidManifest.xml file found.\n"); + return -1; + } + + if (assGroup->getFiles().size() != 1) { + fprintf(stderr, "warning: Multiple AndroidManifest.xml files found, using %s\n", + assGroup->getFiles().valueAt(0)->getPrintableSource().string()); + } + + assFile = assGroup->getFiles().valueAt(0); + + err = parseXMLResource(assFile, &tree); + if (err != NO_ERROR) { + return err; + } + + tree.restart(); + + while ((code=tree.next()) != ResXMLTree::END_DOCUMENT && code != ResXMLTree::BAD_DOCUMENT) { + if (code == ResXMLTree::END_TAG) { + if (/* name == "Application" && */ depth == 2) { + inApplication = false; + } + depth--; + continue; + } + if (code != ResXMLTree::START_TAG) { + continue; + } + depth++; + String8 tag(tree.getElementName(&len)); + // printf("Depth %d tag %s\n", depth, tag.string()); + bool keepTag = false; + if (depth == 1) { + if (tag != "manifest") { + fprintf(stderr, "ERROR: manifest does not start with tag\n"); + return -1; + } + pkg = getAttribute(tree, NULL, "package", NULL); + } else if (depth == 2) { + if (tag == "application") { + inApplication = true; + keepTag = true; + } else if (tag == "instrumentation") { + keepTag = true; + } + } + if (!keepTag && inApplication && depth == 3) { + if (tag == "activity" || tag == "service" || tag == "receiver" || tag == "provider") { + keepTag = true; + } + } + if (keepTag) { + String8 name = getAttribute(tree, "http://schemas.android.com/apk/res/android", + "name", &error); + if (error != "") { + fprintf(stderr, "ERROR: %s\n", error.string()); + return -1; + } + if (name.length() > 0) { + // asdf --> package.asdf + // .asdf .a.b --> package.asdf package.a.b + // asdf.adsf --> asdf.asdf + String8 rule("-keep class "); + const char* p = name.string(); + const char* q = strchr(p, '.'); + if (p == q) { + rule += pkg; + rule += name; + } else if (q == NULL) { + rule += pkg; + rule += "."; + rule += name; + } else { + rule += name; + } + + String8 location = tag; + location += " "; + location += assFile->getSourceFile(); + char lineno[20]; + sprintf(lineno, ":%d", tree.getLineNumber()); + location += lineno; + + keep->add(rule, location); + } + } + } + + return NO_ERROR; +} + +status_t +writeProguardForLayout(ProguardKeepSet* keep, const sp& layoutFile) +{ + status_t err; + ResXMLTree tree; + size_t len; + ResXMLTree::event_code_t code; + + err = parseXMLResource(layoutFile, &tree); + if (err != NO_ERROR) { + return err; + } + + tree.restart(); + + while ((code=tree.next()) != ResXMLTree::END_DOCUMENT && code != ResXMLTree::BAD_DOCUMENT) { + if (code != ResXMLTree::START_TAG) { + continue; + } + String8 tag(tree.getElementName(&len)); + + // If there is no '.', we'll assume that it's one of the built in names. + if (strchr(tag.string(), '.')) { + String8 rule("-keep class "); + rule += tag; + rule += " { (...); }"; + + String8 location("view "); + location += layoutFile->getSourceFile(); + char lineno[20]; + sprintf(lineno, ":%d", tree.getLineNumber()); + location += lineno; + + keep->add(rule, location); + } + } + + return NO_ERROR; +} + +status_t +writeProguardForLayouts(ProguardKeepSet* keep, const sp& assets) +{ + status_t err; + const Vector >& dirs = assets->resDirs(); + const size_t K = dirs.size(); + for (size_t k=0; k& d = dirs.itemAt(k); + const String8& dirName = d->getLeaf(); + if ((dirName != String8("layout")) && (strncmp(dirName.string(), "layout-", 7) != 0)) { + continue; + } + + const KeyedVector > groups = d->getFiles(); + const size_t N = groups.size(); + for (size_t i=0; i& group = groups.valueAt(i); + const DefaultKeyedVector >& files = group->getFiles(); + const size_t M = files.size(); + for (size_t j=0; j& assets) +{ + status_t err = -1; + + if (!bundle->getProguardFile()) { + return NO_ERROR; + } + + ProguardKeepSet keep; + + err = writeProguardForAndroidManifest(&keep, assets); + if (err < 0) { + return err; + } + + err = writeProguardForLayouts(&keep, assets); + if (err < 0) { + return err; + } + + FILE* fp = fopen(bundle->getProguardFile(), "w+"); + if (fp == NULL) { + fprintf(stderr, "ERROR: Unable to open class file %s: %s\n", + bundle->getProguardFile(), strerror(errno)); + return UNKNOWN_ERROR; + } + + const KeyedVector >& rules = keep.rules; + const size_t N = rules.size(); + for (size_t i=0; i& locations = rules.valueAt(i); + const size_t M = locations.size(); + for (size_t j=0; j

AttributeSummary
AttributeDescription
{@link #%s_%s %s:%s}%s
{@link #%s_%s %s:%s}%s