Add area config parsing.

Add area config parsing to JsonConfigLoader.

Test: atest JsonConfigLoaderUnitTestEnableTestProperties
atest VehicleHalDefaultConfigTestEnableTestProperties
Bug: 238685398

Change-Id: I22c1b54fb5463b6c747645293ed47c5799d5f262
diff --git a/automotive/vehicle/aidl/android/hardware/automotive/vehicle/VehicleProperty.aidl b/automotive/vehicle/aidl/android/hardware/automotive/vehicle/VehicleProperty.aidl
index e8a6c85..1cf8aff 100644
--- a/automotive/vehicle/aidl/android/hardware/automotive/vehicle/VehicleProperty.aidl
+++ b/automotive/vehicle/aidl/android/hardware/automotive/vehicle/VehicleProperty.aidl
@@ -542,7 +542,7 @@
      */
     TRACTION_CONTROL_ACTIVE = 0x040B + 0x10000000 + 0x01000000
             + 0x00200000, // VehiclePropertyGroup:SYSTEM,VehicleArea:GLOBAL,VehiclePropertyType:BOOLEAN
-    /*
+    /**
      * HVAC Properties
      *
      * Additional rules for mapping a zoned HVAC property (except
diff --git a/automotive/vehicle/aidl/impl/default_config/JsonConfigLoader/include/JsonConfigLoader.h b/automotive/vehicle/aidl/impl/default_config/JsonConfigLoader/include/JsonConfigLoader.h
index 225fe32..fd73a26 100644
--- a/automotive/vehicle/aidl/impl/default_config/JsonConfigLoader/include/JsonConfigLoader.h
+++ b/automotive/vehicle/aidl/impl/default_config/JsonConfigLoader/include/JsonConfigLoader.h
@@ -137,9 +137,15 @@
             T* outPtr, std::vector<std::string>* errors);
 
     // Parses a JSON field to RawPropValues.
-    void parsePropValues(const Json::Value& parentJsonNode, const std::string& fieldName,
+    //
+    // @return True if the field exist and can be parsed to a RawPropValues.
+    bool parsePropValues(const Json::Value& parentJsonNode, const std::string& fieldName,
                          aidl::android::hardware::automotive::vehicle::RawPropValues* outPtr,
                          std::vector<std::string>* errors);
+
+    // Prase a JSON field as an array of area configs.
+    void parseAreas(const Json::Value& parentJsonNode, const std::string& fieldName,
+                    ConfigDeclaration* outPtr, std::vector<std::string>* errors);
 };
 
 }  // namespace jsonconfigloader_impl
diff --git a/automotive/vehicle/aidl/impl/default_config/JsonConfigLoader/src/JsonConfigLoader.cpp b/automotive/vehicle/aidl/impl/default_config/JsonConfigLoader/src/JsonConfigLoader.cpp
index c8bbfae..392d540 100644
--- a/automotive/vehicle/aidl/impl/default_config/JsonConfigLoader/src/JsonConfigLoader.cpp
+++ b/automotive/vehicle/aidl/impl/default_config/JsonConfigLoader/src/JsonConfigLoader.cpp
@@ -398,26 +398,73 @@
     return;
 }
 
-void JsonConfigParser::parsePropValues(const Json::Value& parentJsonNode,
+bool JsonConfigParser::parsePropValues(const Json::Value& parentJsonNode,
                                        const std::string& fieldName, RawPropValues* outPtr,
                                        std::vector<std::string>* errors) {
     if (!parentJsonNode.isObject()) {
         errors->push_back("Node: " + parentJsonNode.toStyledString() + " is not an object");
+        return false;
+    }
+    if (!parentJsonNode.isMember(fieldName)) {
+        return false;
+    }
+    const Json::Value& jsonValue = parentJsonNode[fieldName];
+    bool success = true;
+    success &= tryParseJsonArrayToVariable(jsonValue, "int32Values",
+                                           /*optional=*/true, &(outPtr->int32Values), errors);
+    success &= tryParseJsonArrayToVariable(jsonValue, "floatValues",
+                                           /*optional=*/true, &(outPtr->floatValues), errors);
+    success &= tryParseJsonArrayToVariable(jsonValue, "int64Values",
+                                           /*optional=*/true, &(outPtr->int64Values), errors);
+    // We don't support "byteValues" yet.
+    success &= tryParseJsonValueToVariable(jsonValue, "stringValue",
+                                           /*optional=*/true, &(outPtr->stringValue), errors);
+    return success;
+}
+
+void JsonConfigParser::parseAreas(const Json::Value& parentJsonNode, const std::string& fieldName,
+                                  ConfigDeclaration* config, std::vector<std::string>* errors) {
+    if (!parentJsonNode.isObject()) {
+        errors->push_back("Node: " + parentJsonNode.toStyledString() + " is not an object");
         return;
     }
     if (!parentJsonNode.isMember(fieldName)) {
         return;
     }
     const Json::Value& jsonValue = parentJsonNode[fieldName];
-    tryParseJsonArrayToVariable(jsonValue, "int32Values", /*optional=*/true, &(outPtr->int32Values),
-                                errors);
-    tryParseJsonArrayToVariable(jsonValue, "floatValues", /*optional=*/true, &(outPtr->floatValues),
-                                errors);
-    tryParseJsonArrayToVariable(jsonValue, "int64Values", /*optional=*/true, &(outPtr->int64Values),
-                                errors);
-    // We don't support "byteValues" yet.
-    tryParseJsonValueToVariable(jsonValue, "stringValue", /*optional=*/true, &(outPtr->stringValue),
-                                errors);
+
+    if (!jsonValue.isArray()) {
+        errors->push_back("Field: " + fieldName + " is not an array");
+        return;
+    }
+    for (unsigned int i = 0; i < jsonValue.size(); i++) {
+        int32_t areaId;
+        const Json::Value& jsonAreaConfig = jsonValue[i];
+        if (!tryParseJsonValueToVariable(jsonAreaConfig, "areaId",
+                                         /*optional=*/false, &areaId, errors)) {
+            continue;
+        }
+        VehicleAreaConfig areaConfig = {};
+        areaConfig.areaId = areaId;
+        tryParseJsonValueToVariable(jsonAreaConfig, "minInt32Value", /*optional=*/true,
+                                    &areaConfig.minInt32Value, errors);
+        tryParseJsonValueToVariable(jsonAreaConfig, "maxInt32Value", /*optional=*/true,
+                                    &areaConfig.maxInt32Value, errors);
+        tryParseJsonValueToVariable(jsonAreaConfig, "minInt64Value", /*optional=*/true,
+                                    &areaConfig.minInt64Value, errors);
+        tryParseJsonValueToVariable(jsonAreaConfig, "maxInt64Value", /*optional=*/true,
+                                    &areaConfig.maxInt64Value, errors);
+        tryParseJsonValueToVariable(jsonAreaConfig, "minFloatValue", /*optional=*/true,
+                                    &areaConfig.minFloatValue, errors);
+        tryParseJsonValueToVariable(jsonAreaConfig, "maxFloatValue", /*optional=*/true,
+                                    &areaConfig.maxFloatValue, errors);
+        config->config.areaConfigs.push_back(std::move(areaConfig));
+
+        RawPropValues areaValue = {};
+        if (parsePropValues(jsonAreaConfig, "defaultValue", &areaValue, errors)) {
+            config->initialAreaValues[areaId] = std::move(areaValue);
+        }
+    }
 }
 
 std::optional<ConfigDeclaration> JsonConfigParser::parseEachProperty(
@@ -446,8 +493,7 @@
     tryParseJsonArrayToVariable(propJsonValue, "configArray", /*optional=*/true,
                                 &configDecl.config.configArray, errors);
 
-    parsePropValues(propJsonValue, "defaultValue", /*optional=*/true, &configDecl.initialValue,
-                    errors);
+    parsePropValues(propJsonValue, "defaultValue", &configDecl.initialValue, errors);
 
     tryParseJsonValueToVariable(propJsonValue, "minSampleRate", /*optional=*/true,
                                 &configDecl.config.minSampleRate, errors);
@@ -455,7 +501,7 @@
     tryParseJsonValueToVariable(propJsonValue, "maxSampleRate", /*optional=*/true,
                                 &configDecl.config.maxSampleRate, errors);
 
-    // TODO(b/238685398): AreaConfigs
+    parseAreas(propJsonValue, "areas", &configDecl, errors);
 
     if (errors->size() != initialErrorCount) {
         return std::nullopt;
diff --git a/automotive/vehicle/aidl/impl/default_config/JsonConfigLoader/test/JsonConfigLoaderUnitTest.cpp b/automotive/vehicle/aidl/impl/default_config/JsonConfigLoader/test/JsonConfigLoaderUnitTest.cpp
index 469e7d6..cff70d9 100644
--- a/automotive/vehicle/aidl/impl/default_config/JsonConfigLoader/test/JsonConfigLoaderUnitTest.cpp
+++ b/automotive/vehicle/aidl/impl/default_config/JsonConfigLoader/test/JsonConfigLoaderUnitTest.cpp
@@ -27,6 +27,7 @@
 namespace vehicle {
 
 using ::aidl::android::hardware::automotive::vehicle::RawPropValues;
+using ::aidl::android::hardware::automotive::vehicle::VehicleAreaConfig;
 using ::aidl::android::hardware::automotive::vehicle::VehiclePropConfig;
 using ::aidl::android::hardware::automotive::vehicle::VehicleProperty;
 using ::aidl::android::hardware::automotive::vehicle::VehiclePropertyAccess;
@@ -108,7 +109,7 @@
     }
     )");
 
-    ASSERT_FALSE(mLoader.loadPropConfig(iss);.ok()) << "Invalid JSON format must cause error";
+    ASSERT_FALSE(mLoader.loadPropConfig(iss).ok()) << "Invalid JSON format must cause error";
 }
 
 TEST_F(JsonConfigLoaderUnitTest, TestConfigArray) {
@@ -490,9 +491,9 @@
     {
         "properties": [{
             "property": "VehicleProperty::INFO_FUEL_CAPACITY",
-            "defaultValue": [{
+            "defaultValue": {
                 "int32Values": [1.1]
-            }]
+            }
         }]
     }
     )");
@@ -501,6 +502,90 @@
             << "Wrong type for DefaultValue must cause error";
 }
 
+TEST_F(JsonConfigLoaderUnitTest, testAreas_Simple) {
+    std::istringstream iss(R"(
+    {
+        "properties": [{
+            "property": "VehicleProperty::INFO_FUEL_CAPACITY",
+            "areas": [{
+                "areaId": "Constants::HVAC_ALL",
+                "minInt32Value": 1,
+                "maxInt32Value": 7
+            }]
+        }]
+    }
+    )");
+
+    auto result = mLoader.loadPropConfig(iss);
+
+    auto configs = result.value();
+    ASSERT_EQ(configs.size(), 1u);
+
+    const VehiclePropConfig& config = configs[0].config;
+    ASSERT_EQ(config.areaConfigs.size(), 1u);
+    const VehicleAreaConfig& areaConfig = config.areaConfigs[0];
+    ASSERT_EQ(areaConfig.minInt32Value, 1);
+    ASSERT_EQ(areaConfig.maxInt32Value, 7);
+    ASSERT_EQ(areaConfig.areaId, HVAC_ALL);
+}
+
+TEST_F(JsonConfigLoaderUnitTest, testAreas_DefaultValueForEachArea) {
+    std::istringstream iss(R"(
+    {
+        "properties": [{
+            "property": "VehicleProperty::INFO_FUEL_CAPACITY",
+            "areas": [{
+                "areaId": "Constants::HVAC_LEFT",
+                "defaultValue": {
+                    "int32Values": [1]
+                }
+            }, {
+                "areaId": "Constants::HVAC_RIGHT",
+                "defaultValue": {
+                    "int32Values": [2]
+                }
+            }]
+        }]
+    }
+    )");
+
+    auto result = mLoader.loadPropConfig(iss);
+
+    auto configs = result.value();
+    ASSERT_EQ(configs.size(), 1u);
+
+    const VehiclePropConfig& config = configs[0].config;
+    ASSERT_EQ(config.areaConfigs.size(), 2u);
+    ASSERT_EQ(config.areaConfigs[0].areaId, HVAC_LEFT);
+    ASSERT_EQ(config.areaConfigs[1].areaId, HVAC_RIGHT);
+    ASSERT_EQ(configs[0].initialAreaValues[HVAC_LEFT], RawPropValues{.int32Values = {1}});
+    ASSERT_EQ(configs[0].initialAreaValues[HVAC_RIGHT], RawPropValues{.int32Values = {2}});
+}
+
+TEST_F(JsonConfigLoaderUnitTest, testAreas_FailInvalidTypeForOneAreaValue) {
+    std::istringstream iss(R"(
+    {
+        "properties": [{
+            "property": "VehicleProperty::INFO_FUEL_CAPACITY",
+            "areas": [{
+                "areaId": "Constants::HVAC_LEFT",
+                "defaultValue": {
+                    "int32Values": [1]
+                }
+            }, {
+                "areaId": "Constants::HVAC_RIGHT",
+                "defaultValue": {
+                    "int32Values": [2.1]
+                }
+            }]
+        }]
+    }
+    )");
+
+    ASSERT_FALSE(mLoader.loadPropConfig(iss).ok())
+            << "Wrong type for DefaultValue for one area must cause error";
+}
+
 }  // namespace vehicle
 }  // namespace automotive
 }  // namespace hardware
diff --git a/automotive/vehicle/aidl/impl/default_config/test/DefaultConfigTest.cpp b/automotive/vehicle/aidl/impl/default_config/test/DefaultConfigTest.cpp
index ba1100f..b16ea14 100644
--- a/automotive/vehicle/aidl/impl/default_config/test/DefaultConfigTest.cpp
+++ b/automotive/vehicle/aidl/impl/default_config/test/DefaultConfigTest.cpp
@@ -93,8 +93,7 @@
     }
 
     ASSERT_EQ(configsFromHeaderFile.size(), configsFromJson.size());
-    // TODO(b/238685398): Uncomment this once we finish the parser.
-    // ASSERT_THAT(configsFromHeaderFile, UnorderedElementsAreArray(configsFromJson));
+    ASSERT_THAT(configsFromHeaderFile, UnorderedElementsAreArray(configsFromJson));
 }
 
 #endif  // ENABLE_VEHICLE_HAL_TEST_PROPERTIES