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
27namespace app = com::android::app;
28namespace lib_one = com::android::lib_one;
29namespace libclient = com::android::libclient;
30
31namespace android {
32
33class ThemeTest : public ::testing::Test {
34 public:
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
56TEST_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
69TEST_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
93TEST_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
126TEST_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
160TEST_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
194TEST_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
224TEST_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
265TEST_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