AAPT2: Support -c configuration filtering
Change-Id: I1e5855ca73440bdc30c21bcbc1dfdd31a9842363
diff --git a/tools/aapt2/link/Link.cpp b/tools/aapt2/link/Link.cpp
index 3ecb2c4..fd76e88 100644
--- a/tools/aapt2/link/Link.cpp
+++ b/tools/aapt2/link/Link.cpp
@@ -17,8 +17,10 @@
#include "AppInfo.h"
#include "Debug.h"
#include "Flags.h"
+#include "Locale.h"
#include "NameMangler.h"
#include "compile/IdAssigner.h"
+#include "filter/ConfigFilter.h"
#include "flatten/Archive.h"
#include "flatten/TableFlattener.h"
#include "flatten/XmlFlattener.h"
@@ -64,7 +66,7 @@
std::vector<std::string> extensionsToNotCompress;
Maybe<std::u16string> privateSymbols;
ManifestFixerOptions manifestFixerOptions;
-
+ IConfigFilter* configFilter = nullptr;
};
struct LinkContext : public IAaptContext {
@@ -97,8 +99,8 @@
class LinkCommand {
public:
- LinkCommand(const LinkOptions& options) :
- mOptions(options), mContext(), mFinalTable(), mFileCollection(nullptr) {
+ LinkCommand(LinkContext* context, const LinkOptions& options) :
+ mOptions(options), mContext(context), mFinalTable(), mFileCollection(nullptr) {
std::unique_ptr<io::FileCollection> fileCollection =
util::make_unique<io::FileCollection>();
@@ -117,14 +119,14 @@
AssetManagerSymbolTableBuilder builder;
for (const std::string& path : mOptions.includePaths) {
if (mOptions.verbose) {
- mContext.getDiagnostics()->note(DiagMessage(path) << "loading include path");
+ mContext->getDiagnostics()->note(DiagMessage(path) << "loading include path");
}
std::unique_ptr<android::AssetManager> assetManager =
util::make_unique<android::AssetManager>();
int32_t cookie = 0;
if (!assetManager->addAssetPath(android::String8(path.data(), path.size()), &cookie)) {
- mContext.getDiagnostics()->error(
+ mContext->getDiagnostics()->error(
DiagMessage(path) << "failed to load include path");
return {};
}
@@ -135,7 +137,7 @@
std::unique_ptr<ResourceTable> loadTable(const Source& source, const void* data, size_t len) {
std::unique_ptr<ResourceTable> table = util::make_unique<ResourceTable>();
- BinaryResourceParser parser(&mContext, table.get(), source, data, len);
+ BinaryResourceParser parser(mContext, table.get(), source, data, len);
if (!parser.parse()) {
return {};
}
@@ -207,7 +209,7 @@
IArchiveWriter* writer) {
std::unique_ptr<io::IData> data = file->openAsData();
if (!data) {
- mContext.getDiagnostics()->error(DiagMessage(file->getSource())
+ mContext->getDiagnostics()->error(DiagMessage(file->getSource())
<< "failed to open file");
return false;
}
@@ -215,7 +217,7 @@
std::string errorStr;
ssize_t offset = getWrappedDataOffset(data->data(), data->size(), &errorStr);
if (offset < 0) {
- mContext.getDiagnostics()->error(DiagMessage(file->getSource()) << errorStr);
+ mContext->getDiagnostics()->error(DiagMessage(file->getSource()) << errorStr);
return false;
}
@@ -228,7 +230,7 @@
}
}
- mContext.getDiagnostics()->error(
+ mContext->getDiagnostics()->error(
DiagMessage(mOptions.outputPath) << "failed to write file " << outPath);
return false;
}
@@ -252,9 +254,9 @@
*/
bool verifyNoExternalPackages() {
auto isExtPackageFunc = [&](const std::unique_ptr<ResourceTablePackage>& pkg) -> bool {
- return mContext.getCompilationPackage() != pkg->name ||
+ return mContext->getCompilationPackage() != pkg->name ||
!pkg->id ||
- pkg->id.value() != mContext.getPackageId();
+ pkg->id.value() != mContext->getPackageId();
};
bool error = false;
@@ -270,13 +272,13 @@
// 'android' package. This is due to legacy reasons.
if (valueCast<Id>(configValue.value.get()) &&
package->name == u"android") {
- mContext.getDiagnostics()->warn(
+ mContext->getDiagnostics()->warn(
DiagMessage(configValue.value->getSource())
<< "generated id '" << resName
<< "' for external package '" << package->name
<< "'");
} else {
- mContext.getDiagnostics()->error(
+ mContext->getDiagnostics()->error(
DiagMessage(configValue.value->getSource())
<< "defined resource '" << resName
<< "' for external package '" << package->name
@@ -297,9 +299,9 @@
std::unique_ptr<IArchiveWriter> makeArchiveWriter() {
if (mOptions.outputToDirectory) {
- return createDirectoryArchiveWriter(mContext.getDiagnostics(), mOptions.outputPath);
+ return createDirectoryArchiveWriter(mContext->getDiagnostics(), mOptions.outputPath);
} else {
- return createZipFileArchiveWriter(mContext.getDiagnostics(), mOptions.outputPath);
+ return createZipFileArchiveWriter(mContext->getDiagnostics(), mOptions.outputPath);
}
}
@@ -308,7 +310,7 @@
TableFlattenerOptions options = {};
options.useExtendedChunks = mOptions.staticLib;
TableFlattener flattener(&buffer, options);
- if (!flattener.consume(&mContext, table)) {
+ if (!flattener.consume(mContext, table)) {
return false;
}
@@ -320,7 +322,7 @@
}
}
- mContext.getDiagnostics()->error(
+ mContext->getDiagnostics()->error(
DiagMessage() << "failed to write resources.arsc to archive");
return false;
}
@@ -332,7 +334,7 @@
options.keepRawValues = mOptions.staticLib;
options.maxSdkLevel = maxSdkLevel;
XmlFlattener flattener(&buffer, options);
- if (!flattener.consume(&mContext, xmlRes)) {
+ if (!flattener.consume(mContext, xmlRes)) {
return false;
}
@@ -343,7 +345,7 @@
}
}
}
- mContext.getDiagnostics()->error(
+ mContext->getDiagnostics()->error(
DiagMessage() << "failed to write " << path << " to archive");
return false;
}
@@ -361,13 +363,13 @@
std::ofstream fout(outPath, std::ofstream::binary);
if (!fout) {
- mContext.getDiagnostics()->error(DiagMessage() << strerror(errno));
+ mContext->getDiagnostics()->error(DiagMessage() << strerror(errno));
return false;
}
JavaClassGenerator generator(table, javaOptions);
if (!generator.generate(packageNameToGenerate, outPackage, &fout)) {
- mContext.getDiagnostics()->error(DiagMessage(outPath) << generator.getError());
+ mContext->getDiagnostics()->error(DiagMessage(outPath) << generator.getError());
return false;
}
return true;
@@ -380,24 +382,24 @@
std::string outPath = mOptions.generateJavaClassPath.value();
file::appendPath(&outPath,
- file::packageToPath(util::utf16ToUtf8(mContext.getCompilationPackage())));
+ file::packageToPath(util::utf16ToUtf8(mContext->getCompilationPackage())));
file::mkdirs(outPath);
file::appendPath(&outPath, "Manifest.java");
std::ofstream fout(outPath, std::ofstream::binary);
if (!fout) {
- mContext.getDiagnostics()->error(DiagMessage() << strerror(errno));
+ mContext->getDiagnostics()->error(DiagMessage() << strerror(errno));
return false;
}
ManifestClassGenerator generator;
- if (!generator.generate(mContext.getDiagnostics(), mContext.getCompilationPackage(),
+ if (!generator.generate(mContext->getDiagnostics(), mContext->getCompilationPackage(),
manifestXml, &fout)) {
return false;
}
if (!fout) {
- mContext.getDiagnostics()->error(DiagMessage() << strerror(errno));
+ mContext->getDiagnostics()->error(DiagMessage() << strerror(errno));
return false;
}
return true;
@@ -410,13 +412,13 @@
std::ofstream fout(mOptions.generateProguardRulesPath.value(), std::ofstream::binary);
if (!fout) {
- mContext.getDiagnostics()->error(DiagMessage() << strerror(errno));
+ mContext->getDiagnostics()->error(DiagMessage() << strerror(errno));
return false;
}
proguard::writeKeepSet(&fout, keepSet);
if (!fout) {
- mContext.getDiagnostics()->error(DiagMessage() << strerror(errno));
+ mContext->getDiagnostics()->error(DiagMessage() << strerror(errno));
return false;
}
return true;
@@ -425,7 +427,7 @@
bool mergeStaticLibrary(const std::string& input) {
// TODO(adamlesinski): Load resources from a static library APK and merge the table into
// TableMerger.
- mContext.getDiagnostics()->warn(DiagMessage()
+ mContext->getDiagnostics()->warn(DiagMessage()
<< "linking static libraries not supported yet: "
<< input);
return true;
@@ -433,12 +435,12 @@
bool mergeResourceTable(io::IFile* file, bool override) {
if (mOptions.verbose) {
- mContext.getDiagnostics()->note(DiagMessage() << "linking " << file->getSource());
+ mContext->getDiagnostics()->note(DiagMessage() << "linking " << file->getSource());
}
std::unique_ptr<io::IData> data = file->openAsData();
if (!data) {
- mContext.getDiagnostics()->error(DiagMessage(file->getSource())
+ mContext->getDiagnostics()->error(DiagMessage(file->getSource())
<< "failed to open file");
return false;
}
@@ -460,7 +462,7 @@
bool mergeCompiledFile(io::IFile* file, std::unique_ptr<ResourceFile> fileDesc, bool overlay) {
if (mOptions.verbose) {
- mContext.getDiagnostics()->note(DiagMessage() << "adding " << file->getSource());
+ mContext->getDiagnostics()->note(DiagMessage() << "adding " << file->getSource());
}
bool result = false;
@@ -477,12 +479,12 @@
// Add the exports of this file to the table.
for (SourcedResourceName& exportedSymbol : fileDesc->exportedSymbols) {
if (exportedSymbol.name.package.empty()) {
- exportedSymbol.name.package = mContext.getCompilationPackage().toString();
+ exportedSymbol.name.package = mContext->getCompilationPackage().toString();
}
ResourceNameRef resName = exportedSymbol.name;
- Maybe<ResourceName> mangledName = mContext.getNameMangler()->mangleName(
+ Maybe<ResourceName> mangledName = mContext->getNameMangler()->mangleName(
exportedSymbol.name);
if (mangledName) {
resName = mangledName.value();
@@ -491,7 +493,7 @@
std::unique_ptr<Id> id = util::make_unique<Id>();
id->setSource(fileDesc->source.withLine(exportedSymbol.line));
bool result = mFinalTable.addResourceAllowMangled(resName, {}, std::move(id),
- mContext.getDiagnostics());
+ mContext->getDiagnostics());
if (!result) {
return false;
}
@@ -507,7 +509,7 @@
std::unique_ptr<io::ZipFileCollection> collection = io::ZipFileCollection::create(
input, &errorStr);
if (!collection) {
- mContext.getDiagnostics()->error(DiagMessage(input) << errorStr);
+ mContext->getDiagnostics()->error(DiagMessage(input) << errorStr);
return false;
}
@@ -543,12 +545,12 @@
// Try opening the file and looking for an Export header.
std::unique_ptr<io::IData> data = file->openAsData();
if (!data) {
- mContext.getDiagnostics()->error(DiagMessage(src) << "failed to open");
+ mContext->getDiagnostics()->error(DiagMessage(src) << "failed to open");
return false;
}
std::unique_ptr<ResourceFile> resourceFile = loadFileExportHeader(
- src, data->data(), data->size(), mContext.getDiagnostics());
+ src, data->data(), data->size(), mContext->getDiagnostics());
if (resourceFile) {
return mergeCompiledFile(file, std::move(resourceFile), override);
}
@@ -564,62 +566,63 @@
int run(const std::vector<std::string>& inputFiles) {
// Load the AndroidManifest.xml
std::unique_ptr<xml::XmlResource> manifestXml = loadXml(mOptions.manifestPath,
- mContext.getDiagnostics());
+ mContext->getDiagnostics());
if (!manifestXml) {
return 1;
}
if (Maybe<AppInfo> maybeAppInfo = extractAppInfoFromManifest(manifestXml.get())) {
- mContext.mCompilationPackage = maybeAppInfo.value().package;
+ mContext->mCompilationPackage = maybeAppInfo.value().package;
} else {
- mContext.getDiagnostics()->error(DiagMessage(mOptions.manifestPath)
+ mContext->getDiagnostics()->error(DiagMessage(mOptions.manifestPath)
<< "no package specified in <manifest> tag");
return 1;
}
- if (!util::isJavaPackageName(mContext.mCompilationPackage)) {
- mContext.getDiagnostics()->error(DiagMessage(mOptions.manifestPath)
+ if (!util::isJavaPackageName(mContext->mCompilationPackage)) {
+ mContext->getDiagnostics()->error(DiagMessage(mOptions.manifestPath)
<< "invalid package name '"
- << mContext.mCompilationPackage
+ << mContext->mCompilationPackage
<< "'");
return 1;
}
- mContext.mNameMangler = util::make_unique<NameMangler>(
- NameManglerPolicy{ mContext.mCompilationPackage });
+ mContext->mNameMangler = util::make_unique<NameMangler>(
+ NameManglerPolicy{ mContext->mCompilationPackage });
- if (mContext.mCompilationPackage == u"android") {
- mContext.mPackageId = 0x01;
+ if (mContext->mCompilationPackage == u"android") {
+ mContext->mPackageId = 0x01;
} else {
- mContext.mPackageId = 0x7f;
+ mContext->mPackageId = 0x7f;
}
- mContext.mSymbols = createSymbolTableFromIncludePaths();
- if (!mContext.mSymbols) {
+ mContext->mSymbols = createSymbolTableFromIncludePaths();
+ if (!mContext->mSymbols) {
return 1;
}
TableMergerOptions tableMergerOptions;
tableMergerOptions.autoAddOverlay = mOptions.autoAddOverlay;
- mTableMerger = util::make_unique<TableMerger>(&mContext, &mFinalTable, tableMergerOptions);
+ tableMergerOptions.filter = mOptions.configFilter;
+ mTableMerger = util::make_unique<TableMerger>(mContext, &mFinalTable, tableMergerOptions);
if (mOptions.verbose) {
- mContext.getDiagnostics()->note(
- DiagMessage() << "linking package '" << mContext.mCompilationPackage << "' "
- << "with package ID " << std::hex << (int) mContext.mPackageId);
+ mContext->getDiagnostics()->note(
+ DiagMessage() << "linking package '" << mContext->mCompilationPackage << "' "
+ << "with package ID " << std::hex << (int) mContext->mPackageId);
}
for (const std::string& input : inputFiles) {
if (!processFile(input, false)) {
- mContext.getDiagnostics()->error(DiagMessage() << "failed parsing input");
+ mContext->getDiagnostics()->error(DiagMessage() << "failed parsing input");
return 1;
}
}
for (const std::string& input : mOptions.overlayFiles) {
if (!processFile(input, true)) {
- mContext.getDiagnostics()->error(DiagMessage() << "failed parsing overlays");
+ mContext->getDiagnostics()->error(DiagMessage() << "failed parsing overlays");
return 1;
}
}
@@ -630,8 +633,8 @@
if (!mOptions.staticLib) {
PrivateAttributeMover mover;
- if (!mover.consume(&mContext, &mFinalTable)) {
- mContext.getDiagnostics()->error(
+ if (!mover.consume(mContext, &mFinalTable)) {
+ mContext->getDiagnostics()->error(
DiagMessage() << "failed moving private attributes");
return 1;
}
@@ -639,23 +642,23 @@
{
IdAssigner idAssigner;
- if (!idAssigner.consume(&mContext, &mFinalTable)) {
- mContext.getDiagnostics()->error(DiagMessage() << "failed assigning IDs");
+ if (!idAssigner.consume(mContext, &mFinalTable)) {
+ mContext->getDiagnostics()->error(DiagMessage() << "failed assigning IDs");
return 1;
}
}
- mContext.mNameMangler = util::make_unique<NameMangler>(NameManglerPolicy{
- mContext.mCompilationPackage, mTableMerger->getMergedPackages() });
- mContext.mSymbols = JoinedSymbolTableBuilder()
+ mContext->mNameMangler = util::make_unique<NameMangler>(NameManglerPolicy{
+ mContext->mCompilationPackage, mTableMerger->getMergedPackages() });
+ mContext->mSymbols = JoinedSymbolTableBuilder()
.addSymbolTable(util::make_unique<SymbolTableWrapper>(&mFinalTable))
- .addSymbolTable(std::move(mContext.mSymbols))
+ .addSymbolTable(std::move(mContext->mSymbols))
.build();
{
ReferenceLinker linker;
- if (!linker.consume(&mContext, &mFinalTable)) {
- mContext.getDiagnostics()->error(DiagMessage() << "failed linking references");
+ if (!linker.consume(mContext, &mFinalTable)) {
+ mContext->getDiagnostics()->error(DiagMessage() << "failed linking references");
return 1;
}
}
@@ -664,24 +667,24 @@
std::unique_ptr<IArchiveWriter> archiveWriter = makeArchiveWriter();
if (!archiveWriter) {
- mContext.getDiagnostics()->error(DiagMessage() << "failed to create archive");
+ mContext->getDiagnostics()->error(DiagMessage() << "failed to create archive");
return 1;
}
bool error = false;
{
ManifestFixer manifestFixer(mOptions.manifestFixerOptions);
- if (!manifestFixer.consume(&mContext, manifestXml.get())) {
+ if (!manifestFixer.consume(mContext, manifestXml.get())) {
error = true;
}
// AndroidManifest.xml has no resource name, but the CallSite is built from the name
// (aka, which package the AndroidManifest.xml is coming from).
// So we give it a package name so it can see local resources.
- manifestXml->file.name.package = mContext.getCompilationPackage().toString();
+ manifestXml->file.name.package = mContext->getCompilationPackage().toString();
XmlReferenceLinker manifestLinker;
- if (manifestLinker.consume(&mContext, manifestXml.get())) {
+ if (manifestLinker.consume(mContext, manifestXml.get())) {
if (!proguard::collectProguardRulesForManifest(Source(mOptions.manifestPath),
manifestXml.get(),
&proguardKeepSet)) {
@@ -704,7 +707,7 @@
}
if (error) {
- mContext.getDiagnostics()->error(DiagMessage() << "failed processing manifest");
+ mContext->getDiagnostics()->error(DiagMessage() << "failed processing manifest");
return 1;
}
@@ -718,13 +721,13 @@
(util::stringEndsWith<char>(path, ".xml.flat") ||
util::stringEndsWith<char>(path, ".xml"))) {
if (mOptions.verbose) {
- mContext.getDiagnostics()->note(DiagMessage() << "linking " << path);
+ mContext->getDiagnostics()->note(DiagMessage() << "linking " << path);
}
io::IFile* file = fileToMerge.file;
std::unique_ptr<io::IData> data = file->openAsData();
if (!data) {
- mContext.getDiagnostics()->error(DiagMessage(file->getSource())
+ mContext->getDiagnostics()->error(DiagMessage(file->getSource())
<< "failed to open file");
return 1;
}
@@ -733,9 +736,9 @@
if (util::stringEndsWith<char>(path, ".flat")) {
xmlRes = loadBinaryXmlSkipFileExport(file->getSource(),
data->data(), data->size(),
- mContext.getDiagnostics());
+ mContext->getDiagnostics());
} else {
- xmlRes = xml::inflate(data->data(), data->size(), mContext.getDiagnostics(),
+ xmlRes = xml::inflate(data->data(), data->size(), mContext->getDiagnostics(),
file->getSource());
}
@@ -751,7 +754,7 @@
};
XmlReferenceLinker xmlLinker;
- if (xmlLinker.consume(&mContext, xmlRes.get())) {
+ if (xmlLinker.consume(mContext, xmlRes.get())) {
if (!proguard::collectProguardRules(xmlRes->file.source, xmlRes.get(),
&proguardKeepSet)) {
error = true;
@@ -778,14 +781,14 @@
xmlRes->file.config.sdkVersion = sdkLevel;
std::string genResourcePath = ResourceUtils::buildResourceFileName(
- xmlRes->file, mContext.getNameMangler());
+ xmlRes->file, mContext->getNameMangler());
bool added = mFinalTable.addFileReference(
xmlRes->file.name,
xmlRes->file.config,
xmlRes->file.source,
util::utf8ToUtf16(genResourcePath),
- mContext.getDiagnostics());
+ mContext->getDiagnostics());
if (!added) {
error = true;
continue;
@@ -804,7 +807,7 @@
}
} else {
if (mOptions.verbose) {
- mContext.getDiagnostics()->note(DiagMessage() << "copying " << path);
+ mContext->getDiagnostics()->note(DiagMessage() << "copying " << path);
}
if (!copyFileToArchive(fileToMerge.file, fileToMerge.dstPath,
@@ -815,20 +818,20 @@
}
if (error) {
- mContext.getDiagnostics()->error(DiagMessage() << "failed linking file resources");
+ mContext->getDiagnostics()->error(DiagMessage() << "failed linking file resources");
return 1;
}
if (!mOptions.noAutoVersion) {
AutoVersioner versioner;
- if (!versioner.consume(&mContext, &mFinalTable)) {
- mContext.getDiagnostics()->error(DiagMessage() << "failed versioning styles");
+ if (!versioner.consume(mContext, &mFinalTable)) {
+ mContext->getDiagnostics()->error(DiagMessage() << "failed versioning styles");
return 1;
}
}
if (!flattenTable(&mFinalTable, archiveWriter.get())) {
- mContext.getDiagnostics()->error(DiagMessage() << "failed to write resources.arsc");
+ mContext->getDiagnostics()->error(DiagMessage() << "failed to write resources.arsc");
return 1;
}
@@ -840,8 +843,8 @@
options.useFinal = false;
}
- const StringPiece16 actualPackage = mContext.getCompilationPackage();
- StringPiece16 outputPackage = mContext.getCompilationPackage();
+ const StringPiece16 actualPackage = mContext->getCompilationPackage();
+ StringPiece16 outputPackage = mContext->getCompilationPackage();
if (mOptions.customJavaPackage) {
// Override the output java package to the custom one.
outputPackage = mOptions.customJavaPackage.value();
@@ -852,7 +855,7 @@
// to the original package, and private and public symbols to the private package.
options.types = JavaClassGeneratorOptions::SymbolTypes::kPublic;
- if (!writeJavaFile(&mFinalTable, mContext.getCompilationPackage(),
+ if (!writeJavaFile(&mFinalTable, mContext->getCompilationPackage(),
outputPackage, options)) {
return 1;
}
@@ -886,7 +889,7 @@
private:
LinkOptions mOptions;
- LinkContext mContext;
+ LinkContext* mContext;
ResourceTable mFinalTable;
ResourceTable mLocalFileTable;
@@ -907,6 +910,7 @@
Maybe<std::string> versionCode, versionName;
Maybe<std::string> customJavaPackage;
std::vector<std::string> extraJavaPackages;
+ Maybe<std::string> configs;
bool legacyXFlag = false;
bool requireLocalization = false;
Flags flags = Flags()
@@ -928,6 +932,8 @@
&legacyXFlag)
.optionalSwitch("-z", "Require localization of strings marked 'suggested'",
&requireLocalization)
+ .optionalFlag("-c", "Comma separated list of configurations to include. The default\n"
+ "is all configurations", &configs)
.optionalSwitch("--output-to-dir", "Outputs the APK contents to a directory specified "
"by -o",
&options.outputToDirectory)
@@ -967,6 +973,8 @@
return 1;
}
+ LinkContext context;
+
if (privateSymbolsPackage) {
options.privateSymbols = util::utf8ToUtf16(privateSymbolsPackage.value());
}
@@ -1011,7 +1019,31 @@
}
}
- LinkCommand cmd(options);
+ AxisConfigFilter filter;
+ if (configs) {
+ for (const StringPiece& configStr : util::tokenize<char>(configs.value(), ',')) {
+ ConfigDescription config;
+ LocaleValue lv;
+ if (lv.initFromFilterString(configStr)) {
+ lv.writeTo(&config);
+ } else if (!ConfigDescription::parse(configStr, &config)) {
+ context.getDiagnostics()->error(
+ DiagMessage() << "invalid config '" << configStr << "' for -c option");
+ return 1;
+ }
+
+ if (config.density != 0) {
+ context.getDiagnostics()->warn(
+ DiagMessage() << "ignoring density '" << config << "' for -c option");
+ } else {
+ filter.addConfig(config);
+ }
+ }
+
+ options.configFilter = &filter;
+ }
+
+ LinkCommand cmd(&context, options);
return cmd.run(flags.getArgs());
}
diff --git a/tools/aapt2/link/TableMerger.cpp b/tools/aapt2/link/TableMerger.cpp
index 27a23bd..e01a004 100644
--- a/tools/aapt2/link/TableMerger.cpp
+++ b/tools/aapt2/link/TableMerger.cpp
@@ -100,7 +100,7 @@
return false;
}
- mFilesToMerge[ResourceKeyRef{ name, config }] = FileToMerge{
+ mFilesToMerge[ResourceKeyRef(name, config)] = FileToMerge{
f, oldFile->getSource(), util::utf16ToUtf8(*newFile->path) };
return true;
};
@@ -201,6 +201,9 @@
auto iter = std::lower_bound(dstEntry->values.begin(), dstEntry->values.end(),
srcValue.config, cmp::lessThanConfig);
+ const bool stripConfig = mOptions.filter ?
+ !mOptions.filter->match(srcValue.config) : false;
+
if (iter != dstEntry->values.end() && iter->config == srcValue.config) {
const int collisionResult = ResourceTable::resolveValueCollision(
iter->value.get(), srcValue.value.get());
@@ -224,11 +227,15 @@
continue;
}
- } else {
+ } else if (!stripConfig){
// Insert a place holder value. We will fill it in below.
iter = dstEntry->values.insert(iter, ResourceConfigValue{ srcValue.config });
}
+ if (stripConfig) {
+ continue;
+ }
+
if (FileReference* f = valueCast<FileReference>(srcValue.value.get())) {
std::unique_ptr<FileReference> newFileRef;
if (manglePackage) {
@@ -287,7 +294,7 @@
auto callback = [&](const ResourceNameRef& name, const ConfigDescription& config,
FileReference* newFile, FileReference* oldFile) -> bool {
- mFilesToMerge[ResourceKeyRef{ name, config }] = FileToMerge{
+ mFilesToMerge[ResourceKeyRef(name, config)] = FileToMerge{
file, oldFile->getSource(), util::utf16ToUtf8(*newFile->path) };
return true;
};
diff --git a/tools/aapt2/link/TableMerger.h b/tools/aapt2/link/TableMerger.h
index e1be5d5..4539679 100644
--- a/tools/aapt2/link/TableMerger.h
+++ b/tools/aapt2/link/TableMerger.h
@@ -20,6 +20,7 @@
#include "Resource.h"
#include "ResourceTable.h"
#include "ResourceValues.h"
+#include "filter/ConfigFilter.h"
#include "io/File.h"
#include "process/IResourceTableConsumer.h"
#include "util/Util.h"
@@ -51,6 +52,11 @@
* If true, resources in overlays can be added without previously having existed.
*/
bool autoAddOverlay = false;
+
+ /**
+ * A filter that removes resources whose configurations don't match.
+ */
+ IConfigFilter* filter = nullptr;
};
/**
diff --git a/tools/aapt2/link/TableMerger_test.cpp b/tools/aapt2/link/TableMerger_test.cpp
index fa4afd3..45c8c98 100644
--- a/tools/aapt2/link/TableMerger_test.cpp
+++ b/tools/aapt2/link/TableMerger_test.cpp
@@ -14,6 +14,7 @@
* limitations under the License.
*/
+#include "filter/ConfigFilter.h"
#include "io/FileSystem.h"
#include "link/TableMerger.h"
#include "test/Builders.h"
@@ -243,4 +244,36 @@
ASSERT_FALSE(merger.mergeOverlay({}, tableB.get()));
}
+TEST_F(TableMergerTest, MergeAndStripResourcesNotMatchingFilter) {
+ ResourceTable finalTable;
+ TableMergerOptions options;
+ options.autoAddOverlay = false;
+
+ AxisConfigFilter filter;
+ filter.addConfig(test::parseConfigOrDie("en"));
+ options.filter = &filter;
+
+ test::TestFile fileA("res/layout-en/main.xml"), fileB("res/layout-fr-rFR/main.xml");
+ const ResourceName name = test::parseNameOrDie(u"@com.app.a:layout/main");
+ const ConfigDescription configEn = test::parseConfigOrDie("en");
+ const ConfigDescription configFr = test::parseConfigOrDie("fr-rFR");
+
+ TableMerger merger(mContext.get(), &finalTable, options);
+ ASSERT_TRUE(merger.mergeFile(ResourceFile{ name, configEn }, &fileA));
+ ASSERT_TRUE(merger.mergeFile(ResourceFile{ name, configFr }, &fileB));
+
+ EXPECT_NE(nullptr, test::getValueForConfig<FileReference>(&finalTable,
+ u"@com.app.a:layout/main",
+ configEn));
+ EXPECT_EQ(nullptr, test::getValueForConfig<FileReference>(&finalTable,
+ u"@com.app.a:layout/main",
+ configFr));
+
+ EXPECT_NE(merger.getFilesToMerge().end(),
+ merger.getFilesToMerge().find(ResourceKeyRef(name, configEn)));
+
+ EXPECT_EQ(merger.getFilesToMerge().end(),
+ merger.getFilesToMerge().find(ResourceKeyRef(name, configFr)));
+}
+
} // namespace aapt