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