Home | History | Annotate | Download | only in split-select
      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.
     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 
     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 
     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 
     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