1 /*
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
17 #include "androidfw/AssetManager2.h"
18
19 #include "android-base/logging.h"
20
21 #include "TestHelpers.h"
22 #include "androidfw/ResourceUtils.h"
23 #include "data/lib_one/R.h"
24 #include "data/libclient/R.h"
25 #include "data/styles/R.h"
26
27 namespace app = com::android::app;
28 namespace lib_one = com::android::lib_one;
29 namespace libclient = com::android::libclient;
30
31 namespace android {
32
33 class ThemeTest : public ::testing::Test {
34 public:
SetUp()35 void SetUp() override {
36 style_assets_ = ApkAssets::Load(GetTestDataPath() + "/styles/styles.apk");
37 ASSERT_NE(nullptr, style_assets_);
38
39 libclient_assets_ = ApkAssets::Load(GetTestDataPath() + "/libclient/libclient.apk");
40 ASSERT_NE(nullptr, libclient_assets_);
41
42 lib_one_assets_ = ApkAssets::Load(GetTestDataPath() + "/lib_one/lib_one.apk");
43 ASSERT_NE(nullptr, lib_one_assets_);
44
45 lib_two_assets_ = ApkAssets::Load(GetTestDataPath() + "/lib_two/lib_two.apk");
46 ASSERT_NE(nullptr, lib_two_assets_);
47 }
48
49 protected:
50 std::unique_ptr<const ApkAssets> style_assets_;
51 std::unique_ptr<const ApkAssets> libclient_assets_;
52 std::unique_ptr<const ApkAssets> lib_one_assets_;
53 std::unique_ptr<const ApkAssets> lib_two_assets_;
54 };
55
TEST_F(ThemeTest,EmptyTheme)56 TEST_F(ThemeTest, EmptyTheme) {
57 AssetManager2 assetmanager;
58 assetmanager.SetApkAssets({style_assets_.get()});
59
60 std::unique_ptr<Theme> theme = assetmanager.NewTheme();
61 EXPECT_EQ(0u, theme->GetChangingConfigurations());
62 EXPECT_EQ(&assetmanager, theme->GetAssetManager());
63
64 Res_value value;
65 uint32_t flags;
66 EXPECT_EQ(kInvalidCookie, theme->GetAttribute(app::R::attr::attr_one, &value, &flags));
67 }
68
TEST_F(ThemeTest,SingleThemeNoParent)69 TEST_F(ThemeTest, SingleThemeNoParent) {
70 AssetManager2 assetmanager;
71 assetmanager.SetApkAssets({style_assets_.get()});
72
73 std::unique_ptr<Theme> theme = assetmanager.NewTheme();
74 ASSERT_TRUE(theme->ApplyStyle(app::R::style::StyleOne));
75
76 Res_value value;
77 uint32_t flags;
78 ApkAssetsCookie cookie;
79
80 cookie = theme->GetAttribute(app::R::attr::attr_one, &value, &flags);
81 ASSERT_NE(kInvalidCookie, cookie);
82 EXPECT_EQ(Res_value::TYPE_INT_DEC, value.dataType);
83 EXPECT_EQ(1u, value.data);
84 EXPECT_EQ(static_cast<uint32_t>(ResTable_typeSpec::SPEC_PUBLIC), flags);
85
86 cookie = theme->GetAttribute(app::R::attr::attr_two, &value, &flags);
87 ASSERT_NE(kInvalidCookie, cookie);
88 EXPECT_EQ(Res_value::TYPE_INT_DEC, value.dataType);
89 EXPECT_EQ(2u, value.data);
90 EXPECT_EQ(static_cast<uint32_t>(ResTable_typeSpec::SPEC_PUBLIC), flags);
91 }
92
TEST_F(ThemeTest,SingleThemeWithParent)93 TEST_F(ThemeTest, SingleThemeWithParent) {
94 AssetManager2 assetmanager;
95 assetmanager.SetApkAssets({style_assets_.get()});
96
97 std::unique_ptr<Theme> theme = assetmanager.NewTheme();
98 ASSERT_TRUE(theme->ApplyStyle(app::R::style::StyleTwo));
99
100 Res_value value;
101 uint32_t flags;
102 ApkAssetsCookie cookie;
103
104 cookie = theme->GetAttribute(app::R::attr::attr_one, &value, &flags);
105 ASSERT_NE(kInvalidCookie, cookie);
106 EXPECT_EQ(Res_value::TYPE_INT_DEC, value.dataType);
107 EXPECT_EQ(1u, value.data);
108 EXPECT_EQ(static_cast<uint32_t>(ResTable_typeSpec::SPEC_PUBLIC), flags);
109
110 cookie = theme->GetAttribute(app::R::attr::attr_two, &value, &flags);
111 ASSERT_NE(kInvalidCookie, cookie);
112 EXPECT_EQ(Res_value::TYPE_STRING, value.dataType);
113 EXPECT_EQ(0, cookie);
114 EXPECT_EQ(std::string("string"),
115 GetStringFromPool(assetmanager.GetStringPoolForCookie(0), value.data));
116 EXPECT_EQ(static_cast<uint32_t>(ResTable_typeSpec::SPEC_PUBLIC), flags);
117
118 // This attribute should point to an attr_indirect, so the result should be 3.
119 cookie = theme->GetAttribute(app::R::attr::attr_three, &value, &flags);
120 ASSERT_NE(kInvalidCookie, cookie);
121 EXPECT_EQ(Res_value::TYPE_INT_DEC, value.dataType);
122 EXPECT_EQ(3u, value.data);
123 EXPECT_EQ(static_cast<uint32_t>(ResTable_typeSpec::SPEC_PUBLIC), flags);
124 }
125
TEST_F(ThemeTest,MultipleThemesOverlaidNotForce)126 TEST_F(ThemeTest, MultipleThemesOverlaidNotForce) {
127 AssetManager2 assetmanager;
128 assetmanager.SetApkAssets({style_assets_.get()});
129
130 std::unique_ptr<Theme> theme = assetmanager.NewTheme();
131 ASSERT_TRUE(theme->ApplyStyle(app::R::style::StyleTwo));
132 ASSERT_TRUE(theme->ApplyStyle(app::R::style::StyleThree));
133
134 Res_value value;
135 uint32_t flags;
136 ApkAssetsCookie cookie;
137
138 // attr_one is still here from the base.
139 cookie = theme->GetAttribute(app::R::attr::attr_one, &value, &flags);
140 ASSERT_NE(kInvalidCookie, cookie);
141 EXPECT_EQ(Res_value::TYPE_INT_DEC, value.dataType);
142 EXPECT_EQ(1u, value.data);
143 EXPECT_EQ(static_cast<uint32_t>(ResTable_typeSpec::SPEC_PUBLIC), flags);
144
145 // check for the new attr_six
146 cookie = theme->GetAttribute(app::R::attr::attr_six, &value, &flags);
147 ASSERT_NE(kInvalidCookie, cookie);
148 EXPECT_EQ(Res_value::TYPE_INT_DEC, value.dataType);
149 EXPECT_EQ(6u, value.data);
150 EXPECT_EQ(static_cast<uint32_t>(ResTable_typeSpec::SPEC_PUBLIC), flags);
151
152 // check for the old attr_five (force=true was not used).
153 cookie = theme->GetAttribute(app::R::attr::attr_five, &value, &flags);
154 ASSERT_NE(kInvalidCookie, cookie);
155 EXPECT_EQ(Res_value::TYPE_REFERENCE, value.dataType);
156 EXPECT_EQ(app::R::string::string_one, value.data);
157 EXPECT_EQ(static_cast<uint32_t>(ResTable_typeSpec::SPEC_PUBLIC), flags);
158 }
159
TEST_F(ThemeTest,MultipleThemesOverlaidForced)160 TEST_F(ThemeTest, MultipleThemesOverlaidForced) {
161 AssetManager2 assetmanager;
162 assetmanager.SetApkAssets({style_assets_.get()});
163
164 std::unique_ptr<Theme> theme = assetmanager.NewTheme();
165 ASSERT_TRUE(theme->ApplyStyle(app::R::style::StyleTwo));
166 ASSERT_TRUE(theme->ApplyStyle(app::R::style::StyleThree, true /* force */));
167
168 Res_value value;
169 uint32_t flags;
170 ApkAssetsCookie cookie;
171
172 // attr_one is still here from the base.
173 cookie = theme->GetAttribute(app::R::attr::attr_one, &value, &flags);
174 ASSERT_NE(kInvalidCookie, cookie);
175 EXPECT_EQ(Res_value::TYPE_INT_DEC, value.dataType);
176 EXPECT_EQ(1u, value.data);
177 EXPECT_EQ(static_cast<uint32_t>(ResTable_typeSpec::SPEC_PUBLIC), flags);
178
179 // check for the new attr_six
180 cookie = theme->GetAttribute(app::R::attr::attr_six, &value, &flags);
181 ASSERT_NE(kInvalidCookie, cookie);
182 EXPECT_EQ(Res_value::TYPE_INT_DEC, value.dataType);
183 EXPECT_EQ(6u, value.data);
184 EXPECT_EQ(static_cast<uint32_t>(ResTable_typeSpec::SPEC_PUBLIC), flags);
185
186 // check for the new attr_five (force=true was used).
187 cookie = theme->GetAttribute(app::R::attr::attr_five, &value, &flags);
188 ASSERT_NE(kInvalidCookie, cookie);
189 EXPECT_EQ(Res_value::TYPE_INT_DEC, value.dataType);
190 EXPECT_EQ(5u, value.data);
191 EXPECT_EQ(static_cast<uint32_t>(ResTable_typeSpec::SPEC_PUBLIC), flags);
192 }
193
TEST_F(ThemeTest,ResolveDynamicAttributesAndReferencesToSharedLibrary)194 TEST_F(ThemeTest, ResolveDynamicAttributesAndReferencesToSharedLibrary) {
195 AssetManager2 assetmanager;
196 assetmanager.SetApkAssets(
197 {lib_two_assets_.get(), lib_one_assets_.get(), libclient_assets_.get()});
198
199 std::unique_ptr<Theme> theme = assetmanager.NewTheme();
200 ASSERT_TRUE(theme->ApplyStyle(libclient::R::style::Theme, false /*force*/));
201
202 Res_value value;
203 uint32_t flags;
204 ApkAssetsCookie cookie;
205
206 // The attribute should be resolved to the final value.
207 cookie = theme->GetAttribute(libclient::R::attr::foo, &value, &flags);
208 ASSERT_NE(kInvalidCookie, cookie);
209 EXPECT_EQ(Res_value::TYPE_INT_DEC, value.dataType);
210 EXPECT_EQ(700u, value.data);
211 EXPECT_EQ(static_cast<uint32_t>(ResTable_typeSpec::SPEC_PUBLIC), flags);
212
213 // The reference should be resolved to a TYPE_REFERENCE.
214 cookie = theme->GetAttribute(libclient::R::attr::bar, &value, &flags);
215 ASSERT_NE(kInvalidCookie, cookie);
216 EXPECT_EQ(Res_value::TYPE_REFERENCE, value.dataType);
217
218 // lib_one is assigned package ID 0x03.
219 EXPECT_EQ(3u, get_package_id(value.data));
220 EXPECT_EQ(get_type_id(lib_one::R::string::foo), get_type_id(value.data));
221 EXPECT_EQ(get_entry_id(lib_one::R::string::foo), get_entry_id(value.data));
222 }
223
TEST_F(ThemeTest,CopyThemeSameAssetManager)224 TEST_F(ThemeTest, CopyThemeSameAssetManager) {
225 AssetManager2 assetmanager;
226 assetmanager.SetApkAssets({style_assets_.get()});
227
228 std::unique_ptr<Theme> theme_one = assetmanager.NewTheme();
229 ASSERT_TRUE(theme_one->ApplyStyle(app::R::style::StyleOne));
230
231 Res_value value;
232 uint32_t flags;
233 ApkAssetsCookie cookie;
234
235 // attr_one is still here from the base.
236 cookie = theme_one->GetAttribute(app::R::attr::attr_one, &value, &flags);
237 ASSERT_NE(kInvalidCookie, cookie);
238 EXPECT_EQ(Res_value::TYPE_INT_DEC, value.dataType);
239 EXPECT_EQ(1u, value.data);
240 EXPECT_EQ(static_cast<uint32_t>(ResTable_typeSpec::SPEC_PUBLIC), flags);
241
242 // attr_six is not here.
243 EXPECT_EQ(kInvalidCookie, theme_one->GetAttribute(app::R::attr::attr_six, &value, &flags));
244
245 std::unique_ptr<Theme> theme_two = assetmanager.NewTheme();
246 ASSERT_TRUE(theme_two->ApplyStyle(app::R::style::StyleThree));
247
248 // Copy the theme to theme_one.
249 ASSERT_TRUE(theme_one->SetTo(*theme_two));
250
251 // Clear theme_two to make sure we test that there WAS a copy.
252 theme_two->Clear();
253
254 // attr_one is now not here.
255 EXPECT_EQ(kInvalidCookie, theme_one->GetAttribute(app::R::attr::attr_one, &value, &flags));
256
257 // attr_six is now here because it was copied.
258 cookie = theme_one->GetAttribute(app::R::attr::attr_six, &value, &flags);
259 ASSERT_NE(kInvalidCookie, cookie);
260 EXPECT_EQ(Res_value::TYPE_INT_DEC, value.dataType);
261 EXPECT_EQ(6u, value.data);
262 EXPECT_EQ(static_cast<uint32_t>(ResTable_typeSpec::SPEC_PUBLIC), flags);
263 }
264
TEST_F(ThemeTest,FailToCopyThemeWithDifferentAssetManager)265 TEST_F(ThemeTest, FailToCopyThemeWithDifferentAssetManager) {
266 AssetManager2 assetmanager_one;
267 assetmanager_one.SetApkAssets({style_assets_.get()});
268
269 AssetManager2 assetmanager_two;
270 assetmanager_two.SetApkAssets({style_assets_.get()});
271
272 auto theme_one = assetmanager_one.NewTheme();
273 ASSERT_TRUE(theme_one->ApplyStyle(app::R::style::StyleOne));
274
275 auto theme_two = assetmanager_two.NewTheme();
276 ASSERT_TRUE(theme_two->ApplyStyle(app::R::style::StyleTwo));
277
278 EXPECT_FALSE(theme_one->SetTo(*theme_two));
279 }
280
281 } // namespace android
282