Loading core/java/android/content/res/TypedArray.java +5 −3 Original line number Diff line number Diff line Loading @@ -103,7 +103,8 @@ public class TypedArray { } /** * Return the number of indices in the array that actually have data. * Returns the number of indices in the array that actually have data. Attributes with a value * of @empty are included, as this is an explicit indicator. * * @throws RuntimeException if the TypedArray has already been recycled. */ Loading @@ -116,7 +117,8 @@ public class TypedArray { } /** * Returns an index in the array that has data. * Returns an index in the array that has data. Attributes with a value of @empty are included, * as this is an explicit indicator. * * @param at The index you would like to returned, ranging from 0 to * {@link #getIndexCount()}. Loading Loading @@ -1017,7 +1019,7 @@ public class TypedArray { * @param outValue TypedValue object in which to place the attribute's * data. * * @return {@code true} if the value was retrieved, false otherwise. * @return {@code true} if the value was retrieved and not @empty, {@code false} otherwise. * @throws RuntimeException if the TypedArray has already been recycled. */ public boolean getValue(@StyleableRes int index, TypedValue outValue) { Loading libs/androidfw/AttributeResolution.cpp +39 −64 Original line number Diff line number Diff line Loading @@ -44,8 +44,7 @@ class XmlAttributeFinder }; class BagAttributeFinder : public BackTrackingAttributeFinder<BagAttributeFinder, const ResTable::bag_entry*> { : public BackTrackingAttributeFinder<BagAttributeFinder, const ResTable::bag_entry*> { public: BagAttributeFinder(const ResTable::bag_entry* start, const ResTable::bag_entry* end) Loading Loading @@ -76,8 +75,7 @@ bool ResolveAttrs(ResTable::Theme* theme, uint32_t def_style_attr, uint32_t def_style_bag_type_set_flags = 0; if (def_style_attr != 0) { Res_value value; if (theme->getAttribute(def_style_attr, &value, &def_style_bag_type_set_flags) >= 0) { if (theme->getAttribute(def_style_attr, &value, &def_style_bag_type_set_flags) >= 0) { if (value.dataType == Res_value::TYPE_REFERENCE) { def_style_res = value.data; } Loading Loading @@ -127,18 +125,14 @@ bool ResolveAttrs(ResTable::Theme* theme, uint32_t def_style_attr, ALOGI("-> From values: type=0x%x, data=0x%08x", value.dataType, value.data); } } if (value.dataType == Res_value::TYPE_NULL) { const ResTable::bag_entry* const def_style_entry = def_style_attr_finder.Find(cur_ident); } else { const ResTable::bag_entry* const def_style_entry = def_style_attr_finder.Find(cur_ident); if (def_style_entry != def_style_end) { block = def_style_entry->stringBlock; type_set_flags = def_style_type_set_flags; value = def_style_entry->map.value; if (kDebugStyles) { ALOGI("-> From def style: type=0x%x, data=0x%08x", value.dataType, value.data); ALOGI("-> From def style: type=0x%x, data=0x%08x", value.dataType, value.data); } } } Loading @@ -146,29 +140,24 @@ bool ResolveAttrs(ResTable::Theme* theme, uint32_t def_style_attr, uint32_t resid = 0; if (value.dataType != Res_value::TYPE_NULL) { // Take care of resolving the found resource to its final value. ssize_t new_block = theme->resolveAttributeReference( &value, block, &resid, &type_set_flags, &config); ssize_t new_block = theme->resolveAttributeReference(&value, block, &resid, &type_set_flags, &config); if (new_block >= 0) block = new_block; if (kDebugStyles) { ALOGI("-> Resolved attr: type=0x%x, data=0x%08x", value.dataType, value.data); ALOGI("-> Resolved attr: type=0x%x, data=0x%08x", value.dataType, value.data); } } else { } else if (value.data != Res_value::DATA_NULL_EMPTY) { // If we still don't have a value for this attribute, try to find // it in the theme! ssize_t new_block = theme->getAttribute(cur_ident, &value, &type_set_flags); ssize_t new_block = theme->getAttribute(cur_ident, &value, &type_set_flags); if (new_block >= 0) { if (kDebugStyles) { ALOGI("-> From theme: type=0x%x, data=0x%08x", value.dataType, value.data); ALOGI("-> From theme: type=0x%x, data=0x%08x", value.dataType, value.data); } new_block = res.resolveReference(&value, new_block, &resid, &type_set_flags, &config); new_block = res.resolveReference(&value, new_block, &resid, &type_set_flags, &config); if (new_block >= 0) block = new_block; if (kDebugStyles) { ALOGI("-> Resolved theme: type=0x%x, data=0x%08x", value.dataType, value.data); ALOGI("-> Resolved theme: type=0x%x, data=0x%08x", value.dataType, value.data); } } } Loading @@ -184,8 +173,7 @@ bool ResolveAttrs(ResTable::Theme* theme, uint32_t def_style_attr, } if (kDebugStyles) { ALOGI("Attribute 0x%08x: type=0x%x, data=0x%08x", cur_ident, value.dataType, value.data); ALOGI("Attribute 0x%08x: type=0x%x, data=0x%08x", cur_ident, value.dataType, value.data); } // Write the final value back to Java. Loading @@ -198,7 +186,8 @@ bool ResolveAttrs(ResTable::Theme* theme, uint32_t def_style_attr, out_values[STYLE_CHANGING_CONFIGURATIONS] = type_set_flags; out_values[STYLE_DENSITY] = config.density; if (out_indices != nullptr && value.dataType != Res_value::TYPE_NULL) { if (out_indices != nullptr && (value.dataType != Res_value::TYPE_NULL || value.data == Res_value::DATA_NULL_EMPTY)) { indices_idx++; out_indices[indices_idx] = ii; } Loading Loading @@ -247,8 +236,7 @@ void ApplyStyle(ResTable::Theme* theme, ResXMLParser* xml_parser, uint32_t def_s ssize_t idx = xml_parser->indexOfStyle(); if (idx >= 0 && xml_parser->getAttributeValue(idx, &value) >= 0) { if (value.dataType == value.TYPE_ATTRIBUTE) { if (theme->getAttribute(value.data, &value, &style_bag_type_set_flags) < 0) { if (theme->getAttribute(value.data, &value, &style_bag_type_set_flags) < 0) { value.dataType = Res_value::TYPE_NULL; } } Loading Loading @@ -318,41 +306,34 @@ void ApplyStyle(ResTable::Theme* theme, ResXMLParser* xml_parser, uint32_t def_s // We found the attribute we were looking for. xml_parser->getAttributeValue(xml_attr_idx, &value); if (kDebugStyles) { ALOGI("-> From XML: type=0x%x, data=0x%08x", value.dataType, value.data); ALOGI("-> From XML: type=0x%x, data=0x%08x", value.dataType, value.data); } } if (value.dataType == Res_value::TYPE_NULL) { // Walk through the style class values looking for the requested // attribute. const ResTable::bag_entry* const style_attr_entry = style_attr_finder.Find(cur_ident); if (value.dataType == Res_value::TYPE_NULL && value.data != Res_value::DATA_NULL_EMPTY) { // Walk through the style class values looking for the requested attribute. const ResTable::bag_entry* const style_attr_entry = style_attr_finder.Find(cur_ident); if (style_attr_entry != style_attr_end) { // We found the attribute we were looking for. block = style_attr_entry->stringBlock; type_set_flags = style_type_set_flags; value = style_attr_entry->map.value; if (kDebugStyles) { ALOGI("-> From style: type=0x%x, data=0x%08x", value.dataType, value.data); ALOGI("-> From style: type=0x%x, data=0x%08x", value.dataType, value.data); } } } if (value.dataType == Res_value::TYPE_NULL) { // Walk through the default style values looking for the requested // attribute. const ResTable::bag_entry* const def_style_attr_entry = def_style_attr_finder.Find(cur_ident); if (value.dataType == Res_value::TYPE_NULL && value.data != Res_value::DATA_NULL_EMPTY) { // Walk through the default style values looking for the requested attribute. const ResTable::bag_entry* const def_style_attr_entry = def_style_attr_finder.Find(cur_ident); if (def_style_attr_entry != def_style_attr_end) { // We found the attribute we were looking for. block = def_style_attr_entry->stringBlock; type_set_flags = style_type_set_flags; value = def_style_attr_entry->map.value; if (kDebugStyles) { ALOGI("-> From def style: type=0x%x, data=0x%08x", value.dataType, value.data); ALOGI("-> From def style: type=0x%x, data=0x%08x", value.dataType, value.data); } } } Loading @@ -360,35 +341,29 @@ void ApplyStyle(ResTable::Theme* theme, ResXMLParser* xml_parser, uint32_t def_s uint32_t resid = 0; if (value.dataType != Res_value::TYPE_NULL) { // Take care of resolving the found resource to its final value. ssize_t new_block = theme->resolveAttributeReference( &value, block, &resid, &type_set_flags, &config); ssize_t new_block = theme->resolveAttributeReference(&value, block, &resid, &type_set_flags, &config); if (new_block >= 0) { block = new_block; } if (kDebugStyles) { ALOGI("-> Resolved attr: type=0x%x, data=0x%08x", value.dataType, value.data); ALOGI("-> Resolved attr: type=0x%x, data=0x%08x", value.dataType, value.data); } } else { // If we still don't have a value for this attribute, try to find // it in the theme! ssize_t new_block = theme->getAttribute(cur_ident, &value, &type_set_flags); } else if (value.data != Res_value::DATA_NULL_EMPTY) { // If we still don't have a value for this attribute, try to find it in the theme! ssize_t new_block = theme->getAttribute(cur_ident, &value, &type_set_flags); if (new_block >= 0) { if (kDebugStyles) { ALOGI("-> From theme: type=0x%x, data=0x%08x", value.dataType, value.data); ALOGI("-> From theme: type=0x%x, data=0x%08x", value.dataType, value.data); } new_block = res.resolveReference(&value, new_block, &resid, &type_set_flags, &config); new_block = res.resolveReference(&value, new_block, &resid, &type_set_flags, &config); if (new_block >= 0) { block = new_block; } if (kDebugStyles) { ALOGI("-> Resolved theme: type=0x%x, data=0x%08x", value.dataType, value.data); ALOGI("-> Resolved theme: type=0x%x, data=0x%08x", value.dataType, value.data); } } } Loading @@ -404,8 +379,7 @@ void ApplyStyle(ResTable::Theme* theme, ResXMLParser* xml_parser, uint32_t def_s } if (kDebugStyles) { ALOGI("Attribute 0x%08x: type=0x%x, data=0x%08x", cur_ident, value.dataType, value.data); ALOGI("Attribute 0x%08x: type=0x%x, data=0x%08x", cur_ident, value.dataType, value.data); } // Write the final value back to Java. Loading @@ -418,7 +392,7 @@ void ApplyStyle(ResTable::Theme* theme, ResXMLParser* xml_parser, uint32_t def_s out_values[STYLE_CHANGING_CONFIGURATIONS] = type_set_flags; out_values[STYLE_DENSITY] = config.density; if (value.dataType != Res_value::TYPE_NULL) { if (value.dataType != Res_value::TYPE_NULL || value.data == Res_value::DATA_NULL_EMPTY) { indices_idx++; // out_indices must NOT be nullptr. Loading Loading @@ -502,7 +476,8 @@ bool RetrieveAttributes(const ResTable* res, ResXMLParser* xml_parser, out_values[STYLE_CHANGING_CONFIGURATIONS] = type_set_flags; out_values[STYLE_DENSITY] = config.density; if (out_indices != nullptr && value.dataType != Res_value::TYPE_NULL) { if (out_indices != nullptr && (value.dataType != Res_value::TYPE_NULL || value.data == Res_value::DATA_NULL_EMPTY)) { indices_idx++; out_indices[indices_idx] = ii; } Loading libs/androidfw/ResourceTypes.cpp +4 −2 Original line number Diff line number Diff line Loading @@ -3538,7 +3538,8 @@ status_t ResTable::Theme::applyStyle(uint32_t resID, bool force) attrRes, bag->map.value.dataType, bag->map.value.data, curEntry->value.dataType); } if (force || curEntry->value.dataType == Res_value::TYPE_NULL) { if (force || (curEntry->value.dataType == Res_value::TYPE_NULL && curEntry->value.data != Res_value::DATA_NULL_EMPTY)) { curEntry->stringBlock = bag->stringBlock; curEntry->typeSpecFlags |= bagTypeSpecFlags; curEntry->value = bag->map.value; Loading Loading @@ -3674,7 +3675,8 @@ ssize_t ResTable::Theme::getAttribute(uint32_t resID, Res_value* outValue, } ALOGW("Too many attribute references, stopped at: 0x%08x\n", resID); return BAD_INDEX; } else if (type != Res_value::TYPE_NULL) { } else if (type != Res_value::TYPE_NULL || te.value.data == Res_value::DATA_NULL_EMPTY) { *outValue = te.value; return te.stringBlock; } Loading libs/androidfw/tests/AssetManager2_test.cpp +6 −1 Original line number Diff line number Diff line Loading @@ -264,7 +264,7 @@ TEST_F(AssetManager2Test, MergesStylesWithParentFromSingleApkAssets) { const ResolvedBag* bag_two = assetmanager.GetBag(app::R::style::StyleTwo); ASSERT_NE(nullptr, bag_two); ASSERT_EQ(5u, bag_two->entry_count); ASSERT_EQ(6u, bag_two->entry_count); // attr_one is inherited from StyleOne. EXPECT_EQ(app::R::attr::attr_one, bag_two->entries[0].key); Loading Loading @@ -295,6 +295,11 @@ TEST_F(AssetManager2Test, MergesStylesWithParentFromSingleApkAssets) { EXPECT_EQ(Res_value::TYPE_INT_DEC, bag_two->entries[4].value.dataType); EXPECT_EQ(3u, bag_two->entries[4].value.data); EXPECT_EQ(0, bag_two->entries[4].cookie); EXPECT_EQ(app::R::attr::attr_empty, bag_two->entries[5].key); EXPECT_EQ(Res_value::TYPE_NULL, bag_two->entries[5].value.dataType); EXPECT_EQ(Res_value::DATA_NULL_EMPTY, bag_two->entries[5].value.data); EXPECT_EQ(0, bag_two->entries[5].cookie); } TEST_F(AssetManager2Test, ResolveReferenceToResource) { Loading libs/androidfw/tests/AttributeResolution_test.cpp +44 −12 Original line number Diff line number Diff line Loading @@ -69,8 +69,8 @@ TEST_F(AttributeResolutionTest, Theme) { ResTable::Theme theme(table_); ASSERT_EQ(NO_ERROR, theme.applyStyle(R::style::StyleTwo)); std::array<uint32_t, 4> attrs{ {R::attr::attr_one, R::attr::attr_two, R::attr::attr_three, R::attr::attr_four}}; std::array<uint32_t, 5> attrs{{R::attr::attr_one, R::attr::attr_two, R::attr::attr_three, R::attr::attr_four, R::attr::attr_empty}}; std::array<uint32_t, attrs.size() * STYLE_NUM_ENTRIES> values; ASSERT_TRUE(ResolveAttrs(&theme, 0 /*def_style_attr*/, 0 /*def_style_res*/, Loading Loading @@ -109,11 +109,21 @@ TEST_F(AttributeResolutionTest, Theme) { EXPECT_EQ(uint32_t(-1), values_cursor[STYLE_ASSET_COOKIE]); EXPECT_EQ(0u, values_cursor[STYLE_DENSITY]); EXPECT_EQ(0u, values_cursor[STYLE_CHANGING_CONFIGURATIONS]); // @empty comes from the theme, so it has the same asset cookie and changing configurations flags // as the theme. values_cursor += STYLE_NUM_ENTRIES; EXPECT_EQ(Res_value::TYPE_NULL, values_cursor[STYLE_TYPE]); EXPECT_EQ(Res_value::DATA_NULL_EMPTY, values_cursor[STYLE_DATA]); EXPECT_EQ(0u, values_cursor[STYLE_RESOURCE_ID]); EXPECT_EQ(1u, values_cursor[STYLE_ASSET_COOKIE]); EXPECT_EQ(0u, values_cursor[STYLE_DENSITY]); EXPECT_EQ(public_flag, values_cursor[STYLE_CHANGING_CONFIGURATIONS]); } TEST_F(AttributeResolutionXmlTest, XmlParser) { std::array<uint32_t, 4> attrs{ {R::attr::attr_one, R::attr::attr_two, R::attr::attr_three, R::attr::attr_four}}; std::array<uint32_t, 5> attrs{{R::attr::attr_one, R::attr::attr_two, R::attr::attr_three, R::attr::attr_four, R::attr::attr_empty}}; std::array<uint32_t, attrs.size() * STYLE_NUM_ENTRIES> values; ASSERT_TRUE(RetrieveAttributes(&table_, &xml_parser_, attrs.data(), attrs.size(), values.data(), Loading @@ -121,7 +131,7 @@ TEST_F(AttributeResolutionXmlTest, XmlParser) { uint32_t* values_cursor = values.data(); EXPECT_EQ(Res_value::TYPE_NULL, values_cursor[STYLE_TYPE]); EXPECT_EQ(0u, values_cursor[STYLE_DATA]); EXPECT_EQ(Res_value::DATA_NULL_EMPTY, values_cursor[STYLE_DATA]); EXPECT_EQ(0u, values_cursor[STYLE_RESOURCE_ID]); EXPECT_EQ(uint32_t(-1), values_cursor[STYLE_ASSET_COOKIE]); EXPECT_EQ(0u, values_cursor[STYLE_DENSITY]); Loading Loading @@ -150,16 +160,24 @@ TEST_F(AttributeResolutionXmlTest, XmlParser) { EXPECT_EQ(uint32_t(-1), values_cursor[STYLE_ASSET_COOKIE]); EXPECT_EQ(0u, values_cursor[STYLE_DENSITY]); EXPECT_EQ(0u, values_cursor[STYLE_CHANGING_CONFIGURATIONS]); values_cursor += STYLE_NUM_ENTRIES; EXPECT_EQ(Res_value::TYPE_NULL, values_cursor[STYLE_TYPE]); EXPECT_EQ(Res_value::DATA_NULL_UNDEFINED, values_cursor[STYLE_DATA]); EXPECT_EQ(0u, values_cursor[STYLE_RESOURCE_ID]); EXPECT_EQ(uint32_t(-1), values_cursor[STYLE_ASSET_COOKIE]); EXPECT_EQ(0u, values_cursor[STYLE_DENSITY]); EXPECT_EQ(0u, values_cursor[STYLE_CHANGING_CONFIGURATIONS]); } TEST_F(AttributeResolutionXmlTest, ThemeAndXmlParser) { ResTable::Theme theme(table_); ASSERT_EQ(NO_ERROR, theme.applyStyle(R::style::StyleTwo)); std::array<uint32_t, 5> attrs{{R::attr::attr_one, R::attr::attr_two, R::attr::attr_three, R::attr::attr_four, R::attr::attr_five}}; std::array<uint32_t, 6> attrs{{R::attr::attr_one, R::attr::attr_two, R::attr::attr_three, R::attr::attr_four, R::attr::attr_five, R::attr::attr_empty}}; std::array<uint32_t, attrs.size() * STYLE_NUM_ENTRIES> values; std::array<uint32_t, attrs.size()> indices; std::array<uint32_t, attrs.size() + 1> indices; ApplyStyle(&theme, &xml_parser_, 0 /*def_style_attr*/, 0 /*def_style_res*/, attrs.data(), attrs.size(), values.data(), indices.data()); Loading @@ -167,12 +185,12 @@ TEST_F(AttributeResolutionXmlTest, ThemeAndXmlParser) { const uint32_t public_flag = ResTable_typeSpec::SPEC_PUBLIC; uint32_t* values_cursor = values.data(); EXPECT_EQ(Res_value::TYPE_INT_DEC, values_cursor[STYLE_TYPE]); EXPECT_EQ(1u, values_cursor[STYLE_DATA]); EXPECT_EQ(Res_value::TYPE_NULL, values_cursor[STYLE_TYPE]); EXPECT_EQ(Res_value::DATA_NULL_EMPTY, values_cursor[STYLE_DATA]); EXPECT_EQ(0u, values_cursor[STYLE_RESOURCE_ID]); EXPECT_EQ(1u, values_cursor[STYLE_ASSET_COOKIE]); EXPECT_EQ(uint32_t(-1), values_cursor[STYLE_ASSET_COOKIE]); EXPECT_EQ(0u, values_cursor[STYLE_DENSITY]); EXPECT_EQ(public_flag, values_cursor[STYLE_CHANGING_CONFIGURATIONS]); EXPECT_EQ(0u, values_cursor[STYLE_CHANGING_CONFIGURATIONS]); values_cursor += STYLE_NUM_ENTRIES; EXPECT_EQ(Res_value::TYPE_STRING, values_cursor[STYLE_TYPE]); Loading Loading @@ -203,6 +221,20 @@ TEST_F(AttributeResolutionXmlTest, ThemeAndXmlParser) { EXPECT_EQ(1u, values_cursor[STYLE_ASSET_COOKIE]); EXPECT_EQ(0u, values_cursor[STYLE_DENSITY]); EXPECT_EQ(public_flag, values_cursor[STYLE_CHANGING_CONFIGURATIONS]); // @empty comes from the theme, so it has the same asset cookie and changing configurations flags // as the theme. values_cursor += STYLE_NUM_ENTRIES; EXPECT_EQ(Res_value::TYPE_NULL, values_cursor[STYLE_TYPE]); EXPECT_EQ(Res_value::DATA_NULL_EMPTY, values_cursor[STYLE_DATA]); EXPECT_EQ(0u, values_cursor[STYLE_RESOURCE_ID]); EXPECT_EQ(1u, values_cursor[STYLE_ASSET_COOKIE]); EXPECT_EQ(0u, values_cursor[STYLE_DENSITY]); EXPECT_EQ(public_flag, values_cursor[STYLE_CHANGING_CONFIGURATIONS]); // The first element of indices contains the number of indices. std::array<uint32_t, 7> expected_indices = {{6u, 0u, 1u, 2u, 3u, 4u, 5u}}; EXPECT_EQ(expected_indices, indices); } } // namespace android Loading Loading
core/java/android/content/res/TypedArray.java +5 −3 Original line number Diff line number Diff line Loading @@ -103,7 +103,8 @@ public class TypedArray { } /** * Return the number of indices in the array that actually have data. * Returns the number of indices in the array that actually have data. Attributes with a value * of @empty are included, as this is an explicit indicator. * * @throws RuntimeException if the TypedArray has already been recycled. */ Loading @@ -116,7 +117,8 @@ public class TypedArray { } /** * Returns an index in the array that has data. * Returns an index in the array that has data. Attributes with a value of @empty are included, * as this is an explicit indicator. * * @param at The index you would like to returned, ranging from 0 to * {@link #getIndexCount()}. Loading Loading @@ -1017,7 +1019,7 @@ public class TypedArray { * @param outValue TypedValue object in which to place the attribute's * data. * * @return {@code true} if the value was retrieved, false otherwise. * @return {@code true} if the value was retrieved and not @empty, {@code false} otherwise. * @throws RuntimeException if the TypedArray has already been recycled. */ public boolean getValue(@StyleableRes int index, TypedValue outValue) { Loading
libs/androidfw/AttributeResolution.cpp +39 −64 Original line number Diff line number Diff line Loading @@ -44,8 +44,7 @@ class XmlAttributeFinder }; class BagAttributeFinder : public BackTrackingAttributeFinder<BagAttributeFinder, const ResTable::bag_entry*> { : public BackTrackingAttributeFinder<BagAttributeFinder, const ResTable::bag_entry*> { public: BagAttributeFinder(const ResTable::bag_entry* start, const ResTable::bag_entry* end) Loading Loading @@ -76,8 +75,7 @@ bool ResolveAttrs(ResTable::Theme* theme, uint32_t def_style_attr, uint32_t def_style_bag_type_set_flags = 0; if (def_style_attr != 0) { Res_value value; if (theme->getAttribute(def_style_attr, &value, &def_style_bag_type_set_flags) >= 0) { if (theme->getAttribute(def_style_attr, &value, &def_style_bag_type_set_flags) >= 0) { if (value.dataType == Res_value::TYPE_REFERENCE) { def_style_res = value.data; } Loading Loading @@ -127,18 +125,14 @@ bool ResolveAttrs(ResTable::Theme* theme, uint32_t def_style_attr, ALOGI("-> From values: type=0x%x, data=0x%08x", value.dataType, value.data); } } if (value.dataType == Res_value::TYPE_NULL) { const ResTable::bag_entry* const def_style_entry = def_style_attr_finder.Find(cur_ident); } else { const ResTable::bag_entry* const def_style_entry = def_style_attr_finder.Find(cur_ident); if (def_style_entry != def_style_end) { block = def_style_entry->stringBlock; type_set_flags = def_style_type_set_flags; value = def_style_entry->map.value; if (kDebugStyles) { ALOGI("-> From def style: type=0x%x, data=0x%08x", value.dataType, value.data); ALOGI("-> From def style: type=0x%x, data=0x%08x", value.dataType, value.data); } } } Loading @@ -146,29 +140,24 @@ bool ResolveAttrs(ResTable::Theme* theme, uint32_t def_style_attr, uint32_t resid = 0; if (value.dataType != Res_value::TYPE_NULL) { // Take care of resolving the found resource to its final value. ssize_t new_block = theme->resolveAttributeReference( &value, block, &resid, &type_set_flags, &config); ssize_t new_block = theme->resolveAttributeReference(&value, block, &resid, &type_set_flags, &config); if (new_block >= 0) block = new_block; if (kDebugStyles) { ALOGI("-> Resolved attr: type=0x%x, data=0x%08x", value.dataType, value.data); ALOGI("-> Resolved attr: type=0x%x, data=0x%08x", value.dataType, value.data); } } else { } else if (value.data != Res_value::DATA_NULL_EMPTY) { // If we still don't have a value for this attribute, try to find // it in the theme! ssize_t new_block = theme->getAttribute(cur_ident, &value, &type_set_flags); ssize_t new_block = theme->getAttribute(cur_ident, &value, &type_set_flags); if (new_block >= 0) { if (kDebugStyles) { ALOGI("-> From theme: type=0x%x, data=0x%08x", value.dataType, value.data); ALOGI("-> From theme: type=0x%x, data=0x%08x", value.dataType, value.data); } new_block = res.resolveReference(&value, new_block, &resid, &type_set_flags, &config); new_block = res.resolveReference(&value, new_block, &resid, &type_set_flags, &config); if (new_block >= 0) block = new_block; if (kDebugStyles) { ALOGI("-> Resolved theme: type=0x%x, data=0x%08x", value.dataType, value.data); ALOGI("-> Resolved theme: type=0x%x, data=0x%08x", value.dataType, value.data); } } } Loading @@ -184,8 +173,7 @@ bool ResolveAttrs(ResTable::Theme* theme, uint32_t def_style_attr, } if (kDebugStyles) { ALOGI("Attribute 0x%08x: type=0x%x, data=0x%08x", cur_ident, value.dataType, value.data); ALOGI("Attribute 0x%08x: type=0x%x, data=0x%08x", cur_ident, value.dataType, value.data); } // Write the final value back to Java. Loading @@ -198,7 +186,8 @@ bool ResolveAttrs(ResTable::Theme* theme, uint32_t def_style_attr, out_values[STYLE_CHANGING_CONFIGURATIONS] = type_set_flags; out_values[STYLE_DENSITY] = config.density; if (out_indices != nullptr && value.dataType != Res_value::TYPE_NULL) { if (out_indices != nullptr && (value.dataType != Res_value::TYPE_NULL || value.data == Res_value::DATA_NULL_EMPTY)) { indices_idx++; out_indices[indices_idx] = ii; } Loading Loading @@ -247,8 +236,7 @@ void ApplyStyle(ResTable::Theme* theme, ResXMLParser* xml_parser, uint32_t def_s ssize_t idx = xml_parser->indexOfStyle(); if (idx >= 0 && xml_parser->getAttributeValue(idx, &value) >= 0) { if (value.dataType == value.TYPE_ATTRIBUTE) { if (theme->getAttribute(value.data, &value, &style_bag_type_set_flags) < 0) { if (theme->getAttribute(value.data, &value, &style_bag_type_set_flags) < 0) { value.dataType = Res_value::TYPE_NULL; } } Loading Loading @@ -318,41 +306,34 @@ void ApplyStyle(ResTable::Theme* theme, ResXMLParser* xml_parser, uint32_t def_s // We found the attribute we were looking for. xml_parser->getAttributeValue(xml_attr_idx, &value); if (kDebugStyles) { ALOGI("-> From XML: type=0x%x, data=0x%08x", value.dataType, value.data); ALOGI("-> From XML: type=0x%x, data=0x%08x", value.dataType, value.data); } } if (value.dataType == Res_value::TYPE_NULL) { // Walk through the style class values looking for the requested // attribute. const ResTable::bag_entry* const style_attr_entry = style_attr_finder.Find(cur_ident); if (value.dataType == Res_value::TYPE_NULL && value.data != Res_value::DATA_NULL_EMPTY) { // Walk through the style class values looking for the requested attribute. const ResTable::bag_entry* const style_attr_entry = style_attr_finder.Find(cur_ident); if (style_attr_entry != style_attr_end) { // We found the attribute we were looking for. block = style_attr_entry->stringBlock; type_set_flags = style_type_set_flags; value = style_attr_entry->map.value; if (kDebugStyles) { ALOGI("-> From style: type=0x%x, data=0x%08x", value.dataType, value.data); ALOGI("-> From style: type=0x%x, data=0x%08x", value.dataType, value.data); } } } if (value.dataType == Res_value::TYPE_NULL) { // Walk through the default style values looking for the requested // attribute. const ResTable::bag_entry* const def_style_attr_entry = def_style_attr_finder.Find(cur_ident); if (value.dataType == Res_value::TYPE_NULL && value.data != Res_value::DATA_NULL_EMPTY) { // Walk through the default style values looking for the requested attribute. const ResTable::bag_entry* const def_style_attr_entry = def_style_attr_finder.Find(cur_ident); if (def_style_attr_entry != def_style_attr_end) { // We found the attribute we were looking for. block = def_style_attr_entry->stringBlock; type_set_flags = style_type_set_flags; value = def_style_attr_entry->map.value; if (kDebugStyles) { ALOGI("-> From def style: type=0x%x, data=0x%08x", value.dataType, value.data); ALOGI("-> From def style: type=0x%x, data=0x%08x", value.dataType, value.data); } } } Loading @@ -360,35 +341,29 @@ void ApplyStyle(ResTable::Theme* theme, ResXMLParser* xml_parser, uint32_t def_s uint32_t resid = 0; if (value.dataType != Res_value::TYPE_NULL) { // Take care of resolving the found resource to its final value. ssize_t new_block = theme->resolveAttributeReference( &value, block, &resid, &type_set_flags, &config); ssize_t new_block = theme->resolveAttributeReference(&value, block, &resid, &type_set_flags, &config); if (new_block >= 0) { block = new_block; } if (kDebugStyles) { ALOGI("-> Resolved attr: type=0x%x, data=0x%08x", value.dataType, value.data); ALOGI("-> Resolved attr: type=0x%x, data=0x%08x", value.dataType, value.data); } } else { // If we still don't have a value for this attribute, try to find // it in the theme! ssize_t new_block = theme->getAttribute(cur_ident, &value, &type_set_flags); } else if (value.data != Res_value::DATA_NULL_EMPTY) { // If we still don't have a value for this attribute, try to find it in the theme! ssize_t new_block = theme->getAttribute(cur_ident, &value, &type_set_flags); if (new_block >= 0) { if (kDebugStyles) { ALOGI("-> From theme: type=0x%x, data=0x%08x", value.dataType, value.data); ALOGI("-> From theme: type=0x%x, data=0x%08x", value.dataType, value.data); } new_block = res.resolveReference(&value, new_block, &resid, &type_set_flags, &config); new_block = res.resolveReference(&value, new_block, &resid, &type_set_flags, &config); if (new_block >= 0) { block = new_block; } if (kDebugStyles) { ALOGI("-> Resolved theme: type=0x%x, data=0x%08x", value.dataType, value.data); ALOGI("-> Resolved theme: type=0x%x, data=0x%08x", value.dataType, value.data); } } } Loading @@ -404,8 +379,7 @@ void ApplyStyle(ResTable::Theme* theme, ResXMLParser* xml_parser, uint32_t def_s } if (kDebugStyles) { ALOGI("Attribute 0x%08x: type=0x%x, data=0x%08x", cur_ident, value.dataType, value.data); ALOGI("Attribute 0x%08x: type=0x%x, data=0x%08x", cur_ident, value.dataType, value.data); } // Write the final value back to Java. Loading @@ -418,7 +392,7 @@ void ApplyStyle(ResTable::Theme* theme, ResXMLParser* xml_parser, uint32_t def_s out_values[STYLE_CHANGING_CONFIGURATIONS] = type_set_flags; out_values[STYLE_DENSITY] = config.density; if (value.dataType != Res_value::TYPE_NULL) { if (value.dataType != Res_value::TYPE_NULL || value.data == Res_value::DATA_NULL_EMPTY) { indices_idx++; // out_indices must NOT be nullptr. Loading Loading @@ -502,7 +476,8 @@ bool RetrieveAttributes(const ResTable* res, ResXMLParser* xml_parser, out_values[STYLE_CHANGING_CONFIGURATIONS] = type_set_flags; out_values[STYLE_DENSITY] = config.density; if (out_indices != nullptr && value.dataType != Res_value::TYPE_NULL) { if (out_indices != nullptr && (value.dataType != Res_value::TYPE_NULL || value.data == Res_value::DATA_NULL_EMPTY)) { indices_idx++; out_indices[indices_idx] = ii; } Loading
libs/androidfw/ResourceTypes.cpp +4 −2 Original line number Diff line number Diff line Loading @@ -3538,7 +3538,8 @@ status_t ResTable::Theme::applyStyle(uint32_t resID, bool force) attrRes, bag->map.value.dataType, bag->map.value.data, curEntry->value.dataType); } if (force || curEntry->value.dataType == Res_value::TYPE_NULL) { if (force || (curEntry->value.dataType == Res_value::TYPE_NULL && curEntry->value.data != Res_value::DATA_NULL_EMPTY)) { curEntry->stringBlock = bag->stringBlock; curEntry->typeSpecFlags |= bagTypeSpecFlags; curEntry->value = bag->map.value; Loading Loading @@ -3674,7 +3675,8 @@ ssize_t ResTable::Theme::getAttribute(uint32_t resID, Res_value* outValue, } ALOGW("Too many attribute references, stopped at: 0x%08x\n", resID); return BAD_INDEX; } else if (type != Res_value::TYPE_NULL) { } else if (type != Res_value::TYPE_NULL || te.value.data == Res_value::DATA_NULL_EMPTY) { *outValue = te.value; return te.stringBlock; } Loading
libs/androidfw/tests/AssetManager2_test.cpp +6 −1 Original line number Diff line number Diff line Loading @@ -264,7 +264,7 @@ TEST_F(AssetManager2Test, MergesStylesWithParentFromSingleApkAssets) { const ResolvedBag* bag_two = assetmanager.GetBag(app::R::style::StyleTwo); ASSERT_NE(nullptr, bag_two); ASSERT_EQ(5u, bag_two->entry_count); ASSERT_EQ(6u, bag_two->entry_count); // attr_one is inherited from StyleOne. EXPECT_EQ(app::R::attr::attr_one, bag_two->entries[0].key); Loading Loading @@ -295,6 +295,11 @@ TEST_F(AssetManager2Test, MergesStylesWithParentFromSingleApkAssets) { EXPECT_EQ(Res_value::TYPE_INT_DEC, bag_two->entries[4].value.dataType); EXPECT_EQ(3u, bag_two->entries[4].value.data); EXPECT_EQ(0, bag_two->entries[4].cookie); EXPECT_EQ(app::R::attr::attr_empty, bag_two->entries[5].key); EXPECT_EQ(Res_value::TYPE_NULL, bag_two->entries[5].value.dataType); EXPECT_EQ(Res_value::DATA_NULL_EMPTY, bag_two->entries[5].value.data); EXPECT_EQ(0, bag_two->entries[5].cookie); } TEST_F(AssetManager2Test, ResolveReferenceToResource) { Loading
libs/androidfw/tests/AttributeResolution_test.cpp +44 −12 Original line number Diff line number Diff line Loading @@ -69,8 +69,8 @@ TEST_F(AttributeResolutionTest, Theme) { ResTable::Theme theme(table_); ASSERT_EQ(NO_ERROR, theme.applyStyle(R::style::StyleTwo)); std::array<uint32_t, 4> attrs{ {R::attr::attr_one, R::attr::attr_two, R::attr::attr_three, R::attr::attr_four}}; std::array<uint32_t, 5> attrs{{R::attr::attr_one, R::attr::attr_two, R::attr::attr_three, R::attr::attr_four, R::attr::attr_empty}}; std::array<uint32_t, attrs.size() * STYLE_NUM_ENTRIES> values; ASSERT_TRUE(ResolveAttrs(&theme, 0 /*def_style_attr*/, 0 /*def_style_res*/, Loading Loading @@ -109,11 +109,21 @@ TEST_F(AttributeResolutionTest, Theme) { EXPECT_EQ(uint32_t(-1), values_cursor[STYLE_ASSET_COOKIE]); EXPECT_EQ(0u, values_cursor[STYLE_DENSITY]); EXPECT_EQ(0u, values_cursor[STYLE_CHANGING_CONFIGURATIONS]); // @empty comes from the theme, so it has the same asset cookie and changing configurations flags // as the theme. values_cursor += STYLE_NUM_ENTRIES; EXPECT_EQ(Res_value::TYPE_NULL, values_cursor[STYLE_TYPE]); EXPECT_EQ(Res_value::DATA_NULL_EMPTY, values_cursor[STYLE_DATA]); EXPECT_EQ(0u, values_cursor[STYLE_RESOURCE_ID]); EXPECT_EQ(1u, values_cursor[STYLE_ASSET_COOKIE]); EXPECT_EQ(0u, values_cursor[STYLE_DENSITY]); EXPECT_EQ(public_flag, values_cursor[STYLE_CHANGING_CONFIGURATIONS]); } TEST_F(AttributeResolutionXmlTest, XmlParser) { std::array<uint32_t, 4> attrs{ {R::attr::attr_one, R::attr::attr_two, R::attr::attr_three, R::attr::attr_four}}; std::array<uint32_t, 5> attrs{{R::attr::attr_one, R::attr::attr_two, R::attr::attr_three, R::attr::attr_four, R::attr::attr_empty}}; std::array<uint32_t, attrs.size() * STYLE_NUM_ENTRIES> values; ASSERT_TRUE(RetrieveAttributes(&table_, &xml_parser_, attrs.data(), attrs.size(), values.data(), Loading @@ -121,7 +131,7 @@ TEST_F(AttributeResolutionXmlTest, XmlParser) { uint32_t* values_cursor = values.data(); EXPECT_EQ(Res_value::TYPE_NULL, values_cursor[STYLE_TYPE]); EXPECT_EQ(0u, values_cursor[STYLE_DATA]); EXPECT_EQ(Res_value::DATA_NULL_EMPTY, values_cursor[STYLE_DATA]); EXPECT_EQ(0u, values_cursor[STYLE_RESOURCE_ID]); EXPECT_EQ(uint32_t(-1), values_cursor[STYLE_ASSET_COOKIE]); EXPECT_EQ(0u, values_cursor[STYLE_DENSITY]); Loading Loading @@ -150,16 +160,24 @@ TEST_F(AttributeResolutionXmlTest, XmlParser) { EXPECT_EQ(uint32_t(-1), values_cursor[STYLE_ASSET_COOKIE]); EXPECT_EQ(0u, values_cursor[STYLE_DENSITY]); EXPECT_EQ(0u, values_cursor[STYLE_CHANGING_CONFIGURATIONS]); values_cursor += STYLE_NUM_ENTRIES; EXPECT_EQ(Res_value::TYPE_NULL, values_cursor[STYLE_TYPE]); EXPECT_EQ(Res_value::DATA_NULL_UNDEFINED, values_cursor[STYLE_DATA]); EXPECT_EQ(0u, values_cursor[STYLE_RESOURCE_ID]); EXPECT_EQ(uint32_t(-1), values_cursor[STYLE_ASSET_COOKIE]); EXPECT_EQ(0u, values_cursor[STYLE_DENSITY]); EXPECT_EQ(0u, values_cursor[STYLE_CHANGING_CONFIGURATIONS]); } TEST_F(AttributeResolutionXmlTest, ThemeAndXmlParser) { ResTable::Theme theme(table_); ASSERT_EQ(NO_ERROR, theme.applyStyle(R::style::StyleTwo)); std::array<uint32_t, 5> attrs{{R::attr::attr_one, R::attr::attr_two, R::attr::attr_three, R::attr::attr_four, R::attr::attr_five}}; std::array<uint32_t, 6> attrs{{R::attr::attr_one, R::attr::attr_two, R::attr::attr_three, R::attr::attr_four, R::attr::attr_five, R::attr::attr_empty}}; std::array<uint32_t, attrs.size() * STYLE_NUM_ENTRIES> values; std::array<uint32_t, attrs.size()> indices; std::array<uint32_t, attrs.size() + 1> indices; ApplyStyle(&theme, &xml_parser_, 0 /*def_style_attr*/, 0 /*def_style_res*/, attrs.data(), attrs.size(), values.data(), indices.data()); Loading @@ -167,12 +185,12 @@ TEST_F(AttributeResolutionXmlTest, ThemeAndXmlParser) { const uint32_t public_flag = ResTable_typeSpec::SPEC_PUBLIC; uint32_t* values_cursor = values.data(); EXPECT_EQ(Res_value::TYPE_INT_DEC, values_cursor[STYLE_TYPE]); EXPECT_EQ(1u, values_cursor[STYLE_DATA]); EXPECT_EQ(Res_value::TYPE_NULL, values_cursor[STYLE_TYPE]); EXPECT_EQ(Res_value::DATA_NULL_EMPTY, values_cursor[STYLE_DATA]); EXPECT_EQ(0u, values_cursor[STYLE_RESOURCE_ID]); EXPECT_EQ(1u, values_cursor[STYLE_ASSET_COOKIE]); EXPECT_EQ(uint32_t(-1), values_cursor[STYLE_ASSET_COOKIE]); EXPECT_EQ(0u, values_cursor[STYLE_DENSITY]); EXPECT_EQ(public_flag, values_cursor[STYLE_CHANGING_CONFIGURATIONS]); EXPECT_EQ(0u, values_cursor[STYLE_CHANGING_CONFIGURATIONS]); values_cursor += STYLE_NUM_ENTRIES; EXPECT_EQ(Res_value::TYPE_STRING, values_cursor[STYLE_TYPE]); Loading Loading @@ -203,6 +221,20 @@ TEST_F(AttributeResolutionXmlTest, ThemeAndXmlParser) { EXPECT_EQ(1u, values_cursor[STYLE_ASSET_COOKIE]); EXPECT_EQ(0u, values_cursor[STYLE_DENSITY]); EXPECT_EQ(public_flag, values_cursor[STYLE_CHANGING_CONFIGURATIONS]); // @empty comes from the theme, so it has the same asset cookie and changing configurations flags // as the theme. values_cursor += STYLE_NUM_ENTRIES; EXPECT_EQ(Res_value::TYPE_NULL, values_cursor[STYLE_TYPE]); EXPECT_EQ(Res_value::DATA_NULL_EMPTY, values_cursor[STYLE_DATA]); EXPECT_EQ(0u, values_cursor[STYLE_RESOURCE_ID]); EXPECT_EQ(1u, values_cursor[STYLE_ASSET_COOKIE]); EXPECT_EQ(0u, values_cursor[STYLE_DENSITY]); EXPECT_EQ(public_flag, values_cursor[STYLE_CHANGING_CONFIGURATIONS]); // The first element of indices contains the number of indices. std::array<uint32_t, 7> expected_indices = {{6u, 0u, 1u, 2u, 3u, 4u, 5u}}; EXPECT_EQ(expected_indices, indices); } } // namespace android Loading