Merge "AAPT: Handle all old unversioned attribute usage" into lmp-mr1-dev
This commit is contained in:
committed by
Android (Google) Code Review
commit
94e30215f9
@ -21,5 +21,7 @@
|
|||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_centerInParent="true"
|
android:layout_centerInParent="true"
|
||||||
|
android:colorAccent="#ffffffff"
|
||||||
|
android:paddingStart="13dp"
|
||||||
android:src="@drawable/image"/>
|
android:src="@drawable/image"/>
|
||||||
</RelativeLayout>
|
</RelativeLayout>
|
||||||
|
28
tests/Split/res/values-v10/values.xml
Normal file
28
tests/Split/res/values-v10/values.xml
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!-- Copyright (C) 2014 The Android Open Source Project
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
-->
|
||||||
|
|
||||||
|
<resources>
|
||||||
|
<style name="toop">
|
||||||
|
<item name="android:paddingStart">12dp</item>
|
||||||
|
<item name="android:layout_width">23dp</item>
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<style name="temp">
|
||||||
|
<item name="android:versionName">hey</item>
|
||||||
|
<item name="android:allowBackup">true</item>
|
||||||
|
<item name="android:colorAccent">#ffffffff</item>
|
||||||
|
</style>
|
||||||
|
</resources>
|
24
tests/Split/res/values-v17/values.xml
Normal file
24
tests/Split/res/values-v17/values.xml
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!-- Copyright (C) 2014 The Android Open Source Project
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
-->
|
||||||
|
|
||||||
|
<resources>
|
||||||
|
<style name="toop">
|
||||||
|
<item name="android:paddingStart">12dp</item>
|
||||||
|
<item name="android:layout_width">23dp</item>
|
||||||
|
<item name="android:layout_height">45dp</item>
|
||||||
|
</style>
|
||||||
|
|
||||||
|
</resources>
|
@ -44,4 +44,10 @@
|
|||||||
<item>@string/boom</item>
|
<item>@string/boom</item>
|
||||||
<item>25dp</item>
|
<item>25dp</item>
|
||||||
</array>
|
</array>
|
||||||
|
|
||||||
|
<style name="temp">
|
||||||
|
<item name="android:versionName">hey</item>
|
||||||
|
<item name="android:allowBackup">true</item>
|
||||||
|
<item name="android:colorAccent">#ffffffff</item>
|
||||||
|
</style>
|
||||||
</resources>
|
</resources>
|
||||||
|
@ -4329,38 +4329,80 @@ bool ResourceTable::getItemValue(
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns true if the given attribute ID comes from
|
* Returns the SDK version at which the attribute was
|
||||||
* a platform version from or after L.
|
* made public, or -1 if the resource ID is not an attribute
|
||||||
|
* or is not public.
|
||||||
*/
|
*/
|
||||||
bool ResourceTable::isAttributeFromL(uint32_t attrId) {
|
int ResourceTable::getPublicAttributeSdkLevel(uint32_t attrId) const {
|
||||||
const uint32_t baseAttrId = 0x010103f7;
|
if (Res_GETPACKAGE(attrId) + 1 != 0x01 || Res_GETTYPE(attrId) + 1 != 0x01) {
|
||||||
if ((attrId & 0xffff0000) != (baseAttrId & 0xffff0000)) {
|
return -1;
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t specFlags;
|
uint32_t specFlags;
|
||||||
if (!mAssets->getIncludedResources().getResourceFlags(attrId, &specFlags)) {
|
if (!mAssets->getIncludedResources().getResourceFlags(attrId, &specFlags)) {
|
||||||
return false;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
return (specFlags & ResTable_typeSpec::SPEC_PUBLIC) != 0 &&
|
if ((specFlags & ResTable_typeSpec::SPEC_PUBLIC) == 0) {
|
||||||
(attrId & 0x0000ffff) >= (baseAttrId & 0x0000ffff);
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
const size_t entryId = Res_GETENTRY(attrId);
|
||||||
|
if (entryId <= 0x021c) {
|
||||||
|
return 1;
|
||||||
|
} else if (entryId <= 0x021d) {
|
||||||
|
return 2;
|
||||||
|
} else if (entryId <= 0x0269) {
|
||||||
|
return SDK_CUPCAKE;
|
||||||
|
} else if (entryId <= 0x028d) {
|
||||||
|
return SDK_DONUT;
|
||||||
|
} else if (entryId <= 0x02ad) {
|
||||||
|
return SDK_ECLAIR;
|
||||||
|
} else if (entryId <= 0x02b3) {
|
||||||
|
return SDK_ECLAIR_0_1;
|
||||||
|
} else if (entryId <= 0x02b5) {
|
||||||
|
return SDK_ECLAIR_MR1;
|
||||||
|
} else if (entryId <= 0x02bd) {
|
||||||
|
return SDK_FROYO;
|
||||||
|
} else if (entryId <= 0x02cb) {
|
||||||
|
return SDK_GINGERBREAD;
|
||||||
|
} else if (entryId <= 0x0361) {
|
||||||
|
return SDK_HONEYCOMB;
|
||||||
|
} else if (entryId <= 0x0366) {
|
||||||
|
return SDK_HONEYCOMB_MR1;
|
||||||
|
} else if (entryId <= 0x03a6) {
|
||||||
|
return SDK_HONEYCOMB_MR2;
|
||||||
|
} else if (entryId <= 0x03ae) {
|
||||||
|
return SDK_JELLY_BEAN;
|
||||||
|
} else if (entryId <= 0x03cc) {
|
||||||
|
return SDK_JELLY_BEAN_MR1;
|
||||||
|
} else if (entryId <= 0x03da) {
|
||||||
|
return SDK_JELLY_BEAN_MR2;
|
||||||
|
} else if (entryId <= 0x03f1) {
|
||||||
|
return SDK_KITKAT;
|
||||||
|
} else if (entryId <= 0x03f6) {
|
||||||
|
return SDK_KITKAT_WATCH;
|
||||||
|
} else if (entryId <= 0x04ce) {
|
||||||
|
return SDK_LOLLIPOP;
|
||||||
|
} else {
|
||||||
|
// Anything else is marked as defined in
|
||||||
|
// SDK_LOLLIPOP_MR1 since after this
|
||||||
|
// version no attribute compat work
|
||||||
|
// needs to be done.
|
||||||
|
return SDK_LOLLIPOP_MR1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool isMinSdkVersionLOrAbove(const Bundle* bundle) {
|
/**
|
||||||
if (bundle->getMinSdkVersion() != NULL && strlen(bundle->getMinSdkVersion()) > 0) {
|
* First check the Manifest, then check the command line flag.
|
||||||
const char firstChar = bundle->getMinSdkVersion()[0];
|
*/
|
||||||
if (firstChar >= 'L' && firstChar <= 'Z') {
|
static int getMinSdkVersion(const Bundle* bundle) {
|
||||||
// L is the code-name for the v21 release.
|
if (bundle->getManifestMinSdkVersion() != NULL && strlen(bundle->getManifestMinSdkVersion()) > 0) {
|
||||||
return true;
|
return atoi(bundle->getManifestMinSdkVersion());
|
||||||
}
|
} else if (bundle->getMinSdkVersion() != NULL && strlen(bundle->getMinSdkVersion()) > 0) {
|
||||||
|
return atoi(bundle->getMinSdkVersion());
|
||||||
const int minSdk = atoi(bundle->getMinSdkVersion());
|
|
||||||
if (minSdk >= SDK_LOLLIPOP) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return false;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -4406,9 +4448,10 @@ static bool isMinSdkVersionLOrAbove(const Bundle* bundle) {
|
|||||||
* attribute will be respected.
|
* attribute will be respected.
|
||||||
*/
|
*/
|
||||||
status_t ResourceTable::modifyForCompat(const Bundle* bundle) {
|
status_t ResourceTable::modifyForCompat(const Bundle* bundle) {
|
||||||
if (isMinSdkVersionLOrAbove(bundle)) {
|
const int minSdk = getMinSdkVersion(bundle);
|
||||||
// If this app will only ever run on L+ devices,
|
if (minSdk >= SDK_LOLLIPOP_MR1) {
|
||||||
// we don't need to do any compatibility work.
|
// Lollipop MR1 and up handles public attributes differently, no
|
||||||
|
// need to do any compat modifications.
|
||||||
return NO_ERROR;
|
return NO_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -4447,20 +4490,19 @@ status_t ResourceTable::modifyForCompat(const Bundle* bundle) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const ConfigDescription& config = entries.keyAt(ei);
|
const ConfigDescription& config = entries.keyAt(ei);
|
||||||
if (config.sdkVersion >= SDK_LOLLIPOP) {
|
if (config.sdkVersion >= SDK_LOLLIPOP_MR1) {
|
||||||
// We don't need to do anything if the resource is
|
|
||||||
// already qualified for version 21 or higher.
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
Vector<String16> attributesToRemove;
|
KeyedVector<int, Vector<String16> > attributesToRemove;
|
||||||
const KeyedVector<String16, Item>& bag = e->getBag();
|
const KeyedVector<String16, Item>& bag = e->getBag();
|
||||||
const size_t bagCount = bag.size();
|
const size_t bagCount = bag.size();
|
||||||
for (size_t bi = 0; bi < bagCount; bi++) {
|
for (size_t bi = 0; bi < bagCount; bi++) {
|
||||||
const Item& item = bag.valueAt(bi);
|
const Item& item = bag.valueAt(bi);
|
||||||
const uint32_t attrId = getResId(bag.keyAt(bi), &attr16);
|
const uint32_t attrId = getResId(bag.keyAt(bi), &attr16);
|
||||||
if (isAttributeFromL(attrId)) {
|
const int sdkLevel = getPublicAttributeSdkLevel(attrId);
|
||||||
attributesToRemove.add(bag.keyAt(bi));
|
if (sdkLevel > 1 && sdkLevel > config.sdkVersion && sdkLevel > minSdk) {
|
||||||
|
AaptUtil::appendValue(attributesToRemove, sdkLevel, bag.keyAt(bi));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -4468,16 +4510,41 @@ status_t ResourceTable::modifyForCompat(const Bundle* bundle) {
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Duplicate the entry under the same configuration
|
const size_t sdkCount = attributesToRemove.size();
|
||||||
// but with sdkVersion == SDK_LOLLIPOP.
|
for (size_t i = 0; i < sdkCount; i++) {
|
||||||
ConfigDescription newConfig(config);
|
const int sdkLevel = attributesToRemove.keyAt(i);
|
||||||
newConfig.sdkVersion = SDK_LOLLIPOP;
|
|
||||||
entriesToAdd.add(key_value_pair_t<ConfigDescription, sp<Entry> >(
|
// Duplicate the entry under the same configuration
|
||||||
newConfig, new Entry(*e)));
|
// but with sdkVersion == sdkLevel.
|
||||||
|
ConfigDescription newConfig(config);
|
||||||
|
newConfig.sdkVersion = sdkLevel;
|
||||||
|
|
||||||
|
sp<Entry> newEntry = new Entry(*e);
|
||||||
|
|
||||||
|
// Remove all items that have a higher SDK level than
|
||||||
|
// the one we are synthesizing.
|
||||||
|
for (size_t j = 0; j < sdkCount; j++) {
|
||||||
|
if (j == i) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (attributesToRemove.keyAt(j) > sdkLevel) {
|
||||||
|
const size_t attrCount = attributesToRemove[j].size();
|
||||||
|
for (size_t k = 0; k < attrCount; k++) {
|
||||||
|
newEntry->removeFromBag(attributesToRemove[j][k]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
entriesToAdd.add(key_value_pair_t<ConfigDescription, sp<Entry> >(
|
||||||
|
newConfig, newEntry));
|
||||||
|
}
|
||||||
|
|
||||||
// Remove the attribute from the original.
|
// Remove the attribute from the original.
|
||||||
for (size_t i = 0; i < attributesToRemove.size(); i++) {
|
for (size_t i = 0; i < attributesToRemove.size(); i++) {
|
||||||
e->removeFromBag(attributesToRemove[i]);
|
for (size_t j = 0; j < attributesToRemove[i].size(); j++) {
|
||||||
|
e->removeFromBag(attributesToRemove[i][j]);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -4494,7 +4561,7 @@ status_t ResourceTable::modifyForCompat(const Bundle* bundle) {
|
|||||||
if (bundle->getVerbose()) {
|
if (bundle->getVerbose()) {
|
||||||
entriesToAdd[i].value->getPos()
|
entriesToAdd[i].value->getPos()
|
||||||
.printf("using v%d attributes; synthesizing resource %s:%s/%s for configuration %s.",
|
.printf("using v%d attributes; synthesizing resource %s:%s/%s for configuration %s.",
|
||||||
SDK_LOLLIPOP,
|
entriesToAdd[i].key.sdkVersion,
|
||||||
String8(p->getName()).string(),
|
String8(p->getName()).string(),
|
||||||
String8(t->getName()).string(),
|
String8(t->getName()).string(),
|
||||||
String8(entriesToAdd[i].value->getName()).string(),
|
String8(entriesToAdd[i].value->getName()).string(),
|
||||||
@ -4517,17 +4584,23 @@ status_t ResourceTable::modifyForCompat(const Bundle* bundle,
|
|||||||
const String16& resourceName,
|
const String16& resourceName,
|
||||||
const sp<AaptFile>& target,
|
const sp<AaptFile>& target,
|
||||||
const sp<XMLNode>& root) {
|
const sp<XMLNode>& root) {
|
||||||
if (isMinSdkVersionLOrAbove(bundle)) {
|
const int minSdk = getMinSdkVersion(bundle);
|
||||||
|
if (minSdk >= SDK_LOLLIPOP_MR1) {
|
||||||
|
// Lollipop MR1 and up handles public attributes differently, no
|
||||||
|
// need to do any compat modifications.
|
||||||
return NO_ERROR;
|
return NO_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (target->getResourceType() == "" || target->getGroupEntry().toParams().sdkVersion >= SDK_LOLLIPOP) {
|
const ConfigDescription config(target->getGroupEntry().toParams());
|
||||||
|
if (target->getResourceType() == "" || config.sdkVersion >= SDK_LOLLIPOP_MR1) {
|
||||||
// Skip resources that have no type (AndroidManifest.xml) or are already version qualified with v21
|
// Skip resources that have no type (AndroidManifest.xml) or are already version qualified with v21
|
||||||
// or higher.
|
// or higher.
|
||||||
return NO_ERROR;
|
return NO_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
sp<XMLNode> newRoot = NULL;
|
sp<XMLNode> newRoot = NULL;
|
||||||
|
ConfigDescription newConfig(target->getGroupEntry().toParams());
|
||||||
|
newConfig.sdkVersion = SDK_LOLLIPOP_MR1;
|
||||||
|
|
||||||
Vector<sp<XMLNode> > nodesToVisit;
|
Vector<sp<XMLNode> > nodesToVisit;
|
||||||
nodesToVisit.push(root);
|
nodesToVisit.push(root);
|
||||||
@ -4538,11 +4611,19 @@ status_t ResourceTable::modifyForCompat(const Bundle* bundle,
|
|||||||
const Vector<XMLNode::attribute_entry>& attrs = node->getAttributes();
|
const Vector<XMLNode::attribute_entry>& attrs = node->getAttributes();
|
||||||
for (size_t i = 0; i < attrs.size(); i++) {
|
for (size_t i = 0; i < attrs.size(); i++) {
|
||||||
const XMLNode::attribute_entry& attr = attrs[i];
|
const XMLNode::attribute_entry& attr = attrs[i];
|
||||||
if (isAttributeFromL(attr.nameResId)) {
|
const int sdkLevel = getPublicAttributeSdkLevel(attr.nameResId);
|
||||||
|
if (sdkLevel > 1 && sdkLevel > config.sdkVersion && sdkLevel > minSdk) {
|
||||||
if (newRoot == NULL) {
|
if (newRoot == NULL) {
|
||||||
newRoot = root->clone();
|
newRoot = root->clone();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Find the smallest sdk version that we need to synthesize for
|
||||||
|
// and do that one. Subsequent versions will be processed on
|
||||||
|
// the next pass.
|
||||||
|
if (sdkLevel < newConfig.sdkVersion) {
|
||||||
|
newConfig.sdkVersion = sdkLevel;
|
||||||
|
}
|
||||||
|
|
||||||
if (bundle->getVerbose()) {
|
if (bundle->getVerbose()) {
|
||||||
SourcePos(node->getFilename(), node->getStartLineNumber()).printf(
|
SourcePos(node->getFilename(), node->getStartLineNumber()).printf(
|
||||||
"removing attribute %s%s%s from <%s>",
|
"removing attribute %s%s%s from <%s>",
|
||||||
@ -4568,9 +4649,6 @@ status_t ResourceTable::modifyForCompat(const Bundle* bundle,
|
|||||||
return NO_ERROR;
|
return NO_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
ConfigDescription newConfig(target->getGroupEntry().toParams());
|
|
||||||
newConfig.sdkVersion = SDK_LOLLIPOP;
|
|
||||||
|
|
||||||
// Look to see if we already have an overriding v21 configuration.
|
// Look to see if we already have an overriding v21 configuration.
|
||||||
sp<ConfigList> cl = getConfigList(String16(mAssets->getPackage()),
|
sp<ConfigList> cl = getConfigList(String16(mAssets->getPackage()),
|
||||||
String16(target->getResourceType()), resourceName);
|
String16(target->getResourceType()), resourceName);
|
||||||
@ -4587,7 +4665,7 @@ status_t ResourceTable::modifyForCompat(const Bundle* bundle,
|
|||||||
if (bundle->getVerbose()) {
|
if (bundle->getVerbose()) {
|
||||||
SourcePos(target->getSourceFile(), -1).printf(
|
SourcePos(target->getSourceFile(), -1).printf(
|
||||||
"using v%d attributes; synthesizing resource %s:%s/%s for configuration %s.",
|
"using v%d attributes; synthesizing resource %s:%s/%s for configuration %s.",
|
||||||
SDK_LOLLIPOP,
|
newConfig.sdkVersion,
|
||||||
mAssets->getPackage().string(),
|
mAssets->getPackage().string(),
|
||||||
newFile->getResourceType().string(),
|
newFile->getResourceType().string(),
|
||||||
String8(resourceName).string(),
|
String8(resourceName).string(),
|
||||||
|
@ -575,7 +575,7 @@ private:
|
|||||||
const Item* getItem(uint32_t resID, uint32_t attrID) const;
|
const Item* getItem(uint32_t resID, uint32_t attrID) const;
|
||||||
bool getItemValue(uint32_t resID, uint32_t attrID,
|
bool getItemValue(uint32_t resID, uint32_t attrID,
|
||||||
Res_value* outValue);
|
Res_value* outValue);
|
||||||
bool isAttributeFromL(uint32_t attrId);
|
int getPublicAttributeSdkLevel(uint32_t attrId) const;
|
||||||
|
|
||||||
|
|
||||||
String16 mAssetsPackage;
|
String16 mAssetsPackage;
|
||||||
|
@ -37,6 +37,7 @@ enum {
|
|||||||
SDK_KITKAT = 19,
|
SDK_KITKAT = 19,
|
||||||
SDK_KITKAT_WATCH = 20,
|
SDK_KITKAT_WATCH = 20,
|
||||||
SDK_LOLLIPOP = 21,
|
SDK_LOLLIPOP = 21,
|
||||||
|
SDK_LOLLIPOP_MR1 = 22,
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // H_AAPT_SDK_CONSTANTS
|
#endif // H_AAPT_SDK_CONSTANTS
|
||||||
|
Reference in New Issue
Block a user