Loading core/tests/resourceflaggingtests/src/com/android/resourceflaggingtests/ResourceFlaggingTest.java +22 −3 Original line number Diff line number Diff line Loading @@ -68,6 +68,16 @@ public class ResourceFlaggingTest { assertThat(getBoolean("res3")).isTrue(); } @Test public void testFlagDisabledStringArrayElement() { assertThat(getStringArray("strarr1")).isEqualTo(new String[]{"one", "two", "three"}); } @Test public void testFlagDisabledIntArrayElement() { assertThat(getIntArray("intarr1")).isEqualTo(new int[]{1, 2, 3}); } private boolean getBoolean(String name) { int resId = mResources.getIdentifier( name, Loading @@ -77,13 +87,22 @@ public class ResourceFlaggingTest { return mResources.getBoolean(resId); } private String getString(String name) { private String[] getStringArray(String name) { int resId = mResources.getIdentifier( name, "array", "com.android.intenal.flaggedresources"); assertThat(resId).isNotEqualTo(0); return mResources.getStringArray(resId); } private int[] getIntArray(String name) { int resId = mResources.getIdentifier( name, "string", "array", "com.android.intenal.flaggedresources"); assertThat(resId).isNotEqualTo(0); return mResources.getString(resId); return mResources.getIntArray(resId); } private String extractApkAndGetPath(int id) throws Exception { Loading tools/aapt2/ResourceParser.cpp +38 −23 Original line number Diff line number Diff line Loading @@ -151,6 +151,7 @@ static bool AddResourcesToTable(ResourceTable* table, android::IDiagnostics* dia } if (res->value != nullptr) { res->value->SetFlagStatus(res->flag_status); // Attach the comment, source and config to the value. res->value->SetComment(std::move(res->comment)); res->value->SetSource(std::move(res->source)); Loading Loading @@ -546,30 +547,11 @@ bool ResourceParser::ParseResource(xml::XmlPullParser* parser, }); std::string resource_type = parser->element_name(); std::optional<StringPiece> flag = xml::FindAttribute(parser, "http://schemas.android.com/apk/res/android", "featureFlag"); out_resource->flag_status = FlagStatus::NoFlag; if (flag) { auto flag_it = options_.feature_flag_values.find(flag.value()); if (flag_it == options_.feature_flag_values.end()) { diag_->Error(android::DiagMessage(source_.WithLine(parser->line_number())) << "Resource flag value undefined"); return false; } const auto& flag_properties = flag_it->second; if (!flag_properties.read_only) { diag_->Error(android::DiagMessage(source_.WithLine(parser->line_number())) << "Only read only flags may be used with resources"); auto flag_status = GetFlagStatus(parser); if (!flag_status) { return false; } if (!flag_properties.enabled.has_value()) { diag_->Error(android::DiagMessage(source_.WithLine(parser->line_number())) << "Only flags with a value may be used with resources"); return false; } out_resource->flag_status = flag_properties.enabled.value() ? FlagStatus::Enabled : FlagStatus::Disabled; } out_resource->flag_status = flag_status.value(); // The value format accepted for this resource. uint32_t resource_format = 0u; Loading Loading @@ -751,6 +733,33 @@ bool ResourceParser::ParseResource(xml::XmlPullParser* parser, return false; } std::optional<FlagStatus> ResourceParser::GetFlagStatus(xml::XmlPullParser* parser) { auto flag_status = FlagStatus::NoFlag; std::optional<StringPiece> flag = xml::FindAttribute(parser, xml::kSchemaAndroid, "featureFlag"); if (flag) { auto flag_it = options_.feature_flag_values.find(flag.value()); if (flag_it == options_.feature_flag_values.end()) { diag_->Error(android::DiagMessage(source_.WithLine(parser->line_number())) << "Resource flag value undefined"); return {}; } const auto& flag_properties = flag_it->second; if (!flag_properties.read_only) { diag_->Error(android::DiagMessage(source_.WithLine(parser->line_number())) << "Only read only flags may be used with resources"); return {}; } if (!flag_properties.enabled.has_value()) { diag_->Error(android::DiagMessage(source_.WithLine(parser->line_number())) << "Only flags with a value may be used with resources"); return {}; } flag_status = flag_properties.enabled.value() ? FlagStatus::Enabled : FlagStatus::Disabled; } return flag_status; } bool ResourceParser::ParseItem(xml::XmlPullParser* parser, ParsedResource* out_resource, const uint32_t format) { Loading Loading @@ -1657,12 +1666,18 @@ bool ResourceParser::ParseArrayImpl(xml::XmlPullParser* parser, const std::string& element_namespace = parser->element_namespace(); const std::string& element_name = parser->element_name(); if (element_namespace.empty() && element_name == "item") { auto flag_status = GetFlagStatus(parser); if (!flag_status) { error = true; continue; } std::unique_ptr<Item> item = ParseXml(parser, typeMask, kNoRawString); if (!item) { diag_->Error(android::DiagMessage(item_source) << "could not parse array item"); error = true; continue; } item->SetFlagStatus(flag_status.value()); item->SetSource(item_source); array->elements.emplace_back(std::move(item)); Loading tools/aapt2/ResourceParser.h +2 −0 Original line number Diff line number Diff line Loading @@ -85,6 +85,8 @@ class ResourceParser { private: DISALLOW_COPY_AND_ASSIGN(ResourceParser); std::optional<FlagStatus> GetFlagStatus(xml::XmlPullParser* parser); std::optional<FlattenedXmlSubTree> CreateFlattenSubTree(xml::XmlPullParser* parser); // Parses the XML subtree as a StyleString (flattened XML representation for strings with Loading tools/aapt2/ResourceTable.cpp +3 −4 Original line number Diff line number Diff line Loading @@ -605,11 +605,11 @@ bool ResourceTable::AddResource(NewResource&& res, android::IDiagnostics* diag) if (!config_value->value) { // Resource does not exist, add it now. config_value->value = std::move(res.value); config_value->flag_status = res.flag_status; } else { // When validation is enabled, ensure that a resource cannot have multiple values defined for // the same configuration unless protected by flags. auto result = validate ? ResolveFlagCollision(config_value->flag_status, res.flag_status) auto result = validate ? ResolveFlagCollision(config_value->value->GetFlagStatus(), res.flag_status) : CollisionResult::kKeepBoth; if (result == CollisionResult::kConflict) { result = ResolveValueCollision(config_value->value.get(), res.value.get()); Loading @@ -619,7 +619,6 @@ bool ResourceTable::AddResource(NewResource&& res, android::IDiagnostics* diag) // Insert the value ignoring for duplicate configurations entry->values.push_back(util::make_unique<ResourceConfigValue>(res.config, res.product)); entry->values.back()->value = std::move(res.value); entry->values.back()->flag_status = res.flag_status; break; case CollisionResult::kTakeNew: Loading tools/aapt2/ResourceTable.h +0 −2 Original line number Diff line number Diff line Loading @@ -104,8 +104,6 @@ class ResourceConfigValue { // The actual Value. std::unique_ptr<Value> value; FlagStatus flag_status = FlagStatus::NoFlag; ResourceConfigValue(const android::ConfigDescription& config, android::StringPiece product) : config(config), product(product) { } Loading Loading
core/tests/resourceflaggingtests/src/com/android/resourceflaggingtests/ResourceFlaggingTest.java +22 −3 Original line number Diff line number Diff line Loading @@ -68,6 +68,16 @@ public class ResourceFlaggingTest { assertThat(getBoolean("res3")).isTrue(); } @Test public void testFlagDisabledStringArrayElement() { assertThat(getStringArray("strarr1")).isEqualTo(new String[]{"one", "two", "three"}); } @Test public void testFlagDisabledIntArrayElement() { assertThat(getIntArray("intarr1")).isEqualTo(new int[]{1, 2, 3}); } private boolean getBoolean(String name) { int resId = mResources.getIdentifier( name, Loading @@ -77,13 +87,22 @@ public class ResourceFlaggingTest { return mResources.getBoolean(resId); } private String getString(String name) { private String[] getStringArray(String name) { int resId = mResources.getIdentifier( name, "array", "com.android.intenal.flaggedresources"); assertThat(resId).isNotEqualTo(0); return mResources.getStringArray(resId); } private int[] getIntArray(String name) { int resId = mResources.getIdentifier( name, "string", "array", "com.android.intenal.flaggedresources"); assertThat(resId).isNotEqualTo(0); return mResources.getString(resId); return mResources.getIntArray(resId); } private String extractApkAndGetPath(int id) throws Exception { Loading
tools/aapt2/ResourceParser.cpp +38 −23 Original line number Diff line number Diff line Loading @@ -151,6 +151,7 @@ static bool AddResourcesToTable(ResourceTable* table, android::IDiagnostics* dia } if (res->value != nullptr) { res->value->SetFlagStatus(res->flag_status); // Attach the comment, source and config to the value. res->value->SetComment(std::move(res->comment)); res->value->SetSource(std::move(res->source)); Loading Loading @@ -546,30 +547,11 @@ bool ResourceParser::ParseResource(xml::XmlPullParser* parser, }); std::string resource_type = parser->element_name(); std::optional<StringPiece> flag = xml::FindAttribute(parser, "http://schemas.android.com/apk/res/android", "featureFlag"); out_resource->flag_status = FlagStatus::NoFlag; if (flag) { auto flag_it = options_.feature_flag_values.find(flag.value()); if (flag_it == options_.feature_flag_values.end()) { diag_->Error(android::DiagMessage(source_.WithLine(parser->line_number())) << "Resource flag value undefined"); return false; } const auto& flag_properties = flag_it->second; if (!flag_properties.read_only) { diag_->Error(android::DiagMessage(source_.WithLine(parser->line_number())) << "Only read only flags may be used with resources"); auto flag_status = GetFlagStatus(parser); if (!flag_status) { return false; } if (!flag_properties.enabled.has_value()) { diag_->Error(android::DiagMessage(source_.WithLine(parser->line_number())) << "Only flags with a value may be used with resources"); return false; } out_resource->flag_status = flag_properties.enabled.value() ? FlagStatus::Enabled : FlagStatus::Disabled; } out_resource->flag_status = flag_status.value(); // The value format accepted for this resource. uint32_t resource_format = 0u; Loading Loading @@ -751,6 +733,33 @@ bool ResourceParser::ParseResource(xml::XmlPullParser* parser, return false; } std::optional<FlagStatus> ResourceParser::GetFlagStatus(xml::XmlPullParser* parser) { auto flag_status = FlagStatus::NoFlag; std::optional<StringPiece> flag = xml::FindAttribute(parser, xml::kSchemaAndroid, "featureFlag"); if (flag) { auto flag_it = options_.feature_flag_values.find(flag.value()); if (flag_it == options_.feature_flag_values.end()) { diag_->Error(android::DiagMessage(source_.WithLine(parser->line_number())) << "Resource flag value undefined"); return {}; } const auto& flag_properties = flag_it->second; if (!flag_properties.read_only) { diag_->Error(android::DiagMessage(source_.WithLine(parser->line_number())) << "Only read only flags may be used with resources"); return {}; } if (!flag_properties.enabled.has_value()) { diag_->Error(android::DiagMessage(source_.WithLine(parser->line_number())) << "Only flags with a value may be used with resources"); return {}; } flag_status = flag_properties.enabled.value() ? FlagStatus::Enabled : FlagStatus::Disabled; } return flag_status; } bool ResourceParser::ParseItem(xml::XmlPullParser* parser, ParsedResource* out_resource, const uint32_t format) { Loading Loading @@ -1657,12 +1666,18 @@ bool ResourceParser::ParseArrayImpl(xml::XmlPullParser* parser, const std::string& element_namespace = parser->element_namespace(); const std::string& element_name = parser->element_name(); if (element_namespace.empty() && element_name == "item") { auto flag_status = GetFlagStatus(parser); if (!flag_status) { error = true; continue; } std::unique_ptr<Item> item = ParseXml(parser, typeMask, kNoRawString); if (!item) { diag_->Error(android::DiagMessage(item_source) << "could not parse array item"); error = true; continue; } item->SetFlagStatus(flag_status.value()); item->SetSource(item_source); array->elements.emplace_back(std::move(item)); Loading
tools/aapt2/ResourceParser.h +2 −0 Original line number Diff line number Diff line Loading @@ -85,6 +85,8 @@ class ResourceParser { private: DISALLOW_COPY_AND_ASSIGN(ResourceParser); std::optional<FlagStatus> GetFlagStatus(xml::XmlPullParser* parser); std::optional<FlattenedXmlSubTree> CreateFlattenSubTree(xml::XmlPullParser* parser); // Parses the XML subtree as a StyleString (flattened XML representation for strings with Loading
tools/aapt2/ResourceTable.cpp +3 −4 Original line number Diff line number Diff line Loading @@ -605,11 +605,11 @@ bool ResourceTable::AddResource(NewResource&& res, android::IDiagnostics* diag) if (!config_value->value) { // Resource does not exist, add it now. config_value->value = std::move(res.value); config_value->flag_status = res.flag_status; } else { // When validation is enabled, ensure that a resource cannot have multiple values defined for // the same configuration unless protected by flags. auto result = validate ? ResolveFlagCollision(config_value->flag_status, res.flag_status) auto result = validate ? ResolveFlagCollision(config_value->value->GetFlagStatus(), res.flag_status) : CollisionResult::kKeepBoth; if (result == CollisionResult::kConflict) { result = ResolveValueCollision(config_value->value.get(), res.value.get()); Loading @@ -619,7 +619,6 @@ bool ResourceTable::AddResource(NewResource&& res, android::IDiagnostics* diag) // Insert the value ignoring for duplicate configurations entry->values.push_back(util::make_unique<ResourceConfigValue>(res.config, res.product)); entry->values.back()->value = std::move(res.value); entry->values.back()->flag_status = res.flag_status; break; case CollisionResult::kTakeNew: Loading
tools/aapt2/ResourceTable.h +0 −2 Original line number Diff line number Diff line Loading @@ -104,8 +104,6 @@ class ResourceConfigValue { // The actual Value. std::unique_ptr<Value> value; FlagStatus flag_status = FlagStatus::NoFlag; ResourceConfigValue(const android::ConfigDescription& config, android::StringPiece product) : config(config), product(product) { } Loading