blob: 83c97950b0330347a10c46534507806d66e47ddb [file] [log] [blame]
Adam Lesinski40e8eef2014-09-16 14:43:29 -07001/*
2 * Copyright (C) 2014 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 "RuleGenerator.h"
Adam Lesinskidcdfe9f2014-11-06 12:54:36 -080018#include "aapt/SdkConstants.h"
Adam Lesinski40e8eef2014-09-16 14:43:29 -070019
20#include <algorithm>
21#include <cmath>
22#include <vector>
23#include <androidfw/ResourceTypes.h>
24
25using namespace android;
26
27namespace split {
28
29// Calculate the point at which the density selection changes between l and h.
30static inline int findMid(int l, int h) {
31 double root = sqrt((h*h) + (8*l*h));
32 return (double(-h) + root) / 2.0;
33}
34
35sp<Rule> RuleGenerator::generateDensity(const Vector<int>& allDensities, size_t index) {
Adam Lesinskidcdfe9f2014-11-06 12:54:36 -080036 if (allDensities[index] != ResTable_config::DENSITY_ANY) {
37 sp<Rule> densityRule = new Rule();
38 densityRule->op = Rule::AND_SUBRULES;
Adam Lesinski40e8eef2014-09-16 14:43:29 -070039
Adam Lesinskidcdfe9f2014-11-06 12:54:36 -080040 const bool hasAnyDensity = std::find(allDensities.begin(),
Adam Lesinski4d29c662014-11-10 14:32:11 -080041 allDensities.end(), (int) ResTable_config::DENSITY_ANY) != allDensities.end();
Adam Lesinski40e8eef2014-09-16 14:43:29 -070042
Adam Lesinskidcdfe9f2014-11-06 12:54:36 -080043 if (hasAnyDensity) {
44 sp<Rule> version = new Rule();
45 version->op = Rule::LESS_THAN;
46 version->key = Rule::SDK_VERSION;
47 version->longArgs.add((long) SDK_LOLLIPOP);
48 densityRule->subrules.add(version);
49 }
50
Adam Lesinski40e8eef2014-09-16 14:43:29 -070051 if (index > 0) {
52 sp<Rule> gt = new Rule();
53 gt->op = Rule::GREATER_THAN;
54 gt->key = Rule::SCREEN_DENSITY;
55 gt->longArgs.add(findMid(allDensities[index - 1], allDensities[index]) - 1);
56 densityRule->subrules.add(gt);
57 }
58
59 if (index + 1 < allDensities.size() && allDensities[index + 1] != ResTable_config::DENSITY_ANY) {
60 sp<Rule> lt = new Rule();
61 lt->op = Rule::LESS_THAN;
62 lt->key = Rule::SCREEN_DENSITY;
63 lt->longArgs.add(findMid(allDensities[index], allDensities[index + 1]));
64 densityRule->subrules.add(lt);
65 }
Adam Lesinskidcdfe9f2014-11-06 12:54:36 -080066 return densityRule;
67 } else {
68 // SDK_VERSION is handled elsewhere, so we always pick DENSITY_ANY if it's
69 // available.
70 sp<Rule> always = new Rule();
71 always->op = Rule::ALWAYS_TRUE;
72 return always;
Adam Lesinski40e8eef2014-09-16 14:43:29 -070073 }
Adam Lesinski40e8eef2014-09-16 14:43:29 -070074}
75
76sp<Rule> RuleGenerator::generateAbi(const Vector<abi::Variant>& splitAbis, size_t index) {
77 const abi::Variant thisAbi = splitAbis[index];
Adam Lesinskic3dc0b52014-11-03 12:05:15 -080078 const Vector<abi::Variant>& familyVariants = abi::getVariants(abi::getFamily(thisAbi));
Adam Lesinski40e8eef2014-09-16 14:43:29 -070079
Adam Lesinskic3dc0b52014-11-03 12:05:15 -080080 Vector<abi::Variant>::const_iterator start =
Adam Lesinski40e8eef2014-09-16 14:43:29 -070081 std::find(familyVariants.begin(), familyVariants.end(), thisAbi);
82
Adam Lesinskic3dc0b52014-11-03 12:05:15 -080083 Vector<abi::Variant>::const_iterator end = familyVariants.end();
Adam Lesinski40e8eef2014-09-16 14:43:29 -070084 if (index + 1 < splitAbis.size()) {
85 end = std::find(start, familyVariants.end(), splitAbis[index + 1]);
86 }
87
88 sp<Rule> abiRule = new Rule();
89 abiRule->op = Rule::CONTAINS_ANY;
90 abiRule->key = Rule::NATIVE_PLATFORM;
91 while (start != end) {
92 abiRule->stringArgs.add(String8(abi::toString(*start)));
93 ++start;
94 }
95 return abiRule;
96}
97
98sp<Rule> RuleGenerator::generate(const SortedVector<SplitDescription>& group, size_t index) {
99 sp<Rule> rootRule = new Rule();
100 rootRule->op = Rule::AND_SUBRULES;
101
102 if (group[index].config.locale != 0) {
103 sp<Rule> locale = new Rule();
104 locale->op = Rule::EQUALS;
105 locale->key = Rule::LANGUAGE;
106 char str[RESTABLE_MAX_LOCALE_LEN];
107 group[index].config.getBcp47Locale(str);
108 locale->stringArgs.add(String8(str));
109 rootRule->subrules.add(locale);
110 }
111
112 if (group[index].config.sdkVersion != 0) {
113 sp<Rule> sdk = new Rule();
114 sdk->op = Rule::GREATER_THAN;
115 sdk->key = Rule::SDK_VERSION;
116 sdk->longArgs.add(group[index].config.sdkVersion - 1);
117 rootRule->subrules.add(sdk);
118 }
119
120 if (group[index].config.density != 0) {
121 size_t densityIndex = 0;
122 Vector<int> allDensities;
123 allDensities.add(group[index].config.density);
124
125 const size_t groupSize = group.size();
126 for (size_t i = 0; i < groupSize; i++) {
127 if (group[i].config.density != group[index].config.density) {
128 // This group differs by density.
129 allDensities.clear();
130 for (size_t j = 0; j < groupSize; j++) {
131 allDensities.add(group[j].config.density);
132 }
133 densityIndex = index;
134 break;
135 }
136 }
137 rootRule->subrules.add(generateDensity(allDensities, densityIndex));
138 }
139
Adam Lesinskic3dc0b52014-11-03 12:05:15 -0800140 if (group[index].abi != abi::Variant_none) {
Adam Lesinski40e8eef2014-09-16 14:43:29 -0700141 size_t abiIndex = 0;
142 Vector<abi::Variant> allVariants;
143 allVariants.add(group[index].abi);
144
145 const size_t groupSize = group.size();
146 for (size_t i = 0; i < groupSize; i++) {
147 if (group[i].abi != group[index].abi) {
148 // This group differs by ABI.
149 allVariants.clear();
150 for (size_t j = 0; j < groupSize; j++) {
151 allVariants.add(group[j].abi);
152 }
153 abiIndex = index;
154 break;
155 }
156 }
157 rootRule->subrules.add(generateAbi(allVariants, abiIndex));
158 }
159
160 return rootRule;
161}
162
163} // namespace split