14452e137ffc02ab4e32aab2b2ec7192b45d9f494Adam Lesinski/*
24452e137ffc02ab4e32aab2b2ec7192b45d9f494Adam Lesinski * Copyright (C) 2016 The Android Open Source Project
34452e137ffc02ab4e32aab2b2ec7192b45d9f494Adam Lesinski *
44452e137ffc02ab4e32aab2b2ec7192b45d9f494Adam Lesinski * Licensed under the Apache License, Version 2.0 (the "License");
54452e137ffc02ab4e32aab2b2ec7192b45d9f494Adam Lesinski * you may not use this file except in compliance with the License.
64452e137ffc02ab4e32aab2b2ec7192b45d9f494Adam Lesinski * You may obtain a copy of the License at
74452e137ffc02ab4e32aab2b2ec7192b45d9f494Adam Lesinski *
84452e137ffc02ab4e32aab2b2ec7192b45d9f494Adam Lesinski *      http://www.apache.org/licenses/LICENSE-2.0
94452e137ffc02ab4e32aab2b2ec7192b45d9f494Adam Lesinski *
104452e137ffc02ab4e32aab2b2ec7192b45d9f494Adam Lesinski * Unless required by applicable law or agreed to in writing, software
114452e137ffc02ab4e32aab2b2ec7192b45d9f494Adam Lesinski * distributed under the License is distributed on an "AS IS" BASIS,
124452e137ffc02ab4e32aab2b2ec7192b45d9f494Adam Lesinski * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
134452e137ffc02ab4e32aab2b2ec7192b45d9f494Adam Lesinski * See the License for the specific language governing permissions and
144452e137ffc02ab4e32aab2b2ec7192b45d9f494Adam Lesinski * limitations under the License.
154452e137ffc02ab4e32aab2b2ec7192b45d9f494Adam Lesinski */
164452e137ffc02ab4e32aab2b2ec7192b45d9f494Adam Lesinski
174452e137ffc02ab4e32aab2b2ec7192b45d9f494Adam Lesinski#include "androidfw/AttributeResolution.h"
184452e137ffc02ab4e32aab2b2ec7192b45d9f494Adam Lesinski
194452e137ffc02ab4e32aab2b2ec7192b45d9f494Adam Lesinski#include <cstdint>
204452e137ffc02ab4e32aab2b2ec7192b45d9f494Adam Lesinski
216f773a0d8717162f81ff21d943baaa539a2d6c7eMark Salyzyn#include <log/log.h>
224c67a475a334e4f65238d439a3339195e03c03beAdam Lesinski
234c67a475a334e4f65238d439a3339195e03c03beAdam Lesinski#include "androidfw/AttributeFinder.h"
244c67a475a334e4f65238d439a3339195e03c03beAdam Lesinski#include "androidfw/ResourceTypes.h"
254c67a475a334e4f65238d439a3339195e03c03beAdam Lesinski
264452e137ffc02ab4e32aab2b2ec7192b45d9f494Adam Lesinskiconstexpr bool kDebugStyles = false;
274452e137ffc02ab4e32aab2b2ec7192b45d9f494Adam Lesinski
284452e137ffc02ab4e32aab2b2ec7192b45d9f494Adam Lesinskinamespace android {
294452e137ffc02ab4e32aab2b2ec7192b45d9f494Adam Lesinski
304c67a475a334e4f65238d439a3339195e03c03beAdam Lesinskiclass XmlAttributeFinder
314c67a475a334e4f65238d439a3339195e03c03beAdam Lesinski    : public BackTrackingAttributeFinder<XmlAttributeFinder, size_t> {
327a37b74d37ff79e805c9e97d977e07bfec753c5aAdam Lesinski public:
337a37b74d37ff79e805c9e97d977e07bfec753c5aAdam Lesinski  explicit XmlAttributeFinder(const ResXMLParser* parser)
344c67a475a334e4f65238d439a3339195e03c03beAdam Lesinski      : BackTrackingAttributeFinder(
354c67a475a334e4f65238d439a3339195e03c03beAdam Lesinski            0, parser != nullptr ? parser->getAttributeCount() : 0),
367a37b74d37ff79e805c9e97d977e07bfec753c5aAdam Lesinski        parser_(parser) {}
374452e137ffc02ab4e32aab2b2ec7192b45d9f494Adam Lesinski
384c67a475a334e4f65238d439a3339195e03c03beAdam Lesinski  inline uint32_t GetAttribute(size_t index) const {
394c67a475a334e4f65238d439a3339195e03c03beAdam Lesinski    return parser_->getAttributeNameResID(index);
404c67a475a334e4f65238d439a3339195e03c03beAdam Lesinski  }
414452e137ffc02ab4e32aab2b2ec7192b45d9f494Adam Lesinski
427a37b74d37ff79e805c9e97d977e07bfec753c5aAdam Lesinski private:
437a37b74d37ff79e805c9e97d977e07bfec753c5aAdam Lesinski  const ResXMLParser* parser_;
444452e137ffc02ab4e32aab2b2ec7192b45d9f494Adam Lesinski};
454452e137ffc02ab4e32aab2b2ec7192b45d9f494Adam Lesinski
467a37b74d37ff79e805c9e97d977e07bfec753c5aAdam Lesinskiclass BagAttributeFinder
4732e7501a27f0f19bccdf9e91f9b87869c093f695Adam Lesinski    : public BackTrackingAttributeFinder<BagAttributeFinder, const ResTable::bag_entry*> {
487a37b74d37ff79e805c9e97d977e07bfec753c5aAdam Lesinski public:
494c67a475a334e4f65238d439a3339195e03c03beAdam Lesinski  BagAttributeFinder(const ResTable::bag_entry* start,
504c67a475a334e4f65238d439a3339195e03c03beAdam Lesinski                     const ResTable::bag_entry* end)
517a37b74d37ff79e805c9e97d977e07bfec753c5aAdam Lesinski      : BackTrackingAttributeFinder(start, end) {}
524452e137ffc02ab4e32aab2b2ec7192b45d9f494Adam Lesinski
537a37b74d37ff79e805c9e97d977e07bfec753c5aAdam Lesinski  inline uint32_t GetAttribute(const ResTable::bag_entry* entry) const {
547a37b74d37ff79e805c9e97d977e07bfec753c5aAdam Lesinski    return entry->map.name.ident;
557a37b74d37ff79e805c9e97d977e07bfec753c5aAdam Lesinski  }
564452e137ffc02ab4e32aab2b2ec7192b45d9f494Adam Lesinski};
574452e137ffc02ab4e32aab2b2ec7192b45d9f494Adam Lesinski
584c67a475a334e4f65238d439a3339195e03c03beAdam Lesinskibool ResolveAttrs(ResTable::Theme* theme, uint32_t def_style_attr,
594c67a475a334e4f65238d439a3339195e03c03beAdam Lesinski                  uint32_t def_style_res, uint32_t* src_values,
604c67a475a334e4f65238d439a3339195e03c03beAdam Lesinski                  size_t src_values_length, uint32_t* attrs,
614c67a475a334e4f65238d439a3339195e03c03beAdam Lesinski                  size_t attrs_length, uint32_t* out_values,
624c67a475a334e4f65238d439a3339195e03c03beAdam Lesinski                  uint32_t* out_indices) {
637a37b74d37ff79e805c9e97d977e07bfec753c5aAdam Lesinski  if (kDebugStyles) {
644c67a475a334e4f65238d439a3339195e03c03beAdam Lesinski    ALOGI("APPLY STYLE: theme=0x%p defStyleAttr=0x%x defStyleRes=0x%x", theme,
654c67a475a334e4f65238d439a3339195e03c03beAdam Lesinski          def_style_attr, def_style_res);
667a37b74d37ff79e805c9e97d977e07bfec753c5aAdam Lesinski  }
674452e137ffc02ab4e32aab2b2ec7192b45d9f494Adam Lesinski
687a37b74d37ff79e805c9e97d977e07bfec753c5aAdam Lesinski  const ResTable& res = theme->getResTable();
697a37b74d37ff79e805c9e97d977e07bfec753c5aAdam Lesinski  ResTable_config config;
707a37b74d37ff79e805c9e97d977e07bfec753c5aAdam Lesinski  Res_value value;
714452e137ffc02ab4e32aab2b2ec7192b45d9f494Adam Lesinski
727a37b74d37ff79e805c9e97d977e07bfec753c5aAdam Lesinski  int indices_idx = 0;
734452e137ffc02ab4e32aab2b2ec7192b45d9f494Adam Lesinski
747a37b74d37ff79e805c9e97d977e07bfec753c5aAdam Lesinski  // Load default style from attribute, if specified...
757a37b74d37ff79e805c9e97d977e07bfec753c5aAdam Lesinski  uint32_t def_style_bag_type_set_flags = 0;
767a37b74d37ff79e805c9e97d977e07bfec753c5aAdam Lesinski  if (def_style_attr != 0) {
777a37b74d37ff79e805c9e97d977e07bfec753c5aAdam Lesinski    Res_value value;
7832e7501a27f0f19bccdf9e91f9b87869c093f695Adam Lesinski    if (theme->getAttribute(def_style_attr, &value, &def_style_bag_type_set_flags) >= 0) {
797a37b74d37ff79e805c9e97d977e07bfec753c5aAdam Lesinski      if (value.dataType == Res_value::TYPE_REFERENCE) {
807a37b74d37ff79e805c9e97d977e07bfec753c5aAdam Lesinski        def_style_res = value.data;
817a37b74d37ff79e805c9e97d977e07bfec753c5aAdam Lesinski      }
824452e137ffc02ab4e32aab2b2ec7192b45d9f494Adam Lesinski    }
837a37b74d37ff79e805c9e97d977e07bfec753c5aAdam Lesinski  }
847a37b74d37ff79e805c9e97d977e07bfec753c5aAdam Lesinski
857a37b74d37ff79e805c9e97d977e07bfec753c5aAdam Lesinski  // Now lock down the resource object and start pulling stuff from it.
867a37b74d37ff79e805c9e97d977e07bfec753c5aAdam Lesinski  res.lock();
877a37b74d37ff79e805c9e97d977e07bfec753c5aAdam Lesinski
887a37b74d37ff79e805c9e97d977e07bfec753c5aAdam Lesinski  // Retrieve the default style bag, if requested.
894c67a475a334e4f65238d439a3339195e03c03beAdam Lesinski  const ResTable::bag_entry* def_style_start = nullptr;
907a37b74d37ff79e805c9e97d977e07bfec753c5aAdam Lesinski  uint32_t def_style_type_set_flags = 0;
914c67a475a334e4f65238d439a3339195e03c03beAdam Lesinski  ssize_t bag_off = def_style_res != 0
924c67a475a334e4f65238d439a3339195e03c03beAdam Lesinski                        ? res.getBagLocked(def_style_res, &def_style_start,
934c67a475a334e4f65238d439a3339195e03c03beAdam Lesinski                                           &def_style_type_set_flags)
944c67a475a334e4f65238d439a3339195e03c03beAdam Lesinski                        : -1;
957a37b74d37ff79e805c9e97d977e07bfec753c5aAdam Lesinski  def_style_type_set_flags |= def_style_bag_type_set_flags;
964c67a475a334e4f65238d439a3339195e03c03beAdam Lesinski  const ResTable::bag_entry* const def_style_end =
974c67a475a334e4f65238d439a3339195e03c03beAdam Lesinski      def_style_start + (bag_off >= 0 ? bag_off : 0);
987a37b74d37ff79e805c9e97d977e07bfec753c5aAdam Lesinski  BagAttributeFinder def_style_attr_finder(def_style_start, def_style_end);
997a37b74d37ff79e805c9e97d977e07bfec753c5aAdam Lesinski
1007a37b74d37ff79e805c9e97d977e07bfec753c5aAdam Lesinski  // Now iterate through all of the attributes that the client has requested,
1017a37b74d37ff79e805c9e97d977e07bfec753c5aAdam Lesinski  // filling in each with whatever data we can find.
1027a37b74d37ff79e805c9e97d977e07bfec753c5aAdam Lesinski  for (size_t ii = 0; ii < attrs_length; ii++) {
1037a37b74d37ff79e805c9e97d977e07bfec753c5aAdam Lesinski    const uint32_t cur_ident = attrs[ii];
1044452e137ffc02ab4e32aab2b2ec7192b45d9f494Adam Lesinski
1057a37b74d37ff79e805c9e97d977e07bfec753c5aAdam Lesinski    if (kDebugStyles) {
1067a37b74d37ff79e805c9e97d977e07bfec753c5aAdam Lesinski      ALOGI("RETRIEVING ATTR 0x%08x...", cur_ident);
1077a37b74d37ff79e805c9e97d977e07bfec753c5aAdam Lesinski    }
1084452e137ffc02ab4e32aab2b2ec7192b45d9f494Adam Lesinski
1097a37b74d37ff79e805c9e97d977e07bfec753c5aAdam Lesinski    ssize_t block = -1;
1107a37b74d37ff79e805c9e97d977e07bfec753c5aAdam Lesinski    uint32_t type_set_flags = 0;
1114452e137ffc02ab4e32aab2b2ec7192b45d9f494Adam Lesinski
1127a37b74d37ff79e805c9e97d977e07bfec753c5aAdam Lesinski    value.dataType = Res_value::TYPE_NULL;
1137a37b74d37ff79e805c9e97d977e07bfec753c5aAdam Lesinski    value.data = Res_value::DATA_NULL_UNDEFINED;
1147a37b74d37ff79e805c9e97d977e07bfec753c5aAdam Lesinski    config.density = 0;
1154452e137ffc02ab4e32aab2b2ec7192b45d9f494Adam Lesinski
1167a37b74d37ff79e805c9e97d977e07bfec753c5aAdam Lesinski    // Try to find a value for this attribute...  we prioritize values
1177a37b74d37ff79e805c9e97d977e07bfec753c5aAdam Lesinski    // coming from, first XML attributes, then XML style, then default
1187a37b74d37ff79e805c9e97d977e07bfec753c5aAdam Lesinski    // style, and finally the theme.
1194452e137ffc02ab4e32aab2b2ec7192b45d9f494Adam Lesinski
1207a37b74d37ff79e805c9e97d977e07bfec753c5aAdam Lesinski    // Retrieve the current input value if available.
1217a37b74d37ff79e805c9e97d977e07bfec753c5aAdam Lesinski    if (src_values_length > 0 && src_values[ii] != 0) {
1227a37b74d37ff79e805c9e97d977e07bfec753c5aAdam Lesinski      value.dataType = Res_value::TYPE_ATTRIBUTE;
1237a37b74d37ff79e805c9e97d977e07bfec753c5aAdam Lesinski      value.data = src_values[ii];
1247a37b74d37ff79e805c9e97d977e07bfec753c5aAdam Lesinski      if (kDebugStyles) {
1254c67a475a334e4f65238d439a3339195e03c03beAdam Lesinski        ALOGI("-> From values: type=0x%x, data=0x%08x", value.dataType,
1264c67a475a334e4f65238d439a3339195e03c03beAdam Lesinski              value.data);
1277a37b74d37ff79e805c9e97d977e07bfec753c5aAdam Lesinski      }
12832e7501a27f0f19bccdf9e91f9b87869c093f695Adam Lesinski    } else {
12932e7501a27f0f19bccdf9e91f9b87869c093f695Adam Lesinski      const ResTable::bag_entry* const def_style_entry = def_style_attr_finder.Find(cur_ident);
1307a37b74d37ff79e805c9e97d977e07bfec753c5aAdam Lesinski      if (def_style_entry != def_style_end) {
1317a37b74d37ff79e805c9e97d977e07bfec753c5aAdam Lesinski        block = def_style_entry->stringBlock;
1327a37b74d37ff79e805c9e97d977e07bfec753c5aAdam Lesinski        type_set_flags = def_style_type_set_flags;
1337a37b74d37ff79e805c9e97d977e07bfec753c5aAdam Lesinski        value = def_style_entry->map.value;
1347a37b74d37ff79e805c9e97d977e07bfec753c5aAdam Lesinski        if (kDebugStyles) {
13532e7501a27f0f19bccdf9e91f9b87869c093f695Adam Lesinski          ALOGI("-> From def style: type=0x%x, data=0x%08x", value.dataType, value.data);
1364452e137ffc02ab4e32aab2b2ec7192b45d9f494Adam Lesinski        }
1377a37b74d37ff79e805c9e97d977e07bfec753c5aAdam Lesinski      }
1387a37b74d37ff79e805c9e97d977e07bfec753c5aAdam Lesinski    }
1394452e137ffc02ab4e32aab2b2ec7192b45d9f494Adam Lesinski
1407a37b74d37ff79e805c9e97d977e07bfec753c5aAdam Lesinski    uint32_t resid = 0;
1417a37b74d37ff79e805c9e97d977e07bfec753c5aAdam Lesinski    if (value.dataType != Res_value::TYPE_NULL) {
1427a37b74d37ff79e805c9e97d977e07bfec753c5aAdam Lesinski      // Take care of resolving the found resource to its final value.
14332e7501a27f0f19bccdf9e91f9b87869c093f695Adam Lesinski      ssize_t new_block =
14432e7501a27f0f19bccdf9e91f9b87869c093f695Adam Lesinski          theme->resolveAttributeReference(&value, block, &resid, &type_set_flags, &config);
1457a37b74d37ff79e805c9e97d977e07bfec753c5aAdam Lesinski      if (new_block >= 0) block = new_block;
1467a37b74d37ff79e805c9e97d977e07bfec753c5aAdam Lesinski      if (kDebugStyles) {
14732e7501a27f0f19bccdf9e91f9b87869c093f695Adam Lesinski        ALOGI("-> Resolved attr: type=0x%x, data=0x%08x", value.dataType, value.data);
1487a37b74d37ff79e805c9e97d977e07bfec753c5aAdam Lesinski      }
14932e7501a27f0f19bccdf9e91f9b87869c093f695Adam Lesinski    } else if (value.data != Res_value::DATA_NULL_EMPTY) {
1507a37b74d37ff79e805c9e97d977e07bfec753c5aAdam Lesinski      // If we still don't have a value for this attribute, try to find
1517a37b74d37ff79e805c9e97d977e07bfec753c5aAdam Lesinski      // it in the theme!
15232e7501a27f0f19bccdf9e91f9b87869c093f695Adam Lesinski      ssize_t new_block = theme->getAttribute(cur_ident, &value, &type_set_flags);
1537a37b74d37ff79e805c9e97d977e07bfec753c5aAdam Lesinski      if (new_block >= 0) {
1544452e137ffc02ab4e32aab2b2ec7192b45d9f494Adam Lesinski        if (kDebugStyles) {
15532e7501a27f0f19bccdf9e91f9b87869c093f695Adam Lesinski          ALOGI("-> From theme: type=0x%x, data=0x%08x", value.dataType, value.data);
1564452e137ffc02ab4e32aab2b2ec7192b45d9f494Adam Lesinski        }
15732e7501a27f0f19bccdf9e91f9b87869c093f695Adam Lesinski        new_block = res.resolveReference(&value, new_block, &resid, &type_set_flags, &config);
1587a37b74d37ff79e805c9e97d977e07bfec753c5aAdam Lesinski        if (new_block >= 0) block = new_block;
1597a37b74d37ff79e805c9e97d977e07bfec753c5aAdam Lesinski        if (kDebugStyles) {
16032e7501a27f0f19bccdf9e91f9b87869c093f695Adam Lesinski          ALOGI("-> Resolved theme: type=0x%x, data=0x%08x", value.dataType, value.data);
1614452e137ffc02ab4e32aab2b2ec7192b45d9f494Adam Lesinski        }
1627a37b74d37ff79e805c9e97d977e07bfec753c5aAdam Lesinski      }
1637a37b74d37ff79e805c9e97d977e07bfec753c5aAdam Lesinski    }
1644452e137ffc02ab4e32aab2b2ec7192b45d9f494Adam Lesinski
1657a37b74d37ff79e805c9e97d977e07bfec753c5aAdam Lesinski    // Deal with the special @null value -- it turns back to TYPE_NULL.
1667a37b74d37ff79e805c9e97d977e07bfec753c5aAdam Lesinski    if (value.dataType == Res_value::TYPE_REFERENCE && value.data == 0) {
1677a37b74d37ff79e805c9e97d977e07bfec753c5aAdam Lesinski      if (kDebugStyles) {
1687a37b74d37ff79e805c9e97d977e07bfec753c5aAdam Lesinski        ALOGI("-> Setting to @null!");
1697a37b74d37ff79e805c9e97d977e07bfec753c5aAdam Lesinski      }
1707a37b74d37ff79e805c9e97d977e07bfec753c5aAdam Lesinski      value.dataType = Res_value::TYPE_NULL;
1717a37b74d37ff79e805c9e97d977e07bfec753c5aAdam Lesinski      value.data = Res_value::DATA_NULL_UNDEFINED;
1727a37b74d37ff79e805c9e97d977e07bfec753c5aAdam Lesinski      block = -1;
1734452e137ffc02ab4e32aab2b2ec7192b45d9f494Adam Lesinski    }
1744452e137ffc02ab4e32aab2b2ec7192b45d9f494Adam Lesinski
1757a37b74d37ff79e805c9e97d977e07bfec753c5aAdam Lesinski    if (kDebugStyles) {
17632e7501a27f0f19bccdf9e91f9b87869c093f695Adam Lesinski      ALOGI("Attribute 0x%08x: type=0x%x, data=0x%08x", cur_ident, value.dataType, value.data);
1777a37b74d37ff79e805c9e97d977e07bfec753c5aAdam Lesinski    }
1784452e137ffc02ab4e32aab2b2ec7192b45d9f494Adam Lesinski
1797a37b74d37ff79e805c9e97d977e07bfec753c5aAdam Lesinski    // Write the final value back to Java.
1807a37b74d37ff79e805c9e97d977e07bfec753c5aAdam Lesinski    out_values[STYLE_TYPE] = value.dataType;
1817a37b74d37ff79e805c9e97d977e07bfec753c5aAdam Lesinski    out_values[STYLE_DATA] = value.data;
1827a37b74d37ff79e805c9e97d977e07bfec753c5aAdam Lesinski    out_values[STYLE_ASSET_COOKIE] =
1834c67a475a334e4f65238d439a3339195e03c03beAdam Lesinski        block != -1 ? static_cast<uint32_t>(res.getTableCookie(block))
1844c67a475a334e4f65238d439a3339195e03c03beAdam Lesinski                    : static_cast<uint32_t>(-1);
1857a37b74d37ff79e805c9e97d977e07bfec753c5aAdam Lesinski    out_values[STYLE_RESOURCE_ID] = resid;
1867a37b74d37ff79e805c9e97d977e07bfec753c5aAdam Lesinski    out_values[STYLE_CHANGING_CONFIGURATIONS] = type_set_flags;
1877a37b74d37ff79e805c9e97d977e07bfec753c5aAdam Lesinski    out_values[STYLE_DENSITY] = config.density;
1887a37b74d37ff79e805c9e97d977e07bfec753c5aAdam Lesinski
18932e7501a27f0f19bccdf9e91f9b87869c093f695Adam Lesinski    if (out_indices != nullptr &&
19032e7501a27f0f19bccdf9e91f9b87869c093f695Adam Lesinski        (value.dataType != Res_value::TYPE_NULL || value.data == Res_value::DATA_NULL_EMPTY)) {
1917a37b74d37ff79e805c9e97d977e07bfec753c5aAdam Lesinski      indices_idx++;
1927a37b74d37ff79e805c9e97d977e07bfec753c5aAdam Lesinski      out_indices[indices_idx] = ii;
1934452e137ffc02ab4e32aab2b2ec7192b45d9f494Adam Lesinski    }
1947a37b74d37ff79e805c9e97d977e07bfec753c5aAdam Lesinski
1957a37b74d37ff79e805c9e97d977e07bfec753c5aAdam Lesinski    out_values += STYLE_NUM_ENTRIES;
1967a37b74d37ff79e805c9e97d977e07bfec753c5aAdam Lesinski  }
1977a37b74d37ff79e805c9e97d977e07bfec753c5aAdam Lesinski
1987a37b74d37ff79e805c9e97d977e07bfec753c5aAdam Lesinski  res.unlock();
1997a37b74d37ff79e805c9e97d977e07bfec753c5aAdam Lesinski
2004c67a475a334e4f65238d439a3339195e03c03beAdam Lesinski  if (out_indices != nullptr) {
2017a37b74d37ff79e805c9e97d977e07bfec753c5aAdam Lesinski    out_indices[0] = indices_idx;
2027a37b74d37ff79e805c9e97d977e07bfec753c5aAdam Lesinski  }
2037a37b74d37ff79e805c9e97d977e07bfec753c5aAdam Lesinski  return true;
2044452e137ffc02ab4e32aab2b2ec7192b45d9f494Adam Lesinski}
2054452e137ffc02ab4e32aab2b2ec7192b45d9f494Adam Lesinski
206f32adf447511d54c2aa0948d3c1ef44d461538acJohn Reckvoid ApplyStyle(ResTable::Theme* theme, ResXMLParser* xml_parser, uint32_t def_style_attr,
207f32adf447511d54c2aa0948d3c1ef44d461538acJohn Reck                uint32_t def_style_res, const uint32_t* attrs, size_t attrs_length,
208f32adf447511d54c2aa0948d3c1ef44d461538acJohn Reck                uint32_t* out_values, uint32_t* out_indices) {
2097a37b74d37ff79e805c9e97d977e07bfec753c5aAdam Lesinski  if (kDebugStyles) {
2104c67a475a334e4f65238d439a3339195e03c03beAdam Lesinski    ALOGI("APPLY STYLE: theme=0x%p defStyleAttr=0x%x defStyleRes=0x%x xml=0x%p",
2114c67a475a334e4f65238d439a3339195e03c03beAdam Lesinski          theme, def_style_attr, def_style_res, xml_parser);
2127a37b74d37ff79e805c9e97d977e07bfec753c5aAdam Lesinski  }
2134452e137ffc02ab4e32aab2b2ec7192b45d9f494Adam Lesinski
2147a37b74d37ff79e805c9e97d977e07bfec753c5aAdam Lesinski  const ResTable& res = theme->getResTable();
2157a37b74d37ff79e805c9e97d977e07bfec753c5aAdam Lesinski  ResTable_config config;
2167a37b74d37ff79e805c9e97d977e07bfec753c5aAdam Lesinski  Res_value value;
2174452e137ffc02ab4e32aab2b2ec7192b45d9f494Adam Lesinski
2187a37b74d37ff79e805c9e97d977e07bfec753c5aAdam Lesinski  int indices_idx = 0;
2194452e137ffc02ab4e32aab2b2ec7192b45d9f494Adam Lesinski
2207a37b74d37ff79e805c9e97d977e07bfec753c5aAdam Lesinski  // Load default style from attribute, if specified...
2217a37b74d37ff79e805c9e97d977e07bfec753c5aAdam Lesinski  uint32_t def_style_bag_type_set_flags = 0;
2227a37b74d37ff79e805c9e97d977e07bfec753c5aAdam Lesinski  if (def_style_attr != 0) {
2237a37b74d37ff79e805c9e97d977e07bfec753c5aAdam Lesinski    Res_value value;
2244c67a475a334e4f65238d439a3339195e03c03beAdam Lesinski    if (theme->getAttribute(def_style_attr, &value,
2254c67a475a334e4f65238d439a3339195e03c03beAdam Lesinski                            &def_style_bag_type_set_flags) >= 0) {
2267a37b74d37ff79e805c9e97d977e07bfec753c5aAdam Lesinski      if (value.dataType == Res_value::TYPE_REFERENCE) {
2277a37b74d37ff79e805c9e97d977e07bfec753c5aAdam Lesinski        def_style_res = value.data;
2287a37b74d37ff79e805c9e97d977e07bfec753c5aAdam Lesinski      }
2297a37b74d37ff79e805c9e97d977e07bfec753c5aAdam Lesinski    }
2307a37b74d37ff79e805c9e97d977e07bfec753c5aAdam Lesinski  }
2317a37b74d37ff79e805c9e97d977e07bfec753c5aAdam Lesinski
2327a37b74d37ff79e805c9e97d977e07bfec753c5aAdam Lesinski  // Retrieve the style class associated with the current XML tag.
2337a37b74d37ff79e805c9e97d977e07bfec753c5aAdam Lesinski  int style = 0;
2347a37b74d37ff79e805c9e97d977e07bfec753c5aAdam Lesinski  uint32_t style_bag_type_set_flags = 0;
2354c67a475a334e4f65238d439a3339195e03c03beAdam Lesinski  if (xml_parser != nullptr) {
2367a37b74d37ff79e805c9e97d977e07bfec753c5aAdam Lesinski    ssize_t idx = xml_parser->indexOfStyle();
2377a37b74d37ff79e805c9e97d977e07bfec753c5aAdam Lesinski    if (idx >= 0 && xml_parser->getAttributeValue(idx, &value) >= 0) {
2387a37b74d37ff79e805c9e97d977e07bfec753c5aAdam Lesinski      if (value.dataType == value.TYPE_ATTRIBUTE) {
23932e7501a27f0f19bccdf9e91f9b87869c093f695Adam Lesinski        if (theme->getAttribute(value.data, &value, &style_bag_type_set_flags) < 0) {
2407a37b74d37ff79e805c9e97d977e07bfec753c5aAdam Lesinski          value.dataType = Res_value::TYPE_NULL;
2414452e137ffc02ab4e32aab2b2ec7192b45d9f494Adam Lesinski        }
2427a37b74d37ff79e805c9e97d977e07bfec753c5aAdam Lesinski      }
2437a37b74d37ff79e805c9e97d977e07bfec753c5aAdam Lesinski      if (value.dataType == value.TYPE_REFERENCE) {
2447a37b74d37ff79e805c9e97d977e07bfec753c5aAdam Lesinski        style = value.data;
2457a37b74d37ff79e805c9e97d977e07bfec753c5aAdam Lesinski      }
2464452e137ffc02ab4e32aab2b2ec7192b45d9f494Adam Lesinski    }
2477a37b74d37ff79e805c9e97d977e07bfec753c5aAdam Lesinski  }
2487a37b74d37ff79e805c9e97d977e07bfec753c5aAdam Lesinski
2497a37b74d37ff79e805c9e97d977e07bfec753c5aAdam Lesinski  // Now lock down the resource object and start pulling stuff from it.
2507a37b74d37ff79e805c9e97d977e07bfec753c5aAdam Lesinski  res.lock();
2517a37b74d37ff79e805c9e97d977e07bfec753c5aAdam Lesinski
2527a37b74d37ff79e805c9e97d977e07bfec753c5aAdam Lesinski  // Retrieve the default style bag, if requested.
2534c67a475a334e4f65238d439a3339195e03c03beAdam Lesinski  const ResTable::bag_entry* def_style_attr_start = nullptr;
2547a37b74d37ff79e805c9e97d977e07bfec753c5aAdam Lesinski  uint32_t def_style_type_set_flags = 0;
2554c67a475a334e4f65238d439a3339195e03c03beAdam Lesinski  ssize_t bag_off = def_style_res != 0
2564c67a475a334e4f65238d439a3339195e03c03beAdam Lesinski                        ? res.getBagLocked(def_style_res, &def_style_attr_start,
2574c67a475a334e4f65238d439a3339195e03c03beAdam Lesinski                                           &def_style_type_set_flags)
2584c67a475a334e4f65238d439a3339195e03c03beAdam Lesinski                        : -1;
2597a37b74d37ff79e805c9e97d977e07bfec753c5aAdam Lesinski  def_style_type_set_flags |= def_style_bag_type_set_flags;
2607a37b74d37ff79e805c9e97d977e07bfec753c5aAdam Lesinski  const ResTable::bag_entry* const def_style_attr_end =
2617a37b74d37ff79e805c9e97d977e07bfec753c5aAdam Lesinski      def_style_attr_start + (bag_off >= 0 ? bag_off : 0);
2624c67a475a334e4f65238d439a3339195e03c03beAdam Lesinski  BagAttributeFinder def_style_attr_finder(def_style_attr_start,
2634c67a475a334e4f65238d439a3339195e03c03beAdam Lesinski                                           def_style_attr_end);
2647a37b74d37ff79e805c9e97d977e07bfec753c5aAdam Lesinski
2657a37b74d37ff79e805c9e97d977e07bfec753c5aAdam Lesinski  // Retrieve the style class bag, if requested.
2664c67a475a334e4f65238d439a3339195e03c03beAdam Lesinski  const ResTable::bag_entry* style_attr_start = nullptr;
2677a37b74d37ff79e805c9e97d977e07bfec753c5aAdam Lesinski  uint32_t style_type_set_flags = 0;
2684c67a475a334e4f65238d439a3339195e03c03beAdam Lesinski  bag_off =
2694c67a475a334e4f65238d439a3339195e03c03beAdam Lesinski      style != 0
2704c67a475a334e4f65238d439a3339195e03c03beAdam Lesinski          ? res.getBagLocked(style, &style_attr_start, &style_type_set_flags)
2714c67a475a334e4f65238d439a3339195e03c03beAdam Lesinski          : -1;
2727a37b74d37ff79e805c9e97d977e07bfec753c5aAdam Lesinski  style_type_set_flags |= style_bag_type_set_flags;
2734c67a475a334e4f65238d439a3339195e03c03beAdam Lesinski  const ResTable::bag_entry* const style_attr_end =
2744c67a475a334e4f65238d439a3339195e03c03beAdam Lesinski      style_attr_start + (bag_off >= 0 ? bag_off : 0);
2757a37b74d37ff79e805c9e97d977e07bfec753c5aAdam Lesinski  BagAttributeFinder style_attr_finder(style_attr_start, style_attr_end);
2767a37b74d37ff79e805c9e97d977e07bfec753c5aAdam Lesinski
2777a37b74d37ff79e805c9e97d977e07bfec753c5aAdam Lesinski  // Retrieve the XML attributes, if requested.
2787a37b74d37ff79e805c9e97d977e07bfec753c5aAdam Lesinski  static const ssize_t kXmlBlock = 0x10000000;
2797a37b74d37ff79e805c9e97d977e07bfec753c5aAdam Lesinski  XmlAttributeFinder xml_attr_finder(xml_parser);
2804c67a475a334e4f65238d439a3339195e03c03beAdam Lesinski  const size_t xml_attr_end =
2814c67a475a334e4f65238d439a3339195e03c03beAdam Lesinski      xml_parser != nullptr ? xml_parser->getAttributeCount() : 0;
2827a37b74d37ff79e805c9e97d977e07bfec753c5aAdam Lesinski
2837a37b74d37ff79e805c9e97d977e07bfec753c5aAdam Lesinski  // Now iterate through all of the attributes that the client has requested,
2847a37b74d37ff79e805c9e97d977e07bfec753c5aAdam Lesinski  // filling in each with whatever data we can find.
2857a37b74d37ff79e805c9e97d977e07bfec753c5aAdam Lesinski  for (size_t ii = 0; ii < attrs_length; ii++) {
2867a37b74d37ff79e805c9e97d977e07bfec753c5aAdam Lesinski    const uint32_t cur_ident = attrs[ii];
2874452e137ffc02ab4e32aab2b2ec7192b45d9f494Adam Lesinski
2887a37b74d37ff79e805c9e97d977e07bfec753c5aAdam Lesinski    if (kDebugStyles) {
2897a37b74d37ff79e805c9e97d977e07bfec753c5aAdam Lesinski      ALOGI("RETRIEVING ATTR 0x%08x...", cur_ident);
2904452e137ffc02ab4e32aab2b2ec7192b45d9f494Adam Lesinski    }
2914452e137ffc02ab4e32aab2b2ec7192b45d9f494Adam Lesinski
2927a37b74d37ff79e805c9e97d977e07bfec753c5aAdam Lesinski    ssize_t block = kXmlBlock;
2937a37b74d37ff79e805c9e97d977e07bfec753c5aAdam Lesinski    uint32_t type_set_flags = 0;
2947a37b74d37ff79e805c9e97d977e07bfec753c5aAdam Lesinski
2957a37b74d37ff79e805c9e97d977e07bfec753c5aAdam Lesinski    value.dataType = Res_value::TYPE_NULL;
2967a37b74d37ff79e805c9e97d977e07bfec753c5aAdam Lesinski    value.data = Res_value::DATA_NULL_UNDEFINED;
2977a37b74d37ff79e805c9e97d977e07bfec753c5aAdam Lesinski    config.density = 0;
2987a37b74d37ff79e805c9e97d977e07bfec753c5aAdam Lesinski
2997a37b74d37ff79e805c9e97d977e07bfec753c5aAdam Lesinski    // Try to find a value for this attribute...  we prioritize values
3007a37b74d37ff79e805c9e97d977e07bfec753c5aAdam Lesinski    // coming from, first XML attributes, then XML style, then default
3017a37b74d37ff79e805c9e97d977e07bfec753c5aAdam Lesinski    // style, and finally the theme.
3027a37b74d37ff79e805c9e97d977e07bfec753c5aAdam Lesinski
3037a37b74d37ff79e805c9e97d977e07bfec753c5aAdam Lesinski    // Walk through the xml attributes looking for the requested attribute.
3047a37b74d37ff79e805c9e97d977e07bfec753c5aAdam Lesinski    const size_t xml_attr_idx = xml_attr_finder.Find(cur_ident);
3057a37b74d37ff79e805c9e97d977e07bfec753c5aAdam Lesinski    if (xml_attr_idx != xml_attr_end) {
3067a37b74d37ff79e805c9e97d977e07bfec753c5aAdam Lesinski      // We found the attribute we were looking for.
3077a37b74d37ff79e805c9e97d977e07bfec753c5aAdam Lesinski      xml_parser->getAttributeValue(xml_attr_idx, &value);
3087a37b74d37ff79e805c9e97d977e07bfec753c5aAdam Lesinski      if (kDebugStyles) {
30932e7501a27f0f19bccdf9e91f9b87869c093f695Adam Lesinski        ALOGI("-> From XML: type=0x%x, data=0x%08x", value.dataType, value.data);
3107a37b74d37ff79e805c9e97d977e07bfec753c5aAdam Lesinski      }
3117a37b74d37ff79e805c9e97d977e07bfec753c5aAdam Lesinski    }
3124452e137ffc02ab4e32aab2b2ec7192b45d9f494Adam Lesinski
31332e7501a27f0f19bccdf9e91f9b87869c093f695Adam Lesinski    if (value.dataType == Res_value::TYPE_NULL && value.data != Res_value::DATA_NULL_EMPTY) {
31432e7501a27f0f19bccdf9e91f9b87869c093f695Adam Lesinski      // Walk through the style class values looking for the requested attribute.
31532e7501a27f0f19bccdf9e91f9b87869c093f695Adam Lesinski      const ResTable::bag_entry* const style_attr_entry = style_attr_finder.Find(cur_ident);
3167a37b74d37ff79e805c9e97d977e07bfec753c5aAdam Lesinski      if (style_attr_entry != style_attr_end) {
3177a37b74d37ff79e805c9e97d977e07bfec753c5aAdam Lesinski        // We found the attribute we were looking for.
3187a37b74d37ff79e805c9e97d977e07bfec753c5aAdam Lesinski        block = style_attr_entry->stringBlock;
3197a37b74d37ff79e805c9e97d977e07bfec753c5aAdam Lesinski        type_set_flags = style_type_set_flags;
3207a37b74d37ff79e805c9e97d977e07bfec753c5aAdam Lesinski        value = style_attr_entry->map.value;
3214452e137ffc02ab4e32aab2b2ec7192b45d9f494Adam Lesinski        if (kDebugStyles) {
32232e7501a27f0f19bccdf9e91f9b87869c093f695Adam Lesinski          ALOGI("-> From style: type=0x%x, data=0x%08x", value.dataType, value.data);
3234452e137ffc02ab4e32aab2b2ec7192b45d9f494Adam Lesinski        }
3247a37b74d37ff79e805c9e97d977e07bfec753c5aAdam Lesinski      }
3257a37b74d37ff79e805c9e97d977e07bfec753c5aAdam Lesinski    }
3264452e137ffc02ab4e32aab2b2ec7192b45d9f494Adam Lesinski
32732e7501a27f0f19bccdf9e91f9b87869c093f695Adam Lesinski    if (value.dataType == Res_value::TYPE_NULL && value.data != Res_value::DATA_NULL_EMPTY) {
32832e7501a27f0f19bccdf9e91f9b87869c093f695Adam Lesinski      // Walk through the default style values looking for the requested attribute.
32932e7501a27f0f19bccdf9e91f9b87869c093f695Adam Lesinski      const ResTable::bag_entry* const def_style_attr_entry = def_style_attr_finder.Find(cur_ident);
3307a37b74d37ff79e805c9e97d977e07bfec753c5aAdam Lesinski      if (def_style_attr_entry != def_style_attr_end) {
3317a37b74d37ff79e805c9e97d977e07bfec753c5aAdam Lesinski        // We found the attribute we were looking for.
3327a37b74d37ff79e805c9e97d977e07bfec753c5aAdam Lesinski        block = def_style_attr_entry->stringBlock;
3337a37b74d37ff79e805c9e97d977e07bfec753c5aAdam Lesinski        type_set_flags = style_type_set_flags;
3347a37b74d37ff79e805c9e97d977e07bfec753c5aAdam Lesinski        value = def_style_attr_entry->map.value;
3357a37b74d37ff79e805c9e97d977e07bfec753c5aAdam Lesinski        if (kDebugStyles) {
33632e7501a27f0f19bccdf9e91f9b87869c093f695Adam Lesinski          ALOGI("-> From def style: type=0x%x, data=0x%08x", value.dataType, value.data);
3374452e137ffc02ab4e32aab2b2ec7192b45d9f494Adam Lesinski        }
3387a37b74d37ff79e805c9e97d977e07bfec753c5aAdam Lesinski      }
3397a37b74d37ff79e805c9e97d977e07bfec753c5aAdam Lesinski    }
3404452e137ffc02ab4e32aab2b2ec7192b45d9f494Adam Lesinski
3417a37b74d37ff79e805c9e97d977e07bfec753c5aAdam Lesinski    uint32_t resid = 0;
3427a37b74d37ff79e805c9e97d977e07bfec753c5aAdam Lesinski    if (value.dataType != Res_value::TYPE_NULL) {
3437a37b74d37ff79e805c9e97d977e07bfec753c5aAdam Lesinski      // Take care of resolving the found resource to its final value.
34432e7501a27f0f19bccdf9e91f9b87869c093f695Adam Lesinski      ssize_t new_block =
34532e7501a27f0f19bccdf9e91f9b87869c093f695Adam Lesinski          theme->resolveAttributeReference(&value, block, &resid, &type_set_flags, &config);
3467a37b74d37ff79e805c9e97d977e07bfec753c5aAdam Lesinski      if (new_block >= 0) {
3477a37b74d37ff79e805c9e97d977e07bfec753c5aAdam Lesinski        block = new_block;
3487a37b74d37ff79e805c9e97d977e07bfec753c5aAdam Lesinski      }
3497a37b74d37ff79e805c9e97d977e07bfec753c5aAdam Lesinski
3507a37b74d37ff79e805c9e97d977e07bfec753c5aAdam Lesinski      if (kDebugStyles) {
35132e7501a27f0f19bccdf9e91f9b87869c093f695Adam Lesinski        ALOGI("-> Resolved attr: type=0x%x, data=0x%08x", value.dataType, value.data);
3527a37b74d37ff79e805c9e97d977e07bfec753c5aAdam Lesinski      }
35332e7501a27f0f19bccdf9e91f9b87869c093f695Adam Lesinski    } else if (value.data != Res_value::DATA_NULL_EMPTY) {
35432e7501a27f0f19bccdf9e91f9b87869c093f695Adam Lesinski      // If we still don't have a value for this attribute, try to find it in the theme!
35532e7501a27f0f19bccdf9e91f9b87869c093f695Adam Lesinski      ssize_t new_block = theme->getAttribute(cur_ident, &value, &type_set_flags);
3567a37b74d37ff79e805c9e97d977e07bfec753c5aAdam Lesinski      if (new_block >= 0) {
3577a37b74d37ff79e805c9e97d977e07bfec753c5aAdam Lesinski        if (kDebugStyles) {
35832e7501a27f0f19bccdf9e91f9b87869c093f695Adam Lesinski          ALOGI("-> From theme: type=0x%x, data=0x%08x", value.dataType, value.data);
3594452e137ffc02ab4e32aab2b2ec7192b45d9f494Adam Lesinski        }
36032e7501a27f0f19bccdf9e91f9b87869c093f695Adam Lesinski        new_block = res.resolveReference(&value, new_block, &resid, &type_set_flags, &config);
3617a37b74d37ff79e805c9e97d977e07bfec753c5aAdam Lesinski        if (new_block >= 0) {
3627a37b74d37ff79e805c9e97d977e07bfec753c5aAdam Lesinski          block = new_block;
3634452e137ffc02ab4e32aab2b2ec7192b45d9f494Adam Lesinski        }
3644452e137ffc02ab4e32aab2b2ec7192b45d9f494Adam Lesinski
3654452e137ffc02ab4e32aab2b2ec7192b45d9f494Adam Lesinski        if (kDebugStyles) {
36632e7501a27f0f19bccdf9e91f9b87869c093f695Adam Lesinski          ALOGI("-> Resolved theme: type=0x%x, data=0x%08x", value.dataType, value.data);
3674452e137ffc02ab4e32aab2b2ec7192b45d9f494Adam Lesinski        }
3687a37b74d37ff79e805c9e97d977e07bfec753c5aAdam Lesinski      }
3697a37b74d37ff79e805c9e97d977e07bfec753c5aAdam Lesinski    }
3704452e137ffc02ab4e32aab2b2ec7192b45d9f494Adam Lesinski
3717a37b74d37ff79e805c9e97d977e07bfec753c5aAdam Lesinski    // Deal with the special @null value -- it turns back to TYPE_NULL.
3727a37b74d37ff79e805c9e97d977e07bfec753c5aAdam Lesinski    if (value.dataType == Res_value::TYPE_REFERENCE && value.data == 0) {
3737a37b74d37ff79e805c9e97d977e07bfec753c5aAdam Lesinski      if (kDebugStyles) {
3747a37b74d37ff79e805c9e97d977e07bfec753c5aAdam Lesinski        ALOGI("-> Setting to @null!");
3757a37b74d37ff79e805c9e97d977e07bfec753c5aAdam Lesinski      }
3767a37b74d37ff79e805c9e97d977e07bfec753c5aAdam Lesinski      value.dataType = Res_value::TYPE_NULL;
3777a37b74d37ff79e805c9e97d977e07bfec753c5aAdam Lesinski      value.data = Res_value::DATA_NULL_UNDEFINED;
3787a37b74d37ff79e805c9e97d977e07bfec753c5aAdam Lesinski      block = kXmlBlock;
3794452e137ffc02ab4e32aab2b2ec7192b45d9f494Adam Lesinski    }
3804452e137ffc02ab4e32aab2b2ec7192b45d9f494Adam Lesinski
3817a37b74d37ff79e805c9e97d977e07bfec753c5aAdam Lesinski    if (kDebugStyles) {
38232e7501a27f0f19bccdf9e91f9b87869c093f695Adam Lesinski      ALOGI("Attribute 0x%08x: type=0x%x, data=0x%08x", cur_ident, value.dataType, value.data);
3837a37b74d37ff79e805c9e97d977e07bfec753c5aAdam Lesinski    }
3844452e137ffc02ab4e32aab2b2ec7192b45d9f494Adam Lesinski
3857a37b74d37ff79e805c9e97d977e07bfec753c5aAdam Lesinski    // Write the final value back to Java.
3867a37b74d37ff79e805c9e97d977e07bfec753c5aAdam Lesinski    out_values[STYLE_TYPE] = value.dataType;
3877a37b74d37ff79e805c9e97d977e07bfec753c5aAdam Lesinski    out_values[STYLE_DATA] = value.data;
3884c67a475a334e4f65238d439a3339195e03c03beAdam Lesinski    out_values[STYLE_ASSET_COOKIE] =
3894c67a475a334e4f65238d439a3339195e03c03beAdam Lesinski        block != kXmlBlock ? static_cast<uint32_t>(res.getTableCookie(block))
3904c67a475a334e4f65238d439a3339195e03c03beAdam Lesinski                           : static_cast<uint32_t>(-1);
3917a37b74d37ff79e805c9e97d977e07bfec753c5aAdam Lesinski    out_values[STYLE_RESOURCE_ID] = resid;
3927a37b74d37ff79e805c9e97d977e07bfec753c5aAdam Lesinski    out_values[STYLE_CHANGING_CONFIGURATIONS] = type_set_flags;
3937a37b74d37ff79e805c9e97d977e07bfec753c5aAdam Lesinski    out_values[STYLE_DENSITY] = config.density;
3947a37b74d37ff79e805c9e97d977e07bfec753c5aAdam Lesinski
39532e7501a27f0f19bccdf9e91f9b87869c093f695Adam Lesinski    if (value.dataType != Res_value::TYPE_NULL || value.data == Res_value::DATA_NULL_EMPTY) {
3967a37b74d37ff79e805c9e97d977e07bfec753c5aAdam Lesinski      indices_idx++;
39706d3e8fec7e2b29f99d755bee849023d88957953Adam Lesinski
39806d3e8fec7e2b29f99d755bee849023d88957953Adam Lesinski      // out_indices must NOT be nullptr.
3997a37b74d37ff79e805c9e97d977e07bfec753c5aAdam Lesinski      out_indices[indices_idx] = ii;
4004452e137ffc02ab4e32aab2b2ec7192b45d9f494Adam Lesinski    }
4014452e137ffc02ab4e32aab2b2ec7192b45d9f494Adam Lesinski
4027a37b74d37ff79e805c9e97d977e07bfec753c5aAdam Lesinski    out_values += STYLE_NUM_ENTRIES;
4037a37b74d37ff79e805c9e97d977e07bfec753c5aAdam Lesinski  }
4044452e137ffc02ab4e32aab2b2ec7192b45d9f494Adam Lesinski
4057a37b74d37ff79e805c9e97d977e07bfec753c5aAdam Lesinski  res.unlock();
4064452e137ffc02ab4e32aab2b2ec7192b45d9f494Adam Lesinski
40706d3e8fec7e2b29f99d755bee849023d88957953Adam Lesinski  // out_indices must NOT be nullptr.
40806d3e8fec7e2b29f99d755bee849023d88957953Adam Lesinski  out_indices[0] = indices_idx;
4097a37b74d37ff79e805c9e97d977e07bfec753c5aAdam Lesinski}
4104452e137ffc02ab4e32aab2b2ec7192b45d9f494Adam Lesinski
4114c67a475a334e4f65238d439a3339195e03c03beAdam Lesinskibool RetrieveAttributes(const ResTable* res, ResXMLParser* xml_parser,
4124c67a475a334e4f65238d439a3339195e03c03beAdam Lesinski                        uint32_t* attrs, size_t attrs_length,
4134c67a475a334e4f65238d439a3339195e03c03beAdam Lesinski                        uint32_t* out_values, uint32_t* out_indices) {
4147a37b74d37ff79e805c9e97d977e07bfec753c5aAdam Lesinski  ResTable_config config;
4157a37b74d37ff79e805c9e97d977e07bfec753c5aAdam Lesinski  Res_value value;
4164452e137ffc02ab4e32aab2b2ec7192b45d9f494Adam Lesinski
4177a37b74d37ff79e805c9e97d977e07bfec753c5aAdam Lesinski  int indices_idx = 0;
4184452e137ffc02ab4e32aab2b2ec7192b45d9f494Adam Lesinski
4197a37b74d37ff79e805c9e97d977e07bfec753c5aAdam Lesinski  // Now lock down the resource object and start pulling stuff from it.
4207a37b74d37ff79e805c9e97d977e07bfec753c5aAdam Lesinski  res->lock();
4214452e137ffc02ab4e32aab2b2ec7192b45d9f494Adam Lesinski
4227a37b74d37ff79e805c9e97d977e07bfec753c5aAdam Lesinski  // Retrieve the XML attributes, if requested.
4237a37b74d37ff79e805c9e97d977e07bfec753c5aAdam Lesinski  const size_t xml_attr_count = xml_parser->getAttributeCount();
4247a37b74d37ff79e805c9e97d977e07bfec753c5aAdam Lesinski  size_t ix = 0;
4257a37b74d37ff79e805c9e97d977e07bfec753c5aAdam Lesinski  uint32_t cur_xml_attr = xml_parser->getAttributeNameResID(ix);
4264452e137ffc02ab4e32aab2b2ec7192b45d9f494Adam Lesinski
4277a37b74d37ff79e805c9e97d977e07bfec753c5aAdam Lesinski  static const ssize_t kXmlBlock = 0x10000000;
4284452e137ffc02ab4e32aab2b2ec7192b45d9f494Adam Lesinski
4297a37b74d37ff79e805c9e97d977e07bfec753c5aAdam Lesinski  // Now iterate through all of the attributes that the client has requested,
4307a37b74d37ff79e805c9e97d977e07bfec753c5aAdam Lesinski  // filling in each with whatever data we can find.
4317a37b74d37ff79e805c9e97d977e07bfec753c5aAdam Lesinski  for (size_t ii = 0; ii < attrs_length; ii++) {
4327a37b74d37ff79e805c9e97d977e07bfec753c5aAdam Lesinski    const uint32_t cur_ident = attrs[ii];
4337a37b74d37ff79e805c9e97d977e07bfec753c5aAdam Lesinski    ssize_t block = kXmlBlock;
4347a37b74d37ff79e805c9e97d977e07bfec753c5aAdam Lesinski    uint32_t type_set_flags = 0;
4354452e137ffc02ab4e32aab2b2ec7192b45d9f494Adam Lesinski
4367a37b74d37ff79e805c9e97d977e07bfec753c5aAdam Lesinski    value.dataType = Res_value::TYPE_NULL;
4377a37b74d37ff79e805c9e97d977e07bfec753c5aAdam Lesinski    value.data = Res_value::DATA_NULL_UNDEFINED;
4387a37b74d37ff79e805c9e97d977e07bfec753c5aAdam Lesinski    config.density = 0;
4394452e137ffc02ab4e32aab2b2ec7192b45d9f494Adam Lesinski
4407a37b74d37ff79e805c9e97d977e07bfec753c5aAdam Lesinski    // Try to find a value for this attribute...
4417a37b74d37ff79e805c9e97d977e07bfec753c5aAdam Lesinski    // Skip through XML attributes until the end or the next possible match.
4427a37b74d37ff79e805c9e97d977e07bfec753c5aAdam Lesinski    while (ix < xml_attr_count && cur_ident > cur_xml_attr) {
4437a37b74d37ff79e805c9e97d977e07bfec753c5aAdam Lesinski      ix++;
4447a37b74d37ff79e805c9e97d977e07bfec753c5aAdam Lesinski      cur_xml_attr = xml_parser->getAttributeNameResID(ix);
4457a37b74d37ff79e805c9e97d977e07bfec753c5aAdam Lesinski    }
4467a37b74d37ff79e805c9e97d977e07bfec753c5aAdam Lesinski    // Retrieve the current XML attribute if it matches, and step to next.
4477a37b74d37ff79e805c9e97d977e07bfec753c5aAdam Lesinski    if (ix < xml_attr_count && cur_ident == cur_xml_attr) {
4487a37b74d37ff79e805c9e97d977e07bfec753c5aAdam Lesinski      xml_parser->getAttributeValue(ix, &value);
4497a37b74d37ff79e805c9e97d977e07bfec753c5aAdam Lesinski      ix++;
4507a37b74d37ff79e805c9e97d977e07bfec753c5aAdam Lesinski      cur_xml_attr = xml_parser->getAttributeNameResID(ix);
4517a37b74d37ff79e805c9e97d977e07bfec753c5aAdam Lesinski    }
4524452e137ffc02ab4e32aab2b2ec7192b45d9f494Adam Lesinski
4537a37b74d37ff79e805c9e97d977e07bfec753c5aAdam Lesinski    uint32_t resid = 0;
4547a37b74d37ff79e805c9e97d977e07bfec753c5aAdam Lesinski    if (value.dataType != Res_value::TYPE_NULL) {
4557a37b74d37ff79e805c9e97d977e07bfec753c5aAdam Lesinski      // Take care of resolving the found resource to its final value.
4567a37b74d37ff79e805c9e97d977e07bfec753c5aAdam Lesinski      // printf("Resolving attribute reference\n");
4574c67a475a334e4f65238d439a3339195e03c03beAdam Lesinski      ssize_t new_block = res->resolveReference(&value, block, &resid,
4584c67a475a334e4f65238d439a3339195e03c03beAdam Lesinski                                                &type_set_flags, &config);
4597a37b74d37ff79e805c9e97d977e07bfec753c5aAdam Lesinski      if (new_block >= 0) block = new_block;
4607a37b74d37ff79e805c9e97d977e07bfec753c5aAdam Lesinski    }
4614452e137ffc02ab4e32aab2b2ec7192b45d9f494Adam Lesinski
4627a37b74d37ff79e805c9e97d977e07bfec753c5aAdam Lesinski    // Deal with the special @null value -- it turns back to TYPE_NULL.
4637a37b74d37ff79e805c9e97d977e07bfec753c5aAdam Lesinski    if (value.dataType == Res_value::TYPE_REFERENCE && value.data == 0) {
4647a37b74d37ff79e805c9e97d977e07bfec753c5aAdam Lesinski      value.dataType = Res_value::TYPE_NULL;
4657a37b74d37ff79e805c9e97d977e07bfec753c5aAdam Lesinski      value.data = Res_value::DATA_NULL_UNDEFINED;
4667a37b74d37ff79e805c9e97d977e07bfec753c5aAdam Lesinski      block = kXmlBlock;
4677a37b74d37ff79e805c9e97d977e07bfec753c5aAdam Lesinski    }
4684452e137ffc02ab4e32aab2b2ec7192b45d9f494Adam Lesinski
4697a37b74d37ff79e805c9e97d977e07bfec753c5aAdam Lesinski    // Write the final value back to Java.
4707a37b74d37ff79e805c9e97d977e07bfec753c5aAdam Lesinski    out_values[STYLE_TYPE] = value.dataType;
4717a37b74d37ff79e805c9e97d977e07bfec753c5aAdam Lesinski    out_values[STYLE_DATA] = value.data;
4724c67a475a334e4f65238d439a3339195e03c03beAdam Lesinski    out_values[STYLE_ASSET_COOKIE] =
4734c67a475a334e4f65238d439a3339195e03c03beAdam Lesinski        block != kXmlBlock ? static_cast<uint32_t>(res->getTableCookie(block))
4744c67a475a334e4f65238d439a3339195e03c03beAdam Lesinski                           : static_cast<uint32_t>(-1);
4757a37b74d37ff79e805c9e97d977e07bfec753c5aAdam Lesinski    out_values[STYLE_RESOURCE_ID] = resid;
4767a37b74d37ff79e805c9e97d977e07bfec753c5aAdam Lesinski    out_values[STYLE_CHANGING_CONFIGURATIONS] = type_set_flags;
4777a37b74d37ff79e805c9e97d977e07bfec753c5aAdam Lesinski    out_values[STYLE_DENSITY] = config.density;
4787a37b74d37ff79e805c9e97d977e07bfec753c5aAdam Lesinski
47932e7501a27f0f19bccdf9e91f9b87869c093f695Adam Lesinski    if (out_indices != nullptr &&
48032e7501a27f0f19bccdf9e91f9b87869c093f695Adam Lesinski        (value.dataType != Res_value::TYPE_NULL || value.data == Res_value::DATA_NULL_EMPTY)) {
4817a37b74d37ff79e805c9e97d977e07bfec753c5aAdam Lesinski      indices_idx++;
4827a37b74d37ff79e805c9e97d977e07bfec753c5aAdam Lesinski      out_indices[indices_idx] = ii;
4834452e137ffc02ab4e32aab2b2ec7192b45d9f494Adam Lesinski    }
4844452e137ffc02ab4e32aab2b2ec7192b45d9f494Adam Lesinski
4857a37b74d37ff79e805c9e97d977e07bfec753c5aAdam Lesinski    out_values += STYLE_NUM_ENTRIES;
4867a37b74d37ff79e805c9e97d977e07bfec753c5aAdam Lesinski  }
4874452e137ffc02ab4e32aab2b2ec7192b45d9f494Adam Lesinski
4887a37b74d37ff79e805c9e97d977e07bfec753c5aAdam Lesinski  res->unlock();
4897a37b74d37ff79e805c9e97d977e07bfec753c5aAdam Lesinski
4904c67a475a334e4f65238d439a3339195e03c03beAdam Lesinski  if (out_indices != nullptr) {
4917a37b74d37ff79e805c9e97d977e07bfec753c5aAdam Lesinski    out_indices[0] = indices_idx;
4927a37b74d37ff79e805c9e97d977e07bfec753c5aAdam Lesinski  }
4937a37b74d37ff79e805c9e97d977e07bfec753c5aAdam Lesinski  return true;
4944452e137ffc02ab4e32aab2b2ec7192b45d9f494Adam Lesinski}
4954452e137ffc02ab4e32aab2b2ec7192b45d9f494Adam Lesinski
4967a37b74d37ff79e805c9e97d977e07bfec753c5aAdam Lesinski}  // namespace android
497