blob: 18d74efdbacf250426927b9eeb20751336654a00 [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
Adam Lesinskibebfcc42018-02-12 14:27:46 -080023#include "androidfw/AssetManager2.h"
Adam Lesinski4c67a472016-11-10 16:43:59 -080024#include "androidfw/AttributeFinder.h"
Adam Lesinski4452e132016-10-12 07:47:28 -070025
26constexpr bool kDebugStyles = false;
27
28namespace android {
29
Adam Lesinskibebfcc42018-02-12 14:27:46 -080030// Java asset cookies have 0 as an invalid cookie, but TypedArray expects < 0.
31static uint32_t ApkAssetsCookieToJavaCookie(ApkAssetsCookie cookie) {
32 return cookie != kInvalidCookie ? static_cast<uint32_t>(cookie + 1) : static_cast<uint32_t>(-1);
33}
34
Adam Lesinski4c67a472016-11-10 16:43:59 -080035class XmlAttributeFinder
36 : public BackTrackingAttributeFinder<XmlAttributeFinder, size_t> {
Adam Lesinski7a37b742016-10-12 14:05:55 -070037 public:
38 explicit XmlAttributeFinder(const ResXMLParser* parser)
Adam Lesinski4c67a472016-11-10 16:43:59 -080039 : BackTrackingAttributeFinder(
40 0, parser != nullptr ? parser->getAttributeCount() : 0),
Adam Lesinski7a37b742016-10-12 14:05:55 -070041 parser_(parser) {}
Adam Lesinski4452e132016-10-12 07:47:28 -070042
Adam Lesinski4c67a472016-11-10 16:43:59 -080043 inline uint32_t GetAttribute(size_t index) const {
44 return parser_->getAttributeNameResID(index);
45 }
Adam Lesinski4452e132016-10-12 07:47:28 -070046
Adam Lesinski7a37b742016-10-12 14:05:55 -070047 private:
48 const ResXMLParser* parser_;
Adam Lesinski4452e132016-10-12 07:47:28 -070049};
50
Adam Lesinski7a37b742016-10-12 14:05:55 -070051class BagAttributeFinder
Adam Lesinskibebfcc42018-02-12 14:27:46 -080052 : public BackTrackingAttributeFinder<BagAttributeFinder, const ResolvedBag::Entry*> {
Adam Lesinski7a37b742016-10-12 14:05:55 -070053 public:
Chih-Hung Hsiehc2ace0c2018-12-20 13:46:53 -080054 explicit BagAttributeFinder(const ResolvedBag* bag)
Adam Lesinskibebfcc42018-02-12 14:27:46 -080055 : BackTrackingAttributeFinder(bag != nullptr ? bag->entries : nullptr,
56 bag != nullptr ? bag->entries + bag->entry_count : nullptr) {
57 }
Adam Lesinski4452e132016-10-12 07:47:28 -070058
Adam Lesinskibebfcc42018-02-12 14:27:46 -080059 inline uint32_t GetAttribute(const ResolvedBag::Entry* entry) const {
60 return entry->key;
Adam Lesinski7a37b742016-10-12 14:05:55 -070061 }
Adam Lesinski4452e132016-10-12 07:47:28 -070062};
63
Adam Lesinskibebfcc42018-02-12 14:27:46 -080064bool ResolveAttrs(Theme* theme, uint32_t def_style_attr, uint32_t def_style_res,
65 uint32_t* src_values, size_t src_values_length, uint32_t* attrs,
66 size_t attrs_length, uint32_t* out_values, uint32_t* out_indices) {
Adam Lesinski7a37b742016-10-12 14:05:55 -070067 if (kDebugStyles) {
Adam Lesinski4c67a472016-11-10 16:43:59 -080068 ALOGI("APPLY STYLE: theme=0x%p defStyleAttr=0x%x defStyleRes=0x%x", theme,
69 def_style_attr, def_style_res);
Adam Lesinski7a37b742016-10-12 14:05:55 -070070 }
71
Adam Lesinskibebfcc42018-02-12 14:27:46 -080072 AssetManager2* assetmanager = theme->GetAssetManager();
Adam Lesinski7a37b742016-10-12 14:05:55 -070073 ResTable_config config;
74 Res_value value;
75
76 int indices_idx = 0;
77
78 // Load default style from attribute, if specified...
Adam Lesinskibebfcc42018-02-12 14:27:46 -080079 uint32_t def_style_flags = 0u;
Adam Lesinski7a37b742016-10-12 14:05:55 -070080 if (def_style_attr != 0) {
81 Res_value value;
Adam Lesinskibebfcc42018-02-12 14:27:46 -080082 if (theme->GetAttribute(def_style_attr, &value, &def_style_flags) != kInvalidCookie) {
Adam Lesinski7a37b742016-10-12 14:05:55 -070083 if (value.dataType == Res_value::TYPE_REFERENCE) {
84 def_style_res = value.data;
85 }
86 }
87 }
88
Adam Lesinskibde1df22018-02-09 11:12:22 -080089 // Retrieve the default style bag, if requested.
Adam Lesinskibebfcc42018-02-12 14:27:46 -080090 const ResolvedBag* default_style_bag = nullptr;
91 if (def_style_res != 0) {
92 default_style_bag = assetmanager->GetBag(def_style_res);
93 if (default_style_bag != nullptr) {
94 def_style_flags |= default_style_bag->type_spec_flags;
95 }
96 }
97
98 BagAttributeFinder def_style_attr_finder(default_style_bag);
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 Lesinskibebfcc42018-02-12 14:27:46 -0800109 ApkAssetsCookie cookie = kInvalidCookie;
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 Lesinskibebfcc42018-02-12 14:27:46 -0800125 ALOGI("-> From values: type=0x%x, data=0x%08x", value.dataType, value.data);
Adam Lesinski7a37b742016-10-12 14:05:55 -0700126 }
Adam Lesinski32e75012017-05-09 15:25:37 -0700127 } else {
Adam Lesinskibebfcc42018-02-12 14:27:46 -0800128 const ResolvedBag::Entry* const entry = def_style_attr_finder.Find(cur_ident);
129 if (entry != def_style_attr_finder.end()) {
130 cookie = entry->cookie;
131 type_set_flags = def_style_flags;
132 value = entry->value;
Adam Lesinski4452e132016-10-12 07:47:28 -0700133 if (kDebugStyles) {
Adam Lesinski32e75012017-05-09 15:25:37 -0700134 ALOGI("-> From def style: type=0x%x, data=0x%08x", value.dataType, value.data);
Adam Lesinski4452e132016-10-12 07:47:28 -0700135 }
Adam Lesinski7a37b742016-10-12 14:05:55 -0700136 }
137 }
Adam Lesinski4452e132016-10-12 07:47:28 -0700138
Adam Lesinski7a37b742016-10-12 14:05:55 -0700139 uint32_t resid = 0;
140 if (value.dataType != Res_value::TYPE_NULL) {
141 // Take care of resolving the found resource to its final value.
Adam Lesinskibebfcc42018-02-12 14:27:46 -0800142 ApkAssetsCookie new_cookie =
143 theme->ResolveAttributeReference(cookie, &value, &config, &type_set_flags, &resid);
144 if (new_cookie != kInvalidCookie) {
145 cookie = new_cookie;
146 }
Adam Lesinski7a37b742016-10-12 14:05:55 -0700147 if (kDebugStyles) {
Adam Lesinski32e75012017-05-09 15:25:37 -0700148 ALOGI("-> Resolved attr: type=0x%x, data=0x%08x", value.dataType, value.data);
Adam Lesinski7a37b742016-10-12 14:05:55 -0700149 }
Adam Lesinski32e75012017-05-09 15:25:37 -0700150 } else if (value.data != Res_value::DATA_NULL_EMPTY) {
Adam Lesinskibebfcc42018-02-12 14:27:46 -0800151 // If we still don't have a value for this attribute, try to find it in the theme!
152 ApkAssetsCookie new_cookie = theme->GetAttribute(cur_ident, &value, &type_set_flags);
153 if (new_cookie != kInvalidCookie) {
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 Lesinskibebfcc42018-02-12 14:27:46 -0800157 new_cookie =
158 assetmanager->ResolveReference(new_cookie, &value, &config, &type_set_flags, &resid);
159 if (new_cookie != kInvalidCookie) {
160 cookie = new_cookie;
161 }
Adam Lesinski7a37b742016-10-12 14:05:55 -0700162 if (kDebugStyles) {
Adam Lesinski32e75012017-05-09 15:25:37 -0700163 ALOGI("-> Resolved theme: type=0x%x, data=0x%08x", value.dataType, value.data);
Adam Lesinski4452e132016-10-12 07:47:28 -0700164 }
Adam Lesinski7a37b742016-10-12 14:05:55 -0700165 }
Adam Lesinski4452e132016-10-12 07:47:28 -0700166 }
167
Adam Lesinski7a37b742016-10-12 14:05:55 -0700168 // Deal with the special @null value -- it turns back to TYPE_NULL.
169 if (value.dataType == Res_value::TYPE_REFERENCE && value.data == 0) {
170 if (kDebugStyles) {
171 ALOGI("-> Setting to @null!");
172 }
173 value.dataType = Res_value::TYPE_NULL;
174 value.data = Res_value::DATA_NULL_UNDEFINED;
Adam Lesinskibebfcc42018-02-12 14:27:46 -0800175 cookie = kInvalidCookie;
Adam Lesinski4452e132016-10-12 07:47:28 -0700176 }
Adam Lesinski4452e132016-10-12 07:47:28 -0700177
Adam Lesinski4452e132016-10-12 07:47:28 -0700178 if (kDebugStyles) {
Adam Lesinski32e75012017-05-09 15:25:37 -0700179 ALOGI("Attribute 0x%08x: type=0x%x, data=0x%08x", cur_ident, value.dataType, value.data);
Adam Lesinski4452e132016-10-12 07:47:28 -0700180 }
181
Adam Lesinski7a37b742016-10-12 14:05:55 -0700182 // Write the final value back to Java.
183 out_values[STYLE_TYPE] = value.dataType;
184 out_values[STYLE_DATA] = value.data;
Adam Lesinskibebfcc42018-02-12 14:27:46 -0800185 out_values[STYLE_ASSET_COOKIE] = ApkAssetsCookieToJavaCookie(cookie);
Adam Lesinski7a37b742016-10-12 14:05:55 -0700186 out_values[STYLE_RESOURCE_ID] = resid;
187 out_values[STYLE_CHANGING_CONFIGURATIONS] = type_set_flags;
188 out_values[STYLE_DENSITY] = config.density;
189
Adam Lesinski32e75012017-05-09 15:25:37 -0700190 if (out_indices != nullptr &&
191 (value.dataType != Res_value::TYPE_NULL || value.data == Res_value::DATA_NULL_EMPTY)) {
Adam Lesinski7a37b742016-10-12 14:05:55 -0700192 indices_idx++;
193 out_indices[indices_idx] = ii;
194 }
195
196 out_values += STYLE_NUM_ENTRIES;
197 }
198
Adam Lesinski4c67a472016-11-10 16:43:59 -0800199 if (out_indices != nullptr) {
Adam Lesinski7a37b742016-10-12 14:05:55 -0700200 out_indices[0] = indices_idx;
201 }
202 return true;
203}
204
Adam Lesinskibebfcc42018-02-12 14:27:46 -0800205void ApplyStyle(Theme* theme, ResXMLParser* xml_parser, uint32_t def_style_attr,
206 uint32_t def_style_resid, const uint32_t* attrs, size_t attrs_length,
John Reckf32adf42016-11-23 10:39:40 -0800207 uint32_t* out_values, uint32_t* out_indices) {
Adam Lesinski7a37b742016-10-12 14:05:55 -0700208 if (kDebugStyles) {
Adam Lesinskibebfcc42018-02-12 14:27:46 -0800209 ALOGI("APPLY STYLE: theme=0x%p defStyleAttr=0x%x defStyleRes=0x%x xml=0x%p", theme,
210 def_style_attr, def_style_resid, xml_parser);
Adam Lesinski7a37b742016-10-12 14:05:55 -0700211 }
212
Adam Lesinskibebfcc42018-02-12 14:27:46 -0800213 AssetManager2* assetmanager = theme->GetAssetManager();
Adam Lesinski7a37b742016-10-12 14:05:55 -0700214 ResTable_config config;
215 Res_value value;
216
217 int indices_idx = 0;
218
219 // Load default style from attribute, if specified...
Adam Lesinskibebfcc42018-02-12 14:27:46 -0800220 uint32_t def_style_flags = 0u;
Adam Lesinski7a37b742016-10-12 14:05:55 -0700221 if (def_style_attr != 0) {
Adam Lesinski4452e132016-10-12 07:47:28 -0700222 Res_value value;
Adam Lesinskibebfcc42018-02-12 14:27:46 -0800223 if (theme->GetAttribute(def_style_attr, &value, &def_style_flags) != kInvalidCookie) {
Adam Lesinski7a37b742016-10-12 14:05:55 -0700224 if (value.dataType == Res_value::TYPE_REFERENCE) {
Adam Lesinskibebfcc42018-02-12 14:27:46 -0800225 def_style_resid = value.data;
Adam Lesinski7a37b742016-10-12 14:05:55 -0700226 }
227 }
228 }
Adam Lesinski4452e132016-10-12 07:47:28 -0700229
Adam Lesinskibebfcc42018-02-12 14:27:46 -0800230 // Retrieve the style resource ID associated with the current XML tag's style attribute.
231 uint32_t style_resid = 0u;
232 uint32_t style_flags = 0u;
Adam Lesinski4c67a472016-11-10 16:43:59 -0800233 if (xml_parser != nullptr) {
Adam Lesinski7a37b742016-10-12 14:05:55 -0700234 ssize_t idx = xml_parser->indexOfStyle();
235 if (idx >= 0 && xml_parser->getAttributeValue(idx, &value) >= 0) {
236 if (value.dataType == value.TYPE_ATTRIBUTE) {
Adam Lesinskibebfcc42018-02-12 14:27:46 -0800237 // Resolve the attribute with out theme.
238 if (theme->GetAttribute(value.data, &value, &style_flags) == kInvalidCookie) {
Adam Lesinski7a37b742016-10-12 14:05:55 -0700239 value.dataType = Res_value::TYPE_NULL;
Adam Lesinski4452e132016-10-12 07:47:28 -0700240 }
Adam Lesinski7a37b742016-10-12 14:05:55 -0700241 }
Adam Lesinskibebfcc42018-02-12 14:27:46 -0800242
Adam Lesinski7a37b742016-10-12 14:05:55 -0700243 if (value.dataType == value.TYPE_REFERENCE) {
Adam Lesinskibebfcc42018-02-12 14:27:46 -0800244 style_resid = value.data;
Adam Lesinski7a37b742016-10-12 14:05:55 -0700245 }
246 }
247 }
248
Adam Lesinskibde1df22018-02-09 11:12:22 -0800249 // Retrieve the default style bag, if requested.
Adam Lesinskibebfcc42018-02-12 14:27:46 -0800250 const ResolvedBag* default_style_bag = nullptr;
251 if (def_style_resid != 0) {
252 default_style_bag = assetmanager->GetBag(def_style_resid);
253 if (default_style_bag != nullptr) {
254 def_style_flags |= default_style_bag->type_spec_flags;
255 }
256 }
257
258 BagAttributeFinder def_style_attr_finder(default_style_bag);
Adam Lesinski7a37b742016-10-12 14:05:55 -0700259
260 // Retrieve the style class bag, if requested.
Adam Lesinskibebfcc42018-02-12 14:27:46 -0800261 const ResolvedBag* xml_style_bag = nullptr;
262 if (style_resid != 0) {
263 xml_style_bag = assetmanager->GetBag(style_resid);
264 if (xml_style_bag != nullptr) {
265 style_flags |= xml_style_bag->type_spec_flags;
266 }
267 }
268
269 BagAttributeFinder xml_style_attr_finder(xml_style_bag);
Adam Lesinski7a37b742016-10-12 14:05:55 -0700270
271 // Retrieve the XML attributes, if requested.
Adam Lesinski7a37b742016-10-12 14:05:55 -0700272 XmlAttributeFinder xml_attr_finder(xml_parser);
Adam Lesinski7a37b742016-10-12 14:05:55 -0700273
274 // Now iterate through all of the attributes that the client has requested,
275 // filling in each with whatever data we can find.
276 for (size_t ii = 0; ii < attrs_length; ii++) {
277 const uint32_t cur_ident = attrs[ii];
278
279 if (kDebugStyles) {
280 ALOGI("RETRIEVING ATTR 0x%08x...", cur_ident);
Adam Lesinski4452e132016-10-12 07:47:28 -0700281 }
282
Adam Lesinskibebfcc42018-02-12 14:27:46 -0800283 ApkAssetsCookie cookie = kInvalidCookie;
284 uint32_t type_set_flags = 0u;
Adam Lesinski7a37b742016-10-12 14:05:55 -0700285
286 value.dataType = Res_value::TYPE_NULL;
287 value.data = Res_value::DATA_NULL_UNDEFINED;
288 config.density = 0;
Aurimas Liutikasce7c99c2018-12-18 16:20:49 -0800289 uint32_t source_style_resid = 0;
Adam Lesinski7a37b742016-10-12 14:05:55 -0700290
291 // Try to find a value for this attribute... we prioritize values
292 // coming from, first XML attributes, then XML style, then default
293 // style, and finally the theme.
294
295 // Walk through the xml attributes looking for the requested attribute.
296 const size_t xml_attr_idx = xml_attr_finder.Find(cur_ident);
Adam Lesinskibebfcc42018-02-12 14:27:46 -0800297 if (xml_attr_idx != xml_attr_finder.end()) {
Adam Lesinski7a37b742016-10-12 14:05:55 -0700298 // We found the attribute we were looking for.
299 xml_parser->getAttributeValue(xml_attr_idx, &value);
300 if (kDebugStyles) {
Adam Lesinski32e75012017-05-09 15:25:37 -0700301 ALOGI("-> From XML: type=0x%x, data=0x%08x", value.dataType, value.data);
Adam Lesinski7a37b742016-10-12 14:05:55 -0700302 }
Adam Lesinski4452e132016-10-12 07:47:28 -0700303 }
304
Adam Lesinski32e75012017-05-09 15:25:37 -0700305 if (value.dataType == Res_value::TYPE_NULL && value.data != Res_value::DATA_NULL_EMPTY) {
306 // Walk through the style class values looking for the requested attribute.
Adam Lesinskibebfcc42018-02-12 14:27:46 -0800307 const ResolvedBag::Entry* entry = xml_style_attr_finder.Find(cur_ident);
308 if (entry != xml_style_attr_finder.end()) {
Adam Lesinski7a37b742016-10-12 14:05:55 -0700309 // We found the attribute we were looking for.
Adam Lesinskibebfcc42018-02-12 14:27:46 -0800310 cookie = entry->cookie;
311 type_set_flags = style_flags;
312 value = entry->value;
Aurimas Liutikasce7c99c2018-12-18 16:20:49 -0800313 source_style_resid = entry->style;
Adam Lesinski4452e132016-10-12 07:47:28 -0700314 if (kDebugStyles) {
Aurimas Liutikasd42a6702018-11-15 15:48:28 -0800315 ALOGI("-> From style: type=0x%x, data=0x%08x, style=0x%08x", value.dataType, value.data,
316 entry->style);
Adam Lesinski4452e132016-10-12 07:47:28 -0700317 }
Adam Lesinski7a37b742016-10-12 14:05:55 -0700318 }
319 }
Adam Lesinski4452e132016-10-12 07:47:28 -0700320
Adam Lesinski32e75012017-05-09 15:25:37 -0700321 if (value.dataType == Res_value::TYPE_NULL && value.data != Res_value::DATA_NULL_EMPTY) {
322 // Walk through the default style values looking for the requested attribute.
Adam Lesinskibebfcc42018-02-12 14:27:46 -0800323 const ResolvedBag::Entry* entry = def_style_attr_finder.Find(cur_ident);
324 if (entry != def_style_attr_finder.end()) {
Adam Lesinski7a37b742016-10-12 14:05:55 -0700325 // We found the attribute we were looking for.
Adam Lesinskibebfcc42018-02-12 14:27:46 -0800326 cookie = entry->cookie;
327 type_set_flags = def_style_flags;
328 value = entry->value;
Adam Lesinski7a37b742016-10-12 14:05:55 -0700329 if (kDebugStyles) {
Aurimas Liutikasce7c99c2018-12-18 16:20:49 -0800330 ALOGI("-> From def style: type=0x%x, data=0x%08x, style=0x%08x", value.dataType, value.data,
331 entry->style);
Adam Lesinski4452e132016-10-12 07:47:28 -0700332 }
Aurimas Liutikasce7c99c2018-12-18 16:20:49 -0800333 source_style_resid = entry->style;
Adam Lesinski7a37b742016-10-12 14:05:55 -0700334 }
335 }
Adam Lesinski4452e132016-10-12 07:47:28 -0700336
Adam Lesinskibebfcc42018-02-12 14:27:46 -0800337 uint32_t resid = 0u;
Adam Lesinski7a37b742016-10-12 14:05:55 -0700338 if (value.dataType != Res_value::TYPE_NULL) {
339 // Take care of resolving the found resource to its final value.
Adam Lesinskibebfcc42018-02-12 14:27:46 -0800340 ApkAssetsCookie new_cookie =
341 theme->ResolveAttributeReference(cookie, &value, &config, &type_set_flags, &resid);
342 if (new_cookie != kInvalidCookie) {
343 cookie = new_cookie;
Adam Lesinski7a37b742016-10-12 14:05:55 -0700344 }
345
346 if (kDebugStyles) {
Adam Lesinski32e75012017-05-09 15:25:37 -0700347 ALOGI("-> Resolved attr: type=0x%x, data=0x%08x", value.dataType, value.data);
Adam Lesinski7a37b742016-10-12 14:05:55 -0700348 }
Adam Lesinski32e75012017-05-09 15:25:37 -0700349 } else if (value.data != Res_value::DATA_NULL_EMPTY) {
350 // If we still don't have a value for this attribute, try to find it in the theme!
Adam Lesinskibebfcc42018-02-12 14:27:46 -0800351 ApkAssetsCookie new_cookie = theme->GetAttribute(cur_ident, &value, &type_set_flags);
352 if (new_cookie != kInvalidCookie) {
Adam Lesinski7a37b742016-10-12 14:05:55 -0700353 if (kDebugStyles) {
Adam Lesinski32e75012017-05-09 15:25:37 -0700354 ALOGI("-> From theme: type=0x%x, data=0x%08x", value.dataType, value.data);
Adam Lesinski4452e132016-10-12 07:47:28 -0700355 }
Adam Lesinskibebfcc42018-02-12 14:27:46 -0800356 new_cookie =
357 assetmanager->ResolveReference(new_cookie, &value, &config, &type_set_flags, &resid);
358 if (new_cookie != kInvalidCookie) {
359 cookie = new_cookie;
Adam Lesinski4452e132016-10-12 07:47:28 -0700360 }
361
362 if (kDebugStyles) {
Adam Lesinski32e75012017-05-09 15:25:37 -0700363 ALOGI("-> Resolved theme: type=0x%x, data=0x%08x", value.dataType, value.data);
Adam Lesinski4452e132016-10-12 07:47:28 -0700364 }
Adam Lesinski7a37b742016-10-12 14:05:55 -0700365 }
Adam Lesinski4452e132016-10-12 07:47:28 -0700366 }
367
Adam Lesinski7a37b742016-10-12 14:05:55 -0700368 // Deal with the special @null value -- it turns back to TYPE_NULL.
369 if (value.dataType == Res_value::TYPE_REFERENCE && value.data == 0) {
370 if (kDebugStyles) {
371 ALOGI("-> Setting to @null!");
372 }
373 value.dataType = Res_value::TYPE_NULL;
374 value.data = Res_value::DATA_NULL_UNDEFINED;
Adam Lesinskibebfcc42018-02-12 14:27:46 -0800375 cookie = kInvalidCookie;
Adam Lesinski4452e132016-10-12 07:47:28 -0700376 }
Adam Lesinski7a37b742016-10-12 14:05:55 -0700377
378 if (kDebugStyles) {
Adam Lesinski32e75012017-05-09 15:25:37 -0700379 ALOGI("Attribute 0x%08x: type=0x%x, data=0x%08x", cur_ident, value.dataType, value.data);
Adam Lesinski7a37b742016-10-12 14:05:55 -0700380 }
381
382 // Write the final value back to Java.
383 out_values[STYLE_TYPE] = value.dataType;
384 out_values[STYLE_DATA] = value.data;
Adam Lesinskibebfcc42018-02-12 14:27:46 -0800385 out_values[STYLE_ASSET_COOKIE] = ApkAssetsCookieToJavaCookie(cookie);
Adam Lesinski7a37b742016-10-12 14:05:55 -0700386 out_values[STYLE_RESOURCE_ID] = resid;
387 out_values[STYLE_CHANGING_CONFIGURATIONS] = type_set_flags;
388 out_values[STYLE_DENSITY] = config.density;
Aurimas Liutikasce7c99c2018-12-18 16:20:49 -0800389 out_values[SYTLE_SOURCE_STYLE] = source_style_resid;
Adam Lesinski7a37b742016-10-12 14:05:55 -0700390
Adam Lesinski32e75012017-05-09 15:25:37 -0700391 if (value.dataType != Res_value::TYPE_NULL || value.data == Res_value::DATA_NULL_EMPTY) {
Adam Lesinski7a37b742016-10-12 14:05:55 -0700392 indices_idx++;
Adam Lesinski06d3e8f2017-01-05 17:03:55 -0800393
394 // out_indices must NOT be nullptr.
Adam Lesinski7a37b742016-10-12 14:05:55 -0700395 out_indices[indices_idx] = ii;
396 }
Adam Lesinski7a37b742016-10-12 14:05:55 -0700397 out_values += STYLE_NUM_ENTRIES;
398 }
399
Adam Lesinski06d3e8f2017-01-05 17:03:55 -0800400 // out_indices must NOT be nullptr.
401 out_indices[0] = indices_idx;
Adam Lesinski4452e132016-10-12 07:47:28 -0700402}
403
Adam Lesinskibebfcc42018-02-12 14:27:46 -0800404bool RetrieveAttributes(AssetManager2* assetmanager, ResXMLParser* xml_parser, uint32_t* attrs,
405 size_t attrs_length, uint32_t* out_values, uint32_t* out_indices) {
Adam Lesinski7a37b742016-10-12 14:05:55 -0700406 ResTable_config config;
407 Res_value value;
Adam Lesinski4452e132016-10-12 07:47:28 -0700408
Adam Lesinski7a37b742016-10-12 14:05:55 -0700409 int indices_idx = 0;
Adam Lesinski4452e132016-10-12 07:47:28 -0700410
Adam Lesinski7a37b742016-10-12 14:05:55 -0700411 // Retrieve the XML attributes, if requested.
412 const size_t xml_attr_count = xml_parser->getAttributeCount();
413 size_t ix = 0;
414 uint32_t cur_xml_attr = xml_parser->getAttributeNameResID(ix);
Adam Lesinski4452e132016-10-12 07:47:28 -0700415
Adam Lesinski7a37b742016-10-12 14:05:55 -0700416 // Now iterate through all of the attributes that the client has requested,
417 // filling in each with whatever data we can find.
418 for (size_t ii = 0; ii < attrs_length; ii++) {
419 const uint32_t cur_ident = attrs[ii];
Adam Lesinskibebfcc42018-02-12 14:27:46 -0800420 ApkAssetsCookie cookie = kInvalidCookie;
421 uint32_t type_set_flags = 0u;
Adam Lesinski4452e132016-10-12 07:47:28 -0700422
Adam Lesinski7a37b742016-10-12 14:05:55 -0700423 value.dataType = Res_value::TYPE_NULL;
424 value.data = Res_value::DATA_NULL_UNDEFINED;
425 config.density = 0;
Adam Lesinski4452e132016-10-12 07:47:28 -0700426
Adam Lesinski7a37b742016-10-12 14:05:55 -0700427 // Try to find a value for this attribute...
428 // Skip through XML attributes until the end or the next possible match.
429 while (ix < xml_attr_count && cur_ident > cur_xml_attr) {
430 ix++;
431 cur_xml_attr = xml_parser->getAttributeNameResID(ix);
432 }
433 // Retrieve the current XML attribute if it matches, and step to next.
434 if (ix < xml_attr_count && cur_ident == cur_xml_attr) {
435 xml_parser->getAttributeValue(ix, &value);
436 ix++;
437 cur_xml_attr = xml_parser->getAttributeNameResID(ix);
Adam Lesinski4452e132016-10-12 07:47:28 -0700438 }
439
Adam Lesinskibebfcc42018-02-12 14:27:46 -0800440 uint32_t resid = 0u;
Adam Lesinski7a37b742016-10-12 14:05:55 -0700441 if (value.dataType != Res_value::TYPE_NULL) {
442 // Take care of resolving the found resource to its final value.
Adam Lesinskibebfcc42018-02-12 14:27:46 -0800443 ApkAssetsCookie new_cookie =
444 assetmanager->ResolveReference(cookie, &value, &config, &type_set_flags, &resid);
445 if (new_cookie != kInvalidCookie) {
446 cookie = new_cookie;
447 }
Adam Lesinski4452e132016-10-12 07:47:28 -0700448 }
Adam Lesinski7a37b742016-10-12 14:05:55 -0700449
450 // Deal with the special @null value -- it turns back to TYPE_NULL.
451 if (value.dataType == Res_value::TYPE_REFERENCE && value.data == 0) {
452 value.dataType = Res_value::TYPE_NULL;
453 value.data = Res_value::DATA_NULL_UNDEFINED;
Adam Lesinskibebfcc42018-02-12 14:27:46 -0800454 cookie = kInvalidCookie;
Adam Lesinski7a37b742016-10-12 14:05:55 -0700455 }
456
457 // Write the final value back to Java.
458 out_values[STYLE_TYPE] = value.dataType;
459 out_values[STYLE_DATA] = value.data;
Adam Lesinskibebfcc42018-02-12 14:27:46 -0800460 out_values[STYLE_ASSET_COOKIE] = ApkAssetsCookieToJavaCookie(cookie);
Adam Lesinski7a37b742016-10-12 14:05:55 -0700461 out_values[STYLE_RESOURCE_ID] = resid;
462 out_values[STYLE_CHANGING_CONFIGURATIONS] = type_set_flags;
463 out_values[STYLE_DENSITY] = config.density;
464
Adam Lesinski32e75012017-05-09 15:25:37 -0700465 if (out_indices != nullptr &&
466 (value.dataType != Res_value::TYPE_NULL || value.data == Res_value::DATA_NULL_EMPTY)) {
Adam Lesinski7a37b742016-10-12 14:05:55 -0700467 indices_idx++;
468 out_indices[indices_idx] = ii;
469 }
470
471 out_values += STYLE_NUM_ENTRIES;
472 }
473
Adam Lesinski4c67a472016-11-10 16:43:59 -0800474 if (out_indices != nullptr) {
Adam Lesinski7a37b742016-10-12 14:05:55 -0700475 out_indices[0] = indices_idx;
476 }
477 return true;
Adam Lesinski4452e132016-10-12 07:47:28 -0700478}
479
Adam Lesinski7a37b742016-10-12 14:05:55 -0700480} // namespace android