diff options
author | Adam Lesinski <adamlesinski@google.com> | 2015-01-13 13:42:41 -0800 |
---|---|---|
committer | Adam Lesinski <adamlesinski@google.com> | 2015-01-14 12:02:15 -0800 |
commit | 28994d8d181c286b39811441ce78399576c2d315 (patch) | |
tree | 2e1d2308c8c49184fc04ad98994f95ed4d462961 | |
parent | 7ce662ef870df34cd189b4ce9e487e496ba407dd (diff) | |
download | frameworks_base-28994d8d181c286b39811441ce78399576c2d315.zip frameworks_base-28994d8d181c286b39811441ce78399576c2d315.tar.gz frameworks_base-28994d8d181c286b39811441ce78399576c2d315.tar.bz2 |
AAPT: Handle all old unversioned attribute usage
All references to attributes defined in pre-LOLLIPOP_MR1 SDK
are moved to version qualified resource entries.
Bug:18221682
Change-Id: Ifd739530ebcf99e6bc7ddb3f10bc5e05f0726e62
-rw-r--r-- | tests/Split/res/layout/main.xml | 2 | ||||
-rw-r--r-- | tests/Split/res/values-v10/values.xml | 28 | ||||
-rw-r--r-- | tests/Split/res/values-v17/values.xml | 24 | ||||
-rw-r--r-- | tests/Split/res/values/values.xml | 6 | ||||
-rw-r--r-- | tools/aapt/ResourceTable.cpp | 172 | ||||
-rw-r--r-- | tools/aapt/ResourceTable.h | 2 | ||||
-rw-r--r-- | tools/aapt/SdkConstants.h | 1 |
7 files changed, 187 insertions, 48 deletions
diff --git a/tests/Split/res/layout/main.xml b/tests/Split/res/layout/main.xml index 607cdb0..5a33c86 100644 --- a/tests/Split/res/layout/main.xml +++ b/tests/Split/res/layout/main.xml @@ -21,5 +21,7 @@ android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_centerInParent="true" + android:colorAccent="#ffffffff" + android:paddingStart="13dp" android:src="@drawable/image"/> </RelativeLayout> diff --git a/tests/Split/res/values-v10/values.xml b/tests/Split/res/values-v10/values.xml new file mode 100644 index 0000000..3d41a84 --- /dev/null +++ b/tests/Split/res/values-v10/values.xml @@ -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> diff --git a/tests/Split/res/values-v17/values.xml b/tests/Split/res/values-v17/values.xml new file mode 100644 index 0000000..c24eeae --- /dev/null +++ b/tests/Split/res/values-v17/values.xml @@ -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> diff --git a/tests/Split/res/values/values.xml b/tests/Split/res/values/values.xml index 68edc77..aabb232 100644 --- a/tests/Split/res/values/values.xml +++ b/tests/Split/res/values/values.xml @@ -44,4 +44,10 @@ <item>@string/boom</item> <item>25dp</item> </array> + + <style name="temp"> + <item name="android:versionName">hey</item> + <item name="android:allowBackup">true</item> + <item name="android:colorAccent">#ffffffff</item> + </style> </resources> diff --git a/tools/aapt/ResourceTable.cpp b/tools/aapt/ResourceTable.cpp index e87138c..e000a1d 100644 --- a/tools/aapt/ResourceTable.cpp +++ b/tools/aapt/ResourceTable.cpp @@ -4329,38 +4329,80 @@ bool ResourceTable::getItemValue( } /** - * Returns true if the given attribute ID comes from - * a platform version from or after L. + * Returns the SDK version at which the attribute was + * made public, or -1 if the resource ID is not an attribute + * or is not public. */ -bool ResourceTable::isAttributeFromL(uint32_t attrId) { - const uint32_t baseAttrId = 0x010103f7; - if ((attrId & 0xffff0000) != (baseAttrId & 0xffff0000)) { - return false; +int ResourceTable::getPublicAttributeSdkLevel(uint32_t attrId) const { + if (Res_GETPACKAGE(attrId) + 1 != 0x01 || Res_GETTYPE(attrId) + 1 != 0x01) { + return -1; } uint32_t specFlags; if (!mAssets->getIncludedResources().getResourceFlags(attrId, &specFlags)) { - return false; + return -1; + } + + if ((specFlags & ResTable_typeSpec::SPEC_PUBLIC) == 0) { + 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; } - - return (specFlags & ResTable_typeSpec::SPEC_PUBLIC) != 0 && - (attrId & 0x0000ffff) >= (baseAttrId & 0x0000ffff); } -static bool isMinSdkVersionLOrAbove(const Bundle* bundle) { - if (bundle->getMinSdkVersion() != NULL && strlen(bundle->getMinSdkVersion()) > 0) { - const char firstChar = bundle->getMinSdkVersion()[0]; - if (firstChar >= 'L' && firstChar <= 'Z') { - // L is the code-name for the v21 release. - return true; - } - - const int minSdk = atoi(bundle->getMinSdkVersion()); - if (minSdk >= SDK_LOLLIPOP) { - return true; - } +/** + * First check the Manifest, then check the command line flag. + */ +static int getMinSdkVersion(const Bundle* bundle) { + if (bundle->getManifestMinSdkVersion() != NULL && strlen(bundle->getManifestMinSdkVersion()) > 0) { + return atoi(bundle->getManifestMinSdkVersion()); + } else if (bundle->getMinSdkVersion() != NULL && strlen(bundle->getMinSdkVersion()) > 0) { + return atoi(bundle->getMinSdkVersion()); } - return false; + return 0; } /** @@ -4406,9 +4448,10 @@ static bool isMinSdkVersionLOrAbove(const Bundle* bundle) { * attribute will be respected. */ status_t ResourceTable::modifyForCompat(const Bundle* bundle) { - if (isMinSdkVersionLOrAbove(bundle)) { - // If this app will only ever run on L+ devices, - // we don't need to do any compatibility work. + 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; } @@ -4447,20 +4490,19 @@ status_t ResourceTable::modifyForCompat(const Bundle* bundle) { } const ConfigDescription& config = entries.keyAt(ei); - if (config.sdkVersion >= SDK_LOLLIPOP) { - // We don't need to do anything if the resource is - // already qualified for version 21 or higher. + if (config.sdkVersion >= SDK_LOLLIPOP_MR1) { continue; } - Vector<String16> attributesToRemove; + KeyedVector<int, Vector<String16> > attributesToRemove; const KeyedVector<String16, Item>& bag = e->getBag(); const size_t bagCount = bag.size(); for (size_t bi = 0; bi < bagCount; bi++) { const Item& item = bag.valueAt(bi); const uint32_t attrId = getResId(bag.keyAt(bi), &attr16); - if (isAttributeFromL(attrId)) { - attributesToRemove.add(bag.keyAt(bi)); + const int sdkLevel = getPublicAttributeSdkLevel(attrId); + 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; } - // Duplicate the entry under the same configuration - // but with sdkVersion == SDK_LOLLIPOP. - ConfigDescription newConfig(config); - newConfig.sdkVersion = SDK_LOLLIPOP; - entriesToAdd.add(key_value_pair_t<ConfigDescription, sp<Entry> >( - newConfig, new Entry(*e))); + const size_t sdkCount = attributesToRemove.size(); + for (size_t i = 0; i < sdkCount; i++) { + const int sdkLevel = attributesToRemove.keyAt(i); + + // Duplicate the entry under the same configuration + // 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. 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()) { entriesToAdd[i].value->getPos() .printf("using v%d attributes; synthesizing resource %s:%s/%s for configuration %s.", - SDK_LOLLIPOP, + entriesToAdd[i].key.sdkVersion, String8(p->getName()).string(), String8(t->getName()).string(), String8(entriesToAdd[i].value->getName()).string(), @@ -4517,17 +4584,23 @@ status_t ResourceTable::modifyForCompat(const Bundle* bundle, const String16& resourceName, const sp<AaptFile>& target, 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; } - 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 // or higher. return NO_ERROR; } sp<XMLNode> newRoot = NULL; + ConfigDescription newConfig(target->getGroupEntry().toParams()); + newConfig.sdkVersion = SDK_LOLLIPOP_MR1; Vector<sp<XMLNode> > nodesToVisit; nodesToVisit.push(root); @@ -4538,11 +4611,19 @@ status_t ResourceTable::modifyForCompat(const Bundle* bundle, const Vector<XMLNode::attribute_entry>& attrs = node->getAttributes(); for (size_t i = 0; i < attrs.size(); 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) { 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()) { SourcePos(node->getFilename(), node->getStartLineNumber()).printf( "removing attribute %s%s%s from <%s>", @@ -4568,9 +4649,6 @@ status_t ResourceTable::modifyForCompat(const Bundle* bundle, return NO_ERROR; } - ConfigDescription newConfig(target->getGroupEntry().toParams()); - newConfig.sdkVersion = SDK_LOLLIPOP; - // Look to see if we already have an overriding v21 configuration. sp<ConfigList> cl = getConfigList(String16(mAssets->getPackage()), String16(target->getResourceType()), resourceName); @@ -4587,7 +4665,7 @@ status_t ResourceTable::modifyForCompat(const Bundle* bundle, if (bundle->getVerbose()) { SourcePos(target->getSourceFile(), -1).printf( "using v%d attributes; synthesizing resource %s:%s/%s for configuration %s.", - SDK_LOLLIPOP, + newConfig.sdkVersion, mAssets->getPackage().string(), newFile->getResourceType().string(), String8(resourceName).string(), diff --git a/tools/aapt/ResourceTable.h b/tools/aapt/ResourceTable.h index 81590bc..eef0ae1 100644 --- a/tools/aapt/ResourceTable.h +++ b/tools/aapt/ResourceTable.h @@ -575,7 +575,7 @@ private: const Item* getItem(uint32_t resID, uint32_t attrID) const; bool getItemValue(uint32_t resID, uint32_t attrID, Res_value* outValue); - bool isAttributeFromL(uint32_t attrId); + int getPublicAttributeSdkLevel(uint32_t attrId) const; String16 mAssetsPackage; diff --git a/tools/aapt/SdkConstants.h b/tools/aapt/SdkConstants.h index 7fd1030..4e0fe10 100644 --- a/tools/aapt/SdkConstants.h +++ b/tools/aapt/SdkConstants.h @@ -37,6 +37,7 @@ enum { SDK_KITKAT = 19, SDK_KITKAT_WATCH = 20, SDK_LOLLIPOP = 21, + SDK_LOLLIPOP_MR1 = 22, }; #endif // H_AAPT_SDK_CONSTANTS |