• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2017 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 "optimize/MultiApkGenerator.h"
18 
19 #include <string>
20 
21 #include "gmock/gmock.h"
22 #include "gtest/gtest.h"
23 
24 #include "LoadedApk.h"
25 #include "ResourceTable.h"
26 #include "configuration/ConfigurationParser.h"
27 #include "filter/Filter.h"
28 #include "format/Archive.h"
29 #include "format/binary/TableFlattener.h"
30 #include "process/IResourceTableConsumer.h"
31 #include "test/Context.h"
32 #include "test/Test.h"
33 
34 namespace aapt {
35 namespace {
36 
37 using ::aapt::configuration::Abi;
38 using ::aapt::configuration::AndroidSdk;
39 using ::aapt::configuration::OutputArtifact;
40 using ::aapt::test::GetValue;
41 using ::aapt::test::GetValueForConfig;
42 using ::aapt::test::ParseConfigOrDie;
43 using ::testing::Eq;
44 using ::testing::IsNull;
45 using ::testing::Not;
46 using ::testing::NotNull;
47 using ::testing::PrintToString;
48 using ::testing::Return;
49 using ::testing::Test;
50 
51 /**
52  * Subclass the MultiApkGenerator class so that we can access the protected FilterTable method to
53  * directly test table filter.
54  */
55 class MultiApkGeneratorWrapper : public MultiApkGenerator {
56  public:
MultiApkGeneratorWrapper(LoadedApk * apk,IAaptContext * context)57   MultiApkGeneratorWrapper(LoadedApk* apk, IAaptContext* context)
58       : MultiApkGenerator(apk, context) {
59   }
60 
FilterTable(IAaptContext * context,const configuration::OutputArtifact & artifact,const ResourceTable & old_table,FilterChain * filter_chain)61   std::unique_ptr<ResourceTable> FilterTable(IAaptContext* context,
62                                              const configuration::OutputArtifact& artifact,
63                                              const ResourceTable& old_table,
64                                              FilterChain* filter_chain) override {
65     return MultiApkGenerator::FilterTable(context, artifact, old_table, filter_chain);
66   }
67 };
68 
69 /** MultiApkGenerator test fixture. */
70 class MultiApkGeneratorTest : public ::testing::Test {
71  public:
BuildTable()72   std::unique_ptr<ResourceTable> BuildTable() {
73     return test::ResourceTableBuilder()
74         .AddFileReference(kResourceName, "res/drawable-mdpi/icon.png", mdpi_)
75         .AddFileReference(kResourceName, "res/drawable-hdpi/icon.png", hdpi_)
76         .AddFileReference(kResourceName, "res/drawable-xhdpi/icon.png", xhdpi_)
77         .AddFileReference(kResourceName, "res/drawable-xxhdpi/icon.png", xxhdpi_)
78         .AddFileReference(kResourceName, "res/drawable-v19/icon.xml", v19_)
79         .AddFileReference(kResourceName, "res/drawable-v21/icon.xml", v21_)
80         .AddSimple("android:string/one")
81         .Build();
82   }
83 
ValueForConfig(ResourceTable * table,const ConfigDescription & config)84   inline FileReference* ValueForConfig(ResourceTable* table, const ConfigDescription& config) {
85     return GetValueForConfig<FileReference>(table, kResourceName, config);
86   };
87 
SetUp()88   void SetUp() override {
89   }
90 
91  protected:
92   static constexpr const char* kResourceName = "android:drawable/icon";
93 
94   ConfigDescription default_ = ParseConfigOrDie("").CopyWithoutSdkVersion();
95   ConfigDescription mdpi_ = ParseConfigOrDie("mdpi").CopyWithoutSdkVersion();
96   ConfigDescription hdpi_ = ParseConfigOrDie("hdpi").CopyWithoutSdkVersion();
97   ConfigDescription xhdpi_ = ParseConfigOrDie("xhdpi").CopyWithoutSdkVersion();
98   ConfigDescription xxhdpi_ = ParseConfigOrDie("xxhdpi").CopyWithoutSdkVersion();
99   ConfigDescription xxxhdpi_ = ParseConfigOrDie("xxxhdpi").CopyWithoutSdkVersion();
100   ConfigDescription v19_ = ParseConfigOrDie("v19");
101   ConfigDescription v21_ = ParseConfigOrDie("v21");
102 };
103 
TEST_F(MultiApkGeneratorTest,VersionFilterNewerVersion)104 TEST_F(MultiApkGeneratorTest, VersionFilterNewerVersion) {
105   std::unique_ptr<ResourceTable> table = BuildTable();
106 
107   LoadedApk apk = {{"test.apk"}, {}, std::move(table), {}, kBinary};
108   std::unique_ptr<IAaptContext> ctx = test::ContextBuilder().SetMinSdkVersion(19).Build();
109   FilterChain chain;
110 
111   OutputArtifact artifact = test::ArtifactBuilder().AddDensity(xhdpi_).SetAndroidSdk(23).Build();
112 
113   MultiApkGeneratorWrapper generator{&apk, ctx.get()};
114   std::unique_ptr<ResourceTable> split =
115       generator.FilterTable(ctx.get(), artifact, *apk.GetResourceTable(), &chain);
116 
117   ResourceTable* new_table = split.get();
118   EXPECT_THAT(ValueForConfig(new_table, mdpi_), IsNull());
119   EXPECT_THAT(ValueForConfig(new_table, hdpi_), IsNull());
120   EXPECT_THAT(ValueForConfig(new_table, xxhdpi_), IsNull());
121   EXPECT_THAT(ValueForConfig(new_table, xxxhdpi_), IsNull());
122   EXPECT_THAT(ValueForConfig(new_table, v19_), IsNull());
123 
124   // xhdpi directly matches one of the required dimensions.
125   EXPECT_THAT(ValueForConfig(new_table, xhdpi_), NotNull());
126   // drawable-v21 was converted to drawable.
127   EXPECT_THAT(ValueForConfig(new_table, default_), NotNull());
128   EXPECT_THAT(GetValue<Id>(new_table, "android:string/one"), NotNull());
129 }
130 
TEST_F(MultiApkGeneratorTest,VersionFilterOlderVersion)131 TEST_F(MultiApkGeneratorTest, VersionFilterOlderVersion) {
132   std::unique_ptr<ResourceTable> table = BuildTable();
133 
134   LoadedApk apk = {{"test.apk"}, {}, std::move(table), {}, kBinary};
135   std::unique_ptr<IAaptContext> ctx = test::ContextBuilder().SetMinSdkVersion(1).Build();
136   FilterChain chain;
137 
138   OutputArtifact artifact = test::ArtifactBuilder().AddDensity(xhdpi_).SetAndroidSdk(4).Build();
139 
140   MultiApkGeneratorWrapper generator{&apk, ctx.get()};;
141   std::unique_ptr<ResourceTable> split =
142       generator.FilterTable(ctx.get(), artifact, *apk.GetResourceTable(), &chain);
143 
144   ResourceTable* new_table = split.get();
145   EXPECT_THAT(ValueForConfig(new_table, mdpi_), IsNull());
146   EXPECT_THAT(ValueForConfig(new_table, hdpi_), IsNull());
147   EXPECT_THAT(ValueForConfig(new_table, xxhdpi_), IsNull());
148   EXPECT_THAT(ValueForConfig(new_table, xxxhdpi_), IsNull());
149 
150   EXPECT_THAT(ValueForConfig(new_table, xhdpi_), NotNull());
151   EXPECT_THAT(ValueForConfig(new_table, v19_), NotNull());
152   EXPECT_THAT(ValueForConfig(new_table, v21_), NotNull());
153   EXPECT_THAT(GetValue<Id>(new_table, "android:string/one"), NotNull());
154 }
155 
TEST_F(MultiApkGeneratorTest,VersionFilterNoVersion)156 TEST_F(MultiApkGeneratorTest, VersionFilterNoVersion) {
157   std::unique_ptr<ResourceTable> table = BuildTable();
158 
159   LoadedApk apk = {{"test.apk"}, {}, std::move(table), {}, kBinary};
160   std::unique_ptr<IAaptContext> ctx = test::ContextBuilder().SetMinSdkVersion(1).Build();
161   FilterChain chain;
162 
163   OutputArtifact artifact = test::ArtifactBuilder().AddDensity(xhdpi_).Build();
164 
165   MultiApkGeneratorWrapper generator{&apk, ctx.get()};
166   std::unique_ptr<ResourceTable> split =
167       generator.FilterTable(ctx.get(), artifact, *apk.GetResourceTable(), &chain);
168 
169   ResourceTable* new_table = split.get();
170   EXPECT_THAT(ValueForConfig(new_table, mdpi_), IsNull());
171   EXPECT_THAT(ValueForConfig(new_table, hdpi_), IsNull());
172   EXPECT_THAT(ValueForConfig(new_table, xxhdpi_), IsNull());
173   EXPECT_THAT(ValueForConfig(new_table, xxxhdpi_), IsNull());
174 
175   EXPECT_THAT(ValueForConfig(new_table, xhdpi_), NotNull());
176   EXPECT_THAT(ValueForConfig(new_table, v19_), NotNull());
177   EXPECT_THAT(ValueForConfig(new_table, v21_), NotNull());
178   EXPECT_THAT(GetValue<Id>(new_table, "android:string/one"), NotNull());
179 }
180 
181 }  // namespace
182 }  // namespace aapt
183