diff options
author | 2017-08-23 13:03:56 -0700 | |
---|---|---|
committer | 2017-08-29 11:10:01 -0700 | |
commit | 46c4d72bf0c30d3bc2071b84e2741e404c45e2b7 (patch) | |
tree | 0e1e7f7c6ded02ae61ab78f66e2eee8554ef4aca | |
parent | d48474969e786eaf911ac51bcd05faa3399b788a (diff) |
AAPT2: Add <overlayable> tag support
This doesn't actually do anything yet, but makes sure
it is not a syntax error and allows teams to start marking
their resources as overlayable.
The syntax form marking a set of resources as overlayable
looks like:
<overlayable policy="system">
<item type="string" name="foo" />
<item type="style" name="bar" />
</overlayable>
Currently, the only supported policy is "system", meaning only
the system will be able to overlay the resources. Leaving
out the policy attribute defaults to "system".
Bug: 64980941
Test: make aapt2_tests
Change-Id: Ied7a9ddae87a4a0af6a0f4d1c213bfce8a0ed612
-rw-r--r-- | tools/aapt2/ResourceParser.cpp | 99 | ||||
-rw-r--r-- | tools/aapt2/ResourceParser.h | 1 | ||||
-rw-r--r-- | tools/aapt2/ResourceParser_test.cpp | 45 |
3 files changed, 136 insertions, 9 deletions
diff --git a/tools/aapt2/ResourceParser.cpp b/tools/aapt2/ResourceParser.cpp index 1c3ac2ad4f17..ee49ba59e640 100644 --- a/tools/aapt2/ResourceParser.cpp +++ b/tools/aapt2/ResourceParser.cpp @@ -392,6 +392,7 @@ bool ResourceParser::ParseResource(xml::XmlPullParser* parser, {"declare-styleable", std::mem_fn(&ResourceParser::ParseDeclareStyleable)}, {"integer-array", std::mem_fn(&ResourceParser::ParseIntegerArray)}, {"java-symbol", std::mem_fn(&ResourceParser::ParseSymbol)}, + {"overlayable", std::mem_fn(&ResourceParser::ParseOverlayable)}, {"plurals", std::mem_fn(&ResourceParser::ParsePlural)}, {"public", std::mem_fn(&ResourceParser::ParsePublic)}, {"public-group", std::mem_fn(&ResourceParser::ParsePublicGroup)}, @@ -498,7 +499,7 @@ bool ResourceParser::ParseResource(xml::XmlPullParser* parser, const auto bag_iter = elToBagMap.find(resource_type); if (bag_iter != elToBagMap.end()) { // Ensure we have a name (unless this is a <public-group>). - if (resource_type != "public-group") { + if (resource_type != "public-group" && resource_type != "overlayable") { if (!maybe_name) { diag_->Error(DiagMessage(out_resource->source) << "<" << parser->element_name() << "> missing 'name' attribute"); @@ -690,6 +691,11 @@ bool ResourceParser::ParseString(xml::XmlPullParser* parser, bool ResourceParser::ParsePublic(xml::XmlPullParser* parser, ParsedResource* out_resource) { + if (out_resource->config != ConfigDescription::DefaultConfig()) { + diag_->Warn(DiagMessage(out_resource->source) + << "ignoring configuration '" << out_resource->config << "' for <public> tag"); + } + Maybe<StringPiece> maybe_type = xml::FindNonEmptyAttribute(parser, "type"); if (!maybe_type) { diag_->Error(DiagMessage(out_resource->source) @@ -726,8 +732,13 @@ bool ResourceParser::ParsePublic(xml::XmlPullParser* parser, return true; } -bool ResourceParser::ParsePublicGroup(xml::XmlPullParser* parser, - ParsedResource* out_resource) { +bool ResourceParser::ParsePublicGroup(xml::XmlPullParser* parser, ParsedResource* out_resource) { + if (out_resource->config != ConfigDescription::DefaultConfig()) { + diag_->Warn(DiagMessage(out_resource->source) + << "ignoring configuration '" << out_resource->config + << "' for <public-group> tag"); + } + Maybe<StringPiece> maybe_type = xml::FindNonEmptyAttribute(parser, "type"); if (!maybe_type) { diag_->Error(DiagMessage(out_resource->source) @@ -842,13 +853,83 @@ bool ResourceParser::ParseSymbolImpl(xml::XmlPullParser* parser, return true; } -bool ResourceParser::ParseSymbol(xml::XmlPullParser* parser, - ParsedResource* out_resource) { - if (ParseSymbolImpl(parser, out_resource)) { - out_resource->symbol_state = SymbolState::kPrivate; - return true; +bool ResourceParser::ParseSymbol(xml::XmlPullParser* parser, ParsedResource* out_resource) { + if (out_resource->config != ConfigDescription::DefaultConfig()) { + diag_->Warn(DiagMessage(out_resource->source) + << "ignoring configuration '" << out_resource->config << "' for <" + << parser->element_name() << "> tag"); } - return false; + + if (!ParseSymbolImpl(parser, out_resource)) { + return false; + } + + out_resource->symbol_state = SymbolState::kPrivate; + return true; +} + +bool ResourceParser::ParseOverlayable(xml::XmlPullParser* parser, ParsedResource* out_resource) { + if (out_resource->config != ConfigDescription::DefaultConfig()) { + diag_->Warn(DiagMessage(out_resource->source) + << "ignoring configuration '" << out_resource->config << "' for <overlayable> tag"); + } + + if (Maybe<StringPiece> maybe_policy = xml::FindNonEmptyAttribute(parser, "policy")) { + const StringPiece& policy = maybe_policy.value(); + if (policy != "system") { + diag_->Error(DiagMessage(out_resource->source) + << "<overlayable> has invalid policy '" << policy << "'"); + return false; + } + } + + bool error = false; + const size_t depth = parser->depth(); + while (xml::XmlPullParser::NextChildNode(parser, depth)) { + if (parser->event() != xml::XmlPullParser::Event::kStartElement) { + // Skip text/comments. + continue; + } + + const Source item_source = source_.WithLine(parser->line_number()); + const std::string& element_namespace = parser->element_namespace(); + const std::string& element_name = parser->element_name(); + if (element_namespace.empty() && element_name == "item") { + Maybe<StringPiece> maybe_name = xml::FindNonEmptyAttribute(parser, "name"); + if (!maybe_name) { + diag_->Error(DiagMessage(item_source) + << "<item> within an <overlayable> tag must have a 'name' attribute"); + error = true; + continue; + } + + Maybe<StringPiece> maybe_type = xml::FindNonEmptyAttribute(parser, "type"); + if (!maybe_type) { + diag_->Error(DiagMessage(item_source) + << "<item> within an <overlayable> tag must have a 'type' attribute"); + error = true; + continue; + } + + const ResourceType* type = ParseResourceType(maybe_type.value()); + if (type == nullptr) { + diag_->Error(DiagMessage(out_resource->source) + << "invalid resource type '" << maybe_type.value() + << "' in <item> within an <overlayable>"); + error = true; + continue; + } + + // TODO(b/64980941): Mark the symbol as overlayable and allow marking which entity can overlay + // the resource (system/app). + + xml::XmlPullParser::SkipCurrentElement(parser); + } else if (!ShouldIgnoreElement(element_namespace, element_name)) { + diag_->Error(DiagMessage(item_source) << ":" << element_name << ">"); + error = true; + } + } + return !error; } bool ResourceParser::ParseAddResource(xml::XmlPullParser* parser, diff --git a/tools/aapt2/ResourceParser.h b/tools/aapt2/ResourceParser.h index 5631dc2ad29c..fb9dbd0cd0fd 100644 --- a/tools/aapt2/ResourceParser.h +++ b/tools/aapt2/ResourceParser.h @@ -91,6 +91,7 @@ class ResourceParser { bool ParsePublicGroup(xml::XmlPullParser* parser, ParsedResource* out_resource); bool ParseSymbolImpl(xml::XmlPullParser* parser, ParsedResource* out_resource); bool ParseSymbol(xml::XmlPullParser* parser, ParsedResource* out_resource); + bool ParseOverlayable(xml::XmlPullParser* parser, ParsedResource* out_resource); bool ParseAddResource(xml::XmlPullParser* parser, ParsedResource* out_resource); bool ParseAttr(xml::XmlPullParser* parser, ParsedResource* out_resource); bool ParseAttrImpl(xml::XmlPullParser* parser, ParsedResource* out_resource, bool weak); diff --git a/tools/aapt2/ResourceParser_test.cpp b/tools/aapt2/ResourceParser_test.cpp index 144ebd22e105..f08b03e7b8af 100644 --- a/tools/aapt2/ResourceParser_test.cpp +++ b/tools/aapt2/ResourceParser_test.cpp @@ -790,4 +790,49 @@ TEST_F(ResourceParserTest, ParsePlatformIndependentNewline) { ASSERT_TRUE(TestParse(R"(<string name="foo">%1$s %n %2$s</string>)")); } +TEST_F(ResourceParserTest, ParseOverlayableTagWithSystemPolicy) { + std::string input = R"( + <overlayable policy="illegal_policy"> + <item type="string" name="foo" /> + </overlayable>)"; + EXPECT_FALSE(TestParse(input)); + + input = R"( + <overlayable policy="system"> + <item name="foo" /> + </overlayable>)"; + EXPECT_FALSE(TestParse(input)); + + input = R"( + <overlayable policy="system"> + <item type="attr" /> + </overlayable>)"; + EXPECT_FALSE(TestParse(input)); + + input = R"( + <overlayable policy="system"> + <item type="bad_type" name="foo" /> + </overlayable>)"; + EXPECT_FALSE(TestParse(input)); + + input = R"(<overlayable policy="system" />)"; + EXPECT_TRUE(TestParse(input)); + + input = R"(<overlayable />)"; + EXPECT_TRUE(TestParse(input)); + + input = R"( + <overlayable policy="system"> + <item type="string" name="foo" /> + <item type="dimen" name="foo" /> + </overlayable>)"; + ASSERT_TRUE(TestParse(input)); + + input = R"( + <overlayable> + <item type="string" name="bar" /> + </overlayable>)"; + ASSERT_TRUE(TestParse(input)); +} + } // namespace aapt |