|  | /* | 
|  | * 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 |