1 /*
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"
18 #include "aapt/SdkConstants.h"
19 
20 #include <algorithm>
21 #include <cmath>
22 #include <vector>
23 #include <androidfw/ResourceTypes.h>
24 
25 using namespace android;
26 
27 namespace split {
28 
29 // Calculate the point at which the density selection changes between l and h.
findMid(int l,int h)30 static 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 
generateDensity(const Vector<int> & allDensities,size_t index)35 sp<Rule> RuleGenerator::generateDensity(const Vector<int>& allDensities, size_t index) {
36     if (allDensities[index] != ResTable_config::DENSITY_ANY) {
37         sp<Rule> densityRule = new Rule();
38         densityRule->op = Rule::AND_SUBRULES;
39 
40         const bool hasAnyDensity = std::find(allDensities.begin(),
41                 allDensities.end(), (int) ResTable_config::DENSITY_ANY) != allDensities.end();
42 
43         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 
51         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         }
66         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;
73     }
74 }
75 
generateAbi(const Vector<abi::Variant> & splitAbis,size_t index)76 sp<Rule> RuleGenerator::generateAbi(const Vector<abi::Variant>& splitAbis, size_t index) {
77     const abi::Variant thisAbi = splitAbis[index];
78     const Vector<abi::Variant>& familyVariants = abi::getVariants(abi::getFamily(thisAbi));
79 
80     Vector<abi::Variant>::const_iterator start =
81             std::find(familyVariants.begin(), familyVariants.end(), thisAbi);
82 
83     Vector<abi::Variant>::const_iterator end = familyVariants.end();
84     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 
generate(const SortedVector<SplitDescription> & group,size_t index)98 sp<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 
140     if (group[index].abi != abi::Variant_none) {
141         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
164