blob: 60e3845d98a9ef121439ce2857e532993be63cf3 [file] [log] [blame]
Adam Lesinski4452e132016-10-12 07:47:28 -07001/*
2 * Copyright (C) 2016 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
Adam Lesinski4452e132016-10-12 07:47:28 -070017#include "androidfw/AttributeResolution.h"
Adam Lesinski4c67a472016-11-10 16:43:59 -080018
19#include <cstdint>
Adam Lesinski4452e132016-10-12 07:47:28 -070020
Mark Salyzyn6f773a02016-09-28 16:15:30 -070021#include <log/log.h>
Adam Lesinski4c67a472016-11-10 16:43:59 -080022
23#include "androidfw/AttributeFinder.h"
Adam Lesinski7fb38312018-01-23 03:17:26 -080024#include "androidfw/ResourceTypes.h"
Adam Lesinski4452e132016-10-12 07:47:28 -070025
26constexpr bool kDebugStyles = false;
27
28namespace android {
29
Adam Lesinski4c67a472016-11-10 16:43:59 -080030class XmlAttributeFinder
31 : public BackTrackingAttributeFinder<XmlAttributeFinder, size_t> {
Adam Lesinski7a37b742016-10-12 14:05:55 -070032 public:
33 explicit XmlAttributeFinder(const ResXMLParser* parser)
Adam Lesinski4c67a472016-11-10 16:43:59 -080034 : BackTrackingAttributeFinder(
35 0, parser != nullptr ? parser->getAttributeCount() : 0),
Adam Lesinski7a37b742016-10-12 14:05:55 -070036 parser_(parser) {}
Adam Lesinski4452e132016-10-12 07:47:28 -070037
Adam Lesinski4c67a472016-11-10 16:43:59 -080038 inline uint32_t GetAttribute(size_t index) const {
39 return parser_->getAttributeNameResID(index);
40 }
Adam Lesinski4452e132016-10-12 07:47:28 -070041
Adam Lesinski7a37b742016-10-12 14:05:55 -070042 private:
43 const ResXMLParser* parser_;
Adam Lesinski4452e132016-10-12 07:47:28 -070044};
45
Adam Lesinski7a37b742016-10-12 14:05:55 -070046class BagAttributeFinder
Adam Lesinski7fb38312018-01-23 03:17:26 -080047 : public BackTrackingAttributeFinder<BagAttributeFinder, const ResTable::bag_entry*> {
Adam Lesinski7a37b742016-10-12 14:05:55 -070048 public:
Adam Lesinski7fb38312018-01-23 03:17:26 -080049 BagAttributeFinder(const ResTable::bag_entry* start,
50 const ResTable::bag_entry* end)
51 : BackTrackingAttributeFinder(start, end) {}
Adam Lesinski4452e132016-10-12 07:47:28 -070052
Adam Lesinski7fb38312018-01-23 03:17:26 -080053 inline uint32_t GetAttribute(const ResTable::bag_entry* entry) const {
54 return entry->map.name.ident;
Adam Lesinski7a37b742016-10-12 14:05:55 -070055 }
Adam Lesinski4452e132016-10-12 07:47:28 -070056};
57
Adam Lesinski7fb38312018-01-23 03:17:26 -080058bool ResolveAttrs(ResTable::Theme* theme, uint32_t def_style_attr,
59 uint32_t def_style_res, uint32_t* src_values,
60 size_t src_values_length, uint32_t* attrs,
61 size_t attrs_length, uint32_t* out_values,
62 uint32_t* out_indices) {
Adam Lesinski7a37b742016-10-12 14:05:55 -070063 if (kDebugStyles) {
Adam Lesinski4c67a472016-11-10 16:43:59 -080064 ALOGI("APPLY STYLE: theme=0x%p defStyleAttr=0x%x defStyleRes=0x%x", theme,
65 def_style_attr, def_style_res);
Adam Lesinski7a37b742016-10-12 14:05:55 -070066 }
67
Adam Lesinski7fb38312018-01-23 03:17:26 -080068 const ResTable& res = theme->getResTable();
Adam Lesinski7a37b742016-10-12 14:05:55 -070069 ResTable_config config;
70 Res_value value;
71
72 int indices_idx = 0;
73
74 // Load default style from attribute, if specified...
Adam Lesinski7fb38312018-01-23 03:17:26 -080075 uint32_t def_style_bag_type_set_flags = 0;
Adam Lesinski7a37b742016-10-12 14:05:55 -070076 if (def_style_attr != 0) {
77 Res_value value;
Adam Lesinski7fb38312018-01-23 03:17:26 -080078 if (theme->getAttribute(def_style_attr, &value, &def_style_bag_type_set_flags) >= 0) {
Adam Lesinski7a37b742016-10-12 14:05:55 -070079 if (value.dataType == Res_value::TYPE_REFERENCE) {
80 def_style_res = value.data;
81 }
82 }
83 }
84
Adam Lesinski7fb38312018-01-23 03:17:26 -080085 // Now lock down the resource object and start pulling stuff from it.
86 res.lock();
Adam Lesinskib20a0ce2017-01-23 12:58:11 -080087
Adam Lesinski7fb38312018-01-23 03:17:26 -080088 // Retrieve the default style bag, if requested.
89 const ResTable::bag_entry* def_style_start = nullptr;
90 uint32_t def_style_type_set_flags = 0;
91 ssize_t bag_off = def_style_res != 0
92 ? res.getBagLocked(def_style_res, &def_style_start,
93 &def_style_type_set_flags)
94 : -1;
95 def_style_type_set_flags |= def_style_bag_type_set_flags;
96 const ResTable::bag_entry* const def_style_end =
97 def_style_start + (bag_off >= 0 ? bag_off : 0);
98 BagAttributeFinder def_style_attr_finder(def_style_start, def_style_end);
Adam Lesinski7a37b742016-10-12 14:05:55 -070099
100 // Now iterate through all of the attributes that the client has requested,
101 // filling in each with whatever data we can find.
102 for (size_t ii = 0; ii < attrs_length; ii++) {
103 const uint32_t cur_ident = attrs[ii];
104
Adam Lesinski4452e132016-10-12 07:47:28 -0700105 if (kDebugStyles) {
Adam Lesinski7a37b742016-10-12 14:05:55 -0700106 ALOGI("RETRIEVING ATTR 0x%08x...", cur_ident);
Adam Lesinski4452e132016-10-12 07:47:28 -0700107 }
108
Adam Lesinski7fb38312018-01-23 03:17:26 -0800109 ssize_t block = -1;
Adam Lesinski7a37b742016-10-12 14:05:55 -0700110 uint32_t type_set_flags = 0;
Adam Lesinski4452e132016-10-12 07:47:28 -0700111
Adam Lesinski7a37b742016-10-12 14:05:55 -0700112 value.dataType = Res_value::TYPE_NULL;
113 value.data = Res_value::DATA_NULL_UNDEFINED;
114 config.density = 0;
Adam Lesinski4452e132016-10-12 07:47:28 -0700115
Adam Lesinski7a37b742016-10-12 14:05:55 -0700116 // Try to find a value for this attribute... we prioritize values
117 // coming from, first XML attributes, then XML style, then default
118 // style, and finally the theme.
119
120 // Retrieve the current input value if available.
121 if (src_values_length > 0 && src_values[ii] != 0) {
122 value.dataType = Res_value::TYPE_ATTRIBUTE;
123 value.data = src_values[ii];
124 if (kDebugStyles) {
Adam Lesinski7fb38312018-01-23 03:17:26 -0800125 ALOGI("-> From values: type=0x%x, data=0x%08x", value.dataType,
126 value.data);
Adam Lesinski7a37b742016-10-12 14:05:55 -0700127 }
Adam Lesinski32e75012017-05-09 15:25:37 -0700128 } else {
Adam Lesinski7fb38312018-01-23 03:17:26 -0800129 const ResTable::bag_entry* const def_style_entry = def_style_attr_finder.Find(cur_ident);
130 if (def_style_entry != def_style_end) {
131 block = def_style_entry->stringBlock;
132 type_set_flags = def_style_type_set_flags;
133 value = def_style_entry->map.value;
Adam Lesinski4452e132016-10-12 07:47:28 -0700134 if (kDebugStyles) {
Adam Lesinski32e75012017-05-09 15:25:37 -0700135 ALOGI("-> From def style: type=0x%x, data=0x%08x", value.dataType, value.data);
Adam Lesinski4452e132016-10-12 07:47:28 -0700136 }
Adam Lesinski7a37b742016-10-12 14:05:55 -0700137 }
138 }
Adam Lesinski4452e132016-10-12 07:47:28 -0700139
Adam Lesinski7a37b742016-10-12 14:05:55 -0700140 uint32_t resid = 0;
141 if (value.dataType != Res_value::TYPE_NULL) {
142 // Take care of resolving the found resource to its final value.
Adam Lesinski7fb38312018-01-23 03:17:26 -0800143 ssize_t new_block =
144 theme->resolveAttributeReference(&value, block, &resid, &type_set_flags, &config);
145 if (new_block >= 0) block = new_block;
Adam Lesinski7a37b742016-10-12 14:05:55 -0700146 if (kDebugStyles) {
Adam Lesinski32e75012017-05-09 15:25:37 -0700147 ALOGI("-> Resolved attr: type=0x%x, data=0x%08x", value.dataType, value.data);
Adam Lesinski7a37b742016-10-12 14:05:55 -0700148 }
Adam Lesinski32e75012017-05-09 15:25:37 -0700149 } else if (value.data != Res_value::DATA_NULL_EMPTY) {
Adam Lesinski7fb38312018-01-23 03:17:26 -0800150 // If we still don't have a value for this attribute, try to find
151 // it in the theme!
152 ssize_t new_block = theme->getAttribute(cur_ident, &value, &type_set_flags);
153 if (new_block >= 0) {
Adam Lesinski4452e132016-10-12 07:47:28 -0700154 if (kDebugStyles) {
Adam Lesinski32e75012017-05-09 15:25:37 -0700155 ALOGI("-> From theme: type=0x%x, data=0x%08x", value.dataType, value.data);
Adam Lesinski4452e132016-10-12 07:47:28 -0700156 }
Adam Lesinski7fb38312018-01-23 03:17:26 -0800157 new_block = res.resolveReference(&value, new_block, &resid, &type_set_flags, &config);
158 if (new_block >= 0) block = new_block;
Adam Lesinski7a37b742016-10-12 14:05:55 -0700159 if (kDebugStyles) {
Adam Lesinski32e75012017-05-09 15:25:37 -0700160 ALOGI("-> Resolved theme: type=0x%x, data=0x%08x", value.dataType, value.data);
Adam Lesinski4452e132016-10-12 07:47:28 -0700161 }
Adam Lesinski7a37b742016-10-12 14:05:55 -0700162 }
Adam Lesinski4452e132016-10-12 07:47:28 -0700163 }
164
Adam Lesinski7a37b742016-10-12 14:05:55 -0700165 // Deal with the special @null value -- it turns back to TYPE_NULL.
166 if (value.dataType == Res_value::TYPE_REFERENCE && value.data == 0) {
167 if (kDebugStyles) {
168 ALOGI("-> Setting to @null!");
169 }
170 value.dataType = Res_value::TYPE_NULL;
171 value.data = Res_value::DATA_NULL_UNDEFINED;
Adam Lesinski7fb38312018-01-23 03:17:26 -0800172 block = -1;
Adam Lesinski4452e132016-10-12 07:47:28 -0700173 }
Adam Lesinski4452e132016-10-12 07:47:28 -0700174
Adam Lesinski4452e132016-10-12 07:47:28 -0700175 if (kDebugStyles) {
Adam Lesinski32e75012017-05-09 15:25:37 -0700176 ALOGI("Attribute 0x%08x: type=0x%x, data=0x%08x", cur_ident, value.dataType, value.data);
Adam Lesinski4452e132016-10-12 07:47:28 -0700177 }
178
Adam Lesinski7a37b742016-10-12 14:05:55 -0700179 // Write the final value back to Java.
180 out_values[STYLE_TYPE] = value.dataType;
181 out_values[STYLE_DATA] = value.data;
Adam Lesinski7fb38312018-01-23 03:17:26 -0800182 out_values[STYLE_ASSET_COOKIE] =
183 block != -1 ? static_cast<uint32_t>(res.getTableCookie(block))
184 : static_cast<uint32_t>(-1);
Adam Lesinski7a37b742016-10-12 14:05:55 -0700185 out_values[STYLE_RESOURCE_ID] = resid;
186 out_values[STYLE_CHANGING_CONFIGURATIONS] = type_set_flags;
187 out_values[STYLE_DENSITY] = config.density;
188
Adam Lesinski32e75012017-05-09 15:25:37 -0700189 if (out_indices != nullptr &&
190 (value.dataType != Res_value::TYPE_NULL || value.data == Res_value::DATA_NULL_EMPTY)) {
Adam Lesinski7a37b742016-10-12 14:05:55 -0700191 indices_idx++;
192 out_indices[indices_idx] = ii;
193 }
194
195 out_values += STYLE_NUM_ENTRIES;
196 }
197
Adam Lesinski7fb38312018-01-23 03:17:26 -0800198 res.unlock();
199
Adam Lesinski4c67a472016-11-10 16:43:59 -0800200 if (out_indices != nullptr) {
Adam Lesinski7a37b742016-10-12 14:05:55 -0700201 out_indices[0] = indices_idx;
202 }
203 return true;
204}
205
Adam Lesinski7fb38312018-01-23 03:17:26 -0800206void ApplyStyle(ResTable::Theme* theme, ResXMLParser* xml_parser, uint32_t def_style_attr,
207 uint32_t def_style_res, const uint32_t* attrs, size_t attrs_length,
John Reckf32adf42016-11-23 10:39:40 -0800208 uint32_t* out_values, uint32_t* out_indices) {
Adam Lesinski7a37b742016-10-12 14:05:55 -0700209 if (kDebugStyles) {
Adam Lesinski7fb38312018-01-23 03:17:26 -0800210 ALOGI("APPLY STYLE: theme=0x%p defStyleAttr=0x%x defStyleRes=0x%x xml=0x%p",
211 theme, def_style_attr, def_style_res, xml_parser);
Adam Lesinski7a37b742016-10-12 14:05:55 -0700212 }
213
Adam Lesinski7fb38312018-01-23 03:17:26 -0800214 const ResTable& res = theme->getResTable();
Adam Lesinski7a37b742016-10-12 14:05:55 -0700215 ResTable_config config;
216 Res_value value;
217
218 int indices_idx = 0;
219
220 // Load default style from attribute, if specified...
Adam Lesinski7fb38312018-01-23 03:17:26 -0800221 uint32_t def_style_bag_type_set_flags = 0;
Adam Lesinski7a37b742016-10-12 14:05:55 -0700222 if (def_style_attr != 0) {
Adam Lesinski4452e132016-10-12 07:47:28 -0700223 Res_value value;
Adam Lesinski7fb38312018-01-23 03:17:26 -0800224 if (theme->getAttribute(def_style_attr, &value,
225 &def_style_bag_type_set_flags) >= 0) {
Adam Lesinski7a37b742016-10-12 14:05:55 -0700226 if (value.dataType == Res_value::TYPE_REFERENCE) {
Adam Lesinski7fb38312018-01-23 03:17:26 -0800227 def_style_res = value.data;
Adam Lesinski7a37b742016-10-12 14:05:55 -0700228 }
229 }
230 }
Adam Lesinski4452e132016-10-12 07:47:28 -0700231
Adam Lesinski7fb38312018-01-23 03:17:26 -0800232 // Retrieve the style class associated with the current XML tag.
233 int style = 0;
234 uint32_t style_bag_type_set_flags = 0;
Adam Lesinski4c67a472016-11-10 16:43:59 -0800235 if (xml_parser != nullptr) {
Adam Lesinski7a37b742016-10-12 14:05:55 -0700236 ssize_t idx = xml_parser->indexOfStyle();
237 if (idx >= 0 && xml_parser->getAttributeValue(idx, &value) >= 0) {
238 if (value.dataType == value.TYPE_ATTRIBUTE) {
Adam Lesinski7fb38312018-01-23 03:17:26 -0800239 if (theme->getAttribute(value.data, &value, &style_bag_type_set_flags) < 0) {
Adam Lesinski7a37b742016-10-12 14:05:55 -0700240 value.dataType = Res_value::TYPE_NULL;
Adam Lesinski4452e132016-10-12 07:47:28 -0700241 }
Adam Lesinski7a37b742016-10-12 14:05:55 -0700242 }
243 if (value.dataType == value.TYPE_REFERENCE) {
Adam Lesinski7fb38312018-01-23 03:17:26 -0800244 style = value.data;
Adam Lesinski7a37b742016-10-12 14:05:55 -0700245 }
246 }
247 }
248
Adam Lesinski7fb38312018-01-23 03:17:26 -0800249 // Now lock down the resource object and start pulling stuff from it.
250 res.lock();
Adam Lesinskib20a0ce2017-01-23 12:58:11 -0800251
Adam Lesinski7fb38312018-01-23 03:17:26 -0800252 // Retrieve the default style bag, if requested.
253 const ResTable::bag_entry* def_style_attr_start = nullptr;
254 uint32_t def_style_type_set_flags = 0;
255 ssize_t bag_off = def_style_res != 0
256 ? res.getBagLocked(def_style_res, &def_style_attr_start,
257 &def_style_type_set_flags)
258 : -1;
259 def_style_type_set_flags |= def_style_bag_type_set_flags;
260 const ResTable::bag_entry* const def_style_attr_end =
261 def_style_attr_start + (bag_off >= 0 ? bag_off : 0);
262 BagAttributeFinder def_style_attr_finder(def_style_attr_start,
263 def_style_attr_end);
Adam Lesinski7a37b742016-10-12 14:05:55 -0700264
265 // Retrieve the style class bag, if requested.
Adam Lesinski7fb38312018-01-23 03:17:26 -0800266 const ResTable::bag_entry* style_attr_start = nullptr;
267 uint32_t style_type_set_flags = 0;
268 bag_off =
269 style != 0
270 ? res.getBagLocked(style, &style_attr_start, &style_type_set_flags)
271 : -1;
272 style_type_set_flags |= style_bag_type_set_flags;
273 const ResTable::bag_entry* const style_attr_end =
274 style_attr_start + (bag_off >= 0 ? bag_off : 0);
275 BagAttributeFinder style_attr_finder(style_attr_start, style_attr_end);
Adam Lesinski7a37b742016-10-12 14:05:55 -0700276
277 // Retrieve the XML attributes, if requested.
Adam Lesinski7fb38312018-01-23 03:17:26 -0800278 static const ssize_t kXmlBlock = 0x10000000;
Adam Lesinski7a37b742016-10-12 14:05:55 -0700279 XmlAttributeFinder xml_attr_finder(xml_parser);
Adam Lesinski7fb38312018-01-23 03:17:26 -0800280 const size_t xml_attr_end =
281 xml_parser != nullptr ? xml_parser->getAttributeCount() : 0;
Adam Lesinski7a37b742016-10-12 14:05:55 -0700282
283 // Now iterate through all of the attributes that the client has requested,
284 // filling in each with whatever data we can find.
285 for (size_t ii = 0; ii < attrs_length; ii++) {
286 const uint32_t cur_ident = attrs[ii];
287
288 if (kDebugStyles) {
289 ALOGI("RETRIEVING ATTR 0x%08x...", cur_ident);
Adam Lesinski4452e132016-10-12 07:47:28 -0700290 }
291
Adam Lesinski7fb38312018-01-23 03:17:26 -0800292 ssize_t block = kXmlBlock;
293 uint32_t type_set_flags = 0;
Adam Lesinski7a37b742016-10-12 14:05:55 -0700294
295 value.dataType = Res_value::TYPE_NULL;
296 value.data = Res_value::DATA_NULL_UNDEFINED;
297 config.density = 0;
298
299 // Try to find a value for this attribute... we prioritize values
300 // coming from, first XML attributes, then XML style, then default
301 // style, and finally the theme.
302
303 // Walk through the xml attributes looking for the requested attribute.
304 const size_t xml_attr_idx = xml_attr_finder.Find(cur_ident);
Adam Lesinski7fb38312018-01-23 03:17:26 -0800305 if (xml_attr_idx != xml_attr_end) {
Adam Lesinski7a37b742016-10-12 14:05:55 -0700306 // We found the attribute we were looking for.
307 xml_parser->getAttributeValue(xml_attr_idx, &value);
308 if (kDebugStyles) {
Adam Lesinski32e75012017-05-09 15:25:37 -0700309 ALOGI("-> From XML: type=0x%x, data=0x%08x", value.dataType, value.data);
Adam Lesinski7a37b742016-10-12 14:05:55 -0700310 }
Adam Lesinski4452e132016-10-12 07:47:28 -0700311 }
312
Adam Lesinski32e75012017-05-09 15:25:37 -0700313 if (value.dataType == Res_value::TYPE_NULL && value.data != Res_value::DATA_NULL_EMPTY) {
314 // Walk through the style class values looking for the requested attribute.
Adam Lesinski7fb38312018-01-23 03:17:26 -0800315 const ResTable::bag_entry* const style_attr_entry = style_attr_finder.Find(cur_ident);
316 if (style_attr_entry != style_attr_end) {
Adam Lesinski7a37b742016-10-12 14:05:55 -0700317 // We found the attribute we were looking for.
Adam Lesinski7fb38312018-01-23 03:17:26 -0800318 block = style_attr_entry->stringBlock;
319 type_set_flags = style_type_set_flags;
320 value = style_attr_entry->map.value;
Adam Lesinski4452e132016-10-12 07:47:28 -0700321 if (kDebugStyles) {
Adam Lesinski32e75012017-05-09 15:25:37 -0700322 ALOGI("-> From style: type=0x%x, data=0x%08x", value.dataType, value.data);
Adam Lesinski4452e132016-10-12 07:47:28 -0700323 }
Adam Lesinski7a37b742016-10-12 14:05:55 -0700324 }
325 }
Adam Lesinski4452e132016-10-12 07:47:28 -0700326
Adam Lesinski32e75012017-05-09 15:25:37 -0700327 if (value.dataType == Res_value::TYPE_NULL && value.data != Res_value::DATA_NULL_EMPTY) {
328 // Walk through the default style values looking for the requested attribute.
Adam Lesinski7fb38312018-01-23 03:17:26 -0800329 const ResTable::bag_entry* const def_style_attr_entry = def_style_attr_finder.Find(cur_ident);
330 if (def_style_attr_entry != def_style_attr_end) {
Adam Lesinski7a37b742016-10-12 14:05:55 -0700331 // We found the attribute we were looking for.
Adam Lesinski7fb38312018-01-23 03:17:26 -0800332 block = def_style_attr_entry->stringBlock;
333 type_set_flags = style_type_set_flags;
334 value = def_style_attr_entry->map.value;
Adam Lesinski7a37b742016-10-12 14:05:55 -0700335 if (kDebugStyles) {
Adam Lesinski32e75012017-05-09 15:25:37 -0700336 ALOGI("-> From def style: type=0x%x, data=0x%08x", value.dataType, value.data);
Adam Lesinski4452e132016-10-12 07:47:28 -0700337 }
Adam Lesinski7a37b742016-10-12 14:05:55 -0700338 }
339 }
Adam Lesinski4452e132016-10-12 07:47:28 -0700340
Adam Lesinski7fb38312018-01-23 03:17:26 -0800341 uint32_t resid = 0;
Adam Lesinski7a37b742016-10-12 14:05:55 -0700342 if (value.dataType != Res_value::TYPE_NULL) {
343 // Take care of resolving the found resource to its final value.
Adam Lesinski7fb38312018-01-23 03:17:26 -0800344 ssize_t new_block =
345 theme->resolveAttributeReference(&value, block, &resid, &type_set_flags, &config);
346 if (new_block >= 0) {
347 block = new_block;
Adam Lesinski7a37b742016-10-12 14:05:55 -0700348 }
349
350 if (kDebugStyles) {
Adam Lesinski32e75012017-05-09 15:25:37 -0700351 ALOGI("-> Resolved attr: type=0x%x, data=0x%08x", value.dataType, value.data);
Adam Lesinski7a37b742016-10-12 14:05:55 -0700352 }
Adam Lesinski32e75012017-05-09 15:25:37 -0700353 } else if (value.data != Res_value::DATA_NULL_EMPTY) {
354 // If we still don't have a value for this attribute, try to find it in the theme!
Adam Lesinski7fb38312018-01-23 03:17:26 -0800355 ssize_t new_block = theme->getAttribute(cur_ident, &value, &type_set_flags);
356 if (new_block >= 0) {
Adam Lesinski7a37b742016-10-12 14:05:55 -0700357 if (kDebugStyles) {
Adam Lesinski32e75012017-05-09 15:25:37 -0700358 ALOGI("-> From theme: type=0x%x, data=0x%08x", value.dataType, value.data);
Adam Lesinski4452e132016-10-12 07:47:28 -0700359 }
Adam Lesinski7fb38312018-01-23 03:17:26 -0800360 new_block = res.resolveReference(&value, new_block, &resid, &type_set_flags, &config);
361 if (new_block >= 0) {
362 block = new_block;
Adam Lesinski4452e132016-10-12 07:47:28 -0700363 }
364
365 if (kDebugStyles) {
Adam Lesinski32e75012017-05-09 15:25:37 -0700366 ALOGI("-> Resolved theme: type=0x%x, data=0x%08x", value.dataType, value.data);
Adam Lesinski4452e132016-10-12 07:47:28 -0700367 }
Adam Lesinski7a37b742016-10-12 14:05:55 -0700368 }
Adam Lesinski4452e132016-10-12 07:47:28 -0700369 }
370
Adam Lesinski7a37b742016-10-12 14:05:55 -0700371 // Deal with the special @null value -- it turns back to TYPE_NULL.
372 if (value.dataType == Res_value::TYPE_REFERENCE && value.data == 0) {
373 if (kDebugStyles) {
374 ALOGI("-> Setting to @null!");
375 }
376 value.dataType = Res_value::TYPE_NULL;
377 value.data = Res_value::DATA_NULL_UNDEFINED;
Adam Lesinski7fb38312018-01-23 03:17:26 -0800378 block = kXmlBlock;
Adam Lesinski4452e132016-10-12 07:47:28 -0700379 }
Adam Lesinski7a37b742016-10-12 14:05:55 -0700380
381 if (kDebugStyles) {
Adam Lesinski32e75012017-05-09 15:25:37 -0700382 ALOGI("Attribute 0x%08x: type=0x%x, data=0x%08x", cur_ident, value.dataType, value.data);
Adam Lesinski7a37b742016-10-12 14:05:55 -0700383 }
384
385 // Write the final value back to Java.
386 out_values[STYLE_TYPE] = value.dataType;
387 out_values[STYLE_DATA] = value.data;
Adam Lesinski7fb38312018-01-23 03:17:26 -0800388 out_values[STYLE_ASSET_COOKIE] =
389 block != kXmlBlock ? static_cast<uint32_t>(res.getTableCookie(block))
390 : static_cast<uint32_t>(-1);
Adam Lesinski7a37b742016-10-12 14:05:55 -0700391 out_values[STYLE_RESOURCE_ID] = resid;
392 out_values[STYLE_CHANGING_CONFIGURATIONS] = type_set_flags;
393 out_values[STYLE_DENSITY] = config.density;
394
Adam Lesinski32e75012017-05-09 15:25:37 -0700395 if (value.dataType != Res_value::TYPE_NULL || value.data == Res_value::DATA_NULL_EMPTY) {
Adam Lesinski7a37b742016-10-12 14:05:55 -0700396 indices_idx++;
Adam Lesinski06d3e8f2017-01-05 17:03:55 -0800397
398 // out_indices must NOT be nullptr.
Adam Lesinski7a37b742016-10-12 14:05:55 -0700399 out_indices[indices_idx] = ii;
400 }
401
402 out_values += STYLE_NUM_ENTRIES;
403 }
404
Adam Lesinski7fb38312018-01-23 03:17:26 -0800405 res.unlock();
406
Adam Lesinski06d3e8f2017-01-05 17:03:55 -0800407 // out_indices must NOT be nullptr.
408 out_indices[0] = indices_idx;
Adam Lesinski4452e132016-10-12 07:47:28 -0700409}
410
Adam Lesinski7fb38312018-01-23 03:17:26 -0800411bool RetrieveAttributes(const ResTable* res, ResXMLParser* xml_parser,
412 uint32_t* attrs, size_t attrs_length,
413 uint32_t* out_values, uint32_t* out_indices) {
Adam Lesinski7a37b742016-10-12 14:05:55 -0700414 ResTable_config config;
415 Res_value value;
Adam Lesinski4452e132016-10-12 07:47:28 -0700416
Adam Lesinski7a37b742016-10-12 14:05:55 -0700417 int indices_idx = 0;
Adam Lesinski4452e132016-10-12 07:47:28 -0700418
Adam Lesinski7fb38312018-01-23 03:17:26 -0800419 // Now lock down the resource object and start pulling stuff from it.
420 res->lock();
421
Adam Lesinski7a37b742016-10-12 14:05:55 -0700422 // Retrieve the XML attributes, if requested.
423 const size_t xml_attr_count = xml_parser->getAttributeCount();
424 size_t ix = 0;
425 uint32_t cur_xml_attr = xml_parser->getAttributeNameResID(ix);
Adam Lesinski4452e132016-10-12 07:47:28 -0700426
Adam Lesinski7fb38312018-01-23 03:17:26 -0800427 static const ssize_t kXmlBlock = 0x10000000;
428
Adam Lesinski7a37b742016-10-12 14:05:55 -0700429 // Now iterate through all of the attributes that the client has requested,
430 // filling in each with whatever data we can find.
431 for (size_t ii = 0; ii < attrs_length; ii++) {
432 const uint32_t cur_ident = attrs[ii];
Adam Lesinski7fb38312018-01-23 03:17:26 -0800433 ssize_t block = kXmlBlock;
434 uint32_t type_set_flags = 0;
Adam Lesinski4452e132016-10-12 07:47:28 -0700435
Adam Lesinski7a37b742016-10-12 14:05:55 -0700436 value.dataType = Res_value::TYPE_NULL;
437 value.data = Res_value::DATA_NULL_UNDEFINED;
438 config.density = 0;
Adam Lesinski4452e132016-10-12 07:47:28 -0700439
Adam Lesinski7a37b742016-10-12 14:05:55 -0700440 // Try to find a value for this attribute...
441 // Skip through XML attributes until the end or the next possible match.
442 while (ix < xml_attr_count && cur_ident > cur_xml_attr) {
443 ix++;
444 cur_xml_attr = xml_parser->getAttributeNameResID(ix);
445 }
446 // Retrieve the current XML attribute if it matches, and step to next.
447 if (ix < xml_attr_count && cur_ident == cur_xml_attr) {
448 xml_parser->getAttributeValue(ix, &value);
449 ix++;
450 cur_xml_attr = xml_parser->getAttributeNameResID(ix);
Adam Lesinski4452e132016-10-12 07:47:28 -0700451 }
452
Adam Lesinski7fb38312018-01-23 03:17:26 -0800453 uint32_t resid = 0;
Adam Lesinski7a37b742016-10-12 14:05:55 -0700454 if (value.dataType != Res_value::TYPE_NULL) {
455 // Take care of resolving the found resource to its final value.
Adam Lesinski7fb38312018-01-23 03:17:26 -0800456 // printf("Resolving attribute reference\n");
457 ssize_t new_block = res->resolveReference(&value, block, &resid,
458 &type_set_flags, &config);
459 if (new_block >= 0) block = new_block;
Adam Lesinski4452e132016-10-12 07:47:28 -0700460 }
Adam Lesinski7a37b742016-10-12 14:05:55 -0700461
462 // Deal with the special @null value -- it turns back to TYPE_NULL.
463 if (value.dataType == Res_value::TYPE_REFERENCE && value.data == 0) {
464 value.dataType = Res_value::TYPE_NULL;
465 value.data = Res_value::DATA_NULL_UNDEFINED;
Adam Lesinski7fb38312018-01-23 03:17:26 -0800466 block = kXmlBlock;
Adam Lesinski7a37b742016-10-12 14:05:55 -0700467 }
468
469 // Write the final value back to Java.
470 out_values[STYLE_TYPE] = value.dataType;
471 out_values[STYLE_DATA] = value.data;
Adam Lesinski7fb38312018-01-23 03:17:26 -0800472 out_values[STYLE_ASSET_COOKIE] =
473 block != kXmlBlock ? static_cast<uint32_t>(res->getTableCookie(block))
474 : static_cast<uint32_t>(-1);
Adam Lesinski7a37b742016-10-12 14:05:55 -0700475 out_values[STYLE_RESOURCE_ID] = resid;
476 out_values[STYLE_CHANGING_CONFIGURATIONS] = type_set_flags;
477 out_values[STYLE_DENSITY] = config.density;
478
Adam Lesinski32e75012017-05-09 15:25:37 -0700479 if (out_indices != nullptr &&
480 (value.dataType != Res_value::TYPE_NULL || value.data == Res_value::DATA_NULL_EMPTY)) {
Adam Lesinski7a37b742016-10-12 14:05:55 -0700481 indices_idx++;
482 out_indices[indices_idx] = ii;
483 }
484
485 out_values += STYLE_NUM_ENTRIES;
486 }
487
Adam Lesinski7fb38312018-01-23 03:17:26 -0800488 res->unlock();
489
Adam Lesinski4c67a472016-11-10 16:43:59 -0800490 if (out_indices != nullptr) {
Adam Lesinski7a37b742016-10-12 14:05:55 -0700491 out_indices[0] = indices_idx;
492 }
493 return true;
Adam Lesinski4452e132016-10-12 07:47:28 -0700494}
495
Adam Lesinski7a37b742016-10-12 14:05:55 -0700496} // namespace android