summaryrefslogtreecommitdiffstats
path: root/tools/aapt
diff options
context:
space:
mode:
Diffstat (limited to 'tools/aapt')
-rw-r--r--tools/aapt/AaptAssets.cpp5
-rw-r--r--tools/aapt/AaptAssets.h3
-rw-r--r--tools/aapt/AaptConfig.cpp26
-rw-r--r--tools/aapt/AaptConfig.h6
-rw-r--r--tools/aapt/AaptUtil.h40
-rw-r--r--tools/aapt/Android.mk58
-rw-r--r--tools/aapt/Bundle.h16
-rw-r--r--tools/aapt/CacheUpdater.h4
-rw-r--r--tools/aapt/Command.cpp58
-rw-r--r--tools/aapt/ConfigDescription.h3
-rw-r--r--tools/aapt/Main.cpp4
-rw-r--r--tools/aapt/Resource.cpp107
-rw-r--r--tools/aapt/ResourceFilter.cpp7
-rw-r--r--tools/aapt/ResourceIdCache.cpp1
-rw-r--r--tools/aapt/ResourceTable.cpp416
-rw-r--r--tools/aapt/ResourceTable.h30
-rw-r--r--tools/aapt/SdkConstants.h43
-rw-r--r--tools/aapt/SourcePos.cpp6
-rw-r--r--tools/aapt/SourcePos.h2
-rw-r--r--tools/aapt/StringPool.cpp14
-rw-r--r--tools/aapt/StringPool.h3
-rw-r--r--tools/aapt/Symbol.h95
22 files changed, 757 insertions, 190 deletions
diff --git a/tools/aapt/AaptAssets.cpp b/tools/aapt/AaptAssets.cpp
index 2849c84..2d35129 100644
--- a/tools/aapt/AaptAssets.cpp
+++ b/tools/aapt/AaptAssets.cpp
@@ -1140,9 +1140,10 @@ bail:
ssize_t AaptAssets::slurpFullTree(Bundle* bundle, const String8& srcDir,
const AaptGroupEntry& kind,
const String8& resType,
- sp<FilePathStore>& fullResPaths)
+ sp<FilePathStore>& fullResPaths,
+ const bool overwrite)
{
- ssize_t res = AaptDir::slurpFullTree(bundle, srcDir, kind, resType, fullResPaths);
+ ssize_t res = AaptDir::slurpFullTree(bundle, srcDir, kind, resType, fullResPaths, overwrite);
if (res > 0) {
mGroupEntries.add(kind);
}
diff --git a/tools/aapt/AaptAssets.h b/tools/aapt/AaptAssets.h
index d809c5b..7ae5368 100644
--- a/tools/aapt/AaptAssets.h
+++ b/tools/aapt/AaptAssets.h
@@ -591,7 +591,8 @@ private:
const String8& srcDir,
const AaptGroupEntry& kind,
const String8& resType,
- sp<FilePathStore>& fullResPaths);
+ sp<FilePathStore>& fullResPaths,
+ const bool overwrite=false);
ssize_t slurpResourceTree(Bundle* bundle, const String8& srcDir);
ssize_t slurpResourceZip(Bundle* bundle, const char* filename);
diff --git a/tools/aapt/AaptConfig.cpp b/tools/aapt/AaptConfig.cpp
index 32a0cd3..ede9e99 100644
--- a/tools/aapt/AaptConfig.cpp
+++ b/tools/aapt/AaptConfig.cpp
@@ -21,6 +21,7 @@
#include "AaptAssets.h"
#include "AaptUtil.h"
#include "ResourceFilter.h"
+#include "SdkConstants.h"
using android::String8;
using android::Vector;
@@ -240,7 +241,9 @@ void applyVersionForCompatibility(ConfigDescription* config) {
}
uint16_t minSdk = 0;
- if (config->smallestScreenWidthDp != ResTable_config::SCREENWIDTH_ANY
+ if (config->density == ResTable_config::DENSITY_ANY) {
+ minSdk = SDK_LOLLIPOP;
+ } else if (config->smallestScreenWidthDp != ResTable_config::SCREENWIDTH_ANY
|| config->screenWidthDp != ResTable_config::SCREENWIDTH_ANY
|| config->screenHeightDp != ResTable_config::SCREENHEIGHT_ANY) {
minSdk = SDK_HONEYCOMB_MR2;
@@ -255,8 +258,6 @@ void applyVersionForCompatibility(ConfigDescription* config) {
!= ResTable_config::SCREENLONG_ANY
|| config->density != ResTable_config::DENSITY_DEFAULT) {
minSdk = SDK_DONUT;
- } else if ((config->density == ResTable_config::DENSITY_ANY)) {
- minSdk = SDK_L;
}
if (minSdk > config->sdkVersion) {
@@ -794,4 +795,23 @@ bool isSameExcept(const ResTable_config& a, const ResTable_config& b, int axisMa
return a.diff(b) == axisMask;
}
+bool isDensityOnly(const ResTable_config& config) {
+ if (config.density == ResTable_config::DENSITY_DEFAULT) {
+ return false;
+ }
+
+ if (config.density == ResTable_config::DENSITY_ANY) {
+ if (config.sdkVersion != SDK_LOLLIPOP) {
+ // Someone modified the sdkVersion from the default, this is not safe to assume.
+ return false;
+ }
+ } else if (config.sdkVersion != SDK_DONUT) {
+ return false;
+ }
+
+ const uint32_t mask = ResTable_config::CONFIG_DENSITY | ResTable_config::CONFIG_VERSION;
+ const ConfigDescription nullConfig;
+ return (nullConfig.diff(config) & ~mask) == 0;
+}
+
} // namespace AaptConfig
diff --git a/tools/aapt/AaptConfig.h b/tools/aapt/AaptConfig.h
index 2963539..f73a508 100644
--- a/tools/aapt/AaptConfig.h
+++ b/tools/aapt/AaptConfig.h
@@ -80,6 +80,12 @@ android::String8 getVersion(const android::ResTable_config& config);
*/
bool isSameExcept(const android::ResTable_config& a, const android::ResTable_config& b, int configMask);
+/**
+ * Returns true if the configuration only has the density specified. In the case
+ * of 'anydpi', the version is ignored.
+ */
+bool isDensityOnly(const android::ResTable_config& config);
+
} // namespace AaptConfig
#endif // __AAPT_CONFIG_H
diff --git a/tools/aapt/AaptUtil.h b/tools/aapt/AaptUtil.h
index 47a704a..89e1ee8 100644
--- a/tools/aapt/AaptUtil.h
+++ b/tools/aapt/AaptUtil.h
@@ -14,9 +14,11 @@
* limitations under the License.
*/
-#ifndef __AAPT_UTIL_H
-#define __AAPT_UTIL_H
+#ifndef H_AAPT_UTIL
+#define H_AAPT_UTIL
+#include <utils/KeyedVector.h>
+#include <utils/SortedVector.h>
#include <utils/String8.h>
#include <utils/Vector.h>
@@ -25,6 +27,38 @@ namespace AaptUtil {
android::Vector<android::String8> split(const android::String8& str, const char sep);
android::Vector<android::String8> splitAndLowerCase(const android::String8& str, const char sep);
+template <typename KEY, typename VALUE>
+void appendValue(android::KeyedVector<KEY, android::Vector<VALUE> >& keyedVector,
+ const KEY& key, const VALUE& value);
+
+template <typename KEY, typename VALUE>
+void appendValue(android::KeyedVector<KEY, android::SortedVector<VALUE> >& keyedVector,
+ const KEY& key, const VALUE& value);
+
+//
+// Implementations
+//
+
+template <typename KEY, typename VALUE>
+void appendValue(android::KeyedVector<KEY, android::Vector<VALUE> >& keyedVector,
+ const KEY& key, const VALUE& value) {
+ ssize_t idx = keyedVector.indexOfKey(key);
+ if (idx < 0) {
+ idx = keyedVector.add(key, android::Vector<VALUE>());
+ }
+ keyedVector.editValueAt(idx).add(value);
+}
+
+template <typename KEY, typename VALUE>
+void appendValue(android::KeyedVector<KEY, android::SortedVector<VALUE> >& keyedVector,
+ const KEY& key, const VALUE& value) {
+ ssize_t idx = keyedVector.indexOfKey(key);
+ if (idx < 0) {
+ idx = keyedVector.add(key, android::SortedVector<VALUE>());
+ }
+ keyedVector.editValueAt(idx).add(value);
+}
+
} // namespace AaptUtil
-#endif // __AAPT_UTIL_H
+#endif // H_AAPT_UTIL
diff --git a/tools/aapt/Android.mk b/tools/aapt/Android.mk
index ba1411e..c5495a5 100644
--- a/tools/aapt/Android.mk
+++ b/tools/aapt/Android.mk
@@ -33,19 +33,19 @@ aaptSources := \
Command.cpp \
CrunchCache.cpp \
FileFinder.cpp \
+ Images.cpp \
Package.cpp \
- StringPool.cpp \
- XMLNode.cpp \
+ pseudolocalize.cpp \
+ Resource.cpp \
ResourceFilter.cpp \
ResourceIdCache.cpp \
ResourceTable.cpp \
- Images.cpp \
- Resource.cpp \
- pseudolocalize.cpp \
SourcePos.cpp \
+ StringPool.cpp \
WorkQueue.cpp \
+ XMLNode.cpp \
ZipEntry.cpp \
- ZipFile.cpp \
+ ZipFile.cpp
aaptTests := \
tests/AaptConfig_test.cpp \
@@ -88,16 +88,13 @@ endif
include $(CLEAR_VARS)
LOCAL_MODULE := libaapt
-
-LOCAL_SRC_FILES := $(aaptSources)
-LOCAL_C_INCLUDES += $(aaptCIncludes)
-
-LOCAL_CFLAGS += -Wno-format-y2k
-LOCAL_CFLAGS += -DSTATIC_ANDROIDFW_FOR_TOOLS
-LOCAL_CFLAGS += $(aaptCFlags)
+LOCAL_CFLAGS += -Wno-format-y2k -DSTATIC_ANDROIDFW_FOR_TOOLS $(aaptCFlags)
+LOCAL_CPPFLAGS += $(aaptCppFlags)
ifeq (darwin,$(HOST_OS))
LOCAL_CFLAGS += -D_DARWIN_UNLIMITED_STREAMS
endif
+LOCAL_C_INCLUDES += $(aaptCIncludes)
+LOCAL_SRC_FILES := $(aaptSources)
include $(BUILD_HOST_STATIC_LIBRARY)
@@ -108,15 +105,11 @@ include $(BUILD_HOST_STATIC_LIBRARY)
include $(CLEAR_VARS)
LOCAL_MODULE := aapt
-
-LOCAL_SRC_FILES := $(aaptMain)
-
-LOCAL_STATIC_LIBRARIES += \
- libaapt \
- $(aaptHostStaticLibs)
-
-LOCAL_LDLIBS += $(aaptHostLdLibs)
LOCAL_CFLAGS += $(aaptCFlags)
+LOCAL_CPPFLAGS += $(aaptCppFlags)
+LOCAL_LDLIBS += $(aaptHostLdLibs)
+LOCAL_SRC_FILES := $(aaptMain)
+LOCAL_STATIC_LIBRARIES += libaapt $(aaptHostStaticLibs)
include $(BUILD_HOST_EXECUTABLE)
@@ -125,18 +118,15 @@ include $(BUILD_HOST_EXECUTABLE)
# Build the host tests: libaapt_tests
# ==========================================================
include $(CLEAR_VARS)
+LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk
LOCAL_MODULE := libaapt_tests
-
+LOCAL_CFLAGS += $(aaptCFlags)
+LOCAL_CPPFLAGS += $(aaptCppFlags)
+LOCAL_LDLIBS += $(aaptHostLdLibs)
LOCAL_SRC_FILES += $(aaptTests)
LOCAL_C_INCLUDES += $(LOCAL_PATH)
-
-LOCAL_STATIC_LIBRARIES += \
- libaapt \
- $(aaptHostStaticLibs)
-
-LOCAL_LDLIBS += $(aaptHostLdLibs)
-LOCAL_CFLAGS += $(aaptCFlags)
+LOCAL_STATIC_LIBRARIES += libaapt $(aaptHostStaticLibs)
include $(BUILD_HOST_NATIVE_TEST)
@@ -148,11 +138,9 @@ ifneq ($(SDK_ONLY),true)
include $(CLEAR_VARS)
LOCAL_MODULE := aapt
-
+LOCAL_CFLAGS += $(aaptCFlags)
LOCAL_SRC_FILES := $(aaptSources) $(aaptMain)
-LOCAL_C_INCLUDES += \
- $(aaptCIncludes) \
-
+LOCAL_C_INCLUDES += $(aaptCIncludes)
LOCAL_SHARED_LIBRARIES := \
libandroidfw \
libutils \
@@ -160,13 +148,9 @@ LOCAL_SHARED_LIBRARIES := \
libpng \
liblog \
libz
-
LOCAL_STATIC_LIBRARIES := \
libexpat_static
-LOCAL_CFLAGS += $(aaptCFlags)
-LOCAL_CPPFLAGS += -Wno-non-virtual-dtor
-
include $(BUILD_EXECUTABLE)
endif # Not SDK_ONLY
diff --git a/tools/aapt/Bundle.h b/tools/aapt/Bundle.h
index cb34448..e7cde74 100644
--- a/tools/aapt/Bundle.h
+++ b/tools/aapt/Bundle.h
@@ -14,18 +14,7 @@
#include <utils/String8.h>
#include <utils/Vector.h>
-enum {
- SDK_CUPCAKE = 3,
- SDK_DONUT = 4,
- SDK_ECLAIR = 5,
- SDK_ECLAIR_0_1 = 6,
- SDK_MR1 = 7,
- SDK_FROYO = 8,
- SDK_HONEYCOMB_MR2 = 13,
- SDK_ICE_CREAM_SANDWICH = 14,
- SDK_ICE_CREAM_SANDWICH_MR1 = 15,
- SDK_L = 21,
-};
+#include "SdkConstants.h"
/*
* Things we can do.
@@ -190,6 +179,8 @@ public:
void setVersionName(const char* val) { mVersionName = val; }
bool getReplaceVersion() { return mReplaceVersion; }
void setReplaceVersion(bool val) { mReplaceVersion = val; }
+ const android::String8& getRevisionCode() { return mRevisionCode; }
+ void setRevisionCode(const char* val) { mRevisionCode = android::String8(val); }
const char* getCustomPackage() const { return mCustomPackage; }
void setCustomPackage(const char* val) { mCustomPackage = val; }
const char* getExtraPackages() const { return mExtraPackages; }
@@ -308,6 +299,7 @@ private:
android::String8 mFeatureOfPackage;
android::String8 mFeatureAfterPackage;
+ android::String8 mRevisionCode;
const char* mManifestMinSdkVersion;
const char* mMinSdkVersion;
const char* mTargetSdkVersion;
diff --git a/tools/aapt/CacheUpdater.h b/tools/aapt/CacheUpdater.h
index cacab03..fade53a 100644
--- a/tools/aapt/CacheUpdater.h
+++ b/tools/aapt/CacheUpdater.h
@@ -30,6 +30,8 @@ using namespace android;
*/
class CacheUpdater {
public:
+ virtual ~CacheUpdater() {}
+
// Make sure all the directories along this path exist
virtual void ensureDirectoriesExist(String8 path) = 0;
@@ -38,8 +40,6 @@ public:
// Process an image from source out to dest
virtual void processImage(String8 source, String8 dest) = 0;
-
- virtual ~CacheUpdater() {}
private:
};
diff --git a/tools/aapt/Command.cpp b/tools/aapt/Command.cpp
index 70044f2..8a0a39c 100644
--- a/tools/aapt/Command.cpp
+++ b/tools/aapt/Command.cpp
@@ -308,6 +308,7 @@ enum {
PUBLIC_KEY_ATTR = 0x010103a6,
CATEGORY_ATTR = 0x010103e8,
BANNER_ATTR = 0x10103f2,
+ ISGAME_ATTR = 0x10103f4,
};
String8 getComponentName(String8 &pkgName, String8 &componentName) {
@@ -516,12 +517,10 @@ static void printFeatureGroup(const FeatureGroup& grp,
const size_t numFeatures = grp.features.size();
for (size_t i = 0; i < numFeatures; i++) {
- if (!grp.features[i]) {
- continue;
- }
+ const bool required = grp.features[i];
const String8& featureName = grp.features.keyAt(i);
- printf(" uses-feature: name='%s'\n",
+ printf(" uses-feature%s: name='%s'\n", (required ? "" : "-not-required"),
ResTable::normalizeForOutput(featureName.string()).string());
}
@@ -1125,13 +1124,35 @@ int doDump(Bundle* bundle)
error.string());
goto bail;
}
+
+ String8 banner = AaptXml::getResolvedAttribute(res, tree, BANNER_ATTR, &error);
+ if (error != "") {
+ fprintf(stderr, "ERROR getting 'android:banner' attribute: %s\n",
+ error.string());
+ goto bail;
+ }
printf("application: label='%s' ",
ResTable::normalizeForOutput(label.string()).string());
- printf("icon='%s'\n", ResTable::normalizeForOutput(icon.string()).string());
+ printf("icon='%s'", ResTable::normalizeForOutput(icon.string()).string());
+ if (banner != "") {
+ printf(" banner='%s'", ResTable::normalizeForOutput(banner.string()).string());
+ }
+ printf("\n");
if (testOnly != 0) {
printf("testOnly='%d'\n", testOnly);
}
+ int32_t isGame = AaptXml::getResolvedIntegerAttribute(res, tree,
+ ISGAME_ATTR, 0, &error);
+ if (error != "") {
+ fprintf(stderr, "ERROR getting 'android:isGame' attribute: %s\n",
+ error.string());
+ goto bail;
+ }
+ if (isGame != 0) {
+ printf("application-isGame\n");
+ }
+
int32_t debuggable = AaptXml::getResolvedIntegerAttribute(res, tree,
DEBUGGABLE_ATTR, 0, &error);
if (error != "") {
@@ -1819,7 +1840,7 @@ int doDump(Bundle* bundle)
}
}
- if (!grp.features.isEmpty()) {
+ if (!grp.features.isEmpty()) {
printFeatureGroup(grp);
}
}
@@ -2510,22 +2531,17 @@ int doSingleCrunch(Bundle* bundle)
int runInDaemonMode(Bundle* bundle) {
std::cout << "Ready" << std::endl;
- for (std::string line; std::getline(std::cin, line);) {
- if (line == "quit") {
+ for (std::string cmd; std::getline(std::cin, cmd);) {
+ if (cmd == "quit") {
return NO_ERROR;
- }
- std::stringstream ss;
- ss << line;
- std::string s;
-
- std::string command, parameterOne, parameterTwo;
- std::getline(ss, command, ' ');
- std::getline(ss, parameterOne, ' ');
- std::getline(ss, parameterTwo, ' ');
- if (command[0] == 's') {
- bundle->setSingleCrunchInputFile(parameterOne.c_str());
- bundle->setSingleCrunchOutputFile(parameterTwo.c_str());
- std::cout << "Crunching " << parameterOne << std::endl;
+ } else if (cmd == "s") {
+ // Two argument crunch
+ std::string inputFile, outputFile;
+ std::getline(std::cin, inputFile);
+ std::getline(std::cin, outputFile);
+ bundle->setSingleCrunchInputFile(inputFile.c_str());
+ bundle->setSingleCrunchOutputFile(outputFile.c_str());
+ std::cout << "Crunching " << inputFile << std::endl;
if (doSingleCrunch(bundle) != NO_ERROR) {
std::cout << "Error" << std::endl;
}
diff --git a/tools/aapt/ConfigDescription.h b/tools/aapt/ConfigDescription.h
index 779c423..4f999a2 100644
--- a/tools/aapt/ConfigDescription.h
+++ b/tools/aapt/ConfigDescription.h
@@ -28,10 +28,12 @@ struct ConfigDescription : public android::ResTable_config {
memset(this, 0, sizeof(*this));
size = sizeof(android::ResTable_config);
}
+
ConfigDescription(const android::ResTable_config&o) {
*static_cast<android::ResTable_config*>(this) = o;
size = sizeof(android::ResTable_config);
}
+
ConfigDescription(const ConfigDescription&o) {
*static_cast<android::ResTable_config*>(this) = o;
}
@@ -41,6 +43,7 @@ struct ConfigDescription : public android::ResTable_config {
size = sizeof(android::ResTable_config);
return *this;
}
+
ConfigDescription& operator=(const ConfigDescription& o) {
*static_cast<android::ResTable_config*>(this) = o;
return *this;
diff --git a/tools/aapt/Main.cpp b/tools/aapt/Main.cpp
index 4ce4b2c..8b416aa 100644
--- a/tools/aapt/Main.cpp
+++ b/tools/aapt/Main.cpp
@@ -11,9 +11,9 @@
#include <utils/List.h>
#include <utils/Errors.h>
-#include <stdlib.h>
+#include <cstdlib>
#include <getopt.h>
-#include <assert.h>
+#include <cassert>
using namespace android;
diff --git a/tools/aapt/Resource.cpp b/tools/aapt/Resource.cpp
index b559002..36299c2 100644
--- a/tools/aapt/Resource.cpp
+++ b/tools/aapt/Resource.cpp
@@ -4,6 +4,7 @@
// Build resource files from raw assets.
//
#include "AaptAssets.h"
+#include "AaptUtil.h"
#include "AaptXml.h"
#include "CacheUpdater.h"
#include "CrunchCache.h"
@@ -13,10 +14,14 @@
#include "Main.h"
#include "ResourceTable.h"
#include "StringPool.h"
+#include "Symbol.h"
#include "WorkQueue.h"
#include "XMLNode.h"
+#include <algorithm>
+
// STATUST: mingw does seem to redefine UNKNOWN_ERROR from our enum value, so a cast is necessary.
+
#if HAVE_PRINTF_ZD
# define ZD "%zd"
# define ZD_TYPE ssize_t
@@ -261,6 +266,11 @@ static status_t parsePackage(Bundle* bundle, const sp<AaptAssets>& assets,
assets->setPackage(String8(block.getAttributeStringValue(nameIndex, &len)));
+ ssize_t revisionCodeIndex = block.indexOfAttribute(RESOURCES_ANDROID_NAMESPACE, "revisionCode");
+ if (revisionCodeIndex >= 0) {
+ bundle->setRevisionCode(String8(block.getAttributeStringValue(revisionCodeIndex, &len)).string());
+ }
+
String16 uses_sdk16("uses-sdk");
while ((code=block.next()) != ResXMLTree::END_DOCUMENT
&& code != ResXMLTree::BAD_DOCUMENT) {
@@ -523,7 +533,7 @@ static int validateAttr(const String8& path, const ResTable& table,
}
if (validChars) {
for (size_t i=0; i<len; i++) {
- uint16_t c = str[i];
+ char16_t c = str[i];
const char* p = validChars;
bool okay = false;
while (*p) {
@@ -1098,6 +1108,14 @@ status_t generateAndroidManifestForSplit(Bundle* bundle, const sp<AaptAssets>& a
return UNKNOWN_ERROR;
}
+ // Add the 'revisionCode' attribute, which is set to the original revisionCode.
+ if (bundle->getRevisionCode().size() > 0) {
+ if (!addTagAttribute(manifest, RESOURCES_ANDROID_NAMESPACE, "revisionCode",
+ bundle->getRevisionCode().string(), true, true)) {
+ return UNKNOWN_ERROR;
+ }
+ }
+
// Add the 'split' attribute which describes the configurations included.
String8 splitName("config.");
splitName.append(split->getPackageSafeName());
@@ -1580,6 +1598,7 @@ status_t buildResources(Bundle* bundle, const sp<AaptAssets>& assets, sp<ApkBuil
// Re-flatten because we may have added new resource IDs
// --------------------------------------------------------------
+
ResTable finalResTable;
sp<AaptFile> resFile;
@@ -1590,6 +1609,13 @@ status_t buildResources(Bundle* bundle, const sp<AaptAssets>& assets, sp<ApkBuil
return err;
}
+ KeyedVector<Symbol, Vector<SymbolDefinition> > densityVaryingResources;
+ if (builder->getSplits().size() > 1) {
+ // Only look for density varying resources if we're generating
+ // splits.
+ table.getDensityVaryingResources(densityVaryingResources);
+ }
+
Vector<sp<ApkSplit> >& splits = builder->getSplits();
const size_t numSplits = splits.size();
for (size_t i = 0; i < numSplits; i++) {
@@ -1613,6 +1639,63 @@ status_t buildResources(Bundle* bundle, const sp<AaptAssets>& assets, sp<ApkBuil
return err;
}
} else {
+ ResTable resTable;
+ err = resTable.add(flattenedTable->getData(), flattenedTable->getSize());
+ if (err != NO_ERROR) {
+ fprintf(stderr, "Generated resource table for split '%s' is corrupt.\n",
+ split->getPrintableName().string());
+ return err;
+ }
+
+ bool hasError = false;
+ const std::set<ConfigDescription>& splitConfigs = split->getConfigs();
+ for (std::set<ConfigDescription>::const_iterator iter = splitConfigs.begin();
+ iter != splitConfigs.end();
+ ++iter) {
+ const ConfigDescription& config = *iter;
+ if (AaptConfig::isDensityOnly(config)) {
+ // Each density only split must contain all
+ // density only resources.
+ Res_value val;
+ resTable.setParameters(&config);
+ const size_t densityVaryingResourceCount = densityVaryingResources.size();
+ for (size_t k = 0; k < densityVaryingResourceCount; k++) {
+ const Symbol& symbol = densityVaryingResources.keyAt(k);
+ ssize_t block = resTable.getResource(symbol.id, &val, true);
+ if (block < 0) {
+ // Maybe it's in the base?
+ finalResTable.setParameters(&config);
+ block = finalResTable.getResource(symbol.id, &val, true);
+ }
+
+ if (block < 0) {
+ hasError = true;
+ SourcePos().error("%s has no definition for density split '%s'",
+ symbol.toString().string(), config.toString().string());
+
+ if (bundle->getVerbose()) {
+ const Vector<SymbolDefinition>& defs = densityVaryingResources[k];
+ const size_t defCount = std::min(size_t(5), defs.size());
+ for (size_t d = 0; d < defCount; d++) {
+ const SymbolDefinition& def = defs[d];
+ def.source.error("%s has definition for %s",
+ symbol.toString().string(), def.config.toString().string());
+ }
+
+ if (defCount < defs.size()) {
+ SourcePos().error("and %d more ...", (int) (defs.size() - defCount));
+ }
+ }
+ }
+ }
+ }
+ }
+
+ if (hasError) {
+ return UNKNOWN_ERROR;
+ }
+
+ // Generate the AndroidManifest for this split.
sp<AaptFile> generatedManifest = new AaptFile(String8("AndroidManifest.xml"),
AaptGroupEntry(), String8());
err = generateAndroidManifestForSplit(bundle, assets, split,
@@ -2946,17 +3029,26 @@ status_t
writeProguardForLayouts(ProguardKeepSet* keep, const sp<AaptAssets>& assets)
{
status_t err;
+ const char* kClass = "class";
+ const char* kFragment = "fragment";
+ const String8 kTransition("transition");
+ const String8 kTransitionPrefix("transition-");
// tag:attribute pairs that should be checked in layout files.
KeyedVector<String8, Vector<NamespaceAttributePair> > kLayoutTagAttrPairs;
- addTagAttrPair(&kLayoutTagAttrPairs, "view", NULL, "class");
- addTagAttrPair(&kLayoutTagAttrPairs, "fragment", NULL, "class");
- addTagAttrPair(&kLayoutTagAttrPairs, "fragment", RESOURCES_ANDROID_NAMESPACE, "name");
+ addTagAttrPair(&kLayoutTagAttrPairs, "view", NULL, kClass);
+ addTagAttrPair(&kLayoutTagAttrPairs, kFragment, NULL, kClass);
+ addTagAttrPair(&kLayoutTagAttrPairs, kFragment, RESOURCES_ANDROID_NAMESPACE, "name");
// tag:attribute pairs that should be checked in xml files.
KeyedVector<String8, Vector<NamespaceAttributePair> > kXmlTagAttrPairs;
- addTagAttrPair(&kXmlTagAttrPairs, "PreferenceScreen", RESOURCES_ANDROID_NAMESPACE, "fragment");
- addTagAttrPair(&kXmlTagAttrPairs, "header", RESOURCES_ANDROID_NAMESPACE, "fragment");
+ addTagAttrPair(&kXmlTagAttrPairs, "PreferenceScreen", RESOURCES_ANDROID_NAMESPACE, kFragment);
+ addTagAttrPair(&kXmlTagAttrPairs, "header", RESOURCES_ANDROID_NAMESPACE, kFragment);
+
+ // tag:attribute pairs that should be checked in transition files.
+ KeyedVector<String8, Vector<NamespaceAttributePair> > kTransitionTagAttrPairs;
+ addTagAttrPair(&kTransitionTagAttrPairs, kTransition.string(), NULL, kClass);
+ addTagAttrPair(&kTransitionTagAttrPairs, "pathMotion", NULL, kClass);
const Vector<sp<AaptDir> >& dirs = assets->resDirs();
const size_t K = dirs.size();
@@ -2975,6 +3067,9 @@ writeProguardForLayouts(ProguardKeepSet* keep, const sp<AaptAssets>& assets)
} else if ((dirName == String8("menu")) || (strncmp(dirName.string(), "menu-", 5) == 0)) {
startTags.add(String8("menu"));
tagAttrPairs = NULL;
+ } else if (dirName == kTransition || (strncmp(dirName.string(), kTransitionPrefix.string(),
+ kTransitionPrefix.size()) == 0)) {
+ tagAttrPairs = &kTransitionTagAttrPairs;
} else {
continue;
}
diff --git a/tools/aapt/ResourceFilter.cpp b/tools/aapt/ResourceFilter.cpp
index fc95e14..8693999 100644
--- a/tools/aapt/ResourceFilter.cpp
+++ b/tools/aapt/ResourceFilter.cpp
@@ -41,6 +41,13 @@ WeakResourceFilter::parse(const String8& str)
// Ignore the version
entry.second &= ~ResTable_config::CONFIG_VERSION;
+ // Ignore any densities. Those are best handled in --preferred-density
+ if ((entry.second & ResTable_config::CONFIG_DENSITY) != 0) {
+ fprintf(stderr, "warning: ignoring flag -c %s. Use --preferred-density instead.\n", entry.first.toString().string());
+ entry.first.density = 0;
+ entry.second &= ~ResTable_config::CONFIG_DENSITY;
+ }
+
mConfigMask |= entry.second;
}
diff --git a/tools/aapt/ResourceIdCache.cpp b/tools/aapt/ResourceIdCache.cpp
index d7b2d10..8835fb0 100644
--- a/tools/aapt/ResourceIdCache.cpp
+++ b/tools/aapt/ResourceIdCache.cpp
@@ -10,7 +10,6 @@
#include "ResourceIdCache.h"
#include <map>
-
static size_t mHits = 0;
static size_t mMisses = 0;
static size_t mCollisions = 0;
diff --git a/tools/aapt/ResourceTable.cpp b/tools/aapt/ResourceTable.cpp
index 9861be2..941a288 100644
--- a/tools/aapt/ResourceTable.cpp
+++ b/tools/aapt/ResourceTable.cpp
@@ -6,10 +6,13 @@
#include "ResourceTable.h"
+#include "AaptUtil.h"
#include "XMLNode.h"
#include "ResourceFilter.h"
#include "ResourceIdCache.h"
+#include "SdkConstants.h"
+#include <algorithm>
#include <androidfw/ResourceTypes.h>
#include <utils/ByteOrder.h>
#include <utils/TypeHelpers.h>
@@ -34,6 +37,8 @@ static const bool kPrintStringMetrics = true;
static const bool kPrintStringMetrics = false;
#endif
+static const char* kAttrPrivateType = "^attr-private";
+
status_t compileXmlFile(const Bundle* bundle,
const sp<AaptAssets>& assets,
const String16& resourceName,
@@ -2151,8 +2156,16 @@ uint32_t ResourceTable::getResId(const String16& package,
if (p == NULL) return 0;
sp<Type> t = p->getTypes().valueFor(type);
if (t == NULL) return 0;
- sp<ConfigList> c = t->getConfigs().valueFor(name);
- if (c == NULL) return 0;
+ sp<ConfigList> c = t->getConfigs().valueFor(name);
+ if (c == NULL) {
+ if (type != String16("attr")) {
+ return 0;
+ }
+ t = p->getTypes().valueFor(String16(kAttrPrivateType));
+ if (t == NULL) return 0;
+ c = t->getConfigs().valueFor(name);
+ if (c == NULL) return 0;
+ }
int32_t ei = c->getEntryIndex();
if (ei < 0) return 0;
@@ -2291,7 +2304,15 @@ uint32_t ResourceTable::getCustomResource(
sp<Type> t = p->getTypes().valueFor(type);
if (t == NULL) return 0;
sp<ConfigList> c = t->getConfigs().valueFor(name);
- if (c == NULL) return 0;
+ if (c == NULL) {
+ if (type != String16("attr")) {
+ return 0;
+ }
+ t = p->getTypes().valueFor(String16(kAttrPrivateType));
+ if (t == NULL) return 0;
+ c = t->getConfigs().valueFor(name);
+ if (c == NULL) return 0;
+ }
int32_t ei = c->getEntryIndex();
if (ei < 0) return 0;
return getResId(p, t, ei);
@@ -2495,6 +2516,10 @@ status_t ResourceTable::assignResourceIds()
continue;
}
+ if (mPackageType == System) {
+ p->movePrivateAttrs();
+ }
+
// This has no sense for packages being built as AppFeature (aka with a non-zero offset).
status_t err = p->applyPublicTypeOrder();
if (err != NO_ERROR && firstError == NO_ERROR) {
@@ -2565,15 +2590,20 @@ status_t ResourceTable::assignResourceIds()
}
}
+
// Assign resource IDs to keys in bags...
for (size_t ti = 0; ti < typeCount; ti++) {
sp<Type> t = p->getOrderedTypes().itemAt(ti);
if (t == NULL) {
continue;
}
+
const size_t N = t->getOrderedConfigs().size();
for (size_t ci=0; ci<N; ci++) {
sp<ConfigList> c = t->getOrderedConfigs().itemAt(ci);
+ if (c == NULL) {
+ continue;
+ }
//printf("Ordered config #%d: %p\n", ci, c.get());
const size_t N = c->getEntries().size();
for (size_t ei=0; ei<N; ei++) {
@@ -2611,9 +2641,15 @@ status_t ResourceTable::addSymbols(const sp<AaptSymbols>& outSymbols) {
if (t == NULL) {
continue;
}
+
const size_t N = t->getOrderedConfigs().size();
- sp<AaptSymbols> typeSymbols =
- outSymbols->addNestedSymbol(String8(t->getName()), t->getPos());
+ sp<AaptSymbols> typeSymbols;
+ if (t->getName() == String16(kAttrPrivateType)) {
+ typeSymbols = outSymbols->addNestedSymbol(String8("attr"), t->getPos());
+ } else {
+ typeSymbols = outSymbols->addNestedSymbol(String8(t->getName()), t->getPos());
+ }
+
if (typeSymbols == NULL) {
return UNKNOWN_ERROR;
}
@@ -2973,6 +3009,10 @@ status_t ResourceTable::flatten(Bundle* bundle, const sp<const ResourceFilter>&
for (size_t ei=0; ei<N; ei++) {
sp<ConfigList> cl = t->getOrderedConfigs().itemAt(ei);
+ if (cl == NULL) {
+ continue;
+ }
+
if (cl->getPublic()) {
typeSpecFlags[ei] |= htodl(ResTable_typeSpec::SPEC_PUBLIC);
}
@@ -3003,12 +3043,16 @@ status_t ResourceTable::flatten(Bundle* bundle, const sp<const ResourceFilter>&
// We need to write one type chunk for each configuration for
// which we have entries in this type.
- const size_t NC = t != NULL ? t->getUniqueConfigs().size() : 0;
+ SortedVector<ConfigDescription> uniqueConfigs;
+ if (t != NULL) {
+ uniqueConfigs = t->getUniqueConfigs();
+ }
const size_t typeSize = sizeof(ResTable_type) + sizeof(uint32_t)*N;
+ const size_t NC = uniqueConfigs.size();
for (size_t ci=0; ci<NC; ci++) {
- ConfigDescription config = t->getUniqueConfigs().itemAt(ci);
+ const ConfigDescription& config = uniqueConfigs[ci];
if (kIsDebug) {
printf("Writing config %zu config: imsi:%d/%d lang:%c%c cnt:%c%c "
@@ -3084,7 +3128,10 @@ status_t ResourceTable::flatten(Bundle* bundle, const sp<const ResourceFilter>&
// Build the entries inside of this type.
for (size_t ei=0; ei<N; ei++) {
sp<ConfigList> cl = t->getOrderedConfigs().itemAt(ei);
- sp<Entry> e = cl->getEntries().valueFor(config);
+ sp<Entry> e = NULL;
+ if (cl != NULL) {
+ e = cl->getEntries().valueFor(config);
+ }
// Set the offset for this entry in its type.
uint32_t* index = (uint32_t*)
@@ -3119,9 +3166,11 @@ status_t ResourceTable::flatten(Bundle* bundle, const sp<const ResourceFilter>&
for (size_t i = 0; i < N; ++i) {
if (!validResources[i]) {
sp<ConfigList> c = t->getOrderedConfigs().itemAt(i);
- fprintf(stderr, "%s: no entries written for %s/%s (0x%08x)\n", log_prefix,
- String8(typeName).string(), String8(c->getName()).string(),
- Res_MAKEID(p->getAssignedId() - 1, ti, i));
+ if (c != NULL) {
+ fprintf(stderr, "%s: no entries written for %s/%s (0x%08x)\n", log_prefix,
+ String8(typeName).string(), String8(c->getName()).string(),
+ Res_MAKEID(p->getAssignedId() - 1, ti, i));
+ }
missing_entry = true;
}
}
@@ -3833,11 +3882,45 @@ sp<ResourceTable::Entry> ResourceTable::Type::getEntry(const String16& entry,
*/
}
- mUniqueConfigs.add(cdesc);
-
return e;
}
+sp<ResourceTable::ConfigList> ResourceTable::Type::removeEntry(const String16& entry) {
+ ssize_t idx = mConfigs.indexOfKey(entry);
+ if (idx < 0) {
+ return NULL;
+ }
+
+ sp<ConfigList> removed = mConfigs.valueAt(idx);
+ mConfigs.removeItemsAt(idx);
+
+ Vector<sp<ConfigList> >::iterator iter = std::find(
+ mOrderedConfigs.begin(), mOrderedConfigs.end(), removed);
+ if (iter != mOrderedConfigs.end()) {
+ mOrderedConfigs.erase(iter);
+ }
+
+ mPublic.removeItem(entry);
+ return removed;
+}
+
+SortedVector<ConfigDescription> ResourceTable::Type::getUniqueConfigs() const {
+ SortedVector<ConfigDescription> unique;
+ const size_t entryCount = mOrderedConfigs.size();
+ for (size_t i = 0; i < entryCount; i++) {
+ if (mOrderedConfigs[i] == NULL) {
+ continue;
+ }
+ const DefaultKeyedVector<ConfigDescription, sp<Entry> >& configs =
+ mOrderedConfigs[i]->getEntries();
+ const size_t configCount = configs.size();
+ for (size_t j = 0; j < configCount; j++) {
+ unique.add(configs.keyAt(j));
+ }
+ }
+ return unique;
+}
+
status_t ResourceTable::Type::applyPublicEntryOrder()
{
size_t N = mOrderedConfigs.size();
@@ -3864,11 +3947,10 @@ status_t ResourceTable::Type::applyPublicEntryOrder()
//printf("#%d: \"%s\"\n", i, String8(e->getName()).string());
if (e->getName() == name) {
if (idx >= (int32_t)mOrderedConfigs.size()) {
- p.sourcePos.error("Public entry identifier 0x%x entry index "
- "is larger than available symbols (index %d, total symbols %d).\n",
- p.ident, idx, mOrderedConfigs.size());
- hasError = true;
- } else if (mOrderedConfigs.itemAt(idx) == NULL) {
+ mOrderedConfigs.resize(idx + 1);
+ }
+
+ if (mOrderedConfigs.itemAt(idx) == NULL) {
e->setPublic(true);
e->setPublicSourcePos(p.sourcePos);
mOrderedConfigs.replaceAt(e, idx);
@@ -4041,6 +4123,61 @@ status_t ResourceTable::Package::applyPublicTypeOrder()
return NO_ERROR;
}
+void ResourceTable::Package::movePrivateAttrs() {
+ sp<Type> attr = mTypes.valueFor(String16("attr"));
+ if (attr == NULL) {
+ // Nothing to do.
+ return;
+ }
+
+ Vector<sp<ConfigList> > privateAttrs;
+
+ bool hasPublic = false;
+ const Vector<sp<ConfigList> >& configs = attr->getOrderedConfigs();
+ const size_t configCount = configs.size();
+ for (size_t i = 0; i < configCount; i++) {
+ if (configs[i] == NULL) {
+ continue;
+ }
+
+ if (attr->isPublic(configs[i]->getName())) {
+ hasPublic = true;
+ } else {
+ privateAttrs.add(configs[i]);
+ }
+ }
+
+ // Only if we have public attributes do we create a separate type for
+ // private attributes.
+ if (!hasPublic) {
+ return;
+ }
+
+ // Create a new type for private attributes.
+ sp<Type> privateAttrType = getType(String16(kAttrPrivateType), SourcePos());
+
+ const size_t privateAttrCount = privateAttrs.size();
+ for (size_t i = 0; i < privateAttrCount; i++) {
+ const sp<ConfigList>& cl = privateAttrs[i];
+
+ // Remove the private attributes from their current type.
+ attr->removeEntry(cl->getName());
+
+ // Add it to the new type.
+ const DefaultKeyedVector<ConfigDescription, sp<Entry> >& entries = cl->getEntries();
+ const size_t entryCount = entries.size();
+ for (size_t j = 0; j < entryCount; j++) {
+ const sp<Entry>& oldEntry = entries[j];
+ sp<Entry> entry = privateAttrType->getEntry(
+ cl->getName(), oldEntry->getPos(), &entries.keyAt(j));
+ *entry = *oldEntry;
+ }
+
+ // Move the symbols to the new type.
+
+ }
+}
+
sp<ResourceTable::Package> ResourceTable::getPackage(const String16& package)
{
if (package != mAssetsPackage) {
@@ -4220,38 +4357,80 @@ bool ResourceTable::getItemValue(
}
/**
- * Returns true if the given attribute ID comes from
- * a platform version from or after L.
+ * Returns the SDK version at which the attribute was
+ * made public, or -1 if the resource ID is not an attribute
+ * or is not public.
*/
-bool ResourceTable::isAttributeFromL(uint32_t attrId) {
- const uint32_t baseAttrId = 0x010103f7;
- if ((attrId & 0xffff0000) != (baseAttrId & 0xffff0000)) {
- return false;
+int ResourceTable::getPublicAttributeSdkLevel(uint32_t attrId) const {
+ if (Res_GETPACKAGE(attrId) + 1 != 0x01 || Res_GETTYPE(attrId) + 1 != 0x01) {
+ return -1;
}
uint32_t specFlags;
if (!mAssets->getIncludedResources().getResourceFlags(attrId, &specFlags)) {
- return false;
+ return -1;
+ }
+
+ if ((specFlags & ResTable_typeSpec::SPEC_PUBLIC) == 0) {
+ return -1;
+ }
+
+ const size_t entryId = Res_GETENTRY(attrId);
+ if (entryId <= 0x021c) {
+ return 1;
+ } else if (entryId <= 0x021d) {
+ return 2;
+ } else if (entryId <= 0x0269) {
+ return SDK_CUPCAKE;
+ } else if (entryId <= 0x028d) {
+ return SDK_DONUT;
+ } else if (entryId <= 0x02ad) {
+ return SDK_ECLAIR;
+ } else if (entryId <= 0x02b3) {
+ return SDK_ECLAIR_0_1;
+ } else if (entryId <= 0x02b5) {
+ return SDK_ECLAIR_MR1;
+ } else if (entryId <= 0x02bd) {
+ return SDK_FROYO;
+ } else if (entryId <= 0x02cb) {
+ return SDK_GINGERBREAD;
+ } else if (entryId <= 0x0361) {
+ return SDK_HONEYCOMB;
+ } else if (entryId <= 0x0366) {
+ return SDK_HONEYCOMB_MR1;
+ } else if (entryId <= 0x03a6) {
+ return SDK_HONEYCOMB_MR2;
+ } else if (entryId <= 0x03ae) {
+ return SDK_JELLY_BEAN;
+ } else if (entryId <= 0x03cc) {
+ return SDK_JELLY_BEAN_MR1;
+ } else if (entryId <= 0x03da) {
+ return SDK_JELLY_BEAN_MR2;
+ } else if (entryId <= 0x03f1) {
+ return SDK_KITKAT;
+ } else if (entryId <= 0x03f6) {
+ return SDK_KITKAT_WATCH;
+ } else if (entryId <= 0x04ce) {
+ return SDK_LOLLIPOP;
+ } else {
+ // Anything else is marked as defined in
+ // SDK_LOLLIPOP_MR1 since after this
+ // version no attribute compat work
+ // needs to be done.
+ return SDK_LOLLIPOP_MR1;
}
-
- return (specFlags & ResTable_typeSpec::SPEC_PUBLIC) != 0 &&
- (attrId & 0x0000ffff) >= (baseAttrId & 0x0000ffff);
}
-static bool isMinSdkVersionLOrAbove(const Bundle* bundle) {
- if (bundle->getMinSdkVersion() != NULL && strlen(bundle->getMinSdkVersion()) > 0) {
- const char firstChar = bundle->getMinSdkVersion()[0];
- if (firstChar >= 'L' && firstChar <= 'Z') {
- // L is the code-name for the v21 release.
- return true;
- }
-
- const int minSdk = atoi(bundle->getMinSdkVersion());
- if (minSdk >= SDK_L) {
- return true;
- }
+/**
+ * First check the Manifest, then check the command line flag.
+ */
+static int getMinSdkVersion(const Bundle* bundle) {
+ if (bundle->getManifestMinSdkVersion() != NULL && strlen(bundle->getManifestMinSdkVersion()) > 0) {
+ return atoi(bundle->getManifestMinSdkVersion());
+ } else if (bundle->getMinSdkVersion() != NULL && strlen(bundle->getMinSdkVersion()) > 0) {
+ return atoi(bundle->getMinSdkVersion());
}
- return false;
+ return 0;
}
/**
@@ -4297,9 +4476,10 @@ static bool isMinSdkVersionLOrAbove(const Bundle* bundle) {
* attribute will be respected.
*/
status_t ResourceTable::modifyForCompat(const Bundle* bundle) {
- if (isMinSdkVersionLOrAbove(bundle)) {
- // If this app will only ever run on L+ devices,
- // we don't need to do any compatibility work.
+ const int minSdk = getMinSdkVersion(bundle);
+ if (minSdk >= SDK_LOLLIPOP_MR1) {
+ // Lollipop MR1 and up handles public attributes differently, no
+ // need to do any compat modifications.
return NO_ERROR;
}
@@ -4338,20 +4518,19 @@ status_t ResourceTable::modifyForCompat(const Bundle* bundle) {
}
const ConfigDescription& config = entries.keyAt(ei);
- if (config.sdkVersion >= SDK_L) {
- // We don't need to do anything if the resource is
- // already qualified for version 21 or higher.
+ if (config.sdkVersion >= SDK_LOLLIPOP_MR1) {
continue;
}
- Vector<String16> attributesToRemove;
+ KeyedVector<int, Vector<String16> > attributesToRemove;
const KeyedVector<String16, Item>& bag = e->getBag();
const size_t bagCount = bag.size();
for (size_t bi = 0; bi < bagCount; bi++) {
const Item& item = bag.valueAt(bi);
const uint32_t attrId = getResId(bag.keyAt(bi), &attr16);
- if (isAttributeFromL(attrId)) {
- attributesToRemove.add(bag.keyAt(bi));
+ const int sdkLevel = getPublicAttributeSdkLevel(attrId);
+ if (sdkLevel > 1 && sdkLevel > config.sdkVersion && sdkLevel > minSdk) {
+ AaptUtil::appendValue(attributesToRemove, sdkLevel, bag.keyAt(bi));
}
}
@@ -4359,16 +4538,41 @@ status_t ResourceTable::modifyForCompat(const Bundle* bundle) {
continue;
}
- // Duplicate the entry under the same configuration
- // but with sdkVersion == SDK_L.
- ConfigDescription newConfig(config);
- newConfig.sdkVersion = SDK_L;
- entriesToAdd.add(key_value_pair_t<ConfigDescription, sp<Entry> >(
- newConfig, new Entry(*e)));
+ const size_t sdkCount = attributesToRemove.size();
+ for (size_t i = 0; i < sdkCount; i++) {
+ const int sdkLevel = attributesToRemove.keyAt(i);
+
+ // Duplicate the entry under the same configuration
+ // but with sdkVersion == sdkLevel.
+ ConfigDescription newConfig(config);
+ newConfig.sdkVersion = sdkLevel;
+
+ sp<Entry> newEntry = new Entry(*e);
+
+ // Remove all items that have a higher SDK level than
+ // the one we are synthesizing.
+ for (size_t j = 0; j < sdkCount; j++) {
+ if (j == i) {
+ continue;
+ }
+
+ if (attributesToRemove.keyAt(j) > sdkLevel) {
+ const size_t attrCount = attributesToRemove[j].size();
+ for (size_t k = 0; k < attrCount; k++) {
+ newEntry->removeFromBag(attributesToRemove[j][k]);
+ }
+ }
+ }
+
+ entriesToAdd.add(key_value_pair_t<ConfigDescription, sp<Entry> >(
+ newConfig, newEntry));
+ }
// Remove the attribute from the original.
for (size_t i = 0; i < attributesToRemove.size(); i++) {
- e->removeFromBag(attributesToRemove[i]);
+ for (size_t j = 0; j < attributesToRemove[i].size(); j++) {
+ e->removeFromBag(attributesToRemove[i][j]);
+ }
}
}
@@ -4385,7 +4589,7 @@ status_t ResourceTable::modifyForCompat(const Bundle* bundle) {
if (bundle->getVerbose()) {
entriesToAdd[i].value->getPos()
.printf("using v%d attributes; synthesizing resource %s:%s/%s for configuration %s.",
- SDK_L,
+ entriesToAdd[i].key.sdkVersion,
String8(p->getName()).string(),
String8(t->getName()).string(),
String8(entriesToAdd[i].value->getName()).string(),
@@ -4408,17 +4612,23 @@ status_t ResourceTable::modifyForCompat(const Bundle* bundle,
const String16& resourceName,
const sp<AaptFile>& target,
const sp<XMLNode>& root) {
- if (isMinSdkVersionLOrAbove(bundle)) {
+ const int minSdk = getMinSdkVersion(bundle);
+ if (minSdk >= SDK_LOLLIPOP_MR1) {
+ // Lollipop MR1 and up handles public attributes differently, no
+ // need to do any compat modifications.
return NO_ERROR;
}
- if (target->getResourceType() == "" || target->getGroupEntry().toParams().sdkVersion >= SDK_L) {
+ const ConfigDescription config(target->getGroupEntry().toParams());
+ if (target->getResourceType() == "" || config.sdkVersion >= SDK_LOLLIPOP_MR1) {
// Skip resources that have no type (AndroidManifest.xml) or are already version qualified with v21
// or higher.
return NO_ERROR;
}
- Vector<key_value_pair_t<sp<XMLNode>, size_t> > attrsToRemove;
+ sp<XMLNode> newRoot = NULL;
+ ConfigDescription newConfig(target->getGroupEntry().toParams());
+ newConfig.sdkVersion = SDK_LOLLIPOP_MR1;
Vector<sp<XMLNode> > nodesToVisit;
nodesToVisit.push(root);
@@ -4427,11 +4637,31 @@ status_t ResourceTable::modifyForCompat(const Bundle* bundle,
nodesToVisit.pop();
const Vector<XMLNode::attribute_entry>& attrs = node->getAttributes();
- const size_t attrCount = attrs.size();
- for (size_t i = 0; i < attrCount; i++) {
+ for (size_t i = 0; i < attrs.size(); i++) {
const XMLNode::attribute_entry& attr = attrs[i];
- if (isAttributeFromL(attr.nameResId)) {
- attrsToRemove.add(key_value_pair_t<sp<XMLNode>, size_t>(node, i));
+ const int sdkLevel = getPublicAttributeSdkLevel(attr.nameResId);
+ if (sdkLevel > 1 && sdkLevel > config.sdkVersion && sdkLevel > minSdk) {
+ if (newRoot == NULL) {
+ newRoot = root->clone();
+ }
+
+ // Find the smallest sdk version that we need to synthesize for
+ // and do that one. Subsequent versions will be processed on
+ // the next pass.
+ if (sdkLevel < newConfig.sdkVersion) {
+ newConfig.sdkVersion = sdkLevel;
+ }
+
+ if (bundle->getVerbose()) {
+ SourcePos(node->getFilename(), node->getStartLineNumber()).printf(
+ "removing attribute %s%s%s from <%s>",
+ String8(attr.ns).string(),
+ (attr.ns.size() == 0 ? "" : ":"),
+ String8(attr.name).string(),
+ String8(node->getElementName()).string());
+ }
+ node->removeAttribute(i);
+ i--;
}
}
@@ -4443,22 +4673,15 @@ status_t ResourceTable::modifyForCompat(const Bundle* bundle,
}
}
- if (attrsToRemove.isEmpty()) {
+ if (newRoot == NULL) {
return NO_ERROR;
}
- ConfigDescription newConfig(target->getGroupEntry().toParams());
- newConfig.sdkVersion = SDK_L;
-
// Look to see if we already have an overriding v21 configuration.
sp<ConfigList> cl = getConfigList(String16(mAssets->getPackage()),
String16(target->getResourceType()), resourceName);
- //if (cl == NULL) {
- // fprintf(stderr, "fuuuuck\n");
- //}
if (cl->getEntries().indexOfKey(newConfig) < 0) {
// We don't have an overriding entry for v21, so we must duplicate this one.
- sp<XMLNode> newRoot = root->clone();
sp<AaptFile> newFile = new AaptFile(target->getSourceFile(),
AaptGroupEntry(newConfig), target->getResourceType());
String8 resPath = String8::format("res/%s/%s",
@@ -4470,7 +4693,7 @@ status_t ResourceTable::modifyForCompat(const Bundle* bundle,
if (bundle->getVerbose()) {
SourcePos(target->getSourceFile(), -1).printf(
"using v%d attributes; synthesizing resource %s:%s/%s for configuration %s.",
- SDK_L,
+ newConfig.sdkVersion,
mAssets->getPackage().string(),
newFile->getResourceType().string(),
String8(resourceName).string(),
@@ -4493,21 +4716,36 @@ status_t ResourceTable::modifyForCompat(const Bundle* bundle,
mWorkQueue.push(item);
}
- const size_t removeCount = attrsToRemove.size();
- for (size_t i = 0; i < removeCount; i++) {
- sp<XMLNode> node = attrsToRemove[i].key;
- size_t attrIndex = attrsToRemove[i].value;
- const XMLNode::attribute_entry& ae = node->getAttributes()[attrIndex];
- if (bundle->getVerbose()) {
- SourcePos(node->getFilename(), node->getStartLineNumber()).printf(
- "removing attribute %s%s%s from <%s>",
- String8(ae.ns).string(),
- (ae.ns.size() == 0 ? "" : ":"),
- String8(ae.name).string(),
- String8(node->getElementName()).string());
+ return NO_ERROR;
+}
+
+void ResourceTable::getDensityVaryingResources(KeyedVector<Symbol, Vector<SymbolDefinition> >& resources) {
+ const ConfigDescription nullConfig;
+
+ const size_t packageCount = mOrderedPackages.size();
+ for (size_t p = 0; p < packageCount; p++) {
+ const Vector<sp<Type> >& types = mOrderedPackages[p]->getOrderedTypes();
+ const size_t typeCount = types.size();
+ for (size_t t = 0; t < typeCount; t++) {
+ const Vector<sp<ConfigList> >& configs = types[t]->getOrderedConfigs();
+ const size_t configCount = configs.size();
+ for (size_t c = 0; c < configCount; c++) {
+ const DefaultKeyedVector<ConfigDescription, sp<Entry> >& configEntries = configs[c]->getEntries();
+ const size_t configEntryCount = configEntries.size();
+ for (size_t ce = 0; ce < configEntryCount; ce++) {
+ const ConfigDescription& config = configEntries.keyAt(ce);
+ if (AaptConfig::isDensityOnly(config)) {
+ // This configuration only varies with regards to density.
+ const Symbol symbol(mOrderedPackages[p]->getName(),
+ types[t]->getName(),
+ configs[c]->getName(),
+ getResId(mOrderedPackages[p], types[t], configs[c]->getEntryIndex()));
+
+ const sp<Entry>& entry = configEntries.valueAt(ce);
+ AaptUtil::appendValue(resources, symbol, SymbolDefinition(symbol, config, entry->getPos()));
+ }
+ }
+ }
}
- node->removeAttribute(attrIndex);
}
-
- return NO_ERROR;
}
diff --git a/tools/aapt/ResourceTable.h b/tools/aapt/ResourceTable.h
index a939dd3..9644224 100644
--- a/tools/aapt/ResourceTable.h
+++ b/tools/aapt/ResourceTable.h
@@ -7,15 +7,16 @@
#ifndef RESOURCE_TABLE_H
#define RESOURCE_TABLE_H
-#include "ConfigDescription.h"
-#include "StringPool.h"
-#include "SourcePos.h"
-#include "ResourceFilter.h"
-
#include <map>
#include <queue>
#include <set>
+#include "ConfigDescription.h"
+#include "ResourceFilter.h"
+#include "SourcePos.h"
+#include "StringPool.h"
+#include "Symbol.h"
+
class XMLNode;
class ResourceTable;
@@ -467,6 +468,14 @@ public:
bool overlay = false,
bool autoAddOverlay = false);
+ bool isPublic(const String16& entry) const {
+ return mPublic.indexOfKey(entry) >= 0;
+ }
+
+ sp<ConfigList> removeEntry(const String16& entry);
+
+ SortedVector<ConfigDescription> getUniqueConfigs() const;
+
const SourcePos& getFirstPublicSourcePos() const { return *mFirstPublicSourcePos; }
int32_t getPublicIndex() const { return mPublicIndex; }
@@ -476,19 +485,16 @@ public:
status_t applyPublicEntryOrder();
- const SortedVector<ConfigDescription>& getUniqueConfigs() const { return mUniqueConfigs; }
-
const DefaultKeyedVector<String16, sp<ConfigList> >& getConfigs() const { return mConfigs; }
const Vector<sp<ConfigList> >& getOrderedConfigs() const { return mOrderedConfigs; }
-
const SortedVector<String16>& getCanAddEntries() const { return mCanAddEntries; }
const SourcePos& getPos() const { return mPos; }
+
private:
String16 mName;
SourcePos* mFirstPublicSourcePos;
DefaultKeyedVector<String16, Public> mPublic;
- SortedVector<ConfigDescription> mUniqueConfigs;
DefaultKeyedVector<String16, sp<ConfigList> > mConfigs;
Vector<sp<ConfigList> > mOrderedConfigs;
SortedVector<String16> mCanAddEntries;
@@ -524,6 +530,8 @@ public:
const DefaultKeyedVector<String16, sp<Type> >& getTypes() const { return mTypes; }
const Vector<sp<Type> >& getOrderedTypes() const { return mOrderedTypes; }
+ void movePrivateAttrs();
+
private:
status_t setStrings(const sp<AaptFile>& data,
ResStringPool* strings,
@@ -541,6 +549,8 @@ public:
DefaultKeyedVector<String16, uint32_t> mKeyStringsMapping;
};
+ void getDensityVaryingResources(KeyedVector<Symbol, Vector<SymbolDefinition> >& resources);
+
private:
void writePublicDefinitions(const String16& package, FILE* fp, bool pub);
sp<Package> getPackage(const String16& package);
@@ -563,7 +573,7 @@ private:
const Item* getItem(uint32_t resID, uint32_t attrID) const;
bool getItemValue(uint32_t resID, uint32_t attrID,
Res_value* outValue);
- bool isAttributeFromL(uint32_t attrId);
+ int getPublicAttributeSdkLevel(uint32_t attrId) const;
String16 mAssetsPackage;
diff --git a/tools/aapt/SdkConstants.h b/tools/aapt/SdkConstants.h
new file mode 100644
index 0000000..4e0fe10
--- /dev/null
+++ b/tools/aapt/SdkConstants.h
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef H_AAPT_SDK_CONSTANTS
+#define H_AAPT_SDK_CONSTANTS
+
+enum {
+ SDK_CUPCAKE = 3,
+ SDK_DONUT = 4,
+ SDK_ECLAIR = 5,
+ SDK_ECLAIR_0_1 = 6,
+ SDK_ECLAIR_MR1 = 7,
+ SDK_FROYO = 8,
+ SDK_GINGERBREAD = 9,
+ SDK_GINGERBREAD_MR1 = 10,
+ SDK_HONEYCOMB = 11,
+ SDK_HONEYCOMB_MR1 = 12,
+ SDK_HONEYCOMB_MR2 = 13,
+ SDK_ICE_CREAM_SANDWICH = 14,
+ SDK_ICE_CREAM_SANDWICH_MR1 = 15,
+ SDK_JELLY_BEAN = 16,
+ SDK_JELLY_BEAN_MR1 = 17,
+ SDK_JELLY_BEAN_MR2 = 18,
+ SDK_KITKAT = 19,
+ SDK_KITKAT_WATCH = 20,
+ SDK_LOLLIPOP = 21,
+ SDK_LOLLIPOP_MR1 = 22,
+};
+
+#endif // H_AAPT_SDK_CONSTANTS
diff --git a/tools/aapt/SourcePos.cpp b/tools/aapt/SourcePos.cpp
index ae25047..3864320 100644
--- a/tools/aapt/SourcePos.cpp
+++ b/tools/aapt/SourcePos.cpp
@@ -141,6 +141,12 @@ SourcePos::printf(const char* fmt, ...) const
}
bool
+SourcePos::operator<(const SourcePos& rhs) const
+{
+ return (file < rhs.file) || (line < rhs.line);
+}
+
+bool
SourcePos::hasErrors()
{
return g_errors.size() > 0;
diff --git a/tools/aapt/SourcePos.h b/tools/aapt/SourcePos.h
index 4ce817f..13cfb9d 100644
--- a/tools/aapt/SourcePos.h
+++ b/tools/aapt/SourcePos.h
@@ -21,6 +21,8 @@ public:
void warning(const char* fmt, ...) const;
void printf(const char* fmt, ...) const;
+ bool operator<(const SourcePos& rhs) const;
+
static bool hasErrors();
static void printErrors(FILE* to);
};
diff --git a/tools/aapt/StringPool.cpp b/tools/aapt/StringPool.cpp
index e3ec0ae..a18e9f1 100644
--- a/tools/aapt/StringPool.cpp
+++ b/tools/aapt/StringPool.cpp
@@ -26,6 +26,7 @@
// Set to true for noisy debug output.
static const bool kIsDebug = false;
+#if __cplusplus >= 201103L
void strcpy16_htod(char16_t* dst, const char16_t* src)
{
while (*src) {
@@ -35,6 +36,17 @@ void strcpy16_htod(char16_t* dst, const char16_t* src)
}
*dst = 0;
}
+#endif
+
+void strcpy16_htod(uint16_t* dst, const char16_t* src)
+{
+ while (*src) {
+ uint16_t s = htods(static_cast<uint16_t>(*src));
+ *dst++ = s;
+ src++;
+ }
+ *dst = 0;
+}
void printStringPool(const ResStringPool* pool)
{
@@ -434,7 +446,7 @@ status_t StringPool::writeStringBlock(const sp<AaptFile>& pool)
return NO_MEMORY;
}
- const size_t charSize = mUTF8 ? sizeof(uint8_t) : sizeof(char16_t);
+ const size_t charSize = mUTF8 ? sizeof(uint8_t) : sizeof(uint16_t);
size_t strPos = 0;
for (i=0; i<STRINGS; i++) {
diff --git a/tools/aapt/StringPool.h b/tools/aapt/StringPool.h
index 0b26538..dbe8c85 100644
--- a/tools/aapt/StringPool.h
+++ b/tools/aapt/StringPool.h
@@ -26,7 +26,10 @@ using namespace android;
#define PRINT_STRING_METRICS 0
+#if __cplusplus >= 201103L
void strcpy16_htod(char16_t* dst, const char16_t* src);
+#endif
+void strcpy16_htod(uint16_t* dst, const char16_t* src);
void printStringPool(const ResStringPool* pool);
diff --git a/tools/aapt/Symbol.h b/tools/aapt/Symbol.h
new file mode 100644
index 0000000..e157541
--- /dev/null
+++ b/tools/aapt/Symbol.h
@@ -0,0 +1,95 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef AAPT_SYMBOL_H
+#define AAPT_SYMBOL_H
+
+#include <utils/String8.h>
+#include <utils/String16.h>
+
+#include "ConfigDescription.h"
+#include "SourcePos.h"
+
+/**
+ * A resource symbol, not attached to any configuration or context.
+ */
+struct Symbol {
+ inline Symbol();
+ inline Symbol(const android::String16& p, const android::String16& t, const android::String16& n, uint32_t i);
+ inline android::String8 toString() const;
+ inline bool operator<(const Symbol& rhs) const;
+
+ android::String16 package;
+ android::String16 type;
+ android::String16 name;
+ uint32_t id;
+
+};
+
+/**
+ * A specific defintion of a symbol, defined with a configuration and a definition site.
+ */
+struct SymbolDefinition {
+ inline SymbolDefinition();
+ inline SymbolDefinition(const Symbol& s, const ConfigDescription& c, const SourcePos& src);
+ inline bool operator<(const SymbolDefinition& rhs) const;
+
+ Symbol symbol;
+ ConfigDescription config;
+ SourcePos source;
+};
+
+//
+// Implementations
+//
+
+Symbol::Symbol() {
+}
+
+Symbol::Symbol(const android::String16& p, const android::String16& t, const android::String16& n, uint32_t i)
+ : package(p)
+ , type(t)
+ , name(n)
+ , id(i) {
+}
+
+android::String8 Symbol::toString() const {
+ return android::String8::format("%s:%s/%s (0x%08x)",
+ android::String8(package).string(),
+ android::String8(type).string(),
+ android::String8(name).string(),
+ (int) id);
+}
+
+bool Symbol::operator<(const Symbol& rhs) const {
+ return (package < rhs.package) || (type < rhs.type) || (name < rhs.name) || (id < rhs.id);
+}
+
+SymbolDefinition::SymbolDefinition() {
+}
+
+SymbolDefinition::SymbolDefinition(const Symbol& s, const ConfigDescription& c, const SourcePos& src)
+ : symbol(s)
+ , config(c)
+ , source(src) {
+}
+
+bool SymbolDefinition::operator<(const SymbolDefinition& rhs) const {
+ return (symbol < rhs.symbol) || (config < rhs.config) || (source < rhs.source);
+}
+
+#endif // AAPT_SYMBOL_H
+