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
diff --git a/libs/androidfw/.clang-format b/libs/androidfw/.clang-format
new file mode 100644
index 0000000..ee1bee2
--- /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 0000000..f281921
--- /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 ad428a4..00f7a42 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 @@
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) {
+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;
+
+ int indices_idx = 0;
+
+ // 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];
+
if (kDebugStyles) {
- ALOGI("APPLY STYLE: theme=0x%p defStyleAttr=0x%x "
- "defStyleRes=0x%x", theme, defStyleAttr, defStyleRes);
+ ALOGI("RETRIEVING ATTR 0x%08x...", cur_ident);
}
- const ResTable& res = theme->getResTable();
- ResTable_config config;
- Res_value value;
+ ssize_t block = -1;
+ uint32_t type_set_flags = 0;
- int indicesIdx = 0;
+ value.dataType = Res_value::TYPE_NULL;
+ value.data = Res_value::DATA_NULL_UNDEFINED;
+ config.density = 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;
- }
- }
+ // 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.
+
+ // 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);
+ }
}
- // 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 (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("RETRIEVING ATTR 0x%08x...", curIdent);
+ 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.
- 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);
- }
- }
-
- 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);
- }
- }
- }
-
- 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);
- }
- }
- }
-
- // 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;
- }
-
+ 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;
+ }
}
- res.unlock();
-
- if (outIndices != NULL) {
- outIndices[0] = indicesIdx;
+ // 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;
}
- 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);
+ ALOGI("Attribute 0x%08x: type=0x%x, data=0x%08x", cur_ident, value.dataType, value.data);
}
- const ResTable& res = theme->getResTable();
- ResTable_config config;
+ // 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;
+ }
+
+ out_values += STYLE_NUM_ENTRIES;
+ }
+
+ res.unlock();
+
+ if (out_indices != NULL) {
+ out_indices[0] = indices_idx;
+ }
+ return true;
+}
+
+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;
+
+ int indices_idx = 0;
+
+ // 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;
+ }
+ }
+ }
- int indicesIdx = 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;
- }
+ // 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];
+
+ if (kDebugStyles) {
+ ALOGI("RETRIEVING ATTR 0x%08x...", cur_ident);
}
- // 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;
- }
- }
+ 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);
+ }
}
- // 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];
-
+ 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);
+ ALOGI("-> From 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.
- 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 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);
}
+ }
+ }
- 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);
- }
- }
+ 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);
}
-
- 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);
- }
- }
- }
-
- 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);
- }
- }
- }
-
- // 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);
+ ALOGI("-> Resolved 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 != 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;
- }
-
- outValues += STYLE_NUM_ENTRIES;
+ }
}
- res.unlock();
-
- if (outIndices != NULL) {
- outIndices[0] = indicesIdx;
+ // 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;
}
- return true;
+
+ if (kDebugStyles) {
+ ALOGI("Attribute 0x%08x: type=0x%x, data=0x%08x", cur_ident, value.dataType, value.data);
+ }
+
+ // 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;
+ }
+
+ out_values += STYLE_NUM_ENTRIES;
+ }
+
+ res.unlock();
+
+ if (out_indices != NULL) {
+ out_indices[0] = indices_idx;
+ }
+ 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;
+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;
- int indicesIdx = 0;
+ int indices_idx = 0;
- // Now lock down the resource object and start pulling stuff from it.
- res->lock();
+ // Now lock down the resource object and start pulling stuff from it.
+ res->lock();
- // Retrieve the XML attributes, if requested.
- const size_t NX = xmlParser->getAttributeCount();
- size_t ix=0;
- uint32_t curXmlAttr = xmlParser->getAttributeNameResID(ix);
+ // 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);
- static const ssize_t kXmlBlock = 0x10000000;
+ static const ssize_t kXmlBlock = 0x10000000;
- // 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 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;
- // 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;
+ value.dataType = Res_value::TYPE_NULL;
+ value.data = Res_value::DATA_NULL_UNDEFINED;
+ config.density = 0;
- // 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);
- }
-
- //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;
- }
-
- // 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;
- }
-
- //printf("Attribute 0x%08x: final type=0x%x, data=0x%08x\n", 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;
- }
-
- outValues += STYLE_NUM_ENTRIES;
+ // 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);
}
- res->unlock();
-
- if (outIndices != NULL) {
- outIndices[0] = indicesIdx;
+ 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;
}
- return true;
+
+ // 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;
+ }
+
+ // 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;
+ }
+
+ out_values += STYLE_NUM_ENTRIES;
+ }
+
+ 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 1fe1773..6837f25 100644
--- a/libs/androidfw/tests/Android.mk
+++ b/libs/androidfw/tests/Android.mk
@@ -40,7 +40,7 @@
-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 @@
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_SHARED_LIBRARIES := \
libandroidfw \
+ libbase \
libcutils \
libutils \
libui \
diff --git a/libs/androidfw/tests/AttributeFinder_test.cpp b/libs/androidfw/tests/AttributeFinder_test.cpp
index 5054624..d9ed48e 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);
- }
+ public:
+ MockAttributeFinder(const uint32_t* attrs, int len) : BackTrackingAttributeFinder(0, len) {
+ attrs_ = new uint32_t[len];
+ memcpy(attrs_, attrs, sizeof(*attrs) * len);
+ }
- ~MockAttributeFinder() {
- delete mAttrs;
- }
+ ~MockAttributeFinder() { delete attrs_; }
- inline uint32_t getAttribute(const int index) const {
- return mAttrs[index];
- }
+ inline uint32_t GetAttribute(const int index) const { return attrs_[index]; }
-private:
- uint32_t* mAttrs;
+ private:
+ uint32_t* attrs_;
};
-static const uint32_t sortedAttributes[] = {
- 0x01010000, 0x01010001, 0x01010002, 0x01010004,
- 0x02010001, 0x02010010, 0x7f010001
-};
+static const uint32_t kSortedAttributes[] = {0x01010000, 0x01010001, 0x01010002, 0x01010004,
+ 0x02010001, 0x02010010, 0x7f010001};
-static const uint32_t packageUnsortedAttributes[] = {
- 0x02010001, 0x02010010, 0x01010000, 0x01010001,
- 0x01010002, 0x01010004, 0x7f010001
-};
+static const uint32_t kPackageUnsortedAttributes[] = {
+ 0x02010001, 0x02010010, 0x01010000, 0x01010001, 0x01010002, 0x01010004, 0x7f010001};
-static const uint32_t singlePackageAttributes[] = {
- 0x7f010007, 0x7f01000a, 0x7f01000d, 0x00000000
-};
+static const uint32_t kSinglePackageAttributes[] = {0x7f010007, 0x7f01000a, 0x7f01000d, 0x00000000};
TEST(AttributeFinderTest, IteratesSequentially) {
- const int end = sizeof(sortedAttributes) / sizeof(*sortedAttributes);
- MockAttributeFinder finder(sortedAttributes, end);
+ 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));
+ 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);
+ 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));
+ 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);
+ 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));
+ 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);
+ 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));
+ 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);
+ 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));
+ 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 0000000..7fbe6d3
--- /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 41a19a7..3d1d5f5 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";
- }
+::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";
- }
+ 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 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();
+ 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 ff9be16..5f0c4552 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 c05cfb0..0000000
--- 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 0000000..5211316
--- /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 0000000..6dc6ede
--- /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 0000000..e763421
--- /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
new file mode 100644
index 0000000..4997e71
--- /dev/null
+++ b/libs/androidfw/tests/data/styles/layout.xml
Binary files differ
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 0000000..f3aa0f8
--- /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 0000000..70c54f6
--- /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
new file mode 100644
index 0000000..8f65c9a
--- /dev/null
+++ b/libs/androidfw/tests/data/styles/resources.arsc
Binary files differ