11ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski/*
21ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski * Copyright (C) 2015 The Android Open Source Project
31ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski *
41ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski * Licensed under the Apache License, Version 2.0 (the "License");
51ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski * you may not use this file except in compliance with the License.
61ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski * You may obtain a copy of the License at
71ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski *
81ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski *      http://www.apache.org/licenses/LICENSE-2.0
91ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski *
101ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski * Unless required by applicable law or agreed to in writing, software
111ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski * distributed under the License is distributed on an "AS IS" BASIS,
121ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
131ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski * See the License for the specific language governing permissions and
141ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski * limitations under the License.
151ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski */
161ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski
171ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski#include "ConfigDescription.h"
181ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski#include "ResourceTable.h"
191ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski#include "SdkConstants.h"
201ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski#include "ValueVisitor.h"
211ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski#include "link/Linkers.h"
221ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski
231ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski#include <algorithm>
241ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski#include <cassert>
251ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski
261ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinskinamespace aapt {
271ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski
281ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinskibool shouldGenerateVersionedResource(const ResourceEntry* entry, const ConfigDescription& config,
291ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski                                     const int sdkVersionToGenerate) {
301ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski    assert(sdkVersionToGenerate > config.sdkVersion);
311ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski    const auto endIter = entry->values.end();
32e4bb9eb5af5b0899dc0921d5580220b20e15bd5aAdam Lesinski    auto iter = entry->values.begin();
33e4bb9eb5af5b0899dc0921d5580220b20e15bd5aAdam Lesinski    for (; iter != endIter; ++iter) {
34e4bb9eb5af5b0899dc0921d5580220b20e15bd5aAdam Lesinski        if ((*iter)->config == config) {
35e4bb9eb5af5b0899dc0921d5580220b20e15bd5aAdam Lesinski            break;
36e4bb9eb5af5b0899dc0921d5580220b20e15bd5aAdam Lesinski        }
37e4bb9eb5af5b0899dc0921d5580220b20e15bd5aAdam Lesinski    }
381ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski
391ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski    // The source config came from this list, so it should be here.
401ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski    assert(iter != entry->values.end());
411ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski    ++iter;
421ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski
431ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski    // The next configuration either only varies in sdkVersion, or it is completely different
441ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski    // and therefore incompatible. If it is incompatible, we must generate the versioned resource.
451ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski
461ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski    // NOTE: The ordering of configurations takes sdkVersion as higher precedence than other
471ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski    // qualifiers, so we need to iterate through the entire list to be sure there
481ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski    // are no higher sdk level versions of this resource.
491ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski    ConfigDescription tempConfig(config);
501ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski    for (; iter != endIter; ++iter) {
51e4bb9eb5af5b0899dc0921d5580220b20e15bd5aAdam Lesinski        tempConfig.sdkVersion = (*iter)->config.sdkVersion;
52e4bb9eb5af5b0899dc0921d5580220b20e15bd5aAdam Lesinski        if (tempConfig == (*iter)->config) {
531ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski            // The two configs are the same, check the sdk version.
54e4bb9eb5af5b0899dc0921d5580220b20e15bd5aAdam Lesinski            return sdkVersionToGenerate < (*iter)->config.sdkVersion;
551ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski        }
561ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski    }
571ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski
581ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski    // No match was found, so we should generate the versioned resource.
591ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski    return true;
601ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski}
611ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski
621ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinskibool AutoVersioner::consume(IAaptContext* context, ResourceTable* table) {
631ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski    for (auto& package : table->packages) {
641ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski        for (auto& type : package->types) {
651ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski            if (type->type != ResourceType::kStyle) {
661ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski                continue;
671ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski            }
681ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski
691ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski            for (auto& entry : type->entries) {
701ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski                for (size_t i = 0; i < entry->values.size(); i++) {
71e4bb9eb5af5b0899dc0921d5580220b20e15bd5aAdam Lesinski                    ResourceConfigValue* configValue = entry->values[i].get();
72e4bb9eb5af5b0899dc0921d5580220b20e15bd5aAdam Lesinski                    if (configValue->config.sdkVersion >= SDK_LOLLIPOP_MR1) {
731ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski                        // If this configuration is only used on L-MR1 then we don't need
741ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski                        // to do anything since we use private attributes since that version.
751ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski                        continue;
761ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski                    }
771ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski
78e4bb9eb5af5b0899dc0921d5580220b20e15bd5aAdam Lesinski                    if (Style* style = valueCast<Style>(configValue->value.get())) {
791ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski                        Maybe<size_t> minSdkStripped;
801ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski                        std::vector<Style::Entry> stripped;
811ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski
821ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski                        auto iter = style->entries.begin();
831ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski                        while (iter != style->entries.end()) {
841ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski                            assert(iter->key.id && "IDs must be assigned and linked");
851ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski
861ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski                            // Find the SDK level that is higher than the configuration allows.
871ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski                            const size_t sdkLevel = findAttributeSdkLevel(iter->key.id.value());
88e4bb9eb5af5b0899dc0921d5580220b20e15bd5aAdam Lesinski                            if (sdkLevel > std::max<size_t>(configValue->config.sdkVersion, 1)) {
891ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski                                // Record that we are about to strip this.
901ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski                                stripped.emplace_back(std::move(*iter));
911ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski
921ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski                                // We use the smallest SDK level to generate the new style.
931ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski                                if (minSdkStripped) {
941ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski                                    minSdkStripped = std::min(minSdkStripped.value(), sdkLevel);
951ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski                                } else {
961ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski                                    minSdkStripped = sdkLevel;
971ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski                                }
981ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski
991ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski                                // Erase this from this style.
1001ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski                                iter = style->entries.erase(iter);
1011ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski                                continue;
1021ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski                            }
1031ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski                            ++iter;
1041ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski                        }
1051ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski
1061ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski                        if (minSdkStripped && !stripped.empty()) {
1071ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski                            // We found attributes from a higher SDK level. Check that
1081ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski                            // there is no other defined resource for the version we want to
1091ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski                            // generate.
110e78fd617ec60139a973a01925fa7adad31febb39Adam Lesinski                            if (shouldGenerateVersionedResource(entry.get(),
111e4bb9eb5af5b0899dc0921d5580220b20e15bd5aAdam Lesinski                                                                configValue->config,
1121ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski                                                                minSdkStripped.value())) {
1131ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski                                // Let's create a new Style for this versioned resource.
114e4bb9eb5af5b0899dc0921d5580220b20e15bd5aAdam Lesinski                                ConfigDescription newConfig(configValue->config);
1151ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski                                newConfig.sdkVersion = minSdkStripped.value();
1161ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski
117e78fd617ec60139a973a01925fa7adad31febb39Adam Lesinski                                std::unique_ptr<Style> newStyle(style->clone(&table->stringPool));
118e78fd617ec60139a973a01925fa7adad31febb39Adam Lesinski                                newStyle->setComment(style->getComment());
119e78fd617ec60139a973a01925fa7adad31febb39Adam Lesinski                                newStyle->setSource(style->getSource());
1201ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski
1211ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski                                // Move the previously stripped attributes into this style.
1221ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski                                newStyle->entries.insert(newStyle->entries.end(),
1231ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski                                                         std::make_move_iterator(stripped.begin()),
1241ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski                                                         std::make_move_iterator(stripped.end()));
1251ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski
1261ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski                                // Insert the new Resource into the correct place.
127e4bb9eb5af5b0899dc0921d5580220b20e15bd5aAdam Lesinski                                entry->findOrCreateValue(newConfig, {})->value =
128e4bb9eb5af5b0899dc0921d5580220b20e15bd5aAdam Lesinski                                        std::move(newStyle);
1291ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski                            }
1301ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski                        }
1311ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski                    }
1321ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski                }
1331ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski            }
1341ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski        }
1351ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski    }
1361ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski    return true;
1371ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski}
1381ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski
1391ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski} // namespace aapt
140