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