diff options
author | 2016-10-12 14:05:55 -0700 | |
---|---|---|
committer | 2016-10-17 18:33:42 -0700 | |
commit | 7a37b74d37ff79e805c9e97d977e07bfec753c5a (patch) | |
tree | 0a911666b2cdd107c7a1c4010279ff7b18943986 | |
parent | 047f5a7b4f528f287a2dad494b8696525b27ad80 (diff) |
Add tests for attribute resolution
- Adds unit tests for attribute resolution. These include
some test data resource tables and compiled XML files.
- Convert touched files to Google style guide.
Test: make libandroidfw_tests
Change-Id: Ib3a36061dc874de5f6a266b4e82c0a12ef435f23
19 files changed, 1085 insertions, 769 deletions
diff --git a/core/jni/android_util_AssetManager.cpp b/core/jni/android_util_AssetManager.cpp index 5a4348e478dd..f9e4e6c153d2 100644 --- a/core/jni/android_util_AssetManager.cpp +++ b/core/jni/android_util_AssetManager.cpp @@ -97,16 +97,6 @@ jclass g_stringClass = NULL; // ---------------------------------------------------------------------------- -enum { - STYLE_NUM_ENTRIES = 6, - STYLE_TYPE = 0, - STYLE_DATA = 1, - STYLE_ASSET_COOKIE = 2, - STYLE_RESOURCE_ID = 3, - STYLE_CHANGING_CONFIGURATIONS = 4, - STYLE_DENSITY = 5 -}; - static jint copyValue(JNIEnv* env, jobject outValue, const ResTable* table, const Res_value& value, uint32_t ref, ssize_t block, uint32_t typeSpecFlags, ResTable_config* config = NULL); @@ -1171,7 +1161,7 @@ static jboolean android_content_AssetManager_resolveAttrs(JNIEnv* env, jobject c } ResTable::Theme* theme = reinterpret_cast<ResTable::Theme*>(themeToken); - bool result = resolveAttrs(theme, defStyleAttr, defStyleRes, + bool result = ResolveAttrs(theme, defStyleAttr, defStyleRes, (uint32_t*) srcValues, NSV, (uint32_t*) src, NI, (uint32_t*) baseDest, @@ -1235,7 +1225,7 @@ static jboolean android_content_AssetManager_applyStyle(JNIEnv* env, jobject cla ResTable::Theme* theme = reinterpret_cast<ResTable::Theme*>(themeToken); ResXMLParser* xmlParser = reinterpret_cast<ResXMLParser*>(xmlParserToken); - bool result = applyStyle(theme, xmlParser, + bool result = ApplyStyle(theme, xmlParser, defStyleAttr, defStyleRes, (uint32_t*) src, NI, (uint32_t*) baseDest, @@ -1300,7 +1290,7 @@ static jboolean android_content_AssetManager_retrieveAttributes(JNIEnv* env, job } } - bool result = retrieveAttributes(&res, xmlParser, + bool result = RetrieveAttributes(&res, xmlParser, (uint32_t*) src, NI, (uint32_t*) baseDest, (uint32_t*) indices); diff --git a/include/androidfw/AttributeFinder.h b/include/androidfw/AttributeFinder.h deleted file mode 100644 index acf70565c4f9..000000000000 --- a/include/androidfw/AttributeFinder.h +++ /dev/null @@ -1,206 +0,0 @@ -/* - * 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. - */ - -#ifndef H_ATTRIBUTE_FINDER -#define H_ATTRIBUTE_FINDER - -#include <stdint.h> -#include <utils/KeyedVector.h> - -namespace android { - -static inline uint32_t getPackage(uint32_t attr) { - return attr >> 24; -} - -/** - * A helper class to search linearly for the requested - * attribute, maintaining it's position and optimizing for - * the case that subsequent searches will involve an attribute with - * a higher attribute ID. - * - * In the case that a subsequent attribute has a different package ID, - * its resource ID may not be larger than the preceding search, so - * back tracking is supported for this case. This - * back tracking requirement is mainly for shared library - * resources, whose package IDs get assigned at runtime - * and thus attributes from a shared library may - * be out of order. - * - * We make two assumptions about the order of attributes: - * 1) The input has the same sorting rules applied to it as - * the attribute data contained by this class. - * 2) Attributes are grouped by package ID. - * 3) Among attributes with the same package ID, the attributes are - * sorted by increasing resource ID. - * - * Ex: 02010000, 02010001, 010100f4, 010100f5, 0x7f010001, 07f010003 - * - * The total order of attributes (including package ID) can not be linear - * as shared libraries get assigned dynamic package IDs at runtime, which - * may break the sort order established at build time. - */ -template <typename Derived, typename Iterator> -class BackTrackingAttributeFinder { -public: - BackTrackingAttributeFinder(const Iterator& begin, const Iterator& end); - - Iterator find(uint32_t attr); - -private: - void jumpToClosestAttribute(uint32_t packageId); - void markCurrentPackageId(uint32_t packageId); - - bool mFirstTime; - Iterator mBegin; - Iterator mEnd; - Iterator mCurrent; - Iterator mLargest; - uint32_t mLastPackageId; - uint32_t mCurrentAttr; - - // Package Offsets (best-case, fast look-up). - Iterator mFrameworkStart; - Iterator mAppStart; - - // Worst case, we have shared-library resources. - KeyedVector<uint32_t, Iterator> mPackageOffsets; -}; - -template <typename Derived, typename Iterator> inline -BackTrackingAttributeFinder<Derived, Iterator>::BackTrackingAttributeFinder(const Iterator& begin, const Iterator& end) - : mFirstTime(true) - , mBegin(begin) - , mEnd(end) - , mCurrent(begin) - , mLargest(begin) - , mLastPackageId(0) - , mCurrentAttr(0) - , mFrameworkStart(end) - , mAppStart(end) { -} - -template <typename Derived, typename Iterator> -void BackTrackingAttributeFinder<Derived, Iterator>::jumpToClosestAttribute(const uint32_t packageId) { - switch (packageId) { - case 0x01: - mCurrent = mFrameworkStart; - break; - case 0x7f: - mCurrent = mAppStart; - break; - default: { - ssize_t idx = mPackageOffsets.indexOfKey(packageId); - if (idx >= 0) { - // We have seen this package ID before, so jump to the first - // attribute with this package ID. - mCurrent = mPackageOffsets[idx]; - } else { - mCurrent = mEnd; - } - break; - } - } - - // We have never seen this package ID yet, so jump to the - // latest/largest index we have processed so far. - if (mCurrent == mEnd) { - mCurrent = mLargest; - } - - if (mCurrent != mEnd) { - mCurrentAttr = static_cast<const Derived*>(this)->getAttribute(mCurrent); - } -} - -template <typename Derived, typename Iterator> -void BackTrackingAttributeFinder<Derived, Iterator>::markCurrentPackageId(const uint32_t packageId) { - switch (packageId) { - case 0x01: - mFrameworkStart = mCurrent; - break; - case 0x7f: - mAppStart = mCurrent; - break; - default: - mPackageOffsets.add(packageId, mCurrent); - break; - } -} - -template <typename Derived, typename Iterator> -Iterator BackTrackingAttributeFinder<Derived, Iterator>::find(uint32_t attr) { - if (!(mBegin < mEnd)) { - return mEnd; - } - - if (mFirstTime) { - // One-time initialization. We do this here instead of the constructor - // because the derived class we access in getAttribute() may not be - // fully constructed. - mFirstTime = false; - mCurrentAttr = static_cast<const Derived*>(this)->getAttribute(mBegin); - mLastPackageId = getPackage(mCurrentAttr); - markCurrentPackageId(mLastPackageId); - } - - // Looking for the needle (attribute we're looking for) - // in the haystack (the attributes we're searching through) - const uint32_t needlePackageId = getPackage(attr); - if (mLastPackageId != needlePackageId) { - jumpToClosestAttribute(needlePackageId); - mLastPackageId = needlePackageId; - } - - // Walk through the xml attributes looking for the requested attribute. - while (mCurrent != mEnd) { - const uint32_t haystackPackageId = getPackage(mCurrentAttr); - if (needlePackageId == haystackPackageId && attr < mCurrentAttr) { - // The attribute we are looking was not found. - break; - } - const uint32_t prevAttr = mCurrentAttr; - - // Move to the next attribute in the XML. - ++mCurrent; - if (mCurrent != mEnd) { - mCurrentAttr = static_cast<const Derived*>(this)->getAttribute(mCurrent); - const uint32_t newHaystackPackageId = getPackage(mCurrentAttr); - if (haystackPackageId != newHaystackPackageId) { - // We've moved to the next group of attributes - // with a new package ID, so we should record - // the offset of this new package ID. - markCurrentPackageId(newHaystackPackageId); - } - } - - if (mCurrent > mLargest) { - // We've moved past the latest attribute we've - // seen. - mLargest = mCurrent; - } - - if (attr == prevAttr) { - // We found the attribute we were looking for. - return mCurrent - 1; - } - } - return mEnd; -} - -} // namespace android - -#endif // H_ATTRIBUTE_FINDER diff --git a/include/androidfw/AttributeResolution.h b/include/androidfw/AttributeResolution.h index 2f60a1d12a20..3ed8bced22ef 100644 --- a/include/androidfw/AttributeResolution.h +++ b/include/androidfw/AttributeResolution.h @@ -21,6 +21,18 @@ namespace android { +// Offsets into the outValues array populated by the methods below. outValues is a uint32_t +// array, but each logical element takes up 6 uint32_t-sized physical elements. +enum { + STYLE_NUM_ENTRIES = 6, + STYLE_TYPE = 0, + STYLE_DATA = 1, + STYLE_ASSET_COOKIE = 2, + STYLE_RESOURCE_ID = 3, + STYLE_CHANGING_CONFIGURATIONS = 4, + STYLE_DENSITY = 5 +}; + // These are all variations of the same method. They each perform the exact same operation, // but on various data sources. I *think* they are re-written to avoid an extra branch // in the inner loop, but after one branch miss (some pointer != null), the branch predictor should @@ -28,26 +40,17 @@ namespace android { // TODO(adamlesinski): Run performance tests against these methods and a new, single method // that uses all the sources and branches to the right ones within the inner loop. -bool resolveAttrs(ResTable::Theme* theme, - uint32_t defStyleAttr, - uint32_t defStyleRes, - uint32_t* srcValues, size_t srcValuesLength, - uint32_t* attrs, size_t attrsLength, - uint32_t* outValues, - uint32_t* outIndices); - -bool applyStyle(ResTable::Theme* theme, ResXMLParser* xmlParser, - uint32_t defStyleAttr, - uint32_t defStyleRes, - uint32_t* attrs, size_t attrsLength, - uint32_t* outValues, - uint32_t* outIndices); - -bool retrieveAttributes(const ResTable* res, ResXMLParser* xmlParser, - uint32_t* attrs, size_t attrsLength, - uint32_t* outValues, - uint32_t* outIndices); - -} // namespace android +bool ResolveAttrs(ResTable::Theme* theme, uint32_t def_style_attr, uint32_t def_style_res, + uint32_t* src_values, size_t src_values_length, uint32_t* attrs, + size_t attrs_length, uint32_t* out_values, uint32_t* out_indices); + +bool ApplyStyle(ResTable::Theme* theme, ResXMLParser* xml_parser, uint32_t def_style_attr, + uint32_t def_style_res, uint32_t* attrs, size_t attrs_length, uint32_t* out_values, + uint32_t* out_indices); + +bool RetrieveAttributes(const ResTable* res, ResXMLParser* xml_parser, uint32_t* attrs, + size_t attrs_length, uint32_t* out_values, uint32_t* out_indices); + +} // namespace android #endif /* ANDROIDFW_ATTRIBUTERESOLUTION_H */ diff --git a/libs/androidfw/.clang-format b/libs/androidfw/.clang-format new file mode 100644 index 000000000000..ee1bee2bc644 --- /dev/null +++ b/libs/androidfw/.clang-format @@ -0,0 +1,2 @@ +BasedOnStyle: Google +ColumnLimit: 100 diff --git a/libs/androidfw/AttributeFinder.h b/libs/androidfw/AttributeFinder.h new file mode 100644 index 000000000000..f281921824e7 --- /dev/null +++ b/libs/androidfw/AttributeFinder.h @@ -0,0 +1,206 @@ +/* + * Copyright (C) 2016 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. + */ + +#ifndef ANDROIDFW_ATTRIBUTE_FINDER_H +#define ANDROIDFW_ATTRIBUTE_FINDER_H + +#include <utils/KeyedVector.h> + +#include <stdint.h> + +namespace android { + +static inline uint32_t get_package(uint32_t attr) { return attr >> 24; } + +/** + * A helper class to search linearly for the requested + * attribute, maintaining it's position and optimizing for + * the case that subsequent searches will involve an attribute with + * a higher attribute ID. + * + * In the case that a subsequent attribute has a different package ID, + * its resource ID may not be larger than the preceding search, so + * back tracking is supported for this case. This + * back tracking requirement is mainly for shared library + * resources, whose package IDs get assigned at runtime + * and thus attributes from a shared library may + * be out of order. + * + * We make two assumptions about the order of attributes: + * 1) The input has the same sorting rules applied to it as + * the attribute data contained by this class. + * 2) Attributes are grouped by package ID. + * 3) Among attributes with the same package ID, the attributes are + * sorted by increasing resource ID. + * + * Ex: 02010000, 02010001, 010100f4, 010100f5, 0x7f010001, 07f010003 + * + * The total order of attributes (including package ID) can not be linear + * as shared libraries get assigned dynamic package IDs at runtime, which + * may break the sort order established at build time. + */ +template <typename Derived, typename Iterator> +class BackTrackingAttributeFinder { + public: + BackTrackingAttributeFinder(const Iterator& begin, const Iterator& end); + + Iterator Find(uint32_t attr); + + private: + void JumpToClosestAttribute(uint32_t package_id); + void MarkCurrentPackageId(uint32_t package_id); + + bool first_time_; + Iterator begin_; + Iterator end_; + Iterator current_; + Iterator largest_; + uint32_t last_package_id_; + uint32_t current_attr_; + + // Package offsets (best-case, fast look-up). + Iterator framework_start_; + Iterator app_start_; + + // Worst case, we have shared-library resources. + KeyedVector<uint32_t, Iterator> package_offsets_; +}; + +template <typename Derived, typename Iterator> +inline BackTrackingAttributeFinder<Derived, Iterator>::BackTrackingAttributeFinder( + const Iterator& begin, const Iterator& end) + : first_time_(true), + begin_(begin), + end_(end), + current_(begin), + largest_(begin), + last_package_id_(0), + current_attr_(0), + framework_start_(end), + app_start_(end) {} + +template <typename Derived, typename Iterator> +void BackTrackingAttributeFinder<Derived, Iterator>::JumpToClosestAttribute( + const uint32_t package_id) { + switch (package_id) { + case 0x01u: + current_ = framework_start_; + break; + case 0x7fu: + current_ = app_start_; + break; + default: { + ssize_t idx = package_offsets_.indexOfKey(package_id); + if (idx >= 0) { + // We have seen this package ID before, so jump to the first + // attribute with this package ID. + current_ = package_offsets_[idx]; + } else { + current_ = end_; + } + break; + } + } + + // We have never seen this package ID yet, so jump to the + // latest/largest index we have processed so far. + if (current_ == end_) { + current_ = largest_; + } + + if (current_ != end_) { + current_attr_ = static_cast<const Derived*>(this)->GetAttribute(current_); + } +} + +template <typename Derived, typename Iterator> +void BackTrackingAttributeFinder<Derived, Iterator>::MarkCurrentPackageId( + const uint32_t package_id) { + switch (package_id) { + case 0x01u: + framework_start_ = current_; + break; + case 0x7fu: + app_start_ = current_; + break; + default: + package_offsets_.add(package_id, current_); + break; + } +} + +template <typename Derived, typename Iterator> +Iterator BackTrackingAttributeFinder<Derived, Iterator>::Find(uint32_t attr) { + if (!(begin_ < end_)) { + return end_; + } + + if (first_time_) { + // One-time initialization. We do this here instead of the constructor + // because the derived class we access in getAttribute() may not be + // fully constructed. + first_time_ = false; + current_attr_ = static_cast<const Derived*>(this)->GetAttribute(begin_); + last_package_id_ = get_package(current_attr_); + MarkCurrentPackageId(last_package_id_); + } + + // Looking for the needle (attribute we're looking for) + // in the haystack (the attributes we're searching through) + const uint32_t needle_package_id = get_package(attr); + if (last_package_id_ != needle_package_id) { + JumpToClosestAttribute(needle_package_id); + last_package_id_ = needle_package_id; + } + + // Walk through the xml attributes looking for the requested attribute. + while (current_ != end_) { + const uint32_t haystack_package_id = get_package(current_attr_); + if (needle_package_id == haystack_package_id && attr < current_attr_) { + // The attribute we are looking was not found. + break; + } + const uint32_t prev_attr = current_attr_; + + // Move to the next attribute in the XML. + ++current_; + if (current_ != end_) { + current_attr_ = static_cast<const Derived*>(this)->GetAttribute(current_); + const uint32_t new_haystack_package_id = get_package(current_attr_); + if (haystack_package_id != new_haystack_package_id) { + // We've moved to the next group of attributes + // with a new package ID, so we should record + // the offset of this new package ID. + MarkCurrentPackageId(new_haystack_package_id); + } + } + + if (current_ > largest_) { + // We've moved past the latest attribute we've seen. + largest_ = current_; + } + + if (attr == prev_attr) { + // We found the attribute we were looking for. + return current_ - 1; + } + } + return end_; +} + +} // namespace android + +#endif // ANDROIDFW_ATTRIBUTE_FINDER_H diff --git a/libs/androidfw/AttributeResolution.cpp b/libs/androidfw/AttributeResolution.cpp index ad428a4ae93b..00f7a42f10e4 100644 --- a/libs/androidfw/AttributeResolution.cpp +++ b/libs/androidfw/AttributeResolution.cpp @@ -14,7 +14,8 @@ * limitations under the License. */ -#include "androidfw/AttributeFinder.h" +#include "AttributeFinder.h" + #include "androidfw/AttributeResolution.h" #include "androidfw/ResourceTypes.h" @@ -25,476 +26,452 @@ constexpr bool kDebugStyles = false; namespace android { -enum { - STYLE_NUM_ENTRIES = 6, - STYLE_TYPE = 0, - STYLE_DATA = 1, - STYLE_ASSET_COOKIE = 2, - STYLE_RESOURCE_ID = 3, - STYLE_CHANGING_CONFIGURATIONS = 4, - STYLE_DENSITY = 5 -}; - class XmlAttributeFinder : public BackTrackingAttributeFinder<XmlAttributeFinder, size_t> { -public: - explicit XmlAttributeFinder(const ResXMLParser* parser) : - BackTrackingAttributeFinder(0, parser != NULL ? parser->getAttributeCount() : 0), - mParser(parser) { - } + public: + explicit XmlAttributeFinder(const ResXMLParser* parser) + : BackTrackingAttributeFinder(0, parser != NULL ? parser->getAttributeCount() : 0), + parser_(parser) {} - inline uint32_t getAttribute(size_t index) const { - return mParser->getAttributeNameResID(index); - } + inline uint32_t GetAttribute(size_t index) const { return parser_->getAttributeNameResID(index); } -private: - const ResXMLParser* mParser; + private: + const ResXMLParser* parser_; }; -class BagAttributeFinder : - public BackTrackingAttributeFinder<BagAttributeFinder, const ResTable::bag_entry*> { -public: - BagAttributeFinder(const ResTable::bag_entry* start, const ResTable::bag_entry* end) : - BackTrackingAttributeFinder(start, end) {} +class BagAttributeFinder + : public BackTrackingAttributeFinder<BagAttributeFinder, const ResTable::bag_entry*> { + public: + BagAttributeFinder(const ResTable::bag_entry* start, const ResTable::bag_entry* end) + : BackTrackingAttributeFinder(start, end) {} - inline uint32_t getAttribute(const ResTable::bag_entry* entry) const { - return entry->map.name.ident; - } + inline uint32_t GetAttribute(const ResTable::bag_entry* entry) const { + return entry->map.name.ident; + } }; -bool resolveAttrs(ResTable::Theme* theme, - uint32_t defStyleAttr, - uint32_t defStyleRes, - uint32_t* srcValues, size_t srcValuesLength, - uint32_t* attrs, size_t attrsLength, - uint32_t* outValues, - uint32_t* outIndices) { - if (kDebugStyles) { - ALOGI("APPLY STYLE: theme=0x%p defStyleAttr=0x%x " - "defStyleRes=0x%x", theme, defStyleAttr, defStyleRes); - } +bool ResolveAttrs(ResTable::Theme* theme, uint32_t def_style_attr, uint32_t def_style_res, + uint32_t* src_values, size_t src_values_length, uint32_t* attrs, + size_t attrs_length, uint32_t* out_values, uint32_t* out_indices) { + if (kDebugStyles) { + ALOGI("APPLY STYLE: theme=0x%p defStyleAttr=0x%x defStyleRes=0x%x", theme, def_style_attr, + def_style_res); + } - const ResTable& res = theme->getResTable(); - ResTable_config config; - Res_value value; + const ResTable& res = theme->getResTable(); + ResTable_config config; + Res_value value; - int indicesIdx = 0; + int indices_idx = 0; - // Load default style from attribute, if specified... - uint32_t defStyleBagTypeSetFlags = 0; - if (defStyleAttr != 0) { - Res_value value; - if (theme->getAttribute(defStyleAttr, &value, &defStyleBagTypeSetFlags) >= 0) { - if (value.dataType == Res_value::TYPE_REFERENCE) { - defStyleRes = value.data; - } - } + // Load default style from attribute, if specified... + uint32_t def_style_bag_type_set_flags = 0; + if (def_style_attr != 0) { + Res_value value; + if (theme->getAttribute(def_style_attr, &value, &def_style_bag_type_set_flags) >= 0) { + if (value.dataType == Res_value::TYPE_REFERENCE) { + def_style_res = value.data; + } } + } + + // Now lock down the resource object and start pulling stuff from it. + res.lock(); + + // Retrieve the default style bag, if requested. + const ResTable::bag_entry* def_style_start = NULL; + uint32_t def_style_type_set_flags = 0; + ssize_t bag_off = + def_style_res != 0 + ? res.getBagLocked(def_style_res, &def_style_start, &def_style_type_set_flags) + : -1; + def_style_type_set_flags |= def_style_bag_type_set_flags; + const ResTable::bag_entry* const def_style_end = def_style_start + (bag_off >= 0 ? bag_off : 0); + BagAttributeFinder def_style_attr_finder(def_style_start, def_style_end); + + // Now iterate through all of the attributes that the client has requested, + // filling in each with whatever data we can find. + for (size_t ii = 0; ii < attrs_length; ii++) { + const uint32_t cur_ident = attrs[ii]; - // Now lock down the resource object and start pulling stuff from it. - res.lock(); - - // Retrieve the default style bag, if requested. - const ResTable::bag_entry* defStyleStart = NULL; - uint32_t defStyleTypeSetFlags = 0; - ssize_t bagOff = defStyleRes != 0 - ? res.getBagLocked(defStyleRes, &defStyleStart, &defStyleTypeSetFlags) : -1; - defStyleTypeSetFlags |= defStyleBagTypeSetFlags; - const ResTable::bag_entry* const defStyleEnd = defStyleStart + (bagOff >= 0 ? bagOff : 0); - BagAttributeFinder defStyleAttrFinder(defStyleStart, defStyleEnd); - - // Now iterate through all of the attributes that the client has requested, - // filling in each with whatever data we can find. - ssize_t block = 0; - uint32_t typeSetFlags; - for (size_t ii=0; ii<attrsLength; ii++) { - const uint32_t curIdent = attrs[ii]; + if (kDebugStyles) { + ALOGI("RETRIEVING ATTR 0x%08x...", cur_ident); + } - if (kDebugStyles) { - ALOGI("RETRIEVING ATTR 0x%08x...", curIdent); - } + ssize_t block = -1; + uint32_t type_set_flags = 0; - // Try to find a value for this attribute... we prioritize values - // coming from, first XML attributes, then XML style, then default - // style, and finally the theme. - value.dataType = Res_value::TYPE_NULL; - value.data = Res_value::DATA_NULL_UNDEFINED; - typeSetFlags = 0; - config.density = 0; - - // Retrieve the current input value if available. - if (srcValuesLength > 0 && srcValues[ii] != 0) { - block = -1; - value.dataType = Res_value::TYPE_ATTRIBUTE; - value.data = srcValues[ii]; - if (kDebugStyles) { - ALOGI("-> From values: type=0x%x, data=0x%08x", value.dataType, value.data); - } - } + value.dataType = Res_value::TYPE_NULL; + value.data = Res_value::DATA_NULL_UNDEFINED; + config.density = 0; - if (value.dataType == Res_value::TYPE_NULL) { - const ResTable::bag_entry* const defStyleEntry = defStyleAttrFinder.find(curIdent); - if (defStyleEntry != defStyleEnd) { - block = defStyleEntry->stringBlock; - typeSetFlags = defStyleTypeSetFlags; - value = defStyleEntry->map.value; - if (kDebugStyles) { - ALOGI("-> From def style: type=0x%x, data=0x%08x", value.dataType, value.data); - } - } - } + // Try to find a value for this attribute... we prioritize values + // coming from, first XML attributes, then XML style, then default + // style, and finally the theme. - uint32_t resid = 0; - if (value.dataType != Res_value::TYPE_NULL) { - // Take care of resolving the found resource to its final value. - ssize_t newBlock = theme->resolveAttributeReference(&value, block, - &resid, &typeSetFlags, &config); - if (newBlock >= 0) block = newBlock; - if (kDebugStyles) { - ALOGI("-> Resolved attr: type=0x%x, data=0x%08x", value.dataType, value.data); - } - } else { - // If we still don't have a value for this attribute, try to find - // it in the theme! - ssize_t newBlock = theme->getAttribute(curIdent, &value, &typeSetFlags); - if (newBlock >= 0) { - if (kDebugStyles) { - ALOGI("-> From theme: type=0x%x, data=0x%08x", value.dataType, value.data); - } - newBlock = res.resolveReference(&value, block, &resid, - &typeSetFlags, &config); - if (newBlock >= 0) block = newBlock; - if (kDebugStyles) { - ALOGI("-> Resolved theme: type=0x%x, data=0x%08x", value.dataType, value.data); - } - } - } + // Retrieve the current input value if available. + if (src_values_length > 0 && src_values[ii] != 0) { + value.dataType = Res_value::TYPE_ATTRIBUTE; + value.data = src_values[ii]; + if (kDebugStyles) { + ALOGI("-> From values: type=0x%x, data=0x%08x", value.dataType, value.data); + } + } - // Deal with the special @null value -- it turns back to TYPE_NULL. - if (value.dataType == Res_value::TYPE_REFERENCE && value.data == 0) { - if (kDebugStyles) { - ALOGI("-> Setting to @null!"); - } - value.dataType = Res_value::TYPE_NULL; - value.data = Res_value::DATA_NULL_UNDEFINED; - block = -1; + if (value.dataType == Res_value::TYPE_NULL) { + const ResTable::bag_entry* const def_style_entry = def_style_attr_finder.Find(cur_ident); + if (def_style_entry != def_style_end) { + block = def_style_entry->stringBlock; + type_set_flags = def_style_type_set_flags; + value = def_style_entry->map.value; + if (kDebugStyles) { + ALOGI("-> From def style: type=0x%x, data=0x%08x", value.dataType, value.data); } + } + } + uint32_t resid = 0; + if (value.dataType != Res_value::TYPE_NULL) { + // Take care of resolving the found resource to its final value. + ssize_t new_block = + theme->resolveAttributeReference(&value, block, &resid, &type_set_flags, &config); + if (new_block >= 0) block = new_block; + if (kDebugStyles) { + ALOGI("-> Resolved attr: type=0x%x, data=0x%08x", value.dataType, value.data); + } + } else { + // If we still don't have a value for this attribute, try to find + // it in the theme! + ssize_t new_block = theme->getAttribute(cur_ident, &value, &type_set_flags); + if (new_block >= 0) { if (kDebugStyles) { - ALOGI("Attribute 0x%08x: type=0x%x, data=0x%08x", curIdent, value.dataType, - value.data); + ALOGI("-> From theme: type=0x%x, data=0x%08x", value.dataType, value.data); } - - // Write the final value back to Java. - outValues[STYLE_TYPE] = value.dataType; - outValues[STYLE_DATA] = value.data; - outValues[STYLE_ASSET_COOKIE] = block != -1 - ? static_cast<uint32_t>(res.getTableCookie(block)) : static_cast<uint32_t>(-1); - outValues[STYLE_RESOURCE_ID] = resid; - outValues[STYLE_CHANGING_CONFIGURATIONS] = typeSetFlags; - outValues[STYLE_DENSITY] = config.density; - - if (outIndices != NULL && value.dataType != Res_value::TYPE_NULL) { - indicesIdx++; - outIndices[indicesIdx] = ii; + new_block = res.resolveReference(&value, new_block, &resid, &type_set_flags, &config); + if (new_block >= 0) block = new_block; + if (kDebugStyles) { + ALOGI("-> Resolved theme: type=0x%x, data=0x%08x", value.dataType, value.data); } + } + } - outValues += STYLE_NUM_ENTRIES; + // Deal with the special @null value -- it turns back to TYPE_NULL. + if (value.dataType == Res_value::TYPE_REFERENCE && value.data == 0) { + if (kDebugStyles) { + ALOGI("-> Setting to @null!"); + } + value.dataType = Res_value::TYPE_NULL; + value.data = Res_value::DATA_NULL_UNDEFINED; + block = -1; } - res.unlock(); + if (kDebugStyles) { + ALOGI("Attribute 0x%08x: type=0x%x, data=0x%08x", cur_ident, value.dataType, value.data); + } - if (outIndices != NULL) { - outIndices[0] = indicesIdx; + // Write the final value back to Java. + out_values[STYLE_TYPE] = value.dataType; + out_values[STYLE_DATA] = value.data; + out_values[STYLE_ASSET_COOKIE] = + block != -1 ? static_cast<uint32_t>(res.getTableCookie(block)) : static_cast<uint32_t>(-1); + out_values[STYLE_RESOURCE_ID] = resid; + out_values[STYLE_CHANGING_CONFIGURATIONS] = type_set_flags; + out_values[STYLE_DENSITY] = config.density; + + if (out_indices != NULL && value.dataType != Res_value::TYPE_NULL) { + indices_idx++; + out_indices[indices_idx] = ii; } - return true; + + out_values += STYLE_NUM_ENTRIES; + } + + res.unlock(); + + if (out_indices != NULL) { + out_indices[0] = indices_idx; + } + return true; } -bool applyStyle(ResTable::Theme* theme, ResXMLParser* xmlParser, - uint32_t defStyleAttr, - uint32_t defStyleRes, - uint32_t* attrs, size_t attrsLength, - uint32_t* outValues, - uint32_t* outIndices) { - if (kDebugStyles) { - ALOGI("APPLY STYLE: theme=0x%p defStyleAttr=0x%x defStyleRes=0x%x xml=0x%p", - theme, defStyleAttr, defStyleRes, xmlParser); - } +bool ApplyStyle(ResTable::Theme* theme, ResXMLParser* xml_parser, uint32_t def_style_attr, + uint32_t def_style_res, uint32_t* attrs, size_t attrs_length, uint32_t* out_values, + uint32_t* out_indices) { + if (kDebugStyles) { + ALOGI("APPLY STYLE: theme=0x%p defStyleAttr=0x%x defStyleRes=0x%x xml=0x%p", theme, + def_style_attr, def_style_res, xml_parser); + } - const ResTable& res = theme->getResTable(); - ResTable_config config; - Res_value value; + const ResTable& res = theme->getResTable(); + ResTable_config config; + Res_value value; - int indicesIdx = 0; + int indices_idx = 0; - // Load default style from attribute, if specified... - uint32_t defStyleBagTypeSetFlags = 0; - if (defStyleAttr != 0) { - Res_value value; - if (theme->getAttribute(defStyleAttr, &value, &defStyleBagTypeSetFlags) >= 0) { - if (value.dataType == Res_value::TYPE_REFERENCE) { - defStyleRes = value.data; - } + // Load default style from attribute, if specified... + uint32_t def_style_bag_type_set_flags = 0; + if (def_style_attr != 0) { + Res_value value; + if (theme->getAttribute(def_style_attr, &value, &def_style_bag_type_set_flags) >= 0) { + if (value.dataType == Res_value::TYPE_REFERENCE) { + def_style_res = value.data; + } + } + } + + // Retrieve the style class associated with the current XML tag. + int style = 0; + uint32_t style_bag_type_set_flags = 0; + if (xml_parser != NULL) { + ssize_t idx = xml_parser->indexOfStyle(); + if (idx >= 0 && xml_parser->getAttributeValue(idx, &value) >= 0) { + if (value.dataType == value.TYPE_ATTRIBUTE) { + if (theme->getAttribute(value.data, &value, &style_bag_type_set_flags) < 0) { + value.dataType = Res_value::TYPE_NULL; } + } + if (value.dataType == value.TYPE_REFERENCE) { + style = value.data; + } } + } + + // Now lock down the resource object and start pulling stuff from it. + res.lock(); + + // Retrieve the default style bag, if requested. + const ResTable::bag_entry* def_style_attr_start = NULL; + uint32_t def_style_type_set_flags = 0; + ssize_t bag_off = + def_style_res != 0 + ? res.getBagLocked(def_style_res, &def_style_attr_start, &def_style_type_set_flags) + : -1; + def_style_type_set_flags |= def_style_bag_type_set_flags; + const ResTable::bag_entry* const def_style_attr_end = + def_style_attr_start + (bag_off >= 0 ? bag_off : 0); + BagAttributeFinder def_style_attr_finder(def_style_attr_start, def_style_attr_end); + + // Retrieve the style class bag, if requested. + const ResTable::bag_entry* style_attr_start = NULL; + uint32_t style_type_set_flags = 0; + bag_off = style != 0 ? res.getBagLocked(style, &style_attr_start, &style_type_set_flags) : -1; + style_type_set_flags |= style_bag_type_set_flags; + const ResTable::bag_entry* const style_attr_end = style_attr_start + (bag_off >= 0 ? bag_off : 0); + BagAttributeFinder style_attr_finder(style_attr_start, style_attr_end); + + // Retrieve the XML attributes, if requested. + static const ssize_t kXmlBlock = 0x10000000; + XmlAttributeFinder xml_attr_finder(xml_parser); + const size_t xml_attr_end = xml_parser != NULL ? xml_parser->getAttributeCount() : 0; + + // Now iterate through all of the attributes that the client has requested, + // filling in each with whatever data we can find. + for (size_t ii = 0; ii < attrs_length; ii++) { + const uint32_t cur_ident = attrs[ii]; - // Retrieve the style class associated with the current XML tag. - int style = 0; - uint32_t styleBagTypeSetFlags = 0; - if (xmlParser != NULL) { - ssize_t idx = xmlParser->indexOfStyle(); - if (idx >= 0 && xmlParser->getAttributeValue(idx, &value) >= 0) { - if (value.dataType == value.TYPE_ATTRIBUTE) { - if (theme->getAttribute(value.data, &value, &styleBagTypeSetFlags) < 0) { - value.dataType = Res_value::TYPE_NULL; - } - } - if (value.dataType == value.TYPE_REFERENCE) { - style = value.data; - } - } + if (kDebugStyles) { + ALOGI("RETRIEVING ATTR 0x%08x...", cur_ident); } - // Now lock down the resource object and start pulling stuff from it. - res.lock(); - - // Retrieve the default style bag, if requested. - const ResTable::bag_entry* defStyleAttrStart = NULL; - uint32_t defStyleTypeSetFlags = 0; - ssize_t bagOff = defStyleRes != 0 - ? res.getBagLocked(defStyleRes, &defStyleAttrStart, &defStyleTypeSetFlags) : -1; - defStyleTypeSetFlags |= defStyleBagTypeSetFlags; - const ResTable::bag_entry* const defStyleAttrEnd = defStyleAttrStart + (bagOff >= 0 ? bagOff : 0); - BagAttributeFinder defStyleAttrFinder(defStyleAttrStart, defStyleAttrEnd); - - // Retrieve the style class bag, if requested. - const ResTable::bag_entry* styleAttrStart = NULL; - uint32_t styleTypeSetFlags = 0; - bagOff = style != 0 ? res.getBagLocked(style, &styleAttrStart, &styleTypeSetFlags) : -1; - styleTypeSetFlags |= styleBagTypeSetFlags; - const ResTable::bag_entry* const styleAttrEnd = styleAttrStart + (bagOff >= 0 ? bagOff : 0); - BagAttributeFinder styleAttrFinder(styleAttrStart, styleAttrEnd); - - // Retrieve the XML attributes, if requested. - static const ssize_t kXmlBlock = 0x10000000; - XmlAttributeFinder xmlAttrFinder(xmlParser); - const size_t xmlAttrEnd = xmlParser != NULL ? xmlParser->getAttributeCount() : 0; - - // Now iterate through all of the attributes that the client has requested, - // filling in each with whatever data we can find. - ssize_t block = 0; - uint32_t typeSetFlags; - for (size_t ii = 0; ii < attrsLength; ii++) { - const uint32_t curIdent = attrs[ii]; + ssize_t block = kXmlBlock; + uint32_t type_set_flags = 0; + + value.dataType = Res_value::TYPE_NULL; + value.data = Res_value::DATA_NULL_UNDEFINED; + config.density = 0; + + // Try to find a value for this attribute... we prioritize values + // coming from, first XML attributes, then XML style, then default + // style, and finally the theme. + + // Walk through the xml attributes looking for the requested attribute. + const size_t xml_attr_idx = xml_attr_finder.Find(cur_ident); + if (xml_attr_idx != xml_attr_end) { + // We found the attribute we were looking for. + xml_parser->getAttributeValue(xml_attr_idx, &value); + if (kDebugStyles) { + ALOGI("-> From XML: type=0x%x, data=0x%08x", value.dataType, value.data); + } + } + if (value.dataType == Res_value::TYPE_NULL) { + // Walk through the style class values looking for the requested attribute. + const ResTable::bag_entry* const style_attr_entry = style_attr_finder.Find(cur_ident); + if (style_attr_entry != style_attr_end) { + // We found the attribute we were looking for. + block = style_attr_entry->stringBlock; + type_set_flags = style_type_set_flags; + value = style_attr_entry->map.value; if (kDebugStyles) { - ALOGI("RETRIEVING ATTR 0x%08x...", curIdent); - } - - // Try to find a value for this attribute... we prioritize values - // coming from, first XML attributes, then XML style, then default - // style, and finally the theme. - value.dataType = Res_value::TYPE_NULL; - value.data = Res_value::DATA_NULL_UNDEFINED; - typeSetFlags = 0; - config.density = 0; - - // Walk through the xml attributes looking for the requested attribute. - const size_t xmlAttrIdx = xmlAttrFinder.find(curIdent); - if (xmlAttrIdx != xmlAttrEnd) { - // We found the attribute we were looking for. - block = kXmlBlock; - xmlParser->getAttributeValue(xmlAttrIdx, &value); - if (kDebugStyles) { - ALOGI("-> From XML: type=0x%x, data=0x%08x", value.dataType, value.data); - } - } - - if (value.dataType == Res_value::TYPE_NULL) { - // Walk through the style class values looking for the requested attribute. - const ResTable::bag_entry* const styleAttrEntry = styleAttrFinder.find(curIdent); - if (styleAttrEntry != styleAttrEnd) { - // We found the attribute we were looking for. - block = styleAttrEntry->stringBlock; - typeSetFlags = styleTypeSetFlags; - value = styleAttrEntry->map.value; - if (kDebugStyles) { - ALOGI("-> From style: type=0x%x, data=0x%08x", value.dataType, value.data); - } - } + ALOGI("-> From style: type=0x%x, data=0x%08x", value.dataType, value.data); } + } + } - if (value.dataType == Res_value::TYPE_NULL) { - // Walk through the default style values looking for the requested attribute. - const ResTable::bag_entry* const defStyleAttrEntry = defStyleAttrFinder.find(curIdent); - if (defStyleAttrEntry != defStyleAttrEnd) { - // We found the attribute we were looking for. - block = defStyleAttrEntry->stringBlock; - typeSetFlags = styleTypeSetFlags; - value = defStyleAttrEntry->map.value; - if (kDebugStyles) { - ALOGI("-> From def style: type=0x%x, data=0x%08x", value.dataType, value.data); - } - } + if (value.dataType == Res_value::TYPE_NULL) { + // Walk through the default style values looking for the requested attribute. + const ResTable::bag_entry* const def_style_attr_entry = def_style_attr_finder.Find(cur_ident); + if (def_style_attr_entry != def_style_attr_end) { + // We found the attribute we were looking for. + block = def_style_attr_entry->stringBlock; + type_set_flags = style_type_set_flags; + value = def_style_attr_entry->map.value; + if (kDebugStyles) { + ALOGI("-> From def style: type=0x%x, data=0x%08x", value.dataType, value.data); } + } + } - uint32_t resid = 0; - if (value.dataType != Res_value::TYPE_NULL) { - // Take care of resolving the found resource to its final value. - ssize_t newBlock = theme->resolveAttributeReference(&value, block, - &resid, &typeSetFlags, &config); - if (newBlock >= 0) { - block = newBlock; - } - - if (kDebugStyles) { - ALOGI("-> Resolved attr: type=0x%x, data=0x%08x", value.dataType, value.data); - } - } else { - // If we still don't have a value for this attribute, try to find - // it in the theme! - ssize_t newBlock = theme->getAttribute(curIdent, &value, &typeSetFlags); - if (newBlock >= 0) { - if (kDebugStyles) { - ALOGI("-> From theme: type=0x%x, data=0x%08x", value.dataType, value.data); - } - newBlock = res.resolveReference(&value, block, &resid, - &typeSetFlags, &config); - - if (newBlock >= 0) { - block = newBlock; - } - - if (kDebugStyles) { - ALOGI("-> Resolved theme: type=0x%x, data=0x%08x", value.dataType, value.data); - } - } + uint32_t resid = 0; + if (value.dataType != Res_value::TYPE_NULL) { + // Take care of resolving the found resource to its final value. + ssize_t new_block = + theme->resolveAttributeReference(&value, block, &resid, &type_set_flags, &config); + if (new_block >= 0) { + block = new_block; + } + + if (kDebugStyles) { + ALOGI("-> Resolved attr: type=0x%x, data=0x%08x", value.dataType, value.data); + } + } else { + // If we still don't have a value for this attribute, try to find + // it in the theme! + ssize_t new_block = theme->getAttribute(cur_ident, &value, &type_set_flags); + if (new_block >= 0) { + if (kDebugStyles) { + ALOGI("-> From theme: type=0x%x, data=0x%08x", value.dataType, value.data); } - - // Deal with the special @null value -- it turns back to TYPE_NULL. - if (value.dataType == Res_value::TYPE_REFERENCE && value.data == 0) { - if (kDebugStyles) { - ALOGI("-> Setting to @null!"); - } - value.dataType = Res_value::TYPE_NULL; - value.data = Res_value::DATA_NULL_UNDEFINED; - block = kXmlBlock; + new_block = res.resolveReference(&value, new_block, &resid, &type_set_flags, &config); + if (new_block >= 0) { + block = new_block; } if (kDebugStyles) { - ALOGI("Attribute 0x%08x: type=0x%x, data=0x%08x", curIdent, value.dataType, value.data); - } - - // Write the final value back to Java. - outValues[STYLE_TYPE] = value.dataType; - outValues[STYLE_DATA] = value.data; - outValues[STYLE_ASSET_COOKIE] = block != kXmlBlock ? - static_cast<uint32_t>(res.getTableCookie(block)) : static_cast<uint32_t>(-1); - outValues[STYLE_RESOURCE_ID] = resid; - outValues[STYLE_CHANGING_CONFIGURATIONS] = typeSetFlags; - outValues[STYLE_DENSITY] = config.density; - - if (outIndices != NULL && value.dataType != Res_value::TYPE_NULL) { - indicesIdx++; - outIndices[indicesIdx] = ii; + ALOGI("-> Resolved theme: type=0x%x, data=0x%08x", value.dataType, value.data); } + } + } - outValues += STYLE_NUM_ENTRIES; + // Deal with the special @null value -- it turns back to TYPE_NULL. + if (value.dataType == Res_value::TYPE_REFERENCE && value.data == 0) { + if (kDebugStyles) { + ALOGI("-> Setting to @null!"); + } + value.dataType = Res_value::TYPE_NULL; + value.data = Res_value::DATA_NULL_UNDEFINED; + block = kXmlBlock; } - res.unlock(); + if (kDebugStyles) { + ALOGI("Attribute 0x%08x: type=0x%x, data=0x%08x", cur_ident, value.dataType, value.data); + } - if (outIndices != NULL) { - outIndices[0] = indicesIdx; + // Write the final value back to Java. + out_values[STYLE_TYPE] = value.dataType; + out_values[STYLE_DATA] = value.data; + out_values[STYLE_ASSET_COOKIE] = block != kXmlBlock + ? static_cast<uint32_t>(res.getTableCookie(block)) + : static_cast<uint32_t>(-1); + out_values[STYLE_RESOURCE_ID] = resid; + out_values[STYLE_CHANGING_CONFIGURATIONS] = type_set_flags; + out_values[STYLE_DENSITY] = config.density; + + if (out_indices != NULL && value.dataType != Res_value::TYPE_NULL) { + indices_idx++; + out_indices[indices_idx] = ii; } - return true; -} -bool retrieveAttributes(const ResTable* res, ResXMLParser* xmlParser, - uint32_t* attrs, size_t attrsLength, - uint32_t* outValues, - uint32_t* outIndices) { - ResTable_config config; - Res_value value; + out_values += STYLE_NUM_ENTRIES; + } - int indicesIdx = 0; + res.unlock(); - // Now lock down the resource object and start pulling stuff from it. - res->lock(); + if (out_indices != NULL) { + out_indices[0] = indices_idx; + } + return true; +} - // Retrieve the XML attributes, if requested. - const size_t NX = xmlParser->getAttributeCount(); - size_t ix=0; - uint32_t curXmlAttr = xmlParser->getAttributeNameResID(ix); +bool RetrieveAttributes(const ResTable* res, ResXMLParser* xml_parser, uint32_t* attrs, + size_t attrs_length, uint32_t* out_values, uint32_t* out_indices) { + ResTable_config config; + Res_value value; - static const ssize_t kXmlBlock = 0x10000000; + int indices_idx = 0; - // Now iterate through all of the attributes that the client has requested, - // filling in each with whatever data we can find. - ssize_t block = 0; - uint32_t typeSetFlags; - for (size_t ii=0; ii<attrsLength; ii++) { - const uint32_t curIdent = attrs[ii]; + // Now lock down the resource object and start pulling stuff from it. + res->lock(); - // Try to find a value for this attribute... - value.dataType = Res_value::TYPE_NULL; - value.data = Res_value::DATA_NULL_UNDEFINED; - typeSetFlags = 0; - config.density = 0; + // Retrieve the XML attributes, if requested. + const size_t xml_attr_count = xml_parser->getAttributeCount(); + size_t ix = 0; + uint32_t cur_xml_attr = xml_parser->getAttributeNameResID(ix); - // Skip through XML attributes until the end or the next possible match. - while (ix < NX && curIdent > curXmlAttr) { - ix++; - curXmlAttr = xmlParser->getAttributeNameResID(ix); - } - // Retrieve the current XML attribute if it matches, and step to next. - if (ix < NX && curIdent == curXmlAttr) { - block = kXmlBlock; - xmlParser->getAttributeValue(ix, &value); - ix++; - curXmlAttr = xmlParser->getAttributeNameResID(ix); - } + static const ssize_t kXmlBlock = 0x10000000; - //printf("Attribute 0x%08x: type=0x%x, data=0x%08x\n", curIdent, value.dataType, value.data); - uint32_t resid = 0; - if (value.dataType != Res_value::TYPE_NULL) { - // Take care of resolving the found resource to its final value. - //printf("Resolving attribute reference\n"); - ssize_t newBlock = res->resolveReference(&value, block, &resid, - &typeSetFlags, &config); - if (newBlock >= 0) block = newBlock; - } + // Now iterate through all of the attributes that the client has requested, + // filling in each with whatever data we can find. + for (size_t ii = 0; ii < attrs_length; ii++) { + const uint32_t cur_ident = attrs[ii]; + ssize_t block = kXmlBlock; + uint32_t type_set_flags = 0; - // Deal with the special @null value -- it turns back to TYPE_NULL. - if (value.dataType == Res_value::TYPE_REFERENCE && value.data == 0) { - value.dataType = Res_value::TYPE_NULL; - value.data = Res_value::DATA_NULL_UNDEFINED; - } + value.dataType = Res_value::TYPE_NULL; + value.data = Res_value::DATA_NULL_UNDEFINED; + config.density = 0; - //printf("Attribute 0x%08x: final type=0x%x, data=0x%08x\n", curIdent, value.dataType, value.data); + // Try to find a value for this attribute... + // Skip through XML attributes until the end or the next possible match. + while (ix < xml_attr_count && cur_ident > cur_xml_attr) { + ix++; + cur_xml_attr = xml_parser->getAttributeNameResID(ix); + } + // Retrieve the current XML attribute if it matches, and step to next. + if (ix < xml_attr_count && cur_ident == cur_xml_attr) { + xml_parser->getAttributeValue(ix, &value); + ix++; + cur_xml_attr = xml_parser->getAttributeNameResID(ix); + } - // Write the final value back to Java. - outValues[STYLE_TYPE] = value.dataType; - outValues[STYLE_DATA] = value.data; - outValues[STYLE_ASSET_COOKIE] = block != kXmlBlock - ? static_cast<uint32_t>(res->getTableCookie(block)) : static_cast<uint32_t>(-1); - outValues[STYLE_RESOURCE_ID] = resid; - outValues[STYLE_CHANGING_CONFIGURATIONS] = typeSetFlags; - outValues[STYLE_DENSITY] = config.density; + uint32_t resid = 0; + if (value.dataType != Res_value::TYPE_NULL) { + // Take care of resolving the found resource to its final value. + // printf("Resolving attribute reference\n"); + ssize_t new_block = res->resolveReference(&value, block, &resid, &type_set_flags, &config); + if (new_block >= 0) block = new_block; + } - if (outIndices != NULL && value.dataType != Res_value::TYPE_NULL) { - indicesIdx++; - outIndices[indicesIdx] = ii; - } + // Deal with the special @null value -- it turns back to TYPE_NULL. + if (value.dataType == Res_value::TYPE_REFERENCE && value.data == 0) { + value.dataType = Res_value::TYPE_NULL; + value.data = Res_value::DATA_NULL_UNDEFINED; + block = kXmlBlock; + } - outValues += STYLE_NUM_ENTRIES; + // Write the final value back to Java. + out_values[STYLE_TYPE] = value.dataType; + out_values[STYLE_DATA] = value.data; + out_values[STYLE_ASSET_COOKIE] = block != kXmlBlock + ? static_cast<uint32_t>(res->getTableCookie(block)) + : static_cast<uint32_t>(-1); + out_values[STYLE_RESOURCE_ID] = resid; + out_values[STYLE_CHANGING_CONFIGURATIONS] = type_set_flags; + out_values[STYLE_DENSITY] = config.density; + + if (out_indices != NULL && value.dataType != Res_value::TYPE_NULL) { + indices_idx++; + out_indices[indices_idx] = ii; } - res->unlock(); + out_values += STYLE_NUM_ENTRIES; + } - if (outIndices != NULL) { - outIndices[0] = indicesIdx; - } - return true; + res->unlock(); + + if (out_indices != NULL) { + out_indices[0] = indices_idx; + } + return true; } -} // namespace android +} // namespace android diff --git a/libs/androidfw/tests/Android.mk b/libs/androidfw/tests/Android.mk index 1fe1773578fa..6837f25b21ec 100644 --- a/libs/androidfw/tests/Android.mk +++ b/libs/androidfw/tests/Android.mk @@ -40,7 +40,7 @@ androidfw_test_cflags := \ -Werror \ -Wunused \ -Wunreachable-code \ - -Wno-missing-field-initializers \ + -Wno-missing-field-initializers # gtest is broken. androidfw_test_cflags += -Wno-unnamed-type-template-args @@ -52,9 +52,10 @@ include $(CLEAR_VARS) LOCAL_MODULE := libandroidfw_tests LOCAL_CFLAGS := $(androidfw_test_cflags) -LOCAL_SRC_FILES := $(testFiles) +LOCAL_SRC_FILES := $(testFiles) AttributeResolution_test.cpp LOCAL_STATIC_LIBRARIES := \ libandroidfw \ + libbase \ libutils \ libcutils \ liblog \ @@ -76,6 +77,7 @@ LOCAL_SRC_FILES := $(testFiles) \ LOCAL_SHARED_LIBRARIES := \ libandroidfw \ + libbase \ libcutils \ libutils \ libui \ diff --git a/libs/androidfw/tests/AttributeFinder_test.cpp b/libs/androidfw/tests/AttributeFinder_test.cpp index 5054624579ea..d9ed48ebe953 100644 --- a/libs/androidfw/tests/AttributeFinder_test.cpp +++ b/libs/androidfw/tests/AttributeFinder_test.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2014 The Android Open Source Project + * Copyright (C) 2016 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. @@ -14,115 +14,105 @@ * limitations under the License. */ -#include <androidfw/AttributeFinder.h> +#include "../AttributeFinder.h" +#include <android-base/macros.h> #include <gtest/gtest.h> using android::BackTrackingAttributeFinder; class MockAttributeFinder : public BackTrackingAttributeFinder<MockAttributeFinder, int> { -public: - MockAttributeFinder(const uint32_t* attrs, int len) - : BackTrackingAttributeFinder(0, len) { - mAttrs = new uint32_t[len]; - memcpy(mAttrs, attrs, sizeof(*attrs) * len); - } - - ~MockAttributeFinder() { - delete mAttrs; - } - - inline uint32_t getAttribute(const int index) const { - return mAttrs[index]; - } - -private: - uint32_t* mAttrs; -}; + public: + MockAttributeFinder(const uint32_t* attrs, int len) : BackTrackingAttributeFinder(0, len) { + attrs_ = new uint32_t[len]; + memcpy(attrs_, attrs, sizeof(*attrs) * len); + } -static const uint32_t sortedAttributes[] = { - 0x01010000, 0x01010001, 0x01010002, 0x01010004, - 0x02010001, 0x02010010, 0x7f010001 -}; + ~MockAttributeFinder() { delete attrs_; } -static const uint32_t packageUnsortedAttributes[] = { - 0x02010001, 0x02010010, 0x01010000, 0x01010001, - 0x01010002, 0x01010004, 0x7f010001 -}; + inline uint32_t GetAttribute(const int index) const { return attrs_[index]; } -static const uint32_t singlePackageAttributes[] = { - 0x7f010007, 0x7f01000a, 0x7f01000d, 0x00000000 + private: + uint32_t* attrs_; }; +static const uint32_t kSortedAttributes[] = {0x01010000, 0x01010001, 0x01010002, 0x01010004, + 0x02010001, 0x02010010, 0x7f010001}; + +static const uint32_t kPackageUnsortedAttributes[] = { + 0x02010001, 0x02010010, 0x01010000, 0x01010001, 0x01010002, 0x01010004, 0x7f010001}; + +static const uint32_t kSinglePackageAttributes[] = {0x7f010007, 0x7f01000a, 0x7f01000d, 0x00000000}; + TEST(AttributeFinderTest, IteratesSequentially) { - const int end = sizeof(sortedAttributes) / sizeof(*sortedAttributes); - MockAttributeFinder finder(sortedAttributes, end); - - EXPECT_EQ(0, finder.find(0x01010000)); - EXPECT_EQ(1, finder.find(0x01010001)); - EXPECT_EQ(2, finder.find(0x01010002)); - EXPECT_EQ(3, finder.find(0x01010004)); - EXPECT_EQ(4, finder.find(0x02010001)); - EXPECT_EQ(5, finder.find(0x02010010)); - EXPECT_EQ(6, finder.find(0x7f010001)); - EXPECT_EQ(end, finder.find(0x7f010002)); + const int end = arraysize(kSortedAttributes); + MockAttributeFinder finder(kSortedAttributes, end); + + EXPECT_EQ(0, finder.Find(0x01010000)); + EXPECT_EQ(1, finder.Find(0x01010001)); + EXPECT_EQ(2, finder.Find(0x01010002)); + EXPECT_EQ(3, finder.Find(0x01010004)); + EXPECT_EQ(4, finder.Find(0x02010001)); + EXPECT_EQ(5, finder.Find(0x02010010)); + EXPECT_EQ(6, finder.Find(0x7f010001)); + EXPECT_EQ(end, finder.Find(0x7f010002)); } TEST(AttributeFinderTest, PackagesAreOutOfOrder) { - const int end = sizeof(sortedAttributes) / sizeof(*sortedAttributes); - MockAttributeFinder finder(sortedAttributes, end); - - EXPECT_EQ(6, finder.find(0x7f010001)); - EXPECT_EQ(end, finder.find(0x7f010002)); - EXPECT_EQ(4, finder.find(0x02010001)); - EXPECT_EQ(5, finder.find(0x02010010)); - EXPECT_EQ(0, finder.find(0x01010000)); - EXPECT_EQ(1, finder.find(0x01010001)); - EXPECT_EQ(2, finder.find(0x01010002)); - EXPECT_EQ(3, finder.find(0x01010004)); + const int end = arraysize(kSortedAttributes); + MockAttributeFinder finder(kSortedAttributes, end); + + EXPECT_EQ(6, finder.Find(0x7f010001)); + EXPECT_EQ(end, finder.Find(0x7f010002)); + EXPECT_EQ(4, finder.Find(0x02010001)); + EXPECT_EQ(5, finder.Find(0x02010010)); + EXPECT_EQ(0, finder.Find(0x01010000)); + EXPECT_EQ(1, finder.Find(0x01010001)); + EXPECT_EQ(2, finder.Find(0x01010002)); + EXPECT_EQ(3, finder.Find(0x01010004)); } TEST(AttributeFinderTest, SomeAttributesAreNotFound) { - const int end = sizeof(sortedAttributes) / sizeof(*sortedAttributes); - MockAttributeFinder finder(sortedAttributes, end); - - EXPECT_EQ(0, finder.find(0x01010000)); - EXPECT_EQ(1, finder.find(0x01010001)); - EXPECT_EQ(2, finder.find(0x01010002)); - EXPECT_EQ(end, finder.find(0x01010003)); - EXPECT_EQ(3, finder.find(0x01010004)); - EXPECT_EQ(end, finder.find(0x01010005)); - EXPECT_EQ(end, finder.find(0x01010006)); - EXPECT_EQ(4, finder.find(0x02010001)); - EXPECT_EQ(end, finder.find(0x02010002)); + const int end = arraysize(kSortedAttributes); + MockAttributeFinder finder(kSortedAttributes, end); + + EXPECT_EQ(0, finder.Find(0x01010000)); + EXPECT_EQ(1, finder.Find(0x01010001)); + EXPECT_EQ(2, finder.Find(0x01010002)); + EXPECT_EQ(end, finder.Find(0x01010003)); + EXPECT_EQ(3, finder.Find(0x01010004)); + EXPECT_EQ(end, finder.Find(0x01010005)); + EXPECT_EQ(end, finder.Find(0x01010006)); + EXPECT_EQ(4, finder.Find(0x02010001)); + EXPECT_EQ(end, finder.Find(0x02010002)); } TEST(AttributeFinderTest, FindAttributesInPackageUnsortedAttributeList) { - const int end = sizeof(packageUnsortedAttributes) / sizeof(*packageUnsortedAttributes); - MockAttributeFinder finder(packageUnsortedAttributes, end); - - EXPECT_EQ(2, finder.find(0x01010000)); - EXPECT_EQ(3, finder.find(0x01010001)); - EXPECT_EQ(4, finder.find(0x01010002)); - EXPECT_EQ(end, finder.find(0x01010003)); - EXPECT_EQ(5, finder.find(0x01010004)); - EXPECT_EQ(end, finder.find(0x01010005)); - EXPECT_EQ(end, finder.find(0x01010006)); - EXPECT_EQ(0, finder.find(0x02010001)); - EXPECT_EQ(end, finder.find(0x02010002)); - EXPECT_EQ(1, finder.find(0x02010010)); - EXPECT_EQ(6, finder.find(0x7f010001)); + const int end = arraysize(kPackageUnsortedAttributes); + MockAttributeFinder finder(kPackageUnsortedAttributes, end); + + EXPECT_EQ(2, finder.Find(0x01010000)); + EXPECT_EQ(3, finder.Find(0x01010001)); + EXPECT_EQ(4, finder.Find(0x01010002)); + EXPECT_EQ(end, finder.Find(0x01010003)); + EXPECT_EQ(5, finder.Find(0x01010004)); + EXPECT_EQ(end, finder.Find(0x01010005)); + EXPECT_EQ(end, finder.Find(0x01010006)); + EXPECT_EQ(0, finder.Find(0x02010001)); + EXPECT_EQ(end, finder.Find(0x02010002)); + EXPECT_EQ(1, finder.Find(0x02010010)); + EXPECT_EQ(6, finder.Find(0x7f010001)); } TEST(AttributeFinderTest, FindAttributesInSinglePackageAttributeList) { - const int end = sizeof(singlePackageAttributes) / sizeof(*singlePackageAttributes); - MockAttributeFinder finder(singlePackageAttributes, end); - - EXPECT_EQ(end, finder.find(0x010100f4)); - EXPECT_EQ(end, finder.find(0x010100f5)); - EXPECT_EQ(end, finder.find(0x010100f6)); - EXPECT_EQ(end, finder.find(0x010100f7)); - EXPECT_EQ(end, finder.find(0x010100f8)); - EXPECT_EQ(end, finder.find(0x010100fa)); - EXPECT_EQ(0, finder.find(0x7f010007)); + const int end = arraysize(kSinglePackageAttributes); + MockAttributeFinder finder(kSinglePackageAttributes, end); + + EXPECT_EQ(end, finder.Find(0x010100f4)); + EXPECT_EQ(end, finder.Find(0x010100f5)); + EXPECT_EQ(end, finder.Find(0x010100f6)); + EXPECT_EQ(end, finder.Find(0x010100f7)); + EXPECT_EQ(end, finder.Find(0x010100f8)); + EXPECT_EQ(end, finder.Find(0x010100fa)); + EXPECT_EQ(0, finder.Find(0x7f010007)); } diff --git a/libs/androidfw/tests/AttributeResolution_test.cpp b/libs/androidfw/tests/AttributeResolution_test.cpp new file mode 100644 index 000000000000..7fbe6d360010 --- /dev/null +++ b/libs/androidfw/tests/AttributeResolution_test.cpp @@ -0,0 +1,201 @@ +/* + * Copyright (C) 2016 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. + */ + +#include "androidfw/AttributeResolution.h" +#include "TestHelpers.h" +#include "data/styles/R.h" + +#include <android-base/file.h> +#include <android-base/macros.h> + +using namespace android; +using android::base::ReadFileToString; +using com::android::app::R; + +class AttributeResolutionTest : public ::testing::Test { + public: + virtual void SetUp() override { + std::string test_source_dir = TestSourceDir(); + std::string contents; + LOG_ALWAYS_FATAL_IF(!ReadFileToString(test_source_dir + "/styles/resources.arsc", &contents)); + LOG_ALWAYS_FATAL_IF( + table_.add(contents.data(), contents.size(), 1 /*cookie*/, true /*copyData*/) != NO_ERROR); + } + + protected: + ResTable table_; +}; + +class AttributeResolutionXmlTest : public AttributeResolutionTest { + public: + virtual void SetUp() override { + AttributeResolutionTest::SetUp(); + std::string test_source_dir = TestSourceDir(); + std::string contents; + LOG_ALWAYS_FATAL_IF(!ReadFileToString(test_source_dir + "/styles/layout.xml", &contents)); + LOG_ALWAYS_FATAL_IF(xml_parser_.setTo(contents.data(), contents.size(), true /*copyData*/) != + NO_ERROR); + + // Skip to the first tag. + while (xml_parser_.next() != ResXMLParser::START_TAG) { + } + } + + protected: + ResXMLTree xml_parser_; +}; + +TEST_F(AttributeResolutionTest, Theme) { + ResTable::Theme theme(table_); + ASSERT_EQ(NO_ERROR, theme.applyStyle(R::style::StyleTwo)); + + uint32_t attrs[] = {R::attr::attr_one, R::attr::attr_two, R::attr::attr_three, + R::attr::attr_four}; + std::vector<uint32_t> values; + values.resize(arraysize(attrs) * 6); + + ASSERT_TRUE(ResolveAttrs(&theme, 0 /*def_style_attr*/, 0 /*def_style_res*/, + nullptr /*src_values*/, 0 /*src_values_length*/, attrs, arraysize(attrs), + values.data(), nullptr /*out_indices*/)); + + const uint32_t public_flag = ResTable_typeSpec::SPEC_PUBLIC; + + const uint32_t* values_cursor = values.data(); + EXPECT_EQ(Res_value::TYPE_INT_DEC, values_cursor[STYLE_TYPE]); + EXPECT_EQ(1u, values_cursor[STYLE_DATA]); + EXPECT_EQ(0u, values_cursor[STYLE_RESOURCE_ID]); + EXPECT_EQ(1u, values_cursor[STYLE_ASSET_COOKIE]); + EXPECT_EQ(0u, values_cursor[STYLE_DENSITY]); + EXPECT_EQ(public_flag, values_cursor[STYLE_CHANGING_CONFIGURATIONS]); + + values_cursor += STYLE_NUM_ENTRIES; + EXPECT_EQ(Res_value::TYPE_STRING, values_cursor[STYLE_TYPE]); + EXPECT_EQ(0u, values_cursor[STYLE_RESOURCE_ID]); + EXPECT_EQ(1u, values_cursor[STYLE_ASSET_COOKIE]); + EXPECT_EQ(0u, values_cursor[STYLE_DENSITY]); + EXPECT_EQ(public_flag, values_cursor[STYLE_CHANGING_CONFIGURATIONS]); + + values_cursor += STYLE_NUM_ENTRIES; + EXPECT_EQ(Res_value::TYPE_INT_DEC, values_cursor[STYLE_TYPE]); + EXPECT_EQ(3u, values_cursor[STYLE_DATA]); + EXPECT_EQ(0u, values_cursor[STYLE_RESOURCE_ID]); + EXPECT_EQ(1u, values_cursor[STYLE_ASSET_COOKIE]); + EXPECT_EQ(0u, values_cursor[STYLE_DENSITY]); + EXPECT_EQ(public_flag, values_cursor[STYLE_CHANGING_CONFIGURATIONS]); + + values_cursor += STYLE_NUM_ENTRIES; + EXPECT_EQ(Res_value::TYPE_NULL, values_cursor[STYLE_TYPE]); + EXPECT_EQ(Res_value::DATA_NULL_UNDEFINED, values_cursor[STYLE_DATA]); + EXPECT_EQ(0u, values_cursor[STYLE_RESOURCE_ID]); + EXPECT_EQ(uint32_t(-1), values_cursor[STYLE_ASSET_COOKIE]); + EXPECT_EQ(0u, values_cursor[STYLE_DENSITY]); + EXPECT_EQ(0u, values_cursor[STYLE_CHANGING_CONFIGURATIONS]); +} + +TEST_F(AttributeResolutionXmlTest, XmlParser) { + uint32_t attrs[] = {R::attr::attr_one, R::attr::attr_two, R::attr::attr_three, + R::attr::attr_four}; + std::vector<uint32_t> values; + values.resize(arraysize(attrs) * 6); + + ASSERT_TRUE(RetrieveAttributes(&table_, &xml_parser_, attrs, arraysize(attrs), values.data(), + nullptr /*out_indices*/)); + + uint32_t* values_cursor = values.data(); + EXPECT_EQ(Res_value::TYPE_NULL, values_cursor[STYLE_TYPE]); + EXPECT_EQ(0u, values_cursor[STYLE_DATA]); + EXPECT_EQ(0u, values_cursor[STYLE_RESOURCE_ID]); + EXPECT_EQ(uint32_t(-1), values_cursor[STYLE_ASSET_COOKIE]); + EXPECT_EQ(0u, values_cursor[STYLE_DENSITY]); + EXPECT_EQ(0u, values_cursor[STYLE_CHANGING_CONFIGURATIONS]); + + values_cursor += STYLE_NUM_ENTRIES; + EXPECT_EQ(Res_value::TYPE_NULL, values_cursor[STYLE_TYPE]); + EXPECT_EQ(0u, values_cursor[STYLE_DATA]); + EXPECT_EQ(0u, values_cursor[STYLE_RESOURCE_ID]); + EXPECT_EQ(uint32_t(-1), values_cursor[STYLE_ASSET_COOKIE]); + EXPECT_EQ(0u, values_cursor[STYLE_DENSITY]); + EXPECT_EQ(0u, values_cursor[STYLE_CHANGING_CONFIGURATIONS]); + + values_cursor += STYLE_NUM_ENTRIES; + EXPECT_EQ(Res_value::TYPE_INT_DEC, values_cursor[STYLE_TYPE]); + EXPECT_EQ(10u, values_cursor[STYLE_DATA]); + EXPECT_EQ(0u, values_cursor[STYLE_RESOURCE_ID]); + EXPECT_EQ(uint32_t(-1), values_cursor[STYLE_ASSET_COOKIE]); + EXPECT_EQ(0u, values_cursor[STYLE_DENSITY]); + EXPECT_EQ(0u, values_cursor[STYLE_CHANGING_CONFIGURATIONS]); + + values_cursor += STYLE_NUM_ENTRIES; + EXPECT_EQ(Res_value::TYPE_ATTRIBUTE, values_cursor[STYLE_TYPE]); + EXPECT_EQ(R::attr::attr_indirect, values_cursor[STYLE_DATA]); + EXPECT_EQ(0u, values_cursor[STYLE_RESOURCE_ID]); + EXPECT_EQ(uint32_t(-1), values_cursor[STYLE_ASSET_COOKIE]); + EXPECT_EQ(0u, values_cursor[STYLE_DENSITY]); + EXPECT_EQ(0u, values_cursor[STYLE_CHANGING_CONFIGURATIONS]); +} + +TEST_F(AttributeResolutionXmlTest, ThemeAndXmlParser) { + ResTable::Theme theme(table_); + ASSERT_EQ(NO_ERROR, theme.applyStyle(R::style::StyleTwo)); + + uint32_t attrs[] = {R::attr::attr_one, R::attr::attr_two, R::attr::attr_three, R::attr::attr_four, + R::attr::attr_five}; + std::vector<uint32_t> values; + values.resize(arraysize(attrs) * 6); + + ASSERT_TRUE(ApplyStyle(&theme, &xml_parser_, 0 /*def_style_attr*/, 0 /*def_style_res*/, attrs, + arraysize(attrs), values.data(), nullptr /*out_indices*/)); + + const uint32_t public_flag = ResTable_typeSpec::SPEC_PUBLIC; + + uint32_t* values_cursor = values.data(); + EXPECT_EQ(Res_value::TYPE_INT_DEC, values_cursor[STYLE_TYPE]); + EXPECT_EQ(1u, values_cursor[STYLE_DATA]); + EXPECT_EQ(0u, values_cursor[STYLE_RESOURCE_ID]); + EXPECT_EQ(1u, values_cursor[STYLE_ASSET_COOKIE]); + EXPECT_EQ(0u, values_cursor[STYLE_DENSITY]); + EXPECT_EQ(public_flag, values_cursor[STYLE_CHANGING_CONFIGURATIONS]); + + values_cursor += STYLE_NUM_ENTRIES; + EXPECT_EQ(Res_value::TYPE_STRING, values_cursor[STYLE_TYPE]); + EXPECT_EQ(0u, values_cursor[STYLE_RESOURCE_ID]); + EXPECT_EQ(1u, values_cursor[STYLE_ASSET_COOKIE]); + EXPECT_EQ(0u, values_cursor[STYLE_DENSITY]); + EXPECT_EQ(public_flag, values_cursor[STYLE_CHANGING_CONFIGURATIONS]); + + values_cursor += STYLE_NUM_ENTRIES; + EXPECT_EQ(Res_value::TYPE_INT_DEC, values_cursor[STYLE_TYPE]); + EXPECT_EQ(10u, values_cursor[STYLE_DATA]); + EXPECT_EQ(0u, values_cursor[STYLE_RESOURCE_ID]); + EXPECT_EQ(uint32_t(-1), values_cursor[STYLE_ASSET_COOKIE]); + EXPECT_EQ(0u, values_cursor[STYLE_DENSITY]); + EXPECT_EQ(0u, values_cursor[STYLE_CHANGING_CONFIGURATIONS]); + + values_cursor += STYLE_NUM_ENTRIES; + EXPECT_EQ(Res_value::TYPE_INT_DEC, values_cursor[STYLE_TYPE]); + EXPECT_EQ(3u, values_cursor[STYLE_DATA]); + EXPECT_EQ(0u, values_cursor[STYLE_RESOURCE_ID]); + EXPECT_EQ(1u, values_cursor[STYLE_ASSET_COOKIE]); + EXPECT_EQ(0u, values_cursor[STYLE_DENSITY]); + EXPECT_EQ(public_flag, values_cursor[STYLE_CHANGING_CONFIGURATIONS]); + + values_cursor += STYLE_NUM_ENTRIES; + EXPECT_EQ(Res_value::TYPE_STRING, values_cursor[STYLE_TYPE]); + EXPECT_EQ(R::string::string_one, values_cursor[STYLE_RESOURCE_ID]); + EXPECT_EQ(1u, values_cursor[STYLE_ASSET_COOKIE]); + EXPECT_EQ(0u, values_cursor[STYLE_DENSITY]); + EXPECT_EQ(public_flag, values_cursor[STYLE_CHANGING_CONFIGURATIONS]); +} diff --git a/libs/androidfw/tests/TestHelpers.cpp b/libs/androidfw/tests/TestHelpers.cpp index 41a19a7f2b24..3d1d5f5209f2 100644 --- a/libs/androidfw/tests/TestHelpers.cpp +++ b/libs/androidfw/tests/TestHelpers.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2014 The Android Open Source Project + * Copyright (C) 2016 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. @@ -17,32 +17,46 @@ #include "TestHelpers.h" #include <androidfw/ResourceTypes.h> -#include <utils/String8.h> #include <gtest/gtest.h> +#include <unistd.h> +#include <utils/String8.h> + +std::string TestSourceDir() { + const char* dir = getenv("ANDROID_BUILD_TOP"); + LOG_ALWAYS_FATAL_IF(dir == nullptr, "Environment variable ANDROID_BUILD_TOP must be set"); + std::string testdir = std::string(dir) + "/frameworks/base/libs/androidfw/tests/data"; + + // Check that the directory exists. + struct stat filestat; + LOG_ALWAYS_FATAL_IF(stat(testdir.c_str(), &filestat) != 0, "test data path '%s' does not exist", + testdir.c_str()); + return testdir; +} namespace android { -::testing::AssertionResult IsStringEqual(const ResTable& table, uint32_t resourceId, const char* expectedStr) { - Res_value val; - ssize_t block = table.getResource(resourceId, &val, MAY_NOT_BE_BAG); - if (block < 0) { - return ::testing::AssertionFailure() << "could not find resource"; - } - - if (val.dataType != Res_value::TYPE_STRING) { - return ::testing::AssertionFailure() << "resource is not a string"; - } - - const ResStringPool* pool = table.getTableStringBlock(block); - if (pool == NULL) { - return ::testing::AssertionFailure() << "table has no string pool for block " << block; - } - - const String8 actual = pool->string8ObjectAt(val.data); - if (String8(expectedStr) != actual) { - return ::testing::AssertionFailure() << actual.string(); - } - return ::testing::AssertionSuccess() << actual.string(); +::testing::AssertionResult IsStringEqual(const ResTable& table, uint32_t resource_id, + const char* expected_str) { + Res_value val; + ssize_t block = table.getResource(resource_id, &val, MAY_NOT_BE_BAG); + if (block < 0) { + return ::testing::AssertionFailure() << "could not find resource"; + } + + if (val.dataType != Res_value::TYPE_STRING) { + return ::testing::AssertionFailure() << "resource is not a string"; + } + + const ResStringPool* pool = table.getTableStringBlock(block); + if (pool == NULL) { + return ::testing::AssertionFailure() << "table has no string pool for block " << block; + } + + const String8 actual_str = pool->string8ObjectAt(val.data); + if (String8(expected_str) != actual_str) { + return ::testing::AssertionFailure() << actual_str.string(); + } + return ::testing::AssertionSuccess() << actual_str.string(); } -} // namespace android +} // namespace android diff --git a/libs/androidfw/tests/TestHelpers.h b/libs/androidfw/tests/TestHelpers.h index ff9be164dbb0..5f0c455211ec 100644 --- a/libs/androidfw/tests/TestHelpers.h +++ b/libs/androidfw/tests/TestHelpers.h @@ -1,35 +1,56 @@ +/* + * Copyright (C) 2016 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. + */ + #ifndef __TEST_HELPERS_H #define __TEST_HELPERS_H -#include <ostream> - #include <androidfw/ResourceTypes.h> -#include <utils/String8.h> -#include <utils/String16.h> #include <gtest/gtest.h> +#include <utils/String16.h> +#include <utils/String8.h> + +#include <ostream> +#include <string> + +std::string TestSourceDir(); static inline ::std::ostream& operator<<(::std::ostream& out, const android::String8& str) { - return out << str.string(); + return out << str.string(); } static inline ::std::ostream& operator<<(::std::ostream& out, const android::String16& str) { - return out << android::String8(str).string(); + return out << android::String8(str).string(); } namespace android { enum { MAY_NOT_BE_BAG = false }; -static inline bool operator==(const android::ResTable_config& a, const android::ResTable_config& b) { - return a.compare(b) == 0; +static inline bool operator==(const android::ResTable_config& a, + const android::ResTable_config& b) { + return a.compare(b) == 0; } static inline ::std::ostream& operator<<(::std::ostream& out, const android::ResTable_config& c) { - return out << c.toString().string(); + return out << c.toString().string(); } -::testing::AssertionResult IsStringEqual(const ResTable& table, uint32_t resourceId, const char* expectedStr); +::testing::AssertionResult IsStringEqual(const ResTable& table, uint32_t resource_id, + const char* expected_str); -} // namespace android +} // namespace android -#endif // __TEST_HELPERS_H +#endif // __TEST_HELPERS_H diff --git a/libs/androidfw/tests/data/.gitignore b/libs/androidfw/tests/data/.gitignore deleted file mode 100644 index c05cfb043024..000000000000 --- a/libs/androidfw/tests/data/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -*.apk -*.arsc diff --git a/libs/androidfw/tests/data/styles/AndroidManifest.xml b/libs/androidfw/tests/data/styles/AndroidManifest.xml new file mode 100644 index 000000000000..521131659cfe --- /dev/null +++ b/libs/androidfw/tests/data/styles/AndroidManifest.xml @@ -0,0 +1,19 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- Copyright (C) 2016 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. +--> + +<manifest xmlns:android="http://schemas.android.com/apk/res/android" + package="com.android.app"> +</manifest> diff --git a/libs/androidfw/tests/data/styles/R.h b/libs/androidfw/tests/data/styles/R.h new file mode 100644 index 000000000000..6dc6edec64ab --- /dev/null +++ b/libs/androidfw/tests/data/styles/R.h @@ -0,0 +1,35 @@ +#include <cstdint> + +namespace com { +namespace android { +namespace app { + +struct R { + struct attr { + enum : uint32_t { + attr_one = 0x7f010000u, + attr_two = 0x7f010001u, + attr_three = 0x7f010002u, + attr_four = 0x7f010003u, + attr_five = 0x7f010004u, + attr_indirect = 0x7f010005u, + }; + }; + + struct string { + enum : uint32_t { + string_one = 0x7f030000u, + }; + }; + + struct style { + enum : uint32_t { + StyleOne = 0x7f020000u, + StyleTwo = 0x7f020001u, + }; + }; +}; + +} // namespace app +} // namespace android +} // namespace com diff --git a/libs/androidfw/tests/data/styles/build.sh b/libs/androidfw/tests/data/styles/build.sh new file mode 100755 index 000000000000..e763421626cf --- /dev/null +++ b/libs/androidfw/tests/data/styles/build.sh @@ -0,0 +1,7 @@ +#!/bin/bash + +set -e + +aapt package -F package.apk -M AndroidManifest.xml -S res +unzip -j package.apk resources.arsc res/layout/layout.xml +rm package.apk diff --git a/libs/androidfw/tests/data/styles/layout.xml b/libs/androidfw/tests/data/styles/layout.xml Binary files differnew file mode 100644 index 000000000000..4997e71dce6d --- /dev/null +++ b/libs/androidfw/tests/data/styles/layout.xml diff --git a/libs/androidfw/tests/data/styles/res/layout/layout.xml b/libs/androidfw/tests/data/styles/res/layout/layout.xml new file mode 100644 index 000000000000..f3aa0f83d9a3 --- /dev/null +++ b/libs/androidfw/tests/data/styles/res/layout/layout.xml @@ -0,0 +1,5 @@ +<?xml version="1.0" encoding="utf-8"?> +<View xmlns:app="http://schemas.android.com/apk/res-auto" + app:attr_four="?attr/attr_indirect" + app:attr_three="10" /> + diff --git a/libs/androidfw/tests/data/styles/res/values/styles.xml b/libs/androidfw/tests/data/styles/res/values/styles.xml new file mode 100644 index 000000000000..70c54f6c4b96 --- /dev/null +++ b/libs/androidfw/tests/data/styles/res/values/styles.xml @@ -0,0 +1,52 @@ +<?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> + <public type="attr" name="attr_one" id="0x7f010000" /> + <attr name="attr_one" /> + + <public type="attr" name="attr_two" id="0x7f010001" /> + <attr name="attr_two" /> + + <public type="attr" name="attr_three" id="0x7f010002" /> + <attr name="attr_three" /> + + <public type="attr" name="attr_four" id="0x7f010003" /> + <attr name="attr_four" /> + + <public type="attr" name="attr_five" id="0x7f010004" /> + <attr name="attr_five" /> + + <public type="attr" name="attr_indirect" id="0x7f010005" /> + <attr name="attr_indirect" /> + + <public type="string" name="string_one" id="0x7f030000" /> + <string name="string_one">Hi</string> + + <public type="style" name="StyleOne" id="0x7f020000" /> + <style name="StyleOne"> + <item name="attr_one">1</item> + </style> + + <public type="style" name="StyleTwo" id="0x7f020001" /> + <style name="StyleTwo" parent="@style/StyleOne"> + <item name="attr_indirect">3</item> + <item name="attr_two">"string"</item> + <item name="attr_three">?attr/attr_indirect</item> + <item name="attr_five">@string/string_one</item> + </style> + +</resources> diff --git a/libs/androidfw/tests/data/styles/resources.arsc b/libs/androidfw/tests/data/styles/resources.arsc Binary files differnew file mode 100644 index 000000000000..8f65c9ad1507 --- /dev/null +++ b/libs/androidfw/tests/data/styles/resources.arsc |