/* * 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 "Rule.h" #include <utils/String8.h> using namespace android; namespace split { inline static void indentStr(String8& str, int indent) { while (indent > 0) { str.append(" "); indent--; } } Rule::Rule(const Rule& rhs) : RefBase() , op(rhs.op) , key(rhs.key) , negate(rhs.negate) , stringArgs(rhs.stringArgs) , longArgs(rhs.longArgs) , subrules(rhs.subrules) { } String8 Rule::toJson(int indent) const { String8 str; indentStr(str, indent); str.append("{\n"); indent++; indentStr(str, indent); str.append("\"op\": \""); switch (op) { case ALWAYS_TRUE: str.append("ALWAYS_TRUE"); break; case GREATER_THAN: str.append("GREATER_THAN"); break; case LESS_THAN: str.append("LESS_THAN"); break; case EQUALS: str.append("EQUALS"); break; case AND_SUBRULES: str.append("AND_SUBRULES"); break; case OR_SUBRULES: str.append("OR_SUBRULES"); break; case CONTAINS_ANY: str.append("CONTAINS_ANY"); break; default: str.appendFormat("%d", op); break; } str.append("\""); if (negate) { str.append(",\n"); indentStr(str, indent); str.append("\"negate\": true"); } bool includeKey = true; switch (op) { case AND_SUBRULES: case OR_SUBRULES: includeKey = false; break; default: break; } if (includeKey) { str.append(",\n"); indentStr(str, indent); str.append("\"property\": \""); switch (key) { case NONE: str.append("NONE"); break; case SDK_VERSION: str.append("SDK_VERSION"); break; case SCREEN_DENSITY: str.append("SCREEN_DENSITY"); break; case NATIVE_PLATFORM: str.append("NATIVE_PLATFORM"); break; case LANGUAGE: str.append("LANGUAGE"); break; default: str.appendFormat("%d", key); break; } str.append("\""); } if (op == AND_SUBRULES || op == OR_SUBRULES) { str.append(",\n"); indentStr(str, indent); str.append("\"subrules\": [\n"); const size_t subruleCount = subrules.size(); for (size_t i = 0; i < subruleCount; i++) { str.append(subrules[i]->toJson(indent + 1)); if (i != subruleCount - 1) { str.append(","); } str.append("\n"); } indentStr(str, indent); str.append("]"); } else { switch (key) { case SDK_VERSION: case SCREEN_DENSITY: { str.append(",\n"); indentStr(str, indent); str.append("\"args\": ["); const size_t argCount = longArgs.size(); for (size_t i = 0; i < argCount; i++) { if (i != 0) { str.append(", "); } str.appendFormat("%d", longArgs[i]); } str.append("]"); break; } case LANGUAGE: case NATIVE_PLATFORM: { str.append(",\n"); indentStr(str, indent); str.append("\"args\": ["); const size_t argCount = stringArgs.size(); for (size_t i = 0; i < argCount; i++) { if (i != 0) { str.append(", "); } str.append(stringArgs[i]); } str.append("]"); break; } default: break; } } str.append("\n"); indent--; indentStr(str, indent); str.append("}"); return str; } sp<Rule> Rule::simplify(sp<Rule> rule) { if (rule->op != AND_SUBRULES && rule->op != OR_SUBRULES) { return rule; } Vector<sp<Rule> > newSubrules; newSubrules.setCapacity(rule->subrules.size()); const size_t subruleCount = rule->subrules.size(); for (size_t i = 0; i < subruleCount; i++) { sp<Rule> simplifiedRule = simplify(rule->subrules.editItemAt(i)); if (simplifiedRule != NULL) { if (simplifiedRule->op == rule->op) { newSubrules.appendVector(simplifiedRule->subrules); } else { newSubrules.add(simplifiedRule); } } } const size_t newSubruleCount = newSubrules.size(); if (newSubruleCount == 0) { return NULL; } else if (subruleCount == 1) { return newSubrules.editTop(); } rule->subrules = newSubrules; return rule; } } // namespace split