Merge "Add actor and name parsing for overlayable"
This commit is contained in:
committed by
Android (Google) Code Review
commit
ed2af4df00
@@ -623,7 +623,7 @@ std::unique_ptr<const LoadedPackage> LoadedPackage::Load(const Chunk& chunk,
|
||||
}
|
||||
|
||||
// Add the pairing of overlayable properties to resource ids to the package
|
||||
OverlayableInfo overlayable_info;
|
||||
OverlayableInfo overlayable_info{};
|
||||
overlayable_info.policy_flags = policy_header->policy_flags;
|
||||
loaded_package->overlayable_infos_.push_back(std::make_pair(overlayable_info, ids));
|
||||
break;
|
||||
|
||||
@@ -99,7 +99,7 @@ struct ParsedResource {
|
||||
ResourceId id;
|
||||
Visibility::Level visibility_level = Visibility::Level::kUndefined;
|
||||
bool allow_new = false;
|
||||
Maybe<Overlayable> overlayable;
|
||||
Maybe<OverlayableItem> overlayable_item;
|
||||
|
||||
std::string comment;
|
||||
std::unique_ptr<Value> value;
|
||||
@@ -133,8 +133,8 @@ static bool AddResourcesToTable(ResourceTable* table, IDiagnostics* diag, Parsed
|
||||
}
|
||||
}
|
||||
|
||||
if (res->overlayable) {
|
||||
if (!table->SetOverlayable(res->name, res->overlayable.value(), diag)) {
|
||||
if (res->overlayable_item) {
|
||||
if (!table->SetOverlayable(res->name, res->overlayable_item.value(), diag)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -1059,92 +1059,119 @@ bool ResourceParser::ParseSymbol(xml::XmlPullParser* parser, ParsedResource* out
|
||||
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");
|
||||
<< "ignoring configuration '" << out_resource->config
|
||||
<< "' for <overlayable> tag");
|
||||
}
|
||||
|
||||
Maybe<StringPiece> overlayable_name = xml::FindNonEmptyAttribute(parser, "name");
|
||||
if (!overlayable_name) {
|
||||
diag_->Error(DiagMessage(out_resource->source)
|
||||
<< "<overlayable> tag must have a 'name' attribute");
|
||||
return false;
|
||||
}
|
||||
|
||||
const std::string kActorUriScheme =
|
||||
android::base::StringPrintf("%s://", Overlayable::kActorScheme);
|
||||
Maybe<StringPiece> overlayable_actor = xml::FindNonEmptyAttribute(parser, "actor");
|
||||
if (overlayable_actor && !util::StartsWith(overlayable_actor.value(), kActorUriScheme)) {
|
||||
diag_->Error(DiagMessage(out_resource->source)
|
||||
<< "specified <overlayable> tag 'actor' attribute must use the scheme '"
|
||||
<< Overlayable::kActorScheme << "'");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Create a overlayable entry grouping that represents this <overlayable>
|
||||
auto overlayable = std::make_shared<Overlayable>(
|
||||
overlayable_name.value(), (overlayable_actor) ? overlayable_actor.value() : "",
|
||||
out_resource->source);
|
||||
|
||||
bool error = false;
|
||||
std::string comment;
|
||||
Overlayable::PolicyFlags current_policies = Overlayable::Policy::kNone;
|
||||
OverlayableItem::PolicyFlags current_policies = OverlayableItem::Policy::kNone;
|
||||
const size_t start_depth = parser->depth();
|
||||
while (xml::XmlPullParser::IsGoodEvent(parser->Next())) {
|
||||
xml::XmlPullParser::Event event = parser->event();
|
||||
if (event == xml::XmlPullParser::Event::kEndElement && parser->depth() == start_depth) {
|
||||
// Break the loop when exiting the overlayable element
|
||||
// Break the loop when exiting the <overlayable>
|
||||
break;
|
||||
} else if (event == xml::XmlPullParser::Event::kEndElement
|
||||
&& parser->depth() == start_depth + 1) {
|
||||
// Clear the current policies when exiting the policy element
|
||||
current_policies = Overlayable::Policy::kNone;
|
||||
// Clear the current policies when exiting the <policy> tags
|
||||
current_policies = OverlayableItem::Policy::kNone;
|
||||
continue;
|
||||
} else if (event == xml::XmlPullParser::Event::kComment) {
|
||||
// Get the comment of individual item elements
|
||||
// Retrieve the comment of individual <item> tags
|
||||
comment = parser->comment();
|
||||
continue;
|
||||
} else if (event != xml::XmlPullParser::Event::kStartElement) {
|
||||
// Skip to the next element
|
||||
// Skip to the start of the next element
|
||||
continue;
|
||||
}
|
||||
|
||||
const Source item_source = source_.WithLine(parser->line_number());
|
||||
const Source element_source = source_.WithLine(parser->line_number());
|
||||
const std::string& element_name = parser->element_name();
|
||||
const std::string& element_namespace = parser->element_namespace();
|
||||
if (element_namespace.empty() && element_name == "item") {
|
||||
// Items specify the name and type of resource that should be overlayable
|
||||
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");
|
||||
Maybe<StringPiece> item_name = xml::FindNonEmptyAttribute(parser, "name");
|
||||
if (!item_name) {
|
||||
diag_->Error(DiagMessage(element_source)
|
||||
<< "<item> within an <overlayable> 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");
|
||||
Maybe<StringPiece> item_type = xml::FindNonEmptyAttribute(parser, "type");
|
||||
if (!item_type) {
|
||||
diag_->Error(DiagMessage(element_source)
|
||||
<< "<item> within an <overlayable> must have a 'type' attribute");
|
||||
error = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
const ResourceType* type = ParseResourceType(maybe_type.value());
|
||||
const ResourceType* type = ParseResourceType(item_type.value());
|
||||
if (type == nullptr) {
|
||||
diag_->Error(DiagMessage(item_source)
|
||||
<< "invalid resource type '" << maybe_type.value()
|
||||
diag_->Error(DiagMessage(element_source)
|
||||
<< "invalid resource type '" << item_type.value()
|
||||
<< "' in <item> within an <overlayable>");
|
||||
error = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
ParsedResource child_resource;
|
||||
OverlayableItem overlayable_item(overlayable);
|
||||
overlayable_item.policies = current_policies;
|
||||
overlayable_item.comment = comment;
|
||||
overlayable_item.source = element_source;
|
||||
|
||||
ParsedResource child_resource{};
|
||||
child_resource.name.type = *type;
|
||||
child_resource.name.entry = maybe_name.value().to_string();
|
||||
child_resource.overlayable = Overlayable{current_policies, item_source, comment};
|
||||
child_resource.name.entry = item_name.value().to_string();
|
||||
child_resource.overlayable_item = overlayable_item;
|
||||
out_resource->child_resources.push_back(std::move(child_resource));
|
||||
|
||||
} else if (element_namespace.empty() && element_name == "policy") {
|
||||
if (current_policies != Overlayable::Policy::kNone) {
|
||||
if (current_policies != OverlayableItem::Policy::kNone) {
|
||||
// If the policy list is not empty, then we are currently inside a policy element
|
||||
diag_->Error(DiagMessage(item_source) << "<policy> blocks cannot be recursively nested");
|
||||
diag_->Error(DiagMessage(element_source) << "<policy> blocks cannot be recursively nested");
|
||||
error = true;
|
||||
break;
|
||||
} else if (Maybe<StringPiece> maybe_type = xml::FindNonEmptyAttribute(parser, "type")) {
|
||||
// Parse the polices separated by vertical bar characters to allow for specifying multiple
|
||||
// policies
|
||||
// policies. Items within the policy tag will have the specified policy.
|
||||
for (StringPiece part : util::Tokenize(maybe_type.value(), '|')) {
|
||||
StringPiece trimmed_part = util::TrimWhitespace(part);
|
||||
if (trimmed_part == "public") {
|
||||
current_policies |= Overlayable::Policy::kPublic;
|
||||
current_policies |= OverlayableItem::Policy::kPublic;
|
||||
} else if (trimmed_part == "product") {
|
||||
current_policies |= Overlayable::Policy::kProduct;
|
||||
current_policies |= OverlayableItem::Policy::kProduct;
|
||||
} else if (trimmed_part == "product_services") {
|
||||
current_policies |= Overlayable::Policy::kProductServices;
|
||||
current_policies |= OverlayableItem::Policy::kProductServices;
|
||||
} else if (trimmed_part == "system") {
|
||||
current_policies |= Overlayable::Policy::kSystem;
|
||||
current_policies |= OverlayableItem::Policy::kSystem;
|
||||
} else if (trimmed_part == "vendor") {
|
||||
current_policies |= Overlayable::Policy::kVendor;
|
||||
current_policies |= OverlayableItem::Policy::kVendor;
|
||||
} else {
|
||||
diag_->Error(DiagMessage(item_source)
|
||||
diag_->Error(DiagMessage(element_source)
|
||||
<< "<policy> has unsupported type '" << trimmed_part << "'");
|
||||
error = true;
|
||||
continue;
|
||||
@@ -1152,11 +1179,13 @@ bool ResourceParser::ParseOverlayable(xml::XmlPullParser* parser, ParsedResource
|
||||
}
|
||||
}
|
||||
} else if (!ShouldIgnoreElement(element_namespace, element_name)) {
|
||||
diag_->Error(DiagMessage(item_source) << "invalid element <" << element_name << "> "
|
||||
diag_->Error(DiagMessage(element_source) << "invalid element <" << element_name << "> "
|
||||
<< " in <overlayable>");
|
||||
error = true;
|
||||
break;
|
||||
}
|
||||
|
||||
comment.clear();
|
||||
}
|
||||
|
||||
return !error;
|
||||
|
||||
@@ -892,11 +892,8 @@ TEST_F(ResourceParserTest, ParsePlatformIndependentNewline) {
|
||||
}
|
||||
|
||||
TEST_F(ResourceParserTest, ParseOverlayable) {
|
||||
std::string input = R"(<overlayable />)";
|
||||
EXPECT_TRUE(TestParse(input));
|
||||
|
||||
input = R"(
|
||||
<overlayable>
|
||||
std::string input = R"(
|
||||
<overlayable name="Name" actor="overlay://theme">
|
||||
<item type="string" name="foo" />
|
||||
<item type="drawable" name="bar" />
|
||||
</overlayable>)";
|
||||
@@ -905,24 +902,35 @@ TEST_F(ResourceParserTest, ParseOverlayable) {
|
||||
auto search_result = table_.FindResource(test::ParseNameOrDie("string/foo"));
|
||||
ASSERT_TRUE(search_result);
|
||||
ASSERT_THAT(search_result.value().entry, NotNull());
|
||||
ASSERT_TRUE(search_result.value().entry->overlayable);
|
||||
EXPECT_THAT(search_result.value().entry->overlayable.value().policies,
|
||||
Eq(Overlayable::Policy::kNone));
|
||||
ASSERT_TRUE(search_result.value().entry->overlayable_item);
|
||||
OverlayableItem& result_overlayable_item = search_result.value().entry->overlayable_item.value();
|
||||
EXPECT_THAT(result_overlayable_item.overlayable->name, Eq("Name"));
|
||||
EXPECT_THAT(result_overlayable_item.overlayable->actor, Eq("overlay://theme"));
|
||||
EXPECT_THAT(result_overlayable_item.policies, Eq(OverlayableItem::Policy::kNone));
|
||||
|
||||
search_result = table_.FindResource(test::ParseNameOrDie("drawable/bar"));
|
||||
ASSERT_TRUE(search_result);
|
||||
ASSERT_THAT(search_result.value().entry, NotNull());
|
||||
ASSERT_TRUE(search_result.value().entry->overlayable);
|
||||
EXPECT_THAT(search_result.value().entry->overlayable.value().policies,
|
||||
Eq(Overlayable::Policy::kNone));
|
||||
ASSERT_TRUE(search_result.value().entry->overlayable_item);
|
||||
result_overlayable_item = search_result.value().entry->overlayable_item.value();
|
||||
EXPECT_THAT(result_overlayable_item.overlayable->name, Eq("Name"));
|
||||
EXPECT_THAT(result_overlayable_item.overlayable->actor, Eq("overlay://theme"));
|
||||
EXPECT_THAT(result_overlayable_item.policies, Eq(OverlayableItem::Policy::kNone));
|
||||
}
|
||||
|
||||
TEST_F(ResourceParserTest, ParseOverlayableRequiresName) {
|
||||
EXPECT_FALSE(TestParse(R"(<overlayable actor="overlay://theme" />)"));
|
||||
EXPECT_TRUE(TestParse(R"(<overlayable name="Name" />)"));
|
||||
EXPECT_TRUE(TestParse(R"(<overlayable name="Name" actor="overlay://theme" />)"));
|
||||
}
|
||||
|
||||
TEST_F(ResourceParserTest, ParseOverlayableBadActorFail) {
|
||||
EXPECT_FALSE(TestParse(R"(<overlayable name="Name" actor="overley://theme" />)"));
|
||||
}
|
||||
|
||||
TEST_F(ResourceParserTest, ParseOverlayablePolicy) {
|
||||
std::string input = R"(<overlayable />)";
|
||||
EXPECT_TRUE(TestParse(input));
|
||||
|
||||
input = R"(
|
||||
<overlayable>
|
||||
std::string input = R"(
|
||||
<overlayable name="Name">
|
||||
<item type="string" name="foo" />
|
||||
<policy type="product">
|
||||
<item type="string" name="bar" />
|
||||
@@ -945,49 +953,55 @@ TEST_F(ResourceParserTest, ParseOverlayablePolicy) {
|
||||
auto search_result = table_.FindResource(test::ParseNameOrDie("string/foo"));
|
||||
ASSERT_TRUE(search_result);
|
||||
ASSERT_THAT(search_result.value().entry, NotNull());
|
||||
ASSERT_TRUE(search_result.value().entry->overlayable);
|
||||
Overlayable& overlayable = search_result.value().entry->overlayable.value();
|
||||
EXPECT_THAT(overlayable.policies, Eq(Overlayable::Policy::kNone));
|
||||
ASSERT_TRUE(search_result.value().entry->overlayable_item);
|
||||
OverlayableItem result_overlayable_item = search_result.value().entry->overlayable_item.value();
|
||||
EXPECT_THAT(result_overlayable_item.overlayable->name, Eq("Name"));
|
||||
EXPECT_THAT(result_overlayable_item.policies, Eq(OverlayableItem::Policy::kNone));
|
||||
|
||||
search_result = table_.FindResource(test::ParseNameOrDie("string/bar"));
|
||||
ASSERT_TRUE(search_result);
|
||||
ASSERT_THAT(search_result.value().entry, NotNull());
|
||||
ASSERT_TRUE(search_result.value().entry->overlayable);
|
||||
overlayable = search_result.value().entry->overlayable.value();
|
||||
EXPECT_THAT(overlayable.policies, Eq(Overlayable::Policy::kProduct));
|
||||
ASSERT_TRUE(search_result.value().entry->overlayable_item);
|
||||
result_overlayable_item = search_result.value().entry->overlayable_item.value();
|
||||
EXPECT_THAT(result_overlayable_item.overlayable->name, Eq("Name"));
|
||||
EXPECT_THAT(result_overlayable_item.policies, Eq(OverlayableItem::Policy::kProduct));
|
||||
|
||||
search_result = table_.FindResource(test::ParseNameOrDie("string/baz"));
|
||||
ASSERT_TRUE(search_result);
|
||||
ASSERT_THAT(search_result.value().entry, NotNull());
|
||||
ASSERT_TRUE(search_result.value().entry->overlayable);
|
||||
overlayable = search_result.value().entry->overlayable.value();
|
||||
EXPECT_THAT(overlayable.policies, Eq(Overlayable::Policy::kProductServices));
|
||||
ASSERT_TRUE(search_result.value().entry->overlayable_item);
|
||||
result_overlayable_item = search_result.value().entry->overlayable_item.value();
|
||||
EXPECT_THAT(result_overlayable_item.overlayable->name, Eq("Name"));
|
||||
EXPECT_THAT(result_overlayable_item.policies, Eq(OverlayableItem::Policy::kProductServices));
|
||||
|
||||
search_result = table_.FindResource(test::ParseNameOrDie("string/fiz"));
|
||||
ASSERT_TRUE(search_result);
|
||||
ASSERT_THAT(search_result.value().entry, NotNull());
|
||||
ASSERT_TRUE(search_result.value().entry->overlayable);
|
||||
overlayable = search_result.value().entry->overlayable.value();
|
||||
EXPECT_THAT(overlayable.policies, Eq(Overlayable::Policy::kSystem));
|
||||
ASSERT_TRUE(search_result.value().entry->overlayable_item);
|
||||
result_overlayable_item = search_result.value().entry->overlayable_item.value();
|
||||
EXPECT_THAT(result_overlayable_item.overlayable->name, Eq("Name"));
|
||||
EXPECT_THAT(result_overlayable_item.policies, Eq(OverlayableItem::Policy::kSystem));
|
||||
|
||||
search_result = table_.FindResource(test::ParseNameOrDie("string/fuz"));
|
||||
ASSERT_TRUE(search_result);
|
||||
ASSERT_THAT(search_result.value().entry, NotNull());
|
||||
ASSERT_TRUE(search_result.value().entry->overlayable);
|
||||
overlayable = search_result.value().entry->overlayable.value();
|
||||
EXPECT_THAT(overlayable.policies, Eq(Overlayable::Policy::kVendor));
|
||||
ASSERT_TRUE(search_result.value().entry->overlayable_item);
|
||||
result_overlayable_item = search_result.value().entry->overlayable_item.value();
|
||||
EXPECT_THAT(result_overlayable_item.overlayable->name, Eq("Name"));
|
||||
EXPECT_THAT(result_overlayable_item.policies, Eq(OverlayableItem::Policy::kVendor));
|
||||
|
||||
search_result = table_.FindResource(test::ParseNameOrDie("string/faz"));
|
||||
ASSERT_TRUE(search_result);
|
||||
ASSERT_THAT(search_result.value().entry, NotNull());
|
||||
ASSERT_TRUE(search_result.value().entry->overlayable);
|
||||
overlayable = search_result.value().entry->overlayable.value();
|
||||
EXPECT_THAT(overlayable.policies, Eq(Overlayable::Policy::kPublic));
|
||||
ASSERT_TRUE(search_result.value().entry->overlayable_item);
|
||||
result_overlayable_item = search_result.value().entry->overlayable_item.value();
|
||||
EXPECT_THAT(result_overlayable_item.overlayable->name, Eq("Name"));
|
||||
EXPECT_THAT(result_overlayable_item.policies, Eq(OverlayableItem::Policy::kPublic));
|
||||
}
|
||||
|
||||
TEST_F(ResourceParserTest, ParseOverlayableBadPolicyError) {
|
||||
std::string input = R"(
|
||||
<overlayable>
|
||||
<overlayable name="Name">
|
||||
<policy type="illegal_policy">
|
||||
<item type="string" name="foo" />
|
||||
</policy>
|
||||
@@ -995,7 +1009,7 @@ TEST_F(ResourceParserTest, ParseOverlayableBadPolicyError) {
|
||||
EXPECT_FALSE(TestParse(input));
|
||||
|
||||
input = R"(
|
||||
<overlayable>
|
||||
<overlayable name="Name">
|
||||
<policy type="product">
|
||||
<item name="foo" />
|
||||
</policy>
|
||||
@@ -1003,7 +1017,7 @@ TEST_F(ResourceParserTest, ParseOverlayableBadPolicyError) {
|
||||
EXPECT_FALSE(TestParse(input));
|
||||
|
||||
input = R"(
|
||||
<overlayable>
|
||||
<overlayable name="Name">
|
||||
<policy type="vendor">
|
||||
<item type="string" />
|
||||
</policy>
|
||||
@@ -1013,7 +1027,7 @@ TEST_F(ResourceParserTest, ParseOverlayableBadPolicyError) {
|
||||
|
||||
TEST_F(ResourceParserTest, ParseOverlayableMultiplePolicy) {
|
||||
std::string input = R"(
|
||||
<overlayable>
|
||||
<overlayable name="Name">
|
||||
<policy type="vendor|product_services">
|
||||
<item type="string" name="foo" />
|
||||
</policy>
|
||||
@@ -1026,39 +1040,59 @@ TEST_F(ResourceParserTest, ParseOverlayableMultiplePolicy) {
|
||||
auto search_result = table_.FindResource(test::ParseNameOrDie("string/foo"));
|
||||
ASSERT_TRUE(search_result);
|
||||
ASSERT_THAT(search_result.value().entry, NotNull());
|
||||
ASSERT_TRUE(search_result.value().entry->overlayable);
|
||||
Overlayable& overlayable = search_result.value().entry->overlayable.value();
|
||||
EXPECT_THAT(overlayable.policies, Eq(Overlayable::Policy::kVendor
|
||||
| Overlayable::Policy::kProductServices));
|
||||
ASSERT_TRUE(search_result.value().entry->overlayable_item);
|
||||
OverlayableItem result_overlayable_item = search_result.value().entry->overlayable_item.value();
|
||||
EXPECT_THAT(result_overlayable_item.overlayable->name, Eq("Name"));
|
||||
EXPECT_THAT(result_overlayable_item.policies, Eq(OverlayableItem::Policy::kVendor
|
||||
| OverlayableItem::Policy::kProductServices));
|
||||
|
||||
search_result = table_.FindResource(test::ParseNameOrDie("string/bar"));
|
||||
ASSERT_TRUE(search_result);
|
||||
ASSERT_THAT(search_result.value().entry, NotNull());
|
||||
ASSERT_TRUE(search_result.value().entry->overlayable);
|
||||
overlayable = search_result.value().entry->overlayable.value();
|
||||
EXPECT_THAT(overlayable.policies, Eq(Overlayable::Policy::kProduct
|
||||
| Overlayable::Policy::kSystem));
|
||||
ASSERT_TRUE(search_result.value().entry->overlayable_item);
|
||||
result_overlayable_item = search_result.value().entry->overlayable_item.value();
|
||||
EXPECT_THAT(result_overlayable_item.overlayable->name, Eq("Name"));
|
||||
EXPECT_THAT(result_overlayable_item.policies, Eq(OverlayableItem::Policy::kProduct
|
||||
| OverlayableItem::Policy::kSystem));
|
||||
}
|
||||
|
||||
TEST_F(ResourceParserTest, DuplicateOverlayableIsError) {
|
||||
std::string input = R"(
|
||||
<overlayable>
|
||||
<overlayable name="Name">
|
||||
<item type="string" name="foo" />
|
||||
<item type="string" name="foo" />
|
||||
</overlayable>)";
|
||||
EXPECT_FALSE(TestParse(input));
|
||||
|
||||
input = R"(
|
||||
<overlayable>
|
||||
<overlayable name="Name">
|
||||
<item type="string" name="foo" />
|
||||
</overlayable>
|
||||
<overlayable>
|
||||
<overlayable name="Name">
|
||||
<item type="string" name="foo" />
|
||||
</overlayable>)";
|
||||
EXPECT_FALSE(TestParse(input));
|
||||
|
||||
input = R"(
|
||||
<overlayable>
|
||||
<overlayable name="Name">
|
||||
<item type="string" name="foo" />
|
||||
</overlayable>
|
||||
<overlayable name="Other">
|
||||
<item type="string" name="foo" />
|
||||
</overlayable>)";
|
||||
EXPECT_FALSE(TestParse(input));
|
||||
|
||||
input = R"(
|
||||
<overlayable name="Name" actor="overlay://my.actor.one">
|
||||
<item type="string" name="foo" />
|
||||
</overlayable>
|
||||
<overlayable name="Other" actor="overlay://my.actor.two">
|
||||
<item type="string" name="foo" />
|
||||
</overlayable>)";
|
||||
EXPECT_FALSE(TestParse(input));
|
||||
|
||||
input = R"(
|
||||
<overlayable name="Name">
|
||||
<policy type="product">
|
||||
<item type="string" name="foo" />
|
||||
<item type="string" name="foo" />
|
||||
@@ -1067,7 +1101,7 @@ TEST_F(ResourceParserTest, DuplicateOverlayableIsError) {
|
||||
EXPECT_FALSE(TestParse(input));
|
||||
|
||||
input = R"(
|
||||
<overlayable>
|
||||
<overlayable name="Name">
|
||||
<policy type="product">
|
||||
<item type="string" name="foo" />
|
||||
</policy>
|
||||
@@ -1076,7 +1110,7 @@ TEST_F(ResourceParserTest, DuplicateOverlayableIsError) {
|
||||
EXPECT_FALSE(TestParse(input));
|
||||
|
||||
input = R"(
|
||||
<overlayable>
|
||||
<overlayable name="Name">
|
||||
<policy type="product">
|
||||
<item type="string" name="foo" />
|
||||
</policy>
|
||||
@@ -1087,13 +1121,13 @@ TEST_F(ResourceParserTest, DuplicateOverlayableIsError) {
|
||||
EXPECT_FALSE(TestParse(input));
|
||||
|
||||
input = R"(
|
||||
<overlayable>
|
||||
<overlayable name="Name">
|
||||
<policy type="product">
|
||||
<item type="string" name="foo" />
|
||||
</policy>
|
||||
</overlayable>
|
||||
|
||||
<overlayable>
|
||||
<overlayable name="Name">
|
||||
<policy type="product">
|
||||
<item type="string" name="foo" />
|
||||
</policy>
|
||||
@@ -1103,7 +1137,7 @@ TEST_F(ResourceParserTest, DuplicateOverlayableIsError) {
|
||||
|
||||
TEST_F(ResourceParserTest, NestPolicyInOverlayableError) {
|
||||
std::string input = R"(
|
||||
<overlayable>
|
||||
<overlayable name="Name">
|
||||
<policy type="vendor|product">
|
||||
<policy type="product_services">
|
||||
<item type="string" name="foo" />
|
||||
|
||||
@@ -40,6 +40,8 @@ using ::android::base::StringPrintf;
|
||||
|
||||
namespace aapt {
|
||||
|
||||
const char* Overlayable::kActorScheme = "overlay";
|
||||
|
||||
static bool less_than_type_and_id(const std::unique_ptr<ResourceTableType>& lhs,
|
||||
const std::pair<ResourceType, Maybe<uint8_t>>& rhs) {
|
||||
return lhs->type < rhs.first || (lhs->type == rhs.first && rhs.second && lhs->id < rhs.second);
|
||||
@@ -625,17 +627,18 @@ bool ResourceTable::SetAllowNewImpl(const ResourceNameRef& name, const AllowNew&
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ResourceTable::SetOverlayable(const ResourceNameRef& name, const Overlayable& overlayable,
|
||||
bool ResourceTable::SetOverlayable(const ResourceNameRef& name, const OverlayableItem& overlayable,
|
||||
IDiagnostics* diag) {
|
||||
return SetOverlayableImpl(name, overlayable, ResourceNameValidator, diag);
|
||||
}
|
||||
|
||||
bool ResourceTable::SetOverlayableMangled(const ResourceNameRef& name,
|
||||
const Overlayable& overlayable, IDiagnostics* diag) {
|
||||
const OverlayableItem& overlayable, IDiagnostics* diag) {
|
||||
return SetOverlayableImpl(name, overlayable, SkipNameValidator, diag);
|
||||
}
|
||||
|
||||
bool ResourceTable::SetOverlayableImpl(const ResourceNameRef& name, const Overlayable& overlayable,
|
||||
bool ResourceTable::SetOverlayableImpl(const ResourceNameRef& name,
|
||||
const OverlayableItem& overlayable,
|
||||
NameValidator name_validator, IDiagnostics *diag) {
|
||||
CHECK(diag != nullptr);
|
||||
|
||||
@@ -647,14 +650,15 @@ bool ResourceTable::SetOverlayableImpl(const ResourceNameRef& name, const Overla
|
||||
ResourceTableType* type = package->FindOrCreateType(name.type);
|
||||
ResourceEntry* entry = type->FindOrCreateEntry(name.entry);
|
||||
|
||||
if (entry->overlayable) {
|
||||
if (entry->overlayable_item) {
|
||||
diag->Error(DiagMessage(overlayable.source)
|
||||
<< "duplicate overlayable declaration for resource '" << name << "'");
|
||||
diag->Error(DiagMessage(entry->overlayable.value().source) << "previous declaration here");
|
||||
<< "duplicate overlayable declaration for resource '" << name << "'");
|
||||
diag->Error(DiagMessage(entry->overlayable_item.value().source)
|
||||
<< "previous declaration here");
|
||||
return false;
|
||||
}
|
||||
|
||||
entry->overlayable = overlayable;
|
||||
entry->overlayable_item = overlayable;
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -690,7 +694,7 @@ std::unique_ptr<ResourceTable> ResourceTable::Clone() const {
|
||||
new_entry->id = entry->id;
|
||||
new_entry->visibility = entry->visibility;
|
||||
new_entry->allow_new = entry->allow_new;
|
||||
new_entry->overlayable = entry->overlayable;
|
||||
new_entry->overlayable_item = entry->overlayable_item;
|
||||
|
||||
for (const auto& config_value : entry->values) {
|
||||
ResourceConfigValue* new_value =
|
||||
|
||||
@@ -57,10 +57,27 @@ struct AllowNew {
|
||||
std::string comment;
|
||||
};
|
||||
|
||||
// Represents a declaration that a resource is overlayable at runtime.
|
||||
struct Overlayable {
|
||||
Overlayable() = default;
|
||||
Overlayable(const android::StringPiece& name, const android::StringPiece& actor)
|
||||
: name(name.to_string()), actor(actor.to_string()) {}
|
||||
Overlayable(const android::StringPiece& name, const android::StringPiece& actor,
|
||||
const Source& source)
|
||||
: name(name.to_string()), actor(actor.to_string()), source(source ){}
|
||||
|
||||
static const char* kActorScheme;
|
||||
std::string name;
|
||||
std::string actor;
|
||||
Source source;
|
||||
};
|
||||
|
||||
// Represents a declaration that a resource is overlayable at runtime.
|
||||
struct OverlayableItem {
|
||||
explicit OverlayableItem(const std::shared_ptr<Overlayable>& overlayable)
|
||||
: overlayable(overlayable) {}
|
||||
|
||||
// Represents the types overlays that are allowed to overlay the resource.
|
||||
typedef uint32_t PolicyFlags;
|
||||
enum Policy : uint32_t {
|
||||
kNone = 0x00,
|
||||
|
||||
@@ -80,11 +97,10 @@ struct Overlayable {
|
||||
kProductServices = 0x10
|
||||
};
|
||||
|
||||
typedef uint32_t PolicyFlags;
|
||||
std::shared_ptr<Overlayable> overlayable;
|
||||
PolicyFlags policies = Policy::kNone;
|
||||
|
||||
Source source;
|
||||
std::string comment;
|
||||
Source source;
|
||||
};
|
||||
|
||||
class ResourceConfigValue {
|
||||
@@ -121,7 +137,7 @@ class ResourceEntry {
|
||||
Maybe<AllowNew> allow_new;
|
||||
|
||||
// The declarations of this resource as overlayable for RROs
|
||||
Maybe<Overlayable> overlayable;
|
||||
Maybe<OverlayableItem> overlayable_item;
|
||||
|
||||
// The resource's values for each configuration.
|
||||
std::vector<std::unique_ptr<ResourceConfigValue>> values;
|
||||
@@ -251,9 +267,9 @@ class ResourceTable {
|
||||
bool SetVisibilityWithIdMangled(const ResourceNameRef& name, const Visibility& visibility,
|
||||
const ResourceId& res_id, IDiagnostics* diag);
|
||||
|
||||
bool SetOverlayable(const ResourceNameRef& name, const Overlayable& overlayable,
|
||||
bool SetOverlayable(const ResourceNameRef& name, const OverlayableItem& overlayable,
|
||||
IDiagnostics *diag);
|
||||
bool SetOverlayableMangled(const ResourceNameRef& name, const Overlayable& overlayable,
|
||||
bool SetOverlayableMangled(const ResourceNameRef& name, const OverlayableItem& overlayable,
|
||||
IDiagnostics* diag);
|
||||
|
||||
bool SetAllowNew(const ResourceNameRef& name, const AllowNew& allow_new, IDiagnostics* diag);
|
||||
@@ -328,7 +344,7 @@ class ResourceTable {
|
||||
bool SetAllowNewImpl(const ResourceNameRef& name, const AllowNew& allow_new,
|
||||
NameValidator name_validator, IDiagnostics* diag);
|
||||
|
||||
bool SetOverlayableImpl(const ResourceNameRef &name, const Overlayable &overlayable,
|
||||
bool SetOverlayableImpl(const ResourceNameRef &name, const OverlayableItem& overlayable,
|
||||
NameValidator name_validator, IDiagnostics *diag);
|
||||
|
||||
bool SetSymbolStateImpl(const ResourceNameRef& name, const ResourceId& res_id,
|
||||
|
||||
@@ -244,48 +244,90 @@ TEST(ResourceTableTest, SetAllowNew) {
|
||||
|
||||
TEST(ResourceTableTest, SetOverlayable) {
|
||||
ResourceTable table;
|
||||
Overlayable overlayable{};
|
||||
overlayable.policies |= Overlayable::Policy::kProduct;
|
||||
overlayable.policies |= Overlayable::Policy::kProductServices;
|
||||
overlayable.comment = "comment";
|
||||
auto overlayable = std::make_shared<Overlayable>("Name", "overlay://theme",
|
||||
Source("res/values/overlayable.xml", 40));
|
||||
OverlayableItem overlayable_item(overlayable);
|
||||
overlayable_item.policies |= OverlayableItem::Policy::kProduct;
|
||||
overlayable_item.policies |= OverlayableItem::Policy::kProductServices;
|
||||
overlayable_item.comment = "comment";
|
||||
overlayable_item.source = Source("res/values/overlayable.xml", 42);
|
||||
|
||||
const ResourceName name = test::ParseNameOrDie("android:string/foo");
|
||||
ASSERT_TRUE(table.SetOverlayable(name, overlayable, test::GetDiagnostics()));
|
||||
ASSERT_TRUE(table.SetOverlayable(name, overlayable_item, test::GetDiagnostics()));
|
||||
Maybe<ResourceTable::SearchResult> search_result = table.FindResource(name);
|
||||
|
||||
ASSERT_TRUE(search_result);
|
||||
ASSERT_TRUE(search_result.value().entry->overlayable);
|
||||
ASSERT_TRUE(search_result.value().entry->overlayable_item);
|
||||
|
||||
Overlayable& result_overlayable = search_result.value().entry->overlayable.value();
|
||||
ASSERT_THAT(result_overlayable.comment, StrEq("comment"));
|
||||
EXPECT_THAT(result_overlayable.policies, Eq(Overlayable::Policy::kProduct
|
||||
| Overlayable::Policy::kProductServices));
|
||||
OverlayableItem& result_overlayable_item = search_result.value().entry->overlayable_item.value();
|
||||
EXPECT_THAT(result_overlayable_item.overlayable->name, Eq("Name"));
|
||||
EXPECT_THAT(result_overlayable_item.overlayable->actor, Eq("overlay://theme"));
|
||||
EXPECT_THAT(result_overlayable_item.overlayable->source.path, Eq("res/values/overlayable.xml"));
|
||||
EXPECT_THAT(result_overlayable_item.overlayable->source.line, 40);
|
||||
EXPECT_THAT(result_overlayable_item.policies, Eq(OverlayableItem::Policy::kProduct
|
||||
| OverlayableItem::Policy::kProductServices));
|
||||
ASSERT_THAT(result_overlayable_item.comment, StrEq("comment"));
|
||||
EXPECT_THAT(result_overlayable_item.source.path, Eq("res/values/overlayable.xml"));
|
||||
EXPECT_THAT(result_overlayable_item.source.line, 42);
|
||||
}
|
||||
|
||||
TEST(ResourceTableTest, AddDuplicateOverlayableSamePolicyFail) {
|
||||
TEST(ResourceTableTest, SetMultipleOverlayableResources) {
|
||||
ResourceTable table;
|
||||
|
||||
const ResourceName foo = test::ParseNameOrDie("android:string/foo");
|
||||
auto group = std::make_shared<Overlayable>("Name", "overlay://theme");
|
||||
OverlayableItem overlayable(group);
|
||||
overlayable.policies = OverlayableItem::Policy::kProduct;
|
||||
ASSERT_TRUE(table.SetOverlayable(foo, overlayable, test::GetDiagnostics()));
|
||||
|
||||
const ResourceName bar = test::ParseNameOrDie("android:string/bar");
|
||||
OverlayableItem overlayable2(group);
|
||||
overlayable2.policies = OverlayableItem::Policy::kProduct;
|
||||
ASSERT_TRUE(table.SetOverlayable(bar, overlayable2, test::GetDiagnostics()));
|
||||
|
||||
const ResourceName baz = test::ParseNameOrDie("android:string/baz");
|
||||
OverlayableItem overlayable3(group);
|
||||
overlayable3.policies = OverlayableItem::Policy::kVendor;
|
||||
ASSERT_TRUE(table.SetOverlayable(baz, overlayable3, test::GetDiagnostics()));
|
||||
}
|
||||
|
||||
TEST(ResourceTableTest, SetOverlayableDifferentResourcesDifferentName) {
|
||||
ResourceTable table;
|
||||
|
||||
const ResourceName foo = test::ParseNameOrDie("android:string/foo");
|
||||
OverlayableItem overlayable_item(std::make_shared<Overlayable>("Name", "overlay://theme"));
|
||||
overlayable_item.policies = OverlayableItem::Policy::kProduct;
|
||||
ASSERT_TRUE(table.SetOverlayable(foo, overlayable_item, test::GetDiagnostics()));
|
||||
|
||||
const ResourceName bar = test::ParseNameOrDie("android:string/bar");
|
||||
OverlayableItem overlayable_item2(std::make_shared<Overlayable>("Name2", "overlay://theme"));
|
||||
overlayable_item2.policies = OverlayableItem::Policy::kProduct;
|
||||
ASSERT_TRUE(table.SetOverlayable(bar, overlayable_item2, test::GetDiagnostics()));
|
||||
}
|
||||
|
||||
TEST(ResourceTableTest, SetOverlayableSameResourcesFail) {
|
||||
ResourceTable table;
|
||||
const ResourceName name = test::ParseNameOrDie("android:string/foo");
|
||||
|
||||
Overlayable overlayable{};
|
||||
overlayable.policies = Overlayable::Policy::kProduct;
|
||||
ASSERT_TRUE(table.SetOverlayable(name, overlayable, test::GetDiagnostics()));
|
||||
auto overlayable = std::make_shared<Overlayable>("Name", "overlay://theme");
|
||||
OverlayableItem overlayable_item(overlayable);
|
||||
ASSERT_TRUE(table.SetOverlayable(name, overlayable_item, test::GetDiagnostics()));
|
||||
|
||||
Overlayable overlayable2{};
|
||||
overlayable2.policies = Overlayable::Policy::kProduct;
|
||||
ASSERT_FALSE(table.SetOverlayable(name, overlayable2, test::GetDiagnostics()));
|
||||
OverlayableItem overlayable_item2(overlayable);
|
||||
ASSERT_FALSE(table.SetOverlayable(name, overlayable_item2, test::GetDiagnostics()));
|
||||
}
|
||||
|
||||
TEST(ResourceTableTest, AddDuplicateOverlayableDifferentPolicyFail) {
|
||||
TEST(ResourceTableTest, SetOverlayableSameResourcesDifferentNameFail) {
|
||||
ResourceTable table;
|
||||
const ResourceName name = test::ParseNameOrDie("android:string/foo");
|
||||
|
||||
Overlayable overlayable{};
|
||||
overlayable.policies = Overlayable::Policy::kProduct;
|
||||
ASSERT_TRUE(table.SetOverlayable(name, overlayable, test::GetDiagnostics()));
|
||||
auto overlayable = std::make_shared<Overlayable>("Name", "overlay://theme");
|
||||
OverlayableItem overlayable_item(overlayable);
|
||||
ASSERT_TRUE(table.SetOverlayable(name, overlayable_item, test::GetDiagnostics()));
|
||||
|
||||
Overlayable overlayable2{};
|
||||
overlayable2.policies = Overlayable::Policy::kVendor;
|
||||
ASSERT_FALSE(table.SetOverlayable(name, overlayable2, test::GetDiagnostics()));
|
||||
auto overlayable2 = std::make_shared<Overlayable>("Other", "overlay://theme");
|
||||
OverlayableItem overlayable_item2(overlayable2);
|
||||
ASSERT_FALSE(table.SetOverlayable(name, overlayable_item2, test::GetDiagnostics()));
|
||||
}
|
||||
|
||||
TEST(ResourceTableTest, AllowDuplictaeResourcesNames) {
|
||||
|
||||
@@ -49,6 +49,9 @@ message ResourceTable {
|
||||
|
||||
// Resource definitions corresponding to an Android package.
|
||||
repeated Package package = 2;
|
||||
|
||||
// The <overlayable> declarations within the resource table.
|
||||
repeated Overlayable overlayable = 3;
|
||||
}
|
||||
|
||||
// A package ID in the range [0x00, 0xff].
|
||||
@@ -133,8 +136,20 @@ message AllowNew {
|
||||
string comment = 2;
|
||||
}
|
||||
|
||||
// Represents a declaration that a resource is overayable at runtime.
|
||||
// Represents a set of overlayable resources.
|
||||
message Overlayable {
|
||||
// The name of the <overlyabale>.
|
||||
string name = 1;
|
||||
|
||||
// The location of the <overlyabale> declaration in the source.
|
||||
Source source = 2;
|
||||
|
||||
// The component responsible for enabling and disabling overlays targeting this <overlayable>.
|
||||
string actor = 3;
|
||||
}
|
||||
|
||||
// Represents an overlayable <item> declaration within an <overlayable> tag.
|
||||
message OverlayableItem {
|
||||
enum Policy {
|
||||
PUBLIC = 0;
|
||||
SYSTEM = 1;
|
||||
@@ -143,14 +158,18 @@ message Overlayable {
|
||||
PRODUCT_SERVICES = 4;
|
||||
}
|
||||
|
||||
// Where this declaration was defined in source.
|
||||
// The location of the <item> declaration in source.
|
||||
Source source = 1;
|
||||
|
||||
// Any comment associated with the declaration.
|
||||
string comment = 2;
|
||||
|
||||
// The policy defined in the overlayable declaration.
|
||||
// The policy defined by the enclosing <policy> tag of this <item>.
|
||||
repeated Policy policy = 3;
|
||||
|
||||
// The index into overlayable list that points to the <overlayable> tag that contains
|
||||
// this <item>.
|
||||
uint32 overlayable_idx = 4;
|
||||
}
|
||||
|
||||
// An entry ID in the range [0x0000, 0xffff].
|
||||
@@ -180,7 +199,7 @@ message Entry {
|
||||
AllowNew allow_new = 4;
|
||||
|
||||
// Whether this resource can be overlaid by a runtime resource overlay (RRO).
|
||||
Overlayable overlayable = 5;
|
||||
OverlayableItem overlayable_item = 5;
|
||||
|
||||
// The set of values defined for this entry, each corresponding to a different
|
||||
// configuration/variant.
|
||||
|
||||
@@ -434,6 +434,8 @@ bool BinaryResourceParser::ParseOverlayable(const ResChunk_header* chunk) {
|
||||
return false;
|
||||
}
|
||||
|
||||
auto overlayable = std::make_shared<Overlayable>();
|
||||
|
||||
ResChunkPullParser parser(GetChunkData(chunk),
|
||||
GetChunkDataLen(chunk));
|
||||
while (ResChunkPullParser::IsGoodEvent(parser.Next())) {
|
||||
@@ -441,25 +443,25 @@ bool BinaryResourceParser::ParseOverlayable(const ResChunk_header* chunk) {
|
||||
const ResTable_overlayable_policy_header* policy_header =
|
||||
ConvertTo<ResTable_overlayable_policy_header>(parser.chunk());
|
||||
|
||||
Overlayable::PolicyFlags policies = Overlayable::Policy::kNone;
|
||||
OverlayableItem::PolicyFlags policies = OverlayableItem::Policy::kNone;
|
||||
if (policy_header->policy_flags & ResTable_overlayable_policy_header::POLICY_PUBLIC) {
|
||||
policies |= Overlayable::Policy::kPublic;
|
||||
policies |= OverlayableItem::Policy::kPublic;
|
||||
}
|
||||
if (policy_header->policy_flags
|
||||
& ResTable_overlayable_policy_header::POLICY_SYSTEM_PARTITION) {
|
||||
policies |= Overlayable::Policy::kSystem;
|
||||
policies |= OverlayableItem::Policy::kSystem;
|
||||
}
|
||||
if (policy_header->policy_flags
|
||||
& ResTable_overlayable_policy_header::POLICY_VENDOR_PARTITION) {
|
||||
policies |= Overlayable::Policy::kVendor;
|
||||
policies |= OverlayableItem::Policy::kVendor;
|
||||
}
|
||||
if (policy_header->policy_flags
|
||||
& ResTable_overlayable_policy_header::POLICY_PRODUCT_PARTITION) {
|
||||
policies |= Overlayable::Policy::kProduct;
|
||||
policies |= OverlayableItem::Policy::kProduct;
|
||||
}
|
||||
if (policy_header->policy_flags
|
||||
& ResTable_overlayable_policy_header::POLICY_PRODUCT_SERVICES_PARTITION) {
|
||||
policies |= Overlayable::Policy::kProductServices;
|
||||
policies |= OverlayableItem::Policy::kProductServices;
|
||||
}
|
||||
|
||||
const ResTable_ref* const ref_begin = reinterpret_cast<const ResTable_ref*>(
|
||||
@@ -478,10 +480,10 @@ bool BinaryResourceParser::ParseOverlayable(const ResChunk_header* chunk) {
|
||||
return false;
|
||||
}
|
||||
|
||||
Overlayable overlayable{};
|
||||
overlayable.source = source_.WithLine(0);
|
||||
overlayable.policies = policies;
|
||||
if (!table_->SetOverlayable(iter->second, overlayable, diag_)) {
|
||||
OverlayableItem overlayable_item(overlayable);
|
||||
overlayable_item.source = source_.WithLine(0);
|
||||
overlayable_item.policies = policies;
|
||||
if (!table_->SetOverlayable(iter->second, overlayable_item, diag_)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -429,29 +429,29 @@ class PackageFlattener {
|
||||
CHECK(bool(type->id)) << "type must have an ID set when flattening <overlayable>";
|
||||
for (auto& entry : type->entries) {
|
||||
CHECK(bool(type->id)) << "entry must have an ID set when flattening <overlayable>";
|
||||
if (!entry->overlayable) {
|
||||
if (!entry->overlayable_item) {
|
||||
continue;
|
||||
}
|
||||
|
||||
Overlayable overlayable = entry->overlayable.value();
|
||||
uint32_t policy_flags = Overlayable::Policy::kNone;
|
||||
if (overlayable.policies & Overlayable::Policy::kPublic) {
|
||||
OverlayableItem& overlayable = entry->overlayable_item.value();
|
||||
uint32_t policy_flags = OverlayableItem::Policy::kNone;
|
||||
if (overlayable.policies & OverlayableItem::Policy::kPublic) {
|
||||
policy_flags |= ResTable_overlayable_policy_header::POLICY_PUBLIC;
|
||||
}
|
||||
if (overlayable.policies & Overlayable::Policy::kSystem) {
|
||||
if (overlayable.policies & OverlayableItem::Policy::kSystem) {
|
||||
policy_flags |= ResTable_overlayable_policy_header::POLICY_SYSTEM_PARTITION;
|
||||
}
|
||||
if (overlayable.policies & Overlayable::Policy::kVendor) {
|
||||
if (overlayable.policies & OverlayableItem::Policy::kVendor) {
|
||||
policy_flags |= ResTable_overlayable_policy_header::POLICY_VENDOR_PARTITION;
|
||||
}
|
||||
if (overlayable.policies & Overlayable::Policy::kProduct) {
|
||||
if (overlayable.policies & OverlayableItem::Policy::kProduct) {
|
||||
policy_flags |= ResTable_overlayable_policy_header::POLICY_PRODUCT_PARTITION;
|
||||
}
|
||||
if (overlayable.policies & Overlayable::Policy::kProductServices) {
|
||||
if (overlayable.policies & OverlayableItem::Policy::kProductServices) {
|
||||
policy_flags |= ResTable_overlayable_policy_header::POLICY_PRODUCT_SERVICES_PARTITION;
|
||||
}
|
||||
|
||||
if (overlayable.policies == Overlayable::Policy::kNone) {
|
||||
if (overlayable.policies == OverlayableItem::Policy::kNone) {
|
||||
// Encode overlayable entries defined without a policy as publicly overlayable
|
||||
policy_flags |= ResTable_overlayable_policy_header::POLICY_PUBLIC;
|
||||
}
|
||||
|
||||
@@ -628,17 +628,17 @@ TEST_F(TableFlattenerTest, ObfuscatingResourceNamesWithWhitelistSucceeds) {
|
||||
}
|
||||
|
||||
TEST_F(TableFlattenerTest, FlattenOverlayable) {
|
||||
Overlayable overlayable{};
|
||||
overlayable.policies |= Overlayable::Policy::kProduct;
|
||||
overlayable.policies |= Overlayable::Policy::kSystem;
|
||||
overlayable.policies |= Overlayable::Policy::kVendor;
|
||||
OverlayableItem overlayable_item(std::make_shared<Overlayable>("TestName", "overlay://theme"));
|
||||
overlayable_item.policies |= OverlayableItem::Policy::kProduct;
|
||||
overlayable_item.policies |= OverlayableItem::Policy::kSystem;
|
||||
overlayable_item.policies |= OverlayableItem::Policy::kVendor;
|
||||
|
||||
std::string name = "com.app.test:integer/overlayable";
|
||||
std::unique_ptr<ResourceTable> table =
|
||||
test::ResourceTableBuilder()
|
||||
.SetPackageId("com.app.test", 0x7f)
|
||||
.AddSimple(name, ResourceId(0x7f020000))
|
||||
.SetOverlayable(name, overlayable)
|
||||
.SetOverlayable(name, overlayable_item)
|
||||
.Build();
|
||||
|
||||
ResourceTable output_table;
|
||||
@@ -647,45 +647,46 @@ TEST_F(TableFlattenerTest, FlattenOverlayable) {
|
||||
auto search_result = output_table.FindResource(test::ParseNameOrDie(name));
|
||||
ASSERT_TRUE(search_result);
|
||||
ASSERT_THAT(search_result.value().entry, NotNull());
|
||||
ASSERT_TRUE(search_result.value().entry->overlayable);
|
||||
Overlayable& result_overlayable = search_result.value().entry->overlayable.value();
|
||||
EXPECT_EQ(result_overlayable.policies, Overlayable::Policy::kSystem
|
||||
| Overlayable::Policy::kVendor
|
||||
| Overlayable::Policy::kProduct);
|
||||
ASSERT_TRUE(search_result.value().entry->overlayable_item);
|
||||
OverlayableItem& result_overlayable_item = search_result.value().entry->overlayable_item.value();
|
||||
EXPECT_EQ(result_overlayable_item.policies, OverlayableItem::Policy::kSystem
|
||||
| OverlayableItem::Policy::kVendor
|
||||
| OverlayableItem::Policy::kProduct);
|
||||
}
|
||||
|
||||
TEST_F(TableFlattenerTest, FlattenMultipleOverlayablePolicies) {
|
||||
std::string name_zero = "com.app.test:integer/overlayable_zero";
|
||||
Overlayable overlayable_zero{};
|
||||
overlayable_zero.policies |= Overlayable::Policy::kProduct;
|
||||
overlayable_zero.policies |= Overlayable::Policy::kSystem;
|
||||
overlayable_zero.policies |= Overlayable::Policy::kProductServices;
|
||||
auto overlayable = std::make_shared<Overlayable>("TestName", "overlay://theme");
|
||||
std::string name_zero = "com.app.test:integer/overlayable_zero_item";
|
||||
OverlayableItem overlayable_zero_item(overlayable);
|
||||
overlayable_zero_item.policies |= OverlayableItem::Policy::kProduct;
|
||||
overlayable_zero_item.policies |= OverlayableItem::Policy::kSystem;
|
||||
overlayable_zero_item.policies |= OverlayableItem::Policy::kProductServices;
|
||||
|
||||
std::string name_one = "com.app.test:integer/overlayable_one";
|
||||
Overlayable overlayable_one{};
|
||||
overlayable_one.policies |= Overlayable::Policy::kPublic;
|
||||
overlayable_one.policies |= Overlayable::Policy::kProductServices;
|
||||
std::string name_one = "com.app.test:integer/overlayable_one_item";
|
||||
OverlayableItem overlayable_one_item(overlayable);
|
||||
overlayable_one_item.policies |= OverlayableItem::Policy::kPublic;
|
||||
overlayable_one_item.policies |= OverlayableItem::Policy::kProductServices;
|
||||
|
||||
std::string name_two = "com.app.test:integer/overlayable_two";
|
||||
Overlayable overlayable_two{};
|
||||
overlayable_two.policies |= Overlayable::Policy::kProduct;
|
||||
overlayable_two.policies |= Overlayable::Policy::kSystem;
|
||||
overlayable_two.policies |= Overlayable::Policy::kVendor;
|
||||
std::string name_two = "com.app.test:integer/overlayable_two_item";
|
||||
OverlayableItem overlayable_two_item(overlayable);
|
||||
overlayable_two_item.policies |= OverlayableItem::Policy::kProduct;
|
||||
overlayable_two_item.policies |= OverlayableItem::Policy::kSystem;
|
||||
overlayable_two_item.policies |= OverlayableItem::Policy::kVendor;
|
||||
|
||||
std::string name_three = "com.app.test:integer/overlayable_three";
|
||||
Overlayable overlayable_three{};
|
||||
std::string name_three = "com.app.test:integer/overlayable_three_item";
|
||||
OverlayableItem overlayable_three_item(overlayable);
|
||||
|
||||
std::unique_ptr<ResourceTable> table =
|
||||
test::ResourceTableBuilder()
|
||||
.SetPackageId("com.app.test", 0x7f)
|
||||
.AddSimple(name_zero, ResourceId(0x7f020000))
|
||||
.SetOverlayable(name_zero, overlayable_zero)
|
||||
.SetOverlayable(name_zero, overlayable_zero_item)
|
||||
.AddSimple(name_one, ResourceId(0x7f020001))
|
||||
.SetOverlayable(name_one, overlayable_one)
|
||||
.SetOverlayable(name_one, overlayable_one_item)
|
||||
.AddSimple(name_two, ResourceId(0x7f020002))
|
||||
.SetOverlayable(name_two, overlayable_two)
|
||||
.SetOverlayable(name_two, overlayable_two_item)
|
||||
.AddSimple(name_three, ResourceId(0x7f020003))
|
||||
.SetOverlayable(name_three, overlayable_three)
|
||||
.SetOverlayable(name_three, overlayable_three_item)
|
||||
.Build();
|
||||
|
||||
ResourceTable output_table;
|
||||
@@ -694,35 +695,35 @@ TEST_F(TableFlattenerTest, FlattenMultipleOverlayablePolicies) {
|
||||
auto search_result = output_table.FindResource(test::ParseNameOrDie(name_zero));
|
||||
ASSERT_TRUE(search_result);
|
||||
ASSERT_THAT(search_result.value().entry, NotNull());
|
||||
ASSERT_TRUE(search_result.value().entry->overlayable);
|
||||
Overlayable& result_overlayable = search_result.value().entry->overlayable.value();
|
||||
EXPECT_EQ(result_overlayable.policies, Overlayable::Policy::kSystem
|
||||
| Overlayable::Policy::kProduct
|
||||
| Overlayable::Policy::kProductServices);
|
||||
ASSERT_TRUE(search_result.value().entry->overlayable_item);
|
||||
OverlayableItem& overlayable_item = search_result.value().entry->overlayable_item.value();
|
||||
EXPECT_EQ(overlayable_item.policies, OverlayableItem::Policy::kSystem
|
||||
| OverlayableItem::Policy::kProduct
|
||||
| OverlayableItem::Policy::kProductServices);
|
||||
|
||||
search_result = output_table.FindResource(test::ParseNameOrDie(name_one));
|
||||
ASSERT_TRUE(search_result);
|
||||
ASSERT_THAT(search_result.value().entry, NotNull());
|
||||
ASSERT_TRUE(search_result.value().entry->overlayable);
|
||||
result_overlayable = search_result.value().entry->overlayable.value();
|
||||
EXPECT_EQ(result_overlayable.policies, Overlayable::Policy::kPublic
|
||||
| Overlayable::Policy::kProductServices);
|
||||
ASSERT_TRUE(search_result.value().entry->overlayable_item);
|
||||
overlayable_item = search_result.value().entry->overlayable_item.value();
|
||||
EXPECT_EQ(overlayable_item.policies, OverlayableItem::Policy::kPublic
|
||||
| OverlayableItem::Policy::kProductServices);
|
||||
|
||||
search_result = output_table.FindResource(test::ParseNameOrDie(name_two));
|
||||
ASSERT_TRUE(search_result);
|
||||
ASSERT_THAT(search_result.value().entry, NotNull());
|
||||
ASSERT_TRUE(search_result.value().entry->overlayable);
|
||||
result_overlayable = search_result.value().entry->overlayable.value();
|
||||
EXPECT_EQ(result_overlayable.policies, Overlayable::Policy::kSystem
|
||||
| Overlayable::Policy::kProduct
|
||||
| Overlayable::Policy::kVendor);
|
||||
ASSERT_TRUE(search_result.value().entry->overlayable_item);
|
||||
overlayable_item = search_result.value().entry->overlayable_item.value();
|
||||
EXPECT_EQ(overlayable_item.policies, OverlayableItem::Policy::kSystem
|
||||
| OverlayableItem::Policy::kProduct
|
||||
| OverlayableItem::Policy::kVendor);
|
||||
|
||||
search_result = output_table.FindResource(test::ParseNameOrDie(name_three));
|
||||
ASSERT_TRUE(search_result);
|
||||
ASSERT_THAT(search_result.value().entry, NotNull());
|
||||
ASSERT_TRUE(search_result.value().entry->overlayable);
|
||||
result_overlayable = search_result.value().entry->overlayable.value();
|
||||
EXPECT_EQ(result_overlayable.policies, Overlayable::Policy::kPublic);
|
||||
ASSERT_TRUE(search_result.value().entry->overlayable_item);
|
||||
overlayable_item = search_result.value().entry->overlayable_item.value();
|
||||
EXPECT_EQ(overlayable_item.policies, OverlayableItem::Policy::kPublic);
|
||||
}
|
||||
|
||||
} // namespace aapt
|
||||
|
||||
@@ -373,9 +373,44 @@ static Visibility::Level DeserializeVisibilityFromPb(const pb::Visibility::Level
|
||||
return Visibility::Level::kUndefined;
|
||||
}
|
||||
|
||||
bool DeserializeOverlayableItemFromPb(const pb::OverlayableItem& pb_overlayable,
|
||||
const android::ResStringPool& src_pool,
|
||||
OverlayableItem* out_overlayable, std::string* out_error) {
|
||||
for (const int policy : pb_overlayable.policy()) {
|
||||
switch (policy) {
|
||||
case pb::OverlayableItem::PUBLIC:
|
||||
out_overlayable->policies |= OverlayableItem::Policy::kPublic;
|
||||
break;
|
||||
case pb::OverlayableItem::SYSTEM:
|
||||
out_overlayable->policies |= OverlayableItem::Policy::kSystem;
|
||||
break;
|
||||
case pb::OverlayableItem::VENDOR:
|
||||
out_overlayable->policies |= OverlayableItem::Policy::kVendor;
|
||||
break;
|
||||
case pb::OverlayableItem::PRODUCT:
|
||||
out_overlayable->policies |= OverlayableItem::Policy::kProduct;
|
||||
break;
|
||||
case pb::OverlayableItem::PRODUCT_SERVICES:
|
||||
out_overlayable->policies |= OverlayableItem::Policy::kProductServices;
|
||||
break;
|
||||
default:
|
||||
*out_error = "unknown overlayable policy";
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (pb_overlayable.has_source()) {
|
||||
DeserializeSourceFromPb(pb_overlayable.source(), src_pool, &out_overlayable->source);
|
||||
}
|
||||
|
||||
out_overlayable->comment = pb_overlayable.comment();
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool DeserializePackageFromPb(const pb::Package& pb_package, const ResStringPool& src_pool,
|
||||
io::IFileCollection* files, ResourceTable* out_table,
|
||||
std::string* out_error) {
|
||||
io::IFileCollection* files,
|
||||
const std::vector<std::shared_ptr<Overlayable>>& overlayables,
|
||||
ResourceTable* out_table, std::string* out_error) {
|
||||
Maybe<uint8_t> id;
|
||||
if (pb_package.has_package_id()) {
|
||||
id = static_cast<uint8_t>(pb_package.package_id().id());
|
||||
@@ -437,39 +472,22 @@ static bool DeserializePackageFromPb(const pb::Package& pb_package, const ResStr
|
||||
entry->allow_new = std::move(allow_new);
|
||||
}
|
||||
|
||||
if (pb_entry.has_overlayable()) {
|
||||
Overlayable overlayable{};
|
||||
|
||||
const pb::Overlayable& pb_overlayable = pb_entry.overlayable();
|
||||
for (const int policy : pb_overlayable.policy()) {
|
||||
switch (policy) {
|
||||
case pb::Overlayable::PUBLIC:
|
||||
overlayable.policies |= Overlayable::Policy::kPublic;
|
||||
break;
|
||||
case pb::Overlayable::SYSTEM:
|
||||
overlayable.policies |= Overlayable::Policy::kSystem;
|
||||
break;
|
||||
case pb::Overlayable::VENDOR:
|
||||
overlayable.policies |= Overlayable::Policy::kVendor;
|
||||
break;
|
||||
case pb::Overlayable::PRODUCT:
|
||||
overlayable.policies |= Overlayable::Policy::kProduct;
|
||||
break;
|
||||
case pb::Overlayable::PRODUCT_SERVICES:
|
||||
overlayable.policies |= Overlayable::Policy::kProductServices;
|
||||
break;
|
||||
default:
|
||||
*out_error = "unknown overlayable policy";
|
||||
return false;
|
||||
}
|
||||
if (pb_entry.has_overlayable_item()) {
|
||||
// Find the overlayable to which this item belongs
|
||||
pb::OverlayableItem pb_overlayable_item = pb_entry.overlayable_item();
|
||||
if (pb_overlayable_item.overlayable_idx() >= overlayables.size()) {
|
||||
*out_error = android::base::StringPrintf("invalid overlayable_idx value %d",
|
||||
pb_overlayable_item.overlayable_idx());
|
||||
return false;
|
||||
}
|
||||
|
||||
if (pb_overlayable.has_source()) {
|
||||
DeserializeSourceFromPb(pb_overlayable.source(), src_pool, &overlayable.source);
|
||||
OverlayableItem overlayable_item(overlayables[pb_overlayable_item.overlayable_idx()]);
|
||||
if (!DeserializeOverlayableItemFromPb(pb_overlayable_item, src_pool, &overlayable_item,
|
||||
out_error)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
overlayable.comment = pb_overlayable.comment();
|
||||
entry->overlayable = overlayable;
|
||||
entry->overlayable_item = std::move(overlayable_item);
|
||||
}
|
||||
|
||||
ResourceId resid(pb_package.package_id().id(), pb_type.type_id().id(),
|
||||
@@ -522,8 +540,19 @@ bool DeserializeTableFromPb(const pb::ResourceTable& pb_table, io::IFileCollecti
|
||||
}
|
||||
}
|
||||
|
||||
// Deserialize the overlayable groups of the table
|
||||
std::vector<std::shared_ptr<Overlayable>> overlayables;
|
||||
for (const pb::Overlayable& pb_overlayable : pb_table.overlayable()) {
|
||||
auto group = std::make_shared<Overlayable>(pb_overlayable.name(), pb_overlayable.actor());
|
||||
if (pb_overlayable.has_source()) {
|
||||
DeserializeSourceFromPb(pb_overlayable.source(), source_pool, &group->source);
|
||||
}
|
||||
overlayables.push_back(group);
|
||||
}
|
||||
|
||||
for (const pb::Package& pb_package : pb_table.package()) {
|
||||
if (!DeserializePackageFromPb(pb_package, source_pool, files, out_table, out_error)) {
|
||||
if (!DeserializePackageFromPb(pb_package, source_pool, files, overlayables, out_table,
|
||||
out_error)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -272,9 +272,57 @@ void SerializeConfig(const ConfigDescription& config, pb::Configuration* out_pb_
|
||||
out_pb_config->set_sdk_version(config.sdkVersion);
|
||||
}
|
||||
|
||||
static void SerializeOverlayableItemToPb(const OverlayableItem& overlayable_item,
|
||||
std::vector<Overlayable*>& serialized_overlayables,
|
||||
StringPool* source_pool, pb::Entry* pb_entry,
|
||||
pb::ResourceTable* pb_table) {
|
||||
// Retrieve the index of the overlayable in the list of groups that have already been serialized.
|
||||
size_t i;
|
||||
for (i = 0 ; i < serialized_overlayables.size(); i++) {
|
||||
if (overlayable_item.overlayable.get() == serialized_overlayables[i]) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Serialize the overlayable if it has not been serialized already.
|
||||
if (i == serialized_overlayables.size()) {
|
||||
serialized_overlayables.push_back(overlayable_item.overlayable.get());
|
||||
pb::Overlayable* pb_overlayable = pb_table->add_overlayable();
|
||||
pb_overlayable->set_name(overlayable_item.overlayable->name);
|
||||
pb_overlayable->set_actor(overlayable_item.overlayable->actor);
|
||||
SerializeSourceToPb(overlayable_item.overlayable->source, source_pool,
|
||||
pb_overlayable->mutable_source());
|
||||
}
|
||||
|
||||
pb::OverlayableItem* pb_overlayable_item = pb_entry->mutable_overlayable_item();
|
||||
pb_overlayable_item->set_overlayable_idx(i);
|
||||
|
||||
if (overlayable_item.policies & OverlayableItem::Policy::kPublic) {
|
||||
pb_overlayable_item->add_policy(pb::OverlayableItem::PUBLIC);
|
||||
}
|
||||
if (overlayable_item.policies & OverlayableItem::Policy::kProduct) {
|
||||
pb_overlayable_item->add_policy(pb::OverlayableItem::PRODUCT);
|
||||
}
|
||||
if (overlayable_item.policies & OverlayableItem::Policy::kProductServices) {
|
||||
pb_overlayable_item->add_policy(pb::OverlayableItem::PRODUCT_SERVICES);
|
||||
}
|
||||
if (overlayable_item.policies & OverlayableItem::Policy::kSystem) {
|
||||
pb_overlayable_item->add_policy(pb::OverlayableItem::SYSTEM);
|
||||
}
|
||||
if (overlayable_item.policies & OverlayableItem::Policy::kVendor) {
|
||||
pb_overlayable_item->add_policy(pb::OverlayableItem::VENDOR);
|
||||
}
|
||||
|
||||
SerializeSourceToPb(overlayable_item.source, source_pool,
|
||||
pb_overlayable_item->mutable_source());
|
||||
pb_overlayable_item->set_comment(overlayable_item.comment);
|
||||
}
|
||||
|
||||
void SerializeTableToPb(const ResourceTable& table, pb::ResourceTable* out_table,
|
||||
IDiagnostics* diag) {
|
||||
StringPool source_pool;
|
||||
|
||||
std::vector<Overlayable*> overlayables;
|
||||
for (const std::unique_ptr<ResourceTablePackage>& package : table.packages) {
|
||||
pb::Package* pb_package = out_table->add_package();
|
||||
if (package->id) {
|
||||
@@ -310,29 +358,9 @@ void SerializeTableToPb(const ResourceTable& table, pb::ResourceTable* out_table
|
||||
pb_allow_new->set_comment(entry->allow_new.value().comment);
|
||||
}
|
||||
|
||||
if (entry->overlayable) {
|
||||
pb::Overlayable* pb_overlayable = pb_entry->mutable_overlayable();
|
||||
|
||||
Overlayable overlayable = entry->overlayable.value();
|
||||
if (overlayable.policies & Overlayable::Policy::kPublic) {
|
||||
pb_overlayable->add_policy(pb::Overlayable::PUBLIC);
|
||||
}
|
||||
if (overlayable.policies & Overlayable::Policy::kProduct) {
|
||||
pb_overlayable->add_policy(pb::Overlayable::PRODUCT);
|
||||
}
|
||||
if (overlayable.policies & Overlayable::Policy::kProductServices) {
|
||||
pb_overlayable->add_policy(pb::Overlayable::PRODUCT_SERVICES);
|
||||
}
|
||||
if (overlayable.policies & Overlayable::Policy::kSystem) {
|
||||
pb_overlayable->add_policy(pb::Overlayable::SYSTEM);
|
||||
}
|
||||
if (overlayable.policies & Overlayable::Policy::kVendor) {
|
||||
pb_overlayable->add_policy(pb::Overlayable::VENDOR);
|
||||
}
|
||||
|
||||
SerializeSourceToPb(overlayable.source, &source_pool,
|
||||
pb_overlayable->mutable_source());
|
||||
pb_overlayable->set_comment(overlayable.comment);
|
||||
if (entry->overlayable_item) {
|
||||
SerializeOverlayableItemToPb(entry->overlayable_item.value(), overlayables, &source_pool,
|
||||
pb_entry, out_table);
|
||||
}
|
||||
|
||||
for (const std::unique_ptr<ResourceConfigValue>& config_value : entry->values) {
|
||||
|
||||
@@ -93,8 +93,11 @@ TEST(ProtoSerializeTest, SerializeSinglePackage) {
|
||||
util::make_unique<Reference>(expected_ref), context->GetDiagnostics()));
|
||||
|
||||
// Make an overlayable resource.
|
||||
OverlayableItem overlayable_item(std::make_shared<Overlayable>(
|
||||
"OverlayableName", "overlay://theme", Source("res/values/overlayable.xml", 40)));
|
||||
overlayable_item.source = Source("res/values/overlayable.xml", 42);
|
||||
ASSERT_TRUE(table->SetOverlayable(test::ParseNameOrDie("com.app.a:integer/overlayable"),
|
||||
Overlayable{}, test::GetDiagnostics()));
|
||||
overlayable_item, test::GetDiagnostics()));
|
||||
|
||||
pb::ResourceTable pb_table;
|
||||
SerializeTableToPb(*table, &pb_table, context->GetDiagnostics());
|
||||
@@ -160,9 +163,15 @@ TEST(ProtoSerializeTest, SerializeSinglePackage) {
|
||||
new_table.FindResource(test::ParseNameOrDie("com.app.a:integer/overlayable"));
|
||||
ASSERT_TRUE(search_result);
|
||||
ASSERT_THAT(search_result.value().entry, NotNull());
|
||||
ASSERT_TRUE(search_result.value().entry->overlayable);
|
||||
EXPECT_THAT(search_result.value().entry->overlayable.value().policies,
|
||||
Eq(Overlayable::Policy::kNone));
|
||||
ASSERT_TRUE(search_result.value().entry->overlayable_item);
|
||||
OverlayableItem& result_overlayable_item = search_result.value().entry->overlayable_item.value();
|
||||
EXPECT_THAT(result_overlayable_item.overlayable->name, Eq("OverlayableName"));
|
||||
EXPECT_THAT(result_overlayable_item.overlayable->actor, Eq("overlay://theme"));
|
||||
EXPECT_THAT(result_overlayable_item.overlayable->source.path, Eq("res/values/overlayable.xml"));
|
||||
EXPECT_THAT(result_overlayable_item.overlayable->source.line, Eq(40));
|
||||
EXPECT_THAT(result_overlayable_item.policies, Eq(OverlayableItem::Policy::kNone));
|
||||
EXPECT_THAT(result_overlayable_item.source.path, Eq("res/values/overlayable.xml"));
|
||||
EXPECT_THAT(result_overlayable_item.source.line, Eq(42));
|
||||
}
|
||||
|
||||
TEST(ProtoSerializeTest, SerializeAndDeserializeXml) {
|
||||
@@ -503,26 +512,31 @@ TEST(ProtoSerializeTest, SerializeDeserializeConfiguration) {
|
||||
}
|
||||
|
||||
TEST(ProtoSerializeTest, SerializeAndDeserializeOverlayable) {
|
||||
Overlayable overlayable_foo{};
|
||||
overlayable_foo.policies |= Overlayable::Policy::kSystem;
|
||||
overlayable_foo.policies |= Overlayable::Policy::kProduct;
|
||||
OverlayableItem overlayable_item_foo(std::make_shared<Overlayable>(
|
||||
"CustomizableResources", "overlay://customization"));
|
||||
overlayable_item_foo.policies |= OverlayableItem::Policy::kSystem;
|
||||
overlayable_item_foo.policies |= OverlayableItem::Policy::kProduct;
|
||||
|
||||
Overlayable overlayable_bar{};
|
||||
overlayable_bar.policies |= Overlayable::Policy::kProductServices;
|
||||
overlayable_bar.policies |= Overlayable::Policy::kVendor;
|
||||
OverlayableItem overlayable_item_bar(std::make_shared<Overlayable>(
|
||||
"TaskBar", "overlay://theme"));
|
||||
overlayable_item_bar.policies |= OverlayableItem::Policy::kProductServices;
|
||||
overlayable_item_bar.policies |= OverlayableItem::Policy::kVendor;
|
||||
|
||||
Overlayable overlayable_baz{};
|
||||
overlayable_baz.policies |= Overlayable::Policy::kPublic;
|
||||
OverlayableItem overlayable_item_baz(std::make_shared<Overlayable>(
|
||||
"FontPack", "overlay://theme"));
|
||||
overlayable_item_baz.policies |= OverlayableItem::Policy::kPublic;
|
||||
|
||||
Overlayable overlayable_biz{};
|
||||
OverlayableItem overlayable_item_biz(std::make_shared<Overlayable>(
|
||||
"Other", "overlay://customization"));
|
||||
overlayable_item_biz.comment ="comment";
|
||||
|
||||
std::unique_ptr<IAaptContext> context = test::ContextBuilder().Build();
|
||||
std::unique_ptr<ResourceTable> table =
|
||||
test::ResourceTableBuilder()
|
||||
.SetOverlayable("com.app.a:bool/foo", overlayable_foo)
|
||||
.SetOverlayable("com.app.a:bool/bar", overlayable_bar)
|
||||
.SetOverlayable("com.app.a:bool/baz", overlayable_baz)
|
||||
.SetOverlayable("com.app.a:bool/biz", overlayable_biz)
|
||||
.SetOverlayable("com.app.a:bool/foo", overlayable_item_foo)
|
||||
.SetOverlayable("com.app.a:bool/bar", overlayable_item_bar)
|
||||
.SetOverlayable("com.app.a:bool/baz", overlayable_item_baz)
|
||||
.SetOverlayable("com.app.a:bool/biz", overlayable_item_biz)
|
||||
.AddValue("com.app.a:bool/fiz", ResourceUtils::TryParseBool("true"))
|
||||
.Build();
|
||||
|
||||
@@ -538,33 +552,41 @@ TEST(ProtoSerializeTest, SerializeAndDeserializeOverlayable) {
|
||||
Maybe<ResourceTable::SearchResult> search_result =
|
||||
new_table.FindResource(test::ParseNameOrDie("com.app.a:bool/foo"));
|
||||
ASSERT_TRUE(search_result);
|
||||
ASSERT_TRUE(search_result.value().entry->overlayable);
|
||||
Overlayable result_overlayable = search_result.value().entry->overlayable.value();
|
||||
EXPECT_THAT(result_overlayable.policies, Eq(Overlayable::Policy::kSystem
|
||||
| Overlayable::Policy::kProduct));
|
||||
ASSERT_TRUE(search_result.value().entry->overlayable_item);
|
||||
OverlayableItem& overlayable_item = search_result.value().entry->overlayable_item.value();
|
||||
EXPECT_THAT(overlayable_item.overlayable->name, Eq("CustomizableResources"));
|
||||
EXPECT_THAT(overlayable_item.overlayable->actor, Eq("overlay://customization"));
|
||||
EXPECT_THAT(overlayable_item.policies, Eq(OverlayableItem::Policy::kSystem
|
||||
| OverlayableItem::Policy::kProduct));
|
||||
|
||||
search_result = new_table.FindResource(test::ParseNameOrDie("com.app.a:bool/bar"));
|
||||
ASSERT_TRUE(search_result);
|
||||
ASSERT_TRUE(search_result.value().entry->overlayable);
|
||||
result_overlayable = search_result.value().entry->overlayable.value();
|
||||
EXPECT_THAT(result_overlayable.policies, Eq(Overlayable::Policy::kProductServices
|
||||
| Overlayable::Policy::kVendor));
|
||||
ASSERT_TRUE(search_result.value().entry->overlayable_item);
|
||||
overlayable_item = search_result.value().entry->overlayable_item.value();
|
||||
EXPECT_THAT(overlayable_item.overlayable->name, Eq("TaskBar"));
|
||||
EXPECT_THAT(overlayable_item.overlayable->actor, Eq("overlay://theme"));
|
||||
EXPECT_THAT(overlayable_item.policies, Eq(OverlayableItem::Policy::kProductServices
|
||||
| OverlayableItem::Policy::kVendor));
|
||||
|
||||
search_result = new_table.FindResource(test::ParseNameOrDie("com.app.a:bool/baz"));
|
||||
ASSERT_TRUE(search_result);
|
||||
ASSERT_TRUE(search_result.value().entry->overlayable);
|
||||
result_overlayable = search_result.value().entry->overlayable.value();
|
||||
EXPECT_THAT(result_overlayable.policies, Overlayable::Policy::kPublic);
|
||||
ASSERT_TRUE(search_result.value().entry->overlayable_item);
|
||||
overlayable_item = search_result.value().entry->overlayable_item.value();
|
||||
EXPECT_THAT(overlayable_item.overlayable->name, Eq("FontPack"));
|
||||
EXPECT_THAT(overlayable_item.overlayable->actor, Eq("overlay://theme"));
|
||||
EXPECT_THAT(overlayable_item.policies, Eq(OverlayableItem::Policy::kPublic));
|
||||
|
||||
search_result = new_table.FindResource(test::ParseNameOrDie("com.app.a:bool/biz"));
|
||||
ASSERT_TRUE(search_result);
|
||||
ASSERT_TRUE(search_result.value().entry->overlayable);
|
||||
result_overlayable = search_result.value().entry->overlayable.value();
|
||||
EXPECT_THAT(result_overlayable.policies, Overlayable::Policy::kNone);
|
||||
ASSERT_TRUE(search_result.value().entry->overlayable_item);
|
||||
overlayable_item = search_result.value().entry->overlayable_item.value();
|
||||
EXPECT_THAT(overlayable_item.overlayable->name, Eq("Other"));
|
||||
EXPECT_THAT(overlayable_item.policies, Eq(OverlayableItem::Policy::kNone));
|
||||
EXPECT_THAT(overlayable_item.comment, Eq("comment"));
|
||||
|
||||
search_result = new_table.FindResource(test::ParseNameOrDie("com.app.a:bool/fiz"));
|
||||
ASSERT_TRUE(search_result);
|
||||
ASSERT_FALSE(search_result.value().entry->overlayable);
|
||||
ASSERT_FALSE(search_result.value().entry->overlayable_item);
|
||||
}
|
||||
|
||||
} // namespace aapt
|
||||
|
||||
@@ -374,8 +374,8 @@ bool ReferenceLinker::Consume(IAaptContext* context, ResourceTable* table) {
|
||||
}
|
||||
|
||||
// Ensure that definitions for values declared as overlayable exist
|
||||
if (entry->overlayable && entry->values.empty()) {
|
||||
context->GetDiagnostics()->Error(DiagMessage(entry->overlayable.value().source)
|
||||
if (entry->overlayable_item && entry->values.empty()) {
|
||||
context->GetDiagnostics()->Error(DiagMessage(entry->overlayable_item.value().source)
|
||||
<< "no definition for overlayable symbol '"
|
||||
<< name << "'");
|
||||
error = true;
|
||||
|
||||
@@ -134,18 +134,18 @@ static bool MergeEntry(IAaptContext* context, const Source& src,
|
||||
dst_entry->allow_new = std::move(src_entry->allow_new);
|
||||
}
|
||||
|
||||
if (src_entry->overlayable) {
|
||||
if (dst_entry->overlayable) {
|
||||
if (src_entry->overlayable_item) {
|
||||
if (dst_entry->overlayable_item) {
|
||||
// Do not allow a resource with an overlayable declaration to have that overlayable
|
||||
// declaration redefined
|
||||
context->GetDiagnostics()->Error(DiagMessage(src_entry->overlayable.value().source)
|
||||
context->GetDiagnostics()->Error(DiagMessage(src_entry->overlayable_item.value().source)
|
||||
<< "duplicate overlayable declaration for resource '"
|
||||
<< src_entry->name << "'");
|
||||
context->GetDiagnostics()->Error(DiagMessage(dst_entry->overlayable.value().source)
|
||||
context->GetDiagnostics()->Error(DiagMessage(dst_entry->overlayable_item.value().source)
|
||||
<< "previous declaration here");
|
||||
return false;
|
||||
} else {
|
||||
dst_entry->overlayable = std::move(src_entry->overlayable);
|
||||
dst_entry->overlayable_item = std::move(src_entry->overlayable_item);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -437,14 +437,16 @@ TEST_F(TableMergerTest, OverlaidStyleablesAndStylesShouldBeMerged) {
|
||||
}
|
||||
|
||||
TEST_F(TableMergerTest, SetOverlayable) {
|
||||
Overlayable overlayable{};
|
||||
overlayable.policies |= Overlayable::Policy::kProduct;
|
||||
overlayable.policies |= Overlayable::Policy::kVendor;
|
||||
auto overlayable = std::make_shared<Overlayable>("CustomizableResources",
|
||||
"overlay://customization");
|
||||
OverlayableItem overlayable_item(overlayable);
|
||||
overlayable_item.policies |= OverlayableItem::Policy::kProduct;
|
||||
overlayable_item.policies |= OverlayableItem::Policy::kVendor;
|
||||
|
||||
std::unique_ptr<ResourceTable> table_a =
|
||||
test::ResourceTableBuilder()
|
||||
.SetPackageId("com.app.a", 0x7f)
|
||||
.SetOverlayable("bool/foo", overlayable)
|
||||
.SetOverlayable("bool/foo", overlayable_item)
|
||||
.Build();
|
||||
|
||||
std::unique_ptr<ResourceTable> table_b =
|
||||
@@ -463,26 +465,30 @@ TEST_F(TableMergerTest, SetOverlayable) {
|
||||
const ResourceName name = test::ParseNameOrDie("com.app.a:bool/foo");
|
||||
Maybe<ResourceTable::SearchResult> search_result = final_table.FindResource(name);
|
||||
ASSERT_TRUE(search_result);
|
||||
ASSERT_TRUE(search_result.value().entry->overlayable);
|
||||
Overlayable& result_overlayable = search_result.value().entry->overlayable.value();
|
||||
EXPECT_THAT(result_overlayable.policies, Eq(Overlayable::Policy::kProduct
|
||||
| Overlayable::Policy::kVendor));
|
||||
ASSERT_TRUE(search_result.value().entry->overlayable_item);
|
||||
OverlayableItem& result_overlayable_item = search_result.value().entry->overlayable_item.value();
|
||||
EXPECT_THAT(result_overlayable_item.overlayable->name, Eq("CustomizableResources"));
|
||||
EXPECT_THAT(result_overlayable_item.overlayable->actor, Eq("overlay://customization"));
|
||||
EXPECT_THAT(result_overlayable_item.policies, Eq(OverlayableItem::Policy::kProduct
|
||||
| OverlayableItem::Policy::kVendor));
|
||||
}
|
||||
|
||||
TEST_F(TableMergerTest, SetOverlayableLater) {
|
||||
auto overlayable = std::make_shared<Overlayable>("CustomizableResources",
|
||||
"overlay://customization");
|
||||
std::unique_ptr<ResourceTable> table_a =
|
||||
test::ResourceTableBuilder()
|
||||
.SetPackageId("com.app.a", 0x7f)
|
||||
.AddSimple("bool/foo")
|
||||
.Build();
|
||||
|
||||
Overlayable overlayable{};
|
||||
overlayable.policies |= Overlayable::Policy::kPublic;
|
||||
overlayable.policies |= Overlayable::Policy::kProductServices;
|
||||
OverlayableItem overlayable_item(overlayable);
|
||||
overlayable_item.policies |= OverlayableItem::Policy::kPublic;
|
||||
overlayable_item.policies |= OverlayableItem::Policy::kProductServices;
|
||||
std::unique_ptr<ResourceTable> table_b =
|
||||
test::ResourceTableBuilder()
|
||||
.SetPackageId("com.app.a", 0x7f)
|
||||
.SetOverlayable("bool/foo", overlayable)
|
||||
.SetOverlayable("bool/foo", overlayable_item)
|
||||
.Build();
|
||||
|
||||
ResourceTable final_table;
|
||||
@@ -495,27 +501,33 @@ TEST_F(TableMergerTest, SetOverlayableLater) {
|
||||
const ResourceName name = test::ParseNameOrDie("com.app.a:bool/foo");
|
||||
Maybe<ResourceTable::SearchResult> search_result = final_table.FindResource(name);
|
||||
ASSERT_TRUE(search_result);
|
||||
ASSERT_TRUE(search_result.value().entry->overlayable);
|
||||
Overlayable& result_overlayable = search_result.value().entry->overlayable.value();
|
||||
EXPECT_THAT(result_overlayable.policies, Eq(Overlayable::Policy::kPublic
|
||||
| Overlayable::Policy::kProductServices));
|
||||
ASSERT_TRUE(search_result.value().entry->overlayable_item);
|
||||
OverlayableItem& result_overlayable_item = search_result.value().entry->overlayable_item.value();
|
||||
EXPECT_THAT(result_overlayable_item.overlayable->name, Eq("CustomizableResources"));
|
||||
EXPECT_THAT(result_overlayable_item.overlayable->actor, Eq("overlay://customization"));
|
||||
EXPECT_THAT(result_overlayable_item.policies, Eq(OverlayableItem::Policy::kPublic
|
||||
| OverlayableItem::Policy::kProductServices));
|
||||
}
|
||||
|
||||
TEST_F(TableMergerTest, SetOverlayableSamePolicesFail) {
|
||||
Overlayable overlayable_first{};
|
||||
overlayable_first.policies |= Overlayable::Policy::kProduct;
|
||||
TEST_F(TableMergerTest, SameResourceDifferentNameFail) {
|
||||
auto overlayable_first = std::make_shared<Overlayable>("CustomizableResources",
|
||||
"overlay://customization");
|
||||
OverlayableItem overlayable_item_first(overlayable_first);
|
||||
overlayable_item_first.policies |= OverlayableItem::Policy::kProduct;
|
||||
std::unique_ptr<ResourceTable> table_a =
|
||||
test::ResourceTableBuilder()
|
||||
.SetPackageId("com.app.a", 0x7f)
|
||||
.SetOverlayable("bool/foo", overlayable_first)
|
||||
.SetOverlayable("bool/foo", overlayable_item_first)
|
||||
.Build();
|
||||
|
||||
Overlayable overlayable_second{};
|
||||
overlayable_second.policies |= Overlayable::Policy::kProduct;
|
||||
auto overlayable_second = std::make_shared<Overlayable>("ThemeResources",
|
||||
"overlay://theme");
|
||||
OverlayableItem overlayable_item_second(overlayable_second);
|
||||
overlayable_item_second.policies |= OverlayableItem::Policy::kProduct;
|
||||
std::unique_ptr<ResourceTable> table_b =
|
||||
test::ResourceTableBuilder()
|
||||
.SetPackageId("com.app.a", 0x7f)
|
||||
.SetOverlayable("bool/foo", overlayable_second)
|
||||
.SetOverlayable("bool/foo", overlayable_item_second)
|
||||
.Build();
|
||||
|
||||
ResourceTable final_table;
|
||||
@@ -526,21 +538,24 @@ TEST_F(TableMergerTest, SetOverlayableSamePolicesFail) {
|
||||
ASSERT_FALSE(merger.Merge({}, table_b.get(), false /*overlay*/));
|
||||
}
|
||||
|
||||
TEST_F(TableMergerTest, SetOverlayableDifferentPolicesFail) {
|
||||
Overlayable overlayable_first{};
|
||||
overlayable_first.policies |= Overlayable::Policy::kVendor;
|
||||
TEST_F(TableMergerTest, SameResourceSameNameFail) {
|
||||
auto overlayable = std::make_shared<Overlayable>("CustomizableResources",
|
||||
"overlay://customization");
|
||||
|
||||
OverlayableItem overlayable_item_first(overlayable);
|
||||
overlayable_item_first.policies |= OverlayableItem::Policy::kProduct;
|
||||
std::unique_ptr<ResourceTable> table_a =
|
||||
test::ResourceTableBuilder()
|
||||
.SetPackageId("com.app.a", 0x7f)
|
||||
.SetOverlayable("bool/foo",overlayable_first)
|
||||
.SetOverlayable("bool/foo", overlayable_item_first)
|
||||
.Build();
|
||||
|
||||
Overlayable overlayable_second{};
|
||||
overlayable_second.policies |= Overlayable::Policy::kProduct;
|
||||
OverlayableItem overlayable_item_second(overlayable);
|
||||
overlayable_item_second.policies |= OverlayableItem::Policy::kSystem;
|
||||
std::unique_ptr<ResourceTable> table_b =
|
||||
test::ResourceTableBuilder()
|
||||
.SetPackageId("com.app.a", 0x7f)
|
||||
.SetOverlayable("bool/foo", overlayable_second)
|
||||
.SetOverlayable("bool/foo", overlayable_item_second)
|
||||
.Build();
|
||||
|
||||
ResourceTable final_table;
|
||||
|
||||
@@ -248,7 +248,7 @@ void TableSplitter::SplitTable(ResourceTable* original_table) {
|
||||
if (!split_entry->id) {
|
||||
split_entry->id = entry->id;
|
||||
split_entry->visibility = entry->visibility;
|
||||
split_entry->overlayable = entry->overlayable;
|
||||
split_entry->overlayable_item = entry->overlayable_item;
|
||||
}
|
||||
|
||||
// Copy the selected values into the new Split Entry.
|
||||
|
||||
@@ -136,7 +136,7 @@ ResourceTableBuilder& ResourceTableBuilder::SetSymbolState(const StringPiece& na
|
||||
}
|
||||
|
||||
ResourceTableBuilder& ResourceTableBuilder::SetOverlayable(const StringPiece& name,
|
||||
const Overlayable& overlayable) {
|
||||
const OverlayableItem& overlayable) {
|
||||
|
||||
ResourceName res_name = ParseNameOrDie(name);
|
||||
CHECK(table_->SetOverlayable(res_name, overlayable, GetDiagnostics()));
|
||||
|
||||
@@ -74,7 +74,7 @@ class ResourceTableBuilder {
|
||||
ResourceTableBuilder& SetSymbolState(const android::StringPiece& name, const ResourceId& id,
|
||||
Visibility::Level level, bool allow_new = false);
|
||||
ResourceTableBuilder& SetOverlayable(const android::StringPiece& name,
|
||||
const Overlayable& overlayable);
|
||||
const OverlayableItem& overlayable);
|
||||
|
||||
StringPool* string_pool();
|
||||
std::unique_ptr<ResourceTable> Build();
|
||||
|
||||
Reference in New Issue
Block a user