| /* |
| * Copyright (C) 2014 The Android Open Source Project |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| #include "RuleGenerator.h" |
| #include "aapt/SdkConstants.h" |
| |
| #include <algorithm> |
| #include <cmath> |
| #include <vector> |
| #include <androidfw/ResourceTypes.h> |
| |
| using namespace android; |
| |
| namespace split { |
| |
| // Calculate the point at which the density selection changes between l and h. |
| static inline int findMid(int l, int h) { |
| double root = sqrt((h*h) + (8*l*h)); |
| return (double(-h) + root) / 2.0; |
| } |
| |
| sp<Rule> RuleGenerator::generateDensity(const Vector<int>& allDensities, size_t index) { |
| if (allDensities[index] != ResTable_config::DENSITY_ANY) { |
| sp<Rule> densityRule = new Rule(); |
| densityRule->op = Rule::AND_SUBRULES; |
| |
| const bool hasAnyDensity = std::find(allDensities.begin(), |
| allDensities.end(), (int) ResTable_config::DENSITY_ANY) != allDensities.end(); |
| |
| if (hasAnyDensity) { |
| sp<Rule> version = new Rule(); |
| version->op = Rule::LESS_THAN; |
| version->key = Rule::SDK_VERSION; |
| version->longArgs.add((long) SDK_LOLLIPOP); |
| densityRule->subrules.add(version); |
| } |
| |
| if (index > 0) { |
| sp<Rule> gt = new Rule(); |
| gt->op = Rule::GREATER_THAN; |
| gt->key = Rule::SCREEN_DENSITY; |
| gt->longArgs.add(findMid(allDensities[index - 1], allDensities[index]) - 1); |
| densityRule->subrules.add(gt); |
| } |
| |
| if (index + 1 < allDensities.size() && allDensities[index + 1] != ResTable_config::DENSITY_ANY) { |
| sp<Rule> lt = new Rule(); |
| lt->op = Rule::LESS_THAN; |
| lt->key = Rule::SCREEN_DENSITY; |
| lt->longArgs.add(findMid(allDensities[index], allDensities[index + 1])); |
| densityRule->subrules.add(lt); |
| } |
| return densityRule; |
| } else { |
| // SDK_VERSION is handled elsewhere, so we always pick DENSITY_ANY if it's |
| // available. |
| sp<Rule> always = new Rule(); |
| always->op = Rule::ALWAYS_TRUE; |
| return always; |
| } |
| } |
| |
| sp<Rule> RuleGenerator::generateAbi(const Vector<abi::Variant>& splitAbis, size_t index) { |
| const abi::Variant thisAbi = splitAbis[index]; |
| const Vector<abi::Variant>& familyVariants = abi::getVariants(abi::getFamily(thisAbi)); |
| |
| Vector<abi::Variant>::const_iterator start = |
| std::find(familyVariants.begin(), familyVariants.end(), thisAbi); |
| |
| Vector<abi::Variant>::const_iterator end = familyVariants.end(); |
| if (index + 1 < splitAbis.size()) { |
| end = std::find(start, familyVariants.end(), splitAbis[index + 1]); |
| } |
| |
| sp<Rule> abiRule = new Rule(); |
| abiRule->op = Rule::CONTAINS_ANY; |
| abiRule->key = Rule::NATIVE_PLATFORM; |
| while (start != end) { |
| abiRule->stringArgs.add(String8(abi::toString(*start))); |
| ++start; |
| } |
| return abiRule; |
| } |
| |
| sp<Rule> RuleGenerator::generate(const SortedVector<SplitDescription>& group, size_t index) { |
| sp<Rule> rootRule = new Rule(); |
| rootRule->op = Rule::AND_SUBRULES; |
| |
| if (group[index].config.locale != 0) { |
| sp<Rule> locale = new Rule(); |
| locale->op = Rule::EQUALS; |
| locale->key = Rule::LANGUAGE; |
| char str[RESTABLE_MAX_LOCALE_LEN]; |
| group[index].config.getBcp47Locale(str); |
| locale->stringArgs.add(String8(str)); |
| rootRule->subrules.add(locale); |
| } |
| |
| if (group[index].config.sdkVersion != 0) { |
| sp<Rule> sdk = new Rule(); |
| sdk->op = Rule::GREATER_THAN; |
| sdk->key = Rule::SDK_VERSION; |
| sdk->longArgs.add(group[index].config.sdkVersion - 1); |
| rootRule->subrules.add(sdk); |
| } |
| |
| if (group[index].config.density != 0) { |
| size_t densityIndex = 0; |
| Vector<int> allDensities; |
| allDensities.add(group[index].config.density); |
| |
| const size_t groupSize = group.size(); |
| for (size_t i = 0; i < groupSize; i++) { |
| if (group[i].config.density != group[index].config.density) { |
| // This group differs by density. |
| allDensities.clear(); |
| for (size_t j = 0; j < groupSize; j++) { |
| allDensities.add(group[j].config.density); |
| } |
| densityIndex = index; |
| break; |
| } |
| } |
| rootRule->subrules.add(generateDensity(allDensities, densityIndex)); |
| } |
| |
| if (group[index].abi != abi::Variant_none) { |
| size_t abiIndex = 0; |
| Vector<abi::Variant> allVariants; |
| allVariants.add(group[index].abi); |
| |
| const size_t groupSize = group.size(); |
| for (size_t i = 0; i < groupSize; i++) { |
| if (group[i].abi != group[index].abi) { |
| // This group differs by ABI. |
| allVariants.clear(); |
| for (size_t j = 0; j < groupSize; j++) { |
| allVariants.add(group[j].abi); |
| } |
| abiIndex = index; |
| break; |
| } |
| } |
| rootRule->subrules.add(generateAbi(allVariants, abiIndex)); |
| } |
| |
| return rootRule; |
| } |
| |
| } // namespace split |