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