Enable negation of business logic condition return values.

This will preclude us from requiring a "negative" version of each utility
method used in business logic conditions. For instance, checking if a device
lacks a system feature can be done with !FeatureUtil.hasFeature(), instead of
requiring existence of FeatureUtil.hasNoFeature().

bug: 62867056
Test: build CTS, run unit tests
Change-Id: I74c7ae020ff39ab9c6a1a1d989f5fd1bd0f2da78
diff --git a/common/util/src/com/android/compatibility/common/util/BusinessLogic.java b/common/util/src/com/android/compatibility/common/util/BusinessLogic.java
index 3a5c523..adab1eb 100644
--- a/common/util/src/com/android/compatibility/common/util/BusinessLogic.java
+++ b/common/util/src/com/android/compatibility/common/util/BusinessLogic.java
@@ -109,18 +109,24 @@
         /* Stored method name and String args */
         protected String mMethodName;
         protected List<String> mMethodArgs;
+        /* Whether or not the boolean result of this condition should be reversed */
+        protected boolean mNegated;
 
-        public BusinessLogicRuleCondition(String methodName, List<String> methodArgs) {
+
+        public BusinessLogicRuleCondition(String methodName, List<String> methodArgs,
+                boolean negated) {
             mMethodName = methodName;
             mMethodArgs = methodArgs;
+            mNegated = negated;
         }
 
         /**
          * Invoke this Business Logic condition with an executor.
          */
         public boolean invoke(BusinessLogicExecutor executor) {
-            return executor.executeCondition(mMethodName,
-                    mMethodArgs.toArray(new String[mMethodArgs.size()]));
+            // XOR the negated boolean with the return value of the method
+            return (mNegated != executor.executeCondition(mMethodName,
+                    mMethodArgs.toArray(new String[mMethodArgs.size()])));
         }
     }
 
diff --git a/common/util/src/com/android/compatibility/common/util/BusinessLogicFactory.java b/common/util/src/com/android/compatibility/common/util/BusinessLogicFactory.java
index 7d84516..b972ca5 100644
--- a/common/util/src/com/android/compatibility/common/util/BusinessLogicFactory.java
+++ b/common/util/src/com/android/compatibility/common/util/BusinessLogicFactory.java
@@ -117,13 +117,18 @@
         for (int i = 0; i < ruleConditionsJSONArray.length(); i++) {
             JSONObject ruleConditionJSONObject = ruleConditionsJSONArray.getJSONObject(i);
             String methodName = ruleConditionJSONObject.getString(METHOD_NAME);
+            boolean negated = false;
+            if (methodName.startsWith("!")) {
+                methodName = methodName.substring(1); // remove negation from method name string
+                negated = true; // change "negated" property to true
+            }
             // Each condition requires at least one arg, line below throws JSONException if not
             JSONArray methodArgsJSONArray = ruleConditionJSONObject.getJSONArray(METHOD_ARGS);
             List<String> methodArgs = new ArrayList<>();
             for (int j = 0; j < methodArgsJSONArray.length(); j++) {
                 methodArgs.add(methodArgsJSONArray.getString(j));
             }
-            ruleConditions.add(new BusinessLogicRuleCondition(methodName, methodArgs));
+            ruleConditions.add(new BusinessLogicRuleCondition(methodName, methodArgs, negated));
         }
         return ruleConditions;
     }
diff --git a/common/util/tests/src/com/android/compatibility/common/util/BusinessLogicTest.java b/common/util/tests/src/com/android/compatibility/common/util/BusinessLogicTest.java
index 47ce5da..99b5239 100644
--- a/common/util/tests/src/com/android/compatibility/common/util/BusinessLogicTest.java
+++ b/common/util/tests/src/com/android/compatibility/common/util/BusinessLogicTest.java
@@ -17,6 +17,8 @@
 package com.android.compatibility.common.util;
 
 import static junit.framework.Assert.assertEquals;
+import static junit.framework.Assert.assertFalse;
+import static junit.framework.Assert.assertTrue;
 
 import org.junit.Test;
 import org.junit.runner.RunWith;
@@ -97,7 +99,7 @@
             "              ]\n" +
             "            },\n" +
             "            {\n" +
-            "              \"methodName\": \"conditionMethodName2\",\n" +
+            "              \"methodName\": \"!conditionMethodName2\",\n" + // use negation
             "              \"methodArgs\": [\n" +
             "                \"arg2\"\n" +
             "              ]\n" +
@@ -139,6 +141,8 @@
             BusinessLogicRuleCondition rule1Condition = rule1Conditions.get(0);
             assertEquals("Wrong method name for business logic rule condition",
                     "conditionMethodName1", rule1Condition.mMethodName);
+            assertFalse("Wrong negation value for business logic rule condition",
+                    rule1Condition.mNegated);
             assertEquals("Wrong arg string count for business logic rule condition", 1,
                     rule1Condition.mMethodArgs.size());
             assertEquals("Wrong arg for business logic rule condition", "arg1",
@@ -163,6 +167,8 @@
             BusinessLogicRuleCondition rule2Condition = rule2Conditions.get(0);
             assertEquals("Wrong method name for business logic rule condition",
                     "conditionMethodName1", rule2Condition.mMethodName);
+            assertFalse("Wrong negation value for business logic rule condition",
+                    rule2Condition.mNegated);
             assertEquals("Wrong arg string count for business logic rule condition", 1,
                     rule2Condition.mMethodArgs.size());
             assertEquals("Wrong arg for business logic rule condition", "arg1",
@@ -184,6 +190,8 @@
             BusinessLogicRuleCondition rule3Condition1 = rule3Conditions.get(0);
             assertEquals("Wrong method name for business logic rule condition",
                     "conditionMethodName1", rule3Condition1.mMethodName);
+            assertFalse("Wrong negation value for business logic rule condition",
+                    rule3Condition1.mNegated);
             assertEquals("Wrong arg string count for business logic rule condition", 1,
                     rule3Condition1.mMethodArgs.size());
             assertEquals("Wrong arg for business logic rule condition", "arg1",
@@ -191,6 +199,8 @@
             BusinessLogicRuleCondition rule3Condition2 = rule3Conditions.get(1);
             assertEquals("Wrong method name for business logic rule condition",
                     "conditionMethodName2", rule3Condition2.mMethodName);
+            assertTrue("Wrong negation value for business logic rule condition",
+                    rule3Condition2.mNegated);
             assertEquals("Wrong arg string count for business logic rule condition", 1,
                     rule3Condition2.mMethodArgs.size());
             assertEquals("Wrong arg for business logic rule condition", "arg2",