AAPT2: Support CtsContentTestCases build
- Add <feature-group> to ManifestFixer. - Support <meta-data> in <instrumentation> - Add support for <bag> and type="configVarying". Some CTS tests use this old notation, we need to support it (even though configVarying isn't anything supported by the framework convention). Change-Id: I6946fa633ce513ea8437c1496db883cf27dcf6de Test: make aapt2_tests
This commit is contained in:
@@ -25,7 +25,7 @@ namespace aapt {
|
||||
static const char* sMajorVersion = "2";
|
||||
|
||||
// Update minor version whenever a feature or flag is added.
|
||||
static const char* sMinorVersion = "5";
|
||||
static const char* sMinorVersion = "6";
|
||||
|
||||
int PrintVersion() {
|
||||
std::cerr << "Android Asset Packaging Tool (aapt) " << sMajorVersion << "."
|
||||
|
||||
@@ -39,6 +39,8 @@ StringPiece ToString(ResourceType type) {
|
||||
return "bool";
|
||||
case ResourceType::kColor:
|
||||
return "color";
|
||||
case ResourceType::kConfigVarying:
|
||||
return "configVarying";
|
||||
case ResourceType::kDimen:
|
||||
return "dimen";
|
||||
case ResourceType::kDrawable:
|
||||
@@ -85,6 +87,7 @@ static const std::map<StringPiece, ResourceType> sResourceTypeMap{
|
||||
{"^attr-private", ResourceType::kAttrPrivate},
|
||||
{"bool", ResourceType::kBool},
|
||||
{"color", ResourceType::kColor},
|
||||
{"configVarying", ResourceType::kConfigVarying},
|
||||
{"dimen", ResourceType::kDimen},
|
||||
{"drawable", ResourceType::kDrawable},
|
||||
{"font", ResourceType::kFont},
|
||||
|
||||
@@ -44,6 +44,11 @@ enum class ResourceType {
|
||||
kAttrPrivate,
|
||||
kBool,
|
||||
kColor,
|
||||
|
||||
// Not really a type, but it shows up in some CTS tests and
|
||||
// we need to continue respecting it.
|
||||
kConfigVarying,
|
||||
|
||||
kDimen,
|
||||
kDrawable,
|
||||
kFont,
|
||||
|
||||
@@ -338,50 +338,52 @@ bool ResourceParser::ParseResource(xml::XmlPullParser* parser,
|
||||
using BagParseFunc = std::function<bool(ResourceParser*, xml::XmlPullParser*,
|
||||
ParsedResource*)>;
|
||||
|
||||
static const auto elToItemMap =
|
||||
ImmutableMap<std::string, ItemTypeFormat>::CreatePreSorted({
|
||||
{"bool", {ResourceType::kBool, android::ResTable_map::TYPE_BOOLEAN}},
|
||||
{"color", {ResourceType::kColor, android::ResTable_map::TYPE_COLOR}},
|
||||
{"dimen",
|
||||
{ResourceType::kDimen, android::ResTable_map::TYPE_FLOAT |
|
||||
android::ResTable_map::TYPE_FRACTION |
|
||||
android::ResTable_map::TYPE_DIMENSION}},
|
||||
{"drawable",
|
||||
{ResourceType::kDrawable, android::ResTable_map::TYPE_COLOR}},
|
||||
{"fraction",
|
||||
{ResourceType::kFraction,
|
||||
android::ResTable_map::TYPE_FLOAT |
|
||||
android::ResTable_map::TYPE_FRACTION |
|
||||
android::ResTable_map::TYPE_DIMENSION}},
|
||||
{"integer",
|
||||
{ResourceType::kInteger, android::ResTable_map::TYPE_INTEGER}},
|
||||
{"string",
|
||||
{ResourceType::kString, android::ResTable_map::TYPE_STRING}},
|
||||
});
|
||||
static const auto elToItemMap = ImmutableMap<std::string, ItemTypeFormat>::CreatePreSorted({
|
||||
{"bool", {ResourceType::kBool, android::ResTable_map::TYPE_BOOLEAN}},
|
||||
{"color", {ResourceType::kColor, android::ResTable_map::TYPE_COLOR}},
|
||||
{"configVarying", {ResourceType::kConfigVarying, android::ResTable_map::TYPE_ANY}},
|
||||
{"dimen",
|
||||
{ResourceType::kDimen,
|
||||
android::ResTable_map::TYPE_FLOAT | android::ResTable_map::TYPE_FRACTION |
|
||||
android::ResTable_map::TYPE_DIMENSION}},
|
||||
{"drawable", {ResourceType::kDrawable, android::ResTable_map::TYPE_COLOR}},
|
||||
{"fraction",
|
||||
{ResourceType::kFraction,
|
||||
android::ResTable_map::TYPE_FLOAT | android::ResTable_map::TYPE_FRACTION |
|
||||
android::ResTable_map::TYPE_DIMENSION}},
|
||||
{"integer", {ResourceType::kInteger, android::ResTable_map::TYPE_INTEGER}},
|
||||
{"string", {ResourceType::kString, android::ResTable_map::TYPE_STRING}},
|
||||
});
|
||||
|
||||
static const auto elToBagMap =
|
||||
ImmutableMap<std::string, BagParseFunc>::CreatePreSorted({
|
||||
{"add-resource", std::mem_fn(&ResourceParser::ParseAddResource)},
|
||||
{"array", std::mem_fn(&ResourceParser::ParseArray)},
|
||||
{"attr", std::mem_fn(&ResourceParser::ParseAttr)},
|
||||
{"declare-styleable",
|
||||
std::mem_fn(&ResourceParser::ParseDeclareStyleable)},
|
||||
{"integer-array", std::mem_fn(&ResourceParser::ParseIntegerArray)},
|
||||
{"java-symbol", std::mem_fn(&ResourceParser::ParseSymbol)},
|
||||
{"plurals", std::mem_fn(&ResourceParser::ParsePlural)},
|
||||
{"public", std::mem_fn(&ResourceParser::ParsePublic)},
|
||||
{"public-group", std::mem_fn(&ResourceParser::ParsePublicGroup)},
|
||||
{"string-array", std::mem_fn(&ResourceParser::ParseStringArray)},
|
||||
{"style", std::mem_fn(&ResourceParser::ParseStyle)},
|
||||
{"symbol", std::mem_fn(&ResourceParser::ParseSymbol)},
|
||||
});
|
||||
static const auto elToBagMap = ImmutableMap<std::string, BagParseFunc>::CreatePreSorted({
|
||||
{"add-resource", std::mem_fn(&ResourceParser::ParseAddResource)},
|
||||
{"array", std::mem_fn(&ResourceParser::ParseArray)},
|
||||
{"attr", std::mem_fn(&ResourceParser::ParseAttr)},
|
||||
{"configVarying",
|
||||
std::bind(&ResourceParser::ParseStyle, std::placeholders::_1, ResourceType::kConfigVarying,
|
||||
std::placeholders::_2, std::placeholders::_3)},
|
||||
{"declare-styleable", std::mem_fn(&ResourceParser::ParseDeclareStyleable)},
|
||||
{"integer-array", std::mem_fn(&ResourceParser::ParseIntegerArray)},
|
||||
{"java-symbol", std::mem_fn(&ResourceParser::ParseSymbol)},
|
||||
{"plurals", std::mem_fn(&ResourceParser::ParsePlural)},
|
||||
{"public", std::mem_fn(&ResourceParser::ParsePublic)},
|
||||
{"public-group", std::mem_fn(&ResourceParser::ParsePublicGroup)},
|
||||
{"string-array", std::mem_fn(&ResourceParser::ParseStringArray)},
|
||||
{"style", std::bind(&ResourceParser::ParseStyle, std::placeholders::_1, ResourceType::kStyle,
|
||||
std::placeholders::_2, std::placeholders::_3)},
|
||||
{"symbol", std::mem_fn(&ResourceParser::ParseSymbol)},
|
||||
});
|
||||
|
||||
std::string resource_type = parser->element_name();
|
||||
|
||||
// The value format accepted for this resource.
|
||||
uint32_t resource_format = 0u;
|
||||
|
||||
bool can_be_item = true;
|
||||
bool can_be_bag = true;
|
||||
if (resource_type == "item") {
|
||||
can_be_bag = false;
|
||||
|
||||
// Items have their type encoded in the type attribute.
|
||||
if (Maybe<StringPiece> maybe_type =
|
||||
xml::FindNonEmptyAttribute(parser, "type")) {
|
||||
@@ -406,6 +408,17 @@ bool ResourceParser::ParseResource(xml::XmlPullParser* parser,
|
||||
return false;
|
||||
}
|
||||
}
|
||||
} else if (resource_type == "bag") {
|
||||
can_be_item = false;
|
||||
|
||||
// Bags have their type encoded in the type attribute.
|
||||
if (Maybe<StringPiece> maybe_type = xml::FindNonEmptyAttribute(parser, "type")) {
|
||||
resource_type = maybe_type.value().to_string();
|
||||
} else {
|
||||
diag_->Error(DiagMessage(source_.WithLine(parser->line_number()))
|
||||
<< "<bag> must have a 'type' attribute");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Get the name of the resource. This will be checked later, because not all
|
||||
@@ -426,36 +439,61 @@ bool ResourceParser::ParseResource(xml::XmlPullParser* parser,
|
||||
return true;
|
||||
}
|
||||
|
||||
const auto item_iter = elToItemMap.find(resource_type);
|
||||
if (item_iter != elToItemMap.end()) {
|
||||
// This is an item, record its type and format and start parsing.
|
||||
if (can_be_item) {
|
||||
const auto item_iter = elToItemMap.find(resource_type);
|
||||
if (item_iter != elToItemMap.end()) {
|
||||
// This is an item, record its type and format and start parsing.
|
||||
|
||||
if (!maybe_name) {
|
||||
diag_->Error(DiagMessage(out_resource->source)
|
||||
<< "<" << parser->element_name()
|
||||
<< "> missing 'name' attribute");
|
||||
return false;
|
||||
if (!maybe_name) {
|
||||
diag_->Error(DiagMessage(out_resource->source)
|
||||
<< "<" << parser->element_name() << "> missing 'name' attribute");
|
||||
return false;
|
||||
}
|
||||
|
||||
out_resource->name.type = item_iter->second.type;
|
||||
out_resource->name.entry = maybe_name.value().to_string();
|
||||
|
||||
// Only use the implicit format for this type if it wasn't overridden.
|
||||
if (!resource_format) {
|
||||
resource_format = item_iter->second.format;
|
||||
}
|
||||
|
||||
if (!ParseItem(parser, out_resource, resource_format)) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
out_resource->name.type = item_iter->second.type;
|
||||
out_resource->name.entry = maybe_name.value().to_string();
|
||||
|
||||
// Only use the implicit format for this type if it wasn't overridden.
|
||||
if (!resource_format) {
|
||||
resource_format = item_iter->second.format;
|
||||
}
|
||||
|
||||
if (!ParseItem(parser, out_resource, resource_format)) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// This might be a bag or something.
|
||||
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 (can_be_bag) {
|
||||
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 (!maybe_name) {
|
||||
diag_->Error(DiagMessage(out_resource->source)
|
||||
<< "<" << parser->element_name() << "> missing 'name' attribute");
|
||||
return false;
|
||||
}
|
||||
|
||||
out_resource->name.entry = maybe_name.value().to_string();
|
||||
}
|
||||
|
||||
// Call the associated parse method. The type will be filled in by the
|
||||
// parse func.
|
||||
if (!bag_iter->second(this, parser, out_resource)) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
if (can_be_item) {
|
||||
// Try parsing the elementName (or type) as a resource. These shall only be
|
||||
// resources like 'layout' or 'xml' and they can only be references.
|
||||
const ResourceType* parsed_type = ParseResourceType(resource_type);
|
||||
if (parsed_type) {
|
||||
if (!maybe_name) {
|
||||
diag_->Error(DiagMessage(out_resource->source)
|
||||
<< "<" << parser->element_name()
|
||||
@@ -463,39 +501,16 @@ bool ResourceParser::ParseResource(xml::XmlPullParser* parser,
|
||||
return false;
|
||||
}
|
||||
|
||||
out_resource->name.type = *parsed_type;
|
||||
out_resource->name.entry = maybe_name.value().to_string();
|
||||
out_resource->value = ParseXml(parser, android::ResTable_map::TYPE_REFERENCE, kNoRawString);
|
||||
if (!out_resource->value) {
|
||||
diag_->Error(DiagMessage(out_resource->source)
|
||||
<< "invalid value for type '" << *parsed_type << "'. Expected a reference");
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// Call the associated parse method. The type will be filled in by the
|
||||
// parse func.
|
||||
if (!bag_iter->second(this, parser, out_resource)) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// Try parsing the elementName (or type) as a resource. These shall only be
|
||||
// resources like 'layout' or 'xml' and they can only be references.
|
||||
const ResourceType* parsed_type = ParseResourceType(resource_type);
|
||||
if (parsed_type) {
|
||||
if (!maybe_name) {
|
||||
diag_->Error(DiagMessage(out_resource->source)
|
||||
<< "<" << parser->element_name()
|
||||
<< "> missing 'name' attribute");
|
||||
return false;
|
||||
}
|
||||
|
||||
out_resource->name.type = *parsed_type;
|
||||
out_resource->name.entry = maybe_name.value().to_string();
|
||||
out_resource->value =
|
||||
ParseXml(parser, android::ResTable_map::TYPE_REFERENCE, kNoRawString);
|
||||
if (!out_resource->value) {
|
||||
diag_->Error(DiagMessage(out_resource->source)
|
||||
<< "invalid value for type '" << *parsed_type
|
||||
<< "'. Expected a reference");
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
diag_->Warn(DiagMessage(out_resource->source)
|
||||
@@ -1048,9 +1063,9 @@ bool ResourceParser::ParseStyleItem(xml::XmlPullParser* parser, Style* style) {
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ResourceParser::ParseStyle(xml::XmlPullParser* parser,
|
||||
bool ResourceParser::ParseStyle(const ResourceType type, xml::XmlPullParser* parser,
|
||||
ParsedResource* out_resource) {
|
||||
out_resource->name.type = ResourceType::kStyle;
|
||||
out_resource->name.type = type;
|
||||
|
||||
std::unique_ptr<Style> style = util::make_unique<Style>();
|
||||
|
||||
|
||||
@@ -102,7 +102,8 @@ class ResourceParser {
|
||||
bool weak);
|
||||
Maybe<Attribute::Symbol> ParseEnumOrFlagItem(xml::XmlPullParser* parser,
|
||||
const android::StringPiece& tag);
|
||||
bool ParseStyle(xml::XmlPullParser* parser, ParsedResource* out_resource);
|
||||
bool ParseStyle(const ResourceType type, xml::XmlPullParser* parser,
|
||||
ParsedResource* out_resource);
|
||||
bool ParseStyleItem(xml::XmlPullParser* parser, Style* style);
|
||||
bool ParseDeclareStyleable(xml::XmlPullParser* parser,
|
||||
ParsedResource* out_resource);
|
||||
|
||||
@@ -719,4 +719,23 @@ TEST_F(ResourceParserTest, ParseItemElementWithFormat) {
|
||||
EXPECT_EQ(uint32_t(android::Res_value::TYPE_FLOAT), val->value.dataType);
|
||||
}
|
||||
|
||||
TEST_F(ResourceParserTest, ParseConfigVaryingItem) {
|
||||
std::string input = R"EOF(<item name="foo" type="configVarying">Hey</item>)EOF";
|
||||
ASSERT_TRUE(TestParse(input));
|
||||
ASSERT_NE(nullptr, test::GetValue<String>(&table_, "configVarying/foo"));
|
||||
}
|
||||
|
||||
TEST_F(ResourceParserTest, ParseBagElement) {
|
||||
std::string input =
|
||||
R"EOF(<bag name="bag" type="configVarying"><item name="test">Hello!</item></bag>)EOF";
|
||||
ASSERT_TRUE(TestParse(input));
|
||||
|
||||
Style* val = test::GetValue<Style>(&table_, "configVarying/bag");
|
||||
ASSERT_NE(nullptr, val);
|
||||
|
||||
ASSERT_EQ(1u, val->entries.size());
|
||||
EXPECT_EQ(Reference(test::ParseNameOrDie("attr/test")), val->entries[0].key);
|
||||
EXPECT_NE(nullptr, ValueCast<RawString>(val->entries[0].value.get()));
|
||||
}
|
||||
|
||||
} // namespace aapt
|
||||
|
||||
@@ -49,6 +49,10 @@ TEST(ResourceTypeTest, ParseResourceTypes) {
|
||||
ASSERT_NE(type, nullptr);
|
||||
EXPECT_EQ(*type, ResourceType::kColor);
|
||||
|
||||
type = ParseResourceType("configVarying");
|
||||
ASSERT_NE(type, nullptr);
|
||||
EXPECT_EQ(*type, ResourceType::kConfigVarying);
|
||||
|
||||
type = ParseResourceType("dimen");
|
||||
ASSERT_NE(type, nullptr);
|
||||
EXPECT_EQ(*type, ResourceType::kDimen);
|
||||
|
||||
@@ -111,6 +111,36 @@ static bool FixCoreAppAttribute(xml::Element* el, SourcePathDiagnostics* diag) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Checks that <uses-feature> has android:glEsVersion or android:name, not both (or neither).
|
||||
static bool VerifyUsesFeature(xml::Element* el, SourcePathDiagnostics* diag) {
|
||||
bool has_name = false;
|
||||
if (xml::Attribute* attr = el->FindAttribute(xml::kSchemaAndroid, "name")) {
|
||||
if (attr->value.empty()) {
|
||||
diag->Error(DiagMessage(el->line_number)
|
||||
<< "android:name in <uses-feature> must not be empty");
|
||||
return false;
|
||||
}
|
||||
has_name = true;
|
||||
}
|
||||
|
||||
bool has_gl_es_version = false;
|
||||
if (xml::Attribute* attr = el->FindAttribute(xml::kSchemaAndroid, "glEsVersion")) {
|
||||
if (has_name) {
|
||||
diag->Error(DiagMessage(el->line_number)
|
||||
<< "cannot define both android:name and android:glEsVersion in <uses-feature>");
|
||||
return false;
|
||||
}
|
||||
has_gl_es_version = true;
|
||||
}
|
||||
|
||||
if (!has_name && !has_gl_es_version) {
|
||||
diag->Error(DiagMessage(el->line_number)
|
||||
<< "<uses-feature> must have either android:name or android:glEsVersion attribute");
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ManifestFixer::BuildRules(xml::XmlActionExecutor* executor,
|
||||
IDiagnostics* diag) {
|
||||
// First verify some options.
|
||||
@@ -134,15 +164,25 @@ bool ManifestFixer::BuildRules(xml::XmlActionExecutor* executor,
|
||||
}
|
||||
}
|
||||
|
||||
// Common intent-filter actions.
|
||||
// Common <intent-filter> actions.
|
||||
xml::XmlNodeAction intent_filter_action;
|
||||
intent_filter_action["action"];
|
||||
intent_filter_action["category"];
|
||||
intent_filter_action["data"];
|
||||
|
||||
// Common meta-data actions.
|
||||
// Common <meta-data> actions.
|
||||
xml::XmlNodeAction meta_data_action;
|
||||
|
||||
// Common <uses-feature> actions.
|
||||
xml::XmlNodeAction uses_feature_action;
|
||||
uses_feature_action.Action(VerifyUsesFeature);
|
||||
|
||||
// Common component actions.
|
||||
xml::XmlNodeAction component_action;
|
||||
component_action.Action(RequiredNameIsJavaClassName);
|
||||
component_action["intent-filter"] = intent_filter_action;
|
||||
component_action["meta-data"] = meta_data_action;
|
||||
|
||||
// Manifest actions.
|
||||
xml::XmlNodeAction& manifest_action = (*executor)["manifest"];
|
||||
manifest_action.Action(VerifyManifest);
|
||||
@@ -190,6 +230,7 @@ bool ManifestFixer::BuildRules(xml::XmlActionExecutor* executor,
|
||||
});
|
||||
|
||||
// Instrumentation actions.
|
||||
manifest_action["instrumentation"].Action(RequiredNameIsJavaClassName);
|
||||
manifest_action["instrumentation"].Action([&](xml::Element* el) -> bool {
|
||||
if (!options_.rename_instrumentation_target_package) {
|
||||
return true;
|
||||
@@ -201,6 +242,7 @@ bool ManifestFixer::BuildRules(xml::XmlActionExecutor* executor,
|
||||
}
|
||||
return true;
|
||||
});
|
||||
manifest_action["instrumentation"]["meta-data"] = meta_data_action;
|
||||
|
||||
manifest_action["original-package"];
|
||||
manifest_action["protected-broadcast"];
|
||||
@@ -208,51 +250,28 @@ bool ManifestFixer::BuildRules(xml::XmlActionExecutor* executor,
|
||||
manifest_action["permission"];
|
||||
manifest_action["permission-tree"];
|
||||
manifest_action["permission-group"];
|
||||
|
||||
manifest_action["uses-configuration"];
|
||||
manifest_action["uses-feature"];
|
||||
manifest_action["supports-screens"];
|
||||
|
||||
manifest_action["uses-feature"] = uses_feature_action;
|
||||
manifest_action["feature-group"]["uses-feature"] = uses_feature_action;
|
||||
manifest_action["compatible-screens"];
|
||||
manifest_action["compatible-screens"]["screen"];
|
||||
|
||||
manifest_action["supports-gl-texture"];
|
||||
|
||||
manifest_action["meta-data"] = meta_data_action;
|
||||
|
||||
// Application actions.
|
||||
xml::XmlNodeAction& application_action = manifest_action["application"];
|
||||
application_action.Action(OptionalNameIsJavaClassName);
|
||||
|
||||
// Uses library actions.
|
||||
application_action["uses-library"];
|
||||
|
||||
// Meta-data.
|
||||
application_action["meta-data"] = meta_data_action;
|
||||
|
||||
// Activity actions.
|
||||
application_action["activity"].Action(RequiredNameIsJavaClassName);
|
||||
application_action["activity"]["intent-filter"] = intent_filter_action;
|
||||
application_action["activity"]["meta-data"] = meta_data_action;
|
||||
|
||||
// Activity alias actions.
|
||||
application_action["activity-alias"]["intent-filter"] = intent_filter_action;
|
||||
application_action["activity-alias"]["meta-data"] = meta_data_action;
|
||||
|
||||
// Service actions.
|
||||
application_action["service"].Action(RequiredNameIsJavaClassName);
|
||||
application_action["service"]["intent-filter"] = intent_filter_action;
|
||||
application_action["service"]["meta-data"] = meta_data_action;
|
||||
|
||||
// Receiver actions.
|
||||
application_action["receiver"].Action(RequiredNameIsJavaClassName);
|
||||
application_action["receiver"]["intent-filter"] = intent_filter_action;
|
||||
application_action["receiver"]["meta-data"] = meta_data_action;
|
||||
application_action["activity"] = component_action;
|
||||
application_action["activity-alias"] = component_action;
|
||||
application_action["service"] = component_action;
|
||||
application_action["receiver"] = component_action;
|
||||
|
||||
// Provider actions.
|
||||
application_action["provider"].Action(RequiredNameIsJavaClassName);
|
||||
application_action["provider"]["intent-filter"] = intent_filter_action;
|
||||
application_action["provider"]["meta-data"] = meta_data_action;
|
||||
application_action["provider"] = component_action;
|
||||
application_action["provider"]["grant-uri-permissions"];
|
||||
application_action["provider"]["path-permissions"];
|
||||
|
||||
|
||||
@@ -90,7 +90,7 @@ TEST_F(ManifestFixerTest, EnsureManifestHasPackage) {
|
||||
}
|
||||
|
||||
TEST_F(ManifestFixerTest, AllowMetaData) {
|
||||
auto doc = Verify(R"EOF(
|
||||
auto doc = Verify(R"EOF(
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
package="android">
|
||||
<meta-data />
|
||||
@@ -98,12 +98,13 @@ TEST_F(ManifestFixerTest, AllowMetaData) {
|
||||
<meta-data />
|
||||
<activity android:name=".Hi"><meta-data /></activity>
|
||||
<activity-alias android:name=".Ho"><meta-data /></activity-alias>
|
||||
<receiver android:name=".OffToWork"><meta-data /></receiver>
|
||||
<provider android:name=".We"><meta-data /></provider>
|
||||
<service android:name=".Go"><meta-data /></service>
|
||||
<receiver android:name=".OffTo"><meta-data /></receiver>
|
||||
<provider android:name=".Work"><meta-data /></provider>
|
||||
<service android:name=".We"><meta-data /></service>
|
||||
</application>
|
||||
<instrumentation android:name=".Go"><meta-data /></instrumentation>
|
||||
</manifest>)EOF");
|
||||
ASSERT_NE(nullptr, doc);
|
||||
ASSERT_NE(nullptr, doc);
|
||||
}
|
||||
|
||||
TEST_F(ManifestFixerTest, UseDefaultSdkVersionsIfNonePresent) {
|
||||
@@ -290,7 +291,7 @@ TEST_F(ManifestFixerTest,
|
||||
std::unique_ptr<xml::XmlResource> doc = VerifyWithOptions(R"EOF(
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
package="android">
|
||||
<instrumentation android:targetPackage="android" />
|
||||
<instrumentation android:name=".TestRunner" android:targetPackage="android" />
|
||||
</manifest>)EOF",
|
||||
options);
|
||||
ASSERT_NE(nullptr, doc);
|
||||
@@ -354,4 +355,51 @@ TEST_F(ManifestFixerTest, EnsureManifestAttributesAreTyped) {
|
||||
EXPECT_NE(nullptr, ValueCast<BinaryPrimitive>(attr->compiled_value.get()));
|
||||
}
|
||||
|
||||
TEST_F(ManifestFixerTest, UsesFeatureMustHaveNameOrGlEsVersion) {
|
||||
std::string input = R"EOF(
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
package="android">
|
||||
<uses-feature android:name="feature" />
|
||||
<uses-feature android:glEsVersion="1" />
|
||||
<feature-group />
|
||||
<feature-group>
|
||||
<uses-feature android:name="feature_in_group" />
|
||||
<uses-feature android:glEsVersion="2" />
|
||||
</feature-group>
|
||||
</manifest>)EOF";
|
||||
EXPECT_NE(nullptr, Verify(input));
|
||||
|
||||
input = R"EOF(
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
package="android">
|
||||
<uses-feature android:name="feature" android:glEsVersion="1" />
|
||||
</manifest>)EOF";
|
||||
EXPECT_EQ(nullptr, Verify(input));
|
||||
|
||||
input = R"EOF(
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
package="android">
|
||||
<uses-feature />
|
||||
</manifest>)EOF";
|
||||
EXPECT_EQ(nullptr, Verify(input));
|
||||
|
||||
input = R"EOF(
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
package="android">
|
||||
<feature-group>
|
||||
<uses-feature android:name="feature" android:glEsVersion="1" />
|
||||
</feature-group>
|
||||
</manifest>)EOF";
|
||||
EXPECT_EQ(nullptr, Verify(input));
|
||||
|
||||
input = R"EOF(
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
package="android">
|
||||
<feature-group>
|
||||
<uses-feature />
|
||||
</feature-group>
|
||||
</manifest>)EOF";
|
||||
EXPECT_EQ(nullptr, Verify(input));
|
||||
}
|
||||
|
||||
} // namespace aapt
|
||||
|
||||
@@ -1,5 +1,12 @@
|
||||
# Android Asset Packaging Tool 2.0 (AAPT2) release notes
|
||||
|
||||
## Version 2.6
|
||||
### `aapt2`
|
||||
- Support legacy `configVarying` resource type.
|
||||
- Support `<bag>` tag and treat as `<style>` regardless of type.
|
||||
- Add `<feature-group>` manifest tag verification.
|
||||
- Add `<meta-data>` tag support to `<instrumentation>`.
|
||||
|
||||
## Version 2.5
|
||||
### `aapt2 link ...`
|
||||
- Transition XML versioning: Adds a new flag `--no-version-transitions` to disable automatic
|
||||
|
||||
Reference in New Issue
Block a user