Implement get supported values for FakeVehicleHardware.

Use the test property: VENDOR_EXTENSION_INT_PROPERTY as an example
to show a basic implementation for getMinMaxSupportedValues and
getSupportedValuesLists.

This CL also updates json config parser to parse HasSupportedValueInfo
field.

Flag: EXEMPT HAL
Bug: 382563296
Test: atest JsonConfigLoaderUnitTest FakeVehicleHardwareTest
Manual test in KS.

Change-Id: I346a809f6b307ec1b957172aa41176aeaa4bc5f1
diff --git a/automotive/vehicle/aidl/impl/current/default_config/JsonConfigLoader/src/JsonConfigLoader.cpp b/automotive/vehicle/aidl/impl/current/default_config/JsonConfigLoader/src/JsonConfigLoader.cpp
index 7a1f0e0..f910beb 100644
--- a/automotive/vehicle/aidl/impl/current/default_config/JsonConfigLoader/src/JsonConfigLoader.cpp
+++ b/automotive/vehicle/aidl/impl/current/default_config/JsonConfigLoader/src/JsonConfigLoader.cpp
@@ -58,6 +58,7 @@
 using ::aidl::android::hardware::automotive::vehicle::GsrComplianceRequirementType;
 using ::aidl::android::hardware::automotive::vehicle::HandsOnDetectionDriverState;
 using ::aidl::android::hardware::automotive::vehicle::HandsOnDetectionWarning;
+using ::aidl::android::hardware::automotive::vehicle::HasSupportedValueInfo;
 using ::aidl::android::hardware::automotive::vehicle::ImpactSensorLocation;
 using ::aidl::android::hardware::automotive::vehicle::LaneCenteringAssistCommand;
 using ::aidl::android::hardware::automotive::vehicle::LaneCenteringAssistState;
@@ -600,6 +601,22 @@
         if (!supportedEnumValues.empty()) {
             areaConfig.supportedEnumValues = std::move(supportedEnumValues);
         }
+
+        if (jsonAreaConfig.isMember("hasSupportedValueInfo")) {
+            HasSupportedValueInfo hasSupportedValueInfo = HasSupportedValueInfo{};
+            const Json::Value& jsonHasSupportedValueInfo = jsonAreaConfig["hasSupportedValueInfo"];
+            tryParseJsonValueToVariable(jsonHasSupportedValueInfo, "hasMinSupportedValue",
+                                        /*optional=*/true,
+                                        &hasSupportedValueInfo.hasMinSupportedValue, errors);
+            tryParseJsonValueToVariable(jsonHasSupportedValueInfo, "hasMaxSupportedValue",
+                                        /*optional=*/true,
+                                        &hasSupportedValueInfo.hasMaxSupportedValue, errors);
+            tryParseJsonValueToVariable(jsonHasSupportedValueInfo, "hasSupportedValuesList",
+                                        /*optional=*/true,
+                                        &hasSupportedValueInfo.hasSupportedValuesList, errors);
+            areaConfig.hasSupportedValueInfo = std::move(hasSupportedValueInfo);
+        }
+
         config->config.areaConfigs.push_back(std::move(areaConfig));
 
         RawPropValues areaValue = {};
diff --git a/automotive/vehicle/aidl/impl/current/default_config/JsonConfigLoader/test/JsonConfigLoaderUnitTest.cpp b/automotive/vehicle/aidl/impl/current/default_config/JsonConfigLoader/test/JsonConfigLoaderUnitTest.cpp
index 54afbd4..595c2ed 100644
--- a/automotive/vehicle/aidl/impl/current/default_config/JsonConfigLoader/test/JsonConfigLoaderUnitTest.cpp
+++ b/automotive/vehicle/aidl/impl/current/default_config/JsonConfigLoader/test/JsonConfigLoaderUnitTest.cpp
@@ -26,6 +26,7 @@
 namespace automotive {
 namespace vehicle {
 
+using ::aidl::android::hardware::automotive::vehicle::HasSupportedValueInfo;
 using ::aidl::android::hardware::automotive::vehicle::RawPropValues;
 using ::aidl::android::hardware::automotive::vehicle::VehicleAreaConfig;
 using ::aidl::android::hardware::automotive::vehicle::VehiclePropConfig;
@@ -803,6 +804,108 @@
     ASSERT_EQ(areaConfig2.areaId, 1);
 }
 
+TEST_F(JsonConfigLoaderUnitTest, testHasSupportedValueInfo_allTrue) {
+    std::istringstream iss(R"(
+    {
+        "properties": [{
+            "property": "VehicleProperty::CABIN_LIGHTS_SWITCH",
+            "areas": [{
+                "access": "VehiclePropertyAccess::WRITE",
+                "areaId": 0,
+                "hasSupportedValueInfo": {
+                    "hasMinSupportedValue": true,
+                    "hasMaxSupportedValue": true,
+                    "hasSupportedValuesList": true
+                }
+            }],
+            "access": "VehiclePropertyAccess::READ",
+        }]
+    }
+    )");
+
+    auto result = mLoader.loadPropConfig(iss);
+    ASSERT_TRUE(result.ok());
+
+    auto configs = result.value();
+    ASSERT_EQ(configs.size(), 1u);
+
+    const VehiclePropConfig& config = configs.begin()->second.config;
+    ASSERT_EQ(config.access, VehiclePropertyAccess::READ);
+    ASSERT_EQ(config.areaConfigs.size(), 1u);
+
+    const VehicleAreaConfig& areaConfig = config.areaConfigs[0];
+    ASSERT_EQ(areaConfig.hasSupportedValueInfo, HasSupportedValueInfo({
+                                                        .hasMinSupportedValue = true,
+                                                        .hasMaxSupportedValue = true,
+                                                        .hasSupportedValuesList = true,
+                                                }));
+}
+
+TEST_F(JsonConfigLoaderUnitTest, testHasSupportedValueInfo_allFalse) {
+    std::istringstream iss(R"(
+    {
+        "properties": [{
+            "property": "VehicleProperty::CABIN_LIGHTS_SWITCH",
+            "areas": [{
+                "access": "VehiclePropertyAccess::WRITE",
+                "areaId": 0,
+                "hasSupportedValueInfo": {
+                    "hasMinSupportedValue": false,
+                    "hasMaxSupportedValue": false,
+                    "hasSupportedValuesList": false
+                }
+            }],
+            "access": "VehiclePropertyAccess::READ",
+        }]
+    }
+    )");
+
+    auto result = mLoader.loadPropConfig(iss);
+    ASSERT_TRUE(result.ok());
+
+    auto configs = result.value();
+    ASSERT_EQ(configs.size(), 1u);
+
+    const VehiclePropConfig& config = configs.begin()->second.config;
+    ASSERT_EQ(config.access, VehiclePropertyAccess::READ);
+    ASSERT_EQ(config.areaConfigs.size(), 1u);
+
+    const VehicleAreaConfig& areaConfig = config.areaConfigs[0];
+    ASSERT_EQ(areaConfig.hasSupportedValueInfo, HasSupportedValueInfo({
+                                                        .hasMinSupportedValue = false,
+                                                        .hasMaxSupportedValue = false,
+                                                        .hasSupportedValuesList = false,
+                                                }));
+}
+
+TEST_F(JsonConfigLoaderUnitTest, testHasSupportedValueInfo_unspecified) {
+    std::istringstream iss(R"(
+    {
+        "properties": [{
+            "property": "VehicleProperty::CABIN_LIGHTS_SWITCH",
+            "areas": [{
+                "access": "VehiclePropertyAccess::WRITE",
+                "areaId": 0
+            }],
+            "access": "VehiclePropertyAccess::READ",
+        }]
+    }
+    )");
+
+    auto result = mLoader.loadPropConfig(iss);
+    ASSERT_TRUE(result.ok());
+
+    auto configs = result.value();
+    ASSERT_EQ(configs.size(), 1u);
+
+    const VehiclePropConfig& config = configs.begin()->second.config;
+    ASSERT_EQ(config.access, VehiclePropertyAccess::READ);
+    ASSERT_EQ(config.areaConfigs.size(), 1u);
+
+    const VehicleAreaConfig& areaConfig = config.areaConfigs[0];
+    ASSERT_EQ(areaConfig.hasSupportedValueInfo, std::nullopt);
+}
+
 }  // namespace vehicle
 }  // namespace automotive
 }  // namespace hardware
diff --git a/automotive/vehicle/aidl/impl/current/default_config/config/TestProperties.json b/automotive/vehicle/aidl/impl/current/default_config/config/TestProperties.json
index 73e4d44..83debf7 100644
--- a/automotive/vehicle/aidl/impl/current/default_config/config/TestProperties.json
+++ b/automotive/vehicle/aidl/impl/current/default_config/config/TestProperties.json
@@ -99,12 +99,15 @@
                 {
                     "defaultValue": {
                         "int32Values": [
-                            1
+                            2
                         ]
                     },
                     "areaId": "VehicleAreaWindow::FRONT_WINDSHIELD",
-                    "minInt32Value": -100,
-                    "maxInt32Value": 100
+                    "hasSupportedValueInfo": {
+                        "hasMinSupportedValue": true,
+                        "hasMaxSupportedValue": true,
+                        "hasSupportedValuesList": true
+                    }
                 },
                 {
                     "defaultValue": {
diff --git a/automotive/vehicle/aidl/impl/current/fake_impl/hardware/include/FakeVehicleHardware.h b/automotive/vehicle/aidl/impl/current/fake_impl/hardware/include/FakeVehicleHardware.h
index 5916307..b7ada62 100644
--- a/automotive/vehicle/aidl/impl/current/fake_impl/hardware/include/FakeVehicleHardware.h
+++ b/automotive/vehicle/aidl/impl/current/fake_impl/hardware/include/FakeVehicleHardware.h
@@ -108,6 +108,12 @@
     aidl::android::hardware::automotive::vehicle::StatusCode unsubscribe(int32_t propId,
                                                                          int32_t areaId) override;
 
+    std::vector<aidlvhal::MinMaxSupportedValueResult> getMinMaxSupportedValues(
+            const std::vector<PropIdAreaId>& propIdAreaIds) override;
+
+    std::vector<aidlvhal::SupportedValuesListResult> getSupportedValuesLists(
+            const std::vector<PropIdAreaId>& propIdAreaIds) override;
+
   protected:
     // mValuePool is also used in mServerSidePropStore.
     const std::shared_ptr<VehiclePropValuePool> mValuePool;
diff --git a/automotive/vehicle/aidl/impl/current/fake_impl/hardware/src/FakeVehicleHardware.cpp b/automotive/vehicle/aidl/impl/current/fake_impl/hardware/src/FakeVehicleHardware.cpp
index 52daf68..f1aaefc 100644
--- a/automotive/vehicle/aidl/impl/current/fake_impl/hardware/src/FakeVehicleHardware.cpp
+++ b/automotive/vehicle/aidl/impl/current/fake_impl/hardware/src/FakeVehicleHardware.cpp
@@ -62,11 +62,13 @@
 using ::aidl::android::hardware::automotive::vehicle::ErrorState;
 using ::aidl::android::hardware::automotive::vehicle::GetValueRequest;
 using ::aidl::android::hardware::automotive::vehicle::GetValueResult;
+using ::aidl::android::hardware::automotive::vehicle::MinMaxSupportedValueResult;
 using ::aidl::android::hardware::automotive::vehicle::RawPropValues;
 using ::aidl::android::hardware::automotive::vehicle::SetValueRequest;
 using ::aidl::android::hardware::automotive::vehicle::SetValueResult;
 using ::aidl::android::hardware::automotive::vehicle::StatusCode;
 using ::aidl::android::hardware::automotive::vehicle::SubscribeOptions;
+using ::aidl::android::hardware::automotive::vehicle::SupportedValuesListResult;
 using ::aidl::android::hardware::automotive::vehicle::toString;
 using ::aidl::android::hardware::automotive::vehicle::VehicleApPowerStateReport;
 using ::aidl::android::hardware::automotive::vehicle::VehicleApPowerStateReq;
@@ -2299,6 +2301,62 @@
     return StatusCode::OK;
 }
 
+std::vector<MinMaxSupportedValueResult> FakeVehicleHardware::getMinMaxSupportedValues(
+        const std::vector<PropIdAreaId>& propIdAreaIds) {
+    std::vector<MinMaxSupportedValueResult> results;
+    // We only support VENDOR_EXTENSION_INT_PROPERTY
+    for (const auto& propIdAreaId : propIdAreaIds) {
+        int propId = propIdAreaId.propId;
+        int areaId = propIdAreaId.areaId;
+        if (propId != toInt(TestVendorProperty::VENDOR_EXTENSION_INT_PROPERTY)) {
+            results.push_back(MinMaxSupportedValueResult{
+                    .status = StatusCode::INVALID_ARG,
+            });
+            continue;
+        }
+        results.push_back(MinMaxSupportedValueResult{
+                .status = StatusCode::OK,
+                .minSupportedValue =
+                        RawPropValues{
+                                .int32Values = {0},
+                        },
+                .maxSupportedValue =
+                        RawPropValues{
+                                .int32Values = {10},
+                        },
+        });
+    }
+    return results;
+}
+
+std::vector<SupportedValuesListResult> FakeVehicleHardware::getSupportedValuesLists(
+        const std::vector<PropIdAreaId>& propIdAreaIds) {
+    std::vector<SupportedValuesListResult> results;
+    // We only support VENDOR_EXTENSION_INT_PROPERTY
+    for (const auto& propIdAreaId : propIdAreaIds) {
+        int propId = propIdAreaId.propId;
+        int areaId = propIdAreaId.areaId;
+        if (propId != toInt(TestVendorProperty::VENDOR_EXTENSION_INT_PROPERTY)) {
+            results.push_back(SupportedValuesListResult{
+                    .status = StatusCode::INVALID_ARG,
+            });
+            continue;
+        }
+        results.push_back(SupportedValuesListResult{
+                .status = StatusCode::OK,
+                .supportedValuesList = std::vector<std::optional<RawPropValues>>({
+                        RawPropValues{.int32Values = {0}},
+                        RawPropValues{.int32Values = {2}},
+                        RawPropValues{.int32Values = {4}},
+                        RawPropValues{.int32Values = {6}},
+                        RawPropValues{.int32Values = {8}},
+                        RawPropValues{.int32Values = {10}},
+                }),
+        });
+    }
+    return results;
+}
+
 bool FakeVehicleHardware::isVariableUpdateRateSupported(const VehiclePropConfig& vehiclePropConfig,
                                                         int32_t areaId) {
     for (size_t i = 0; i < vehiclePropConfig.areaConfigs.size(); i++) {
diff --git a/automotive/vehicle/aidl/impl/current/fake_impl/hardware/test/FakeVehicleHardwareTest.cpp b/automotive/vehicle/aidl/impl/current/fake_impl/hardware/test/FakeVehicleHardwareTest.cpp
index f6098ca..29a690b 100644
--- a/automotive/vehicle/aidl/impl/current/fake_impl/hardware/test/FakeVehicleHardwareTest.cpp
+++ b/automotive/vehicle/aidl/impl/current/fake_impl/hardware/test/FakeVehicleHardwareTest.cpp
@@ -3884,6 +3884,44 @@
     }
 }
 
+TEST_F(FakeVehicleHardwareTest, testGetMinMaxSupportedValues) {
+    auto results = getHardware()->getMinMaxSupportedValues({
+            PropIdAreaId{.propId = toInt(TestVendorProperty::VENDOR_EXTENSION_INT_PROPERTY),
+                         .areaId = 0},
+            PropIdAreaId{.propId = toInt(VehicleProperty::HVAC_TEMPERATURE_SET), .areaId = 0},
+    });
+
+    ASSERT_EQ(results.size(), 2u);
+    EXPECT_EQ(results[0].status, StatusCode::OK);
+    EXPECT_NE(results[0].minSupportedValue, std::nullopt);
+    EXPECT_EQ(results[0].minSupportedValue.value(), RawPropValues{.int32Values = {0}});
+    EXPECT_NE(results[0].maxSupportedValue, std::nullopt);
+    EXPECT_EQ(results[0].maxSupportedValue.value(), RawPropValues{.int32Values = {10}});
+    EXPECT_EQ(results[1].status, StatusCode::INVALID_ARG);
+}
+
+TEST_F(FakeVehicleHardwareTest, testGetSupportedValuesLists) {
+    auto results = getHardware()->getSupportedValuesLists({
+            PropIdAreaId{.propId = toInt(TestVendorProperty::VENDOR_EXTENSION_INT_PROPERTY),
+                         .areaId = 0},
+            PropIdAreaId{.propId = toInt(VehicleProperty::HVAC_TEMPERATURE_SET), .areaId = 0},
+    });
+
+    ASSERT_EQ(results.size(), 2u);
+    EXPECT_EQ(results[0].status, StatusCode::OK);
+    EXPECT_NE(results[0].supportedValuesList, std::nullopt);
+    EXPECT_NE((results[0].supportedValuesList)->size(), 0u);
+    EXPECT_EQ(results[0].supportedValuesList.value(), std::vector<std::optional<RawPropValues>>({
+                                                              RawPropValues{.int32Values = {0}},
+                                                              RawPropValues{.int32Values = {2}},
+                                                              RawPropValues{.int32Values = {4}},
+                                                              RawPropValues{.int32Values = {6}},
+                                                              RawPropValues{.int32Values = {8}},
+                                                              RawPropValues{.int32Values = {10}},
+                                                      }));
+    EXPECT_EQ(results[1].status, StatusCode::INVALID_ARG);
+}
+
 }  // namespace fake
 }  // namespace vehicle
 }  // namespace automotive