X-Git-Url: https://git.saurik.com/android/aapt.git/blobdiff_plain/ba94e60cc54d23cc40cede96d43153dcdd67c2f8..9f1b920f0ba1eac153da266ec8c6f564f56df591:/Resource.cpp diff --git a/Resource.cpp b/Resource.cpp index 20b0bf4..9fcb21c 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,7 +171,8 @@ 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", @@ -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; } @@ -472,11 +489,11 @@ static bool applyFileOverlay(Bundle *bundle, DefaultKeyedVector > baseFiles = baseGroup->getFiles(); for (size_t i=0; i < baseFiles.size(); i++) { - printf("baseFile %d has flavor %s\n", 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 %d has flavor %s\n", i, + printf("overlayFile %ld has flavor %s\n", i, overlayFiles.keyAt(i).toString().string()); } } @@ -490,7 +507,7 @@ static bool applyFileOverlay(Bundle *bundle, keyAt(overlayGroupIndex)); if(baseFileIndex < UNKNOWN_ERROR) { if (bundle->getVerbose()) { - printf("found a match (%d) for overlay file %s, for flavor %s\n", + printf("found a match (%ld) for overlay file %s, for flavor %s\n", baseFileIndex, overlayGroup->getLeaf().string(), overlayFiles.keyAt(overlayGroupIndex).toString().string()); @@ -545,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")); @@ -574,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; } @@ -597,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; } @@ -613,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. // -------------------------------------------------------------- @@ -763,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); @@ -782,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; } @@ -797,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; } @@ -819,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; } @@ -835,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; } @@ -1150,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); @@ -1787,8 +1888,26 @@ writeProguardForAndroidManifest(ProguardKeepSet* keep, const sp& ass return NO_ERROR; } +void +addProguardKeepRule(ProguardKeepSet* keep, const String8& className, + const String8& srcName, int line) +{ + String8 rule("-keep class "); + rule += className; + rule += " { (...); }"; + + String8 location("view "); + location += srcName; + char lineno[20]; + sprintf(lineno, ":%d", line); + location += lineno; + + keep->add(rule, location); +} + status_t -writeProguardForLayout(ProguardKeepSet* keep, const sp& layoutFile) +writeProguardForXml(ProguardKeepSet* keep, const sp& layoutFile, + const char* startTag, const char* altTag) { status_t err; ResXMLTree tree; @@ -1802,6 +1921,23 @@ writeProguardForLayout(ProguardKeepSet* keep, const sp& layoutFile) tree.restart(); + if (startTag != NULL) { + bool haveStart = false; + while ((code=tree.next()) != ResXMLTree::END_DOCUMENT && code != ResXMLTree::BAD_DOCUMENT) { + if (code != ResXMLTree::START_TAG) { + continue; + } + String8 tag(tree.getElementName(&len)); + if (tag == startTag) { + haveStart = true; + } + break; + } + if (!haveStart) { + return NO_ERROR; + } + } + while ((code=tree.next()) != ResXMLTree::END_DOCUMENT && code != ResXMLTree::BAD_DOCUMENT) { if (code != ResXMLTree::START_TAG) { continue; @@ -1810,17 +1946,19 @@ writeProguardForLayout(ProguardKeepSet* keep, const sp& layoutFile) // 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); + addProguardKeepRule(keep, tag, + layoutFile->getPrintableSource(), tree.getLineNumber()); + } else if (altTag != NULL && tag == altTag) { + ssize_t classIndex = tree.indexOfAttribute(NULL, "class"); + if (classIndex < 0) { + fprintf(stderr, "%s:%d: does not have class attribute.\n", + layoutFile->getPrintableSource().string(), tree.getLineNumber()); + } else { + size_t len; + addProguardKeepRule(keep, + String8(tree.getAttributeStringValue(classIndex, &len)), + layoutFile->getPrintableSource(), tree.getLineNumber()); + } } } @@ -1836,10 +1974,16 @@ writeProguardForLayouts(ProguardKeepSet* keep, const sp& assets) 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)) { + const char* startTag = NULL; + const char* altTag = NULL; + if ((dirName == String8("layout")) || (strncmp(dirName.string(), "layout-", 7) == 0)) { + altTag = "view"; + } else if ((dirName == String8("xml")) || (strncmp(dirName.string(), "xml-", 4) == 0)) { + startTag = "PreferenceScreen"; + } else { continue; } - + const KeyedVector > groups = d->getFiles(); const size_t N = groups.size(); for (size_t i=0; i& assets) const DefaultKeyedVector >& files = group->getFiles(); const size_t M = files.size(); for (size_t j=0; j