Add logic to handle special set values.

Test: atest FakeVehicleHardwareTest
Bug: 201830716
Change-Id: Ibecae5f917148d42a806c2a76faec4eac6d9ec7c
diff --git a/automotive/vehicle/aidl/impl/fake_impl/hardware/Android.bp b/automotive/vehicle/aidl/impl/fake_impl/hardware/Android.bp
index 29dec74..210f316 100644
--- a/automotive/vehicle/aidl/impl/fake_impl/hardware/Android.bp
+++ b/automotive/vehicle/aidl/impl/fake_impl/hardware/Android.bp
@@ -22,6 +22,7 @@
     name: "FakeVehicleHardware",
     vendor: true,
     srcs: ["src/*.cpp"],
+    cflags: ["-DENABLE_VENDOR_CLUSTER_PROPERTY_FOR_TESTING"],
     local_include_dirs: ["include"],
     export_include_dirs: ["include"],
     defaults: ["VehicleHalDefaults"],
diff --git a/automotive/vehicle/aidl/impl/fake_impl/hardware/include/FakeVehicleHardware.h b/automotive/vehicle/aidl/impl/fake_impl/hardware/include/FakeVehicleHardware.h
index ead8bb2..b2d813f 100644
--- a/automotive/vehicle/aidl/impl/fake_impl/hardware/include/FakeVehicleHardware.h
+++ b/automotive/vehicle/aidl/impl/fake_impl/hardware/include/FakeVehicleHardware.h
@@ -103,6 +103,14 @@
     void maybeOverrideProperties(const char* overrideDir);
     // Override the properties using config files in 'overrideDir'.
     void overrideProperties(const char* overrideDir);
+
+    ::aidl::android::hardware::automotive::vehicle::StatusCode maybeSetSpecialValue(
+            const ::aidl::android::hardware::automotive::vehicle::VehiclePropValue& value,
+            bool* isSpecialValue);
+    ::aidl::android::hardware::automotive::vehicle::StatusCode setApPowerStateReport(
+            const ::aidl::android::hardware::automotive::vehicle::VehiclePropValue& value);
+    VehiclePropValuePool::RecyclableType createApPowerStateReq(
+            ::aidl::android::hardware::automotive::vehicle::VehicleApPowerStateReq state);
 };
 
 }  // namespace fake
diff --git a/automotive/vehicle/aidl/impl/fake_impl/hardware/src/FakeVehicleHardware.cpp b/automotive/vehicle/aidl/impl/fake_impl/hardware/src/FakeVehicleHardware.cpp
index 684b2a7..94791da 100644
--- a/automotive/vehicle/aidl/impl/fake_impl/hardware/src/FakeVehicleHardware.cpp
+++ b/automotive/vehicle/aidl/impl/fake_impl/hardware/src/FakeVehicleHardware.cpp
@@ -44,8 +44,13 @@
 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::VehicleApPowerStateReport;
+using ::aidl::android::hardware::automotive::vehicle::VehicleApPowerStateReq;
 using ::aidl::android::hardware::automotive::vehicle::VehiclePropConfig;
+using ::aidl::android::hardware::automotive::vehicle::VehicleProperty;
+using ::aidl::android::hardware::automotive::vehicle::VehiclePropertyGroup;
 using ::aidl::android::hardware::automotive::vehicle::VehiclePropertyStatus;
+using ::aidl::android::hardware::automotive::vehicle::VehiclePropertyType;
 using ::aidl::android::hardware::automotive::vehicle::VehiclePropValue;
 
 const char* VENDOR_OVERRIDE_DIR = "/vendor/etc/automotive/vhaloverride/";
@@ -122,27 +127,160 @@
     return mServerSidePropStore->getAllConfigs();
 }
 
+VehiclePropValuePool::RecyclableType FakeVehicleHardware::createApPowerStateReq(
+        VehicleApPowerStateReq state) {
+    auto req = mValuePool->obtain(VehiclePropertyType::INT32_VEC, 2);
+    req->prop = toInt(VehicleProperty::AP_POWER_STATE_REQ);
+    req->areaId = 0;
+    req->timestamp = elapsedRealtimeNano();
+    req->status = VehiclePropertyStatus::AVAILABLE;
+    req->value.int32Values[0] = toInt(state);
+    // Param = 0.
+    req->value.int32Values[1] = 0;
+    return req;
+}
+
+StatusCode FakeVehicleHardware::setApPowerStateReport(const VehiclePropValue& value) {
+    auto updatedValue = mValuePool->obtain(value);
+    updatedValue->timestamp = elapsedRealtimeNano();
+
+    if (auto writeResult = mServerSidePropStore->writeValue(std::move(updatedValue));
+        !writeResult.ok()) {
+        ALOGE("failed to write value into property store, error: %s",
+              writeResult.error().message().c_str());
+        return StatusCode::INVALID_ARG;
+    }
+
+    VehiclePropValuePool::RecyclableType prop;
+    int32_t state = value.value.int32Values[0];
+    switch (state) {
+        case toInt(VehicleApPowerStateReport::DEEP_SLEEP_EXIT):
+            [[fallthrough]];
+        case toInt(VehicleApPowerStateReport::HIBERNATION_EXIT):
+            [[fallthrough]];
+        case toInt(VehicleApPowerStateReport::SHUTDOWN_CANCELLED):
+            [[fallthrough]];
+        case toInt(VehicleApPowerStateReport::WAIT_FOR_VHAL):
+            // CPMS is in WAIT_FOR_VHAL state, simply move to ON
+            // Send back to HAL
+            // ALWAYS update status for generated property value
+            prop = createApPowerStateReq(VehicleApPowerStateReq::ON);
+            if (auto writeResult =
+                        mServerSidePropStore->writeValue(std::move(prop), /*updateStatus=*/true);
+                !writeResult.ok()) {
+                ALOGE("failed to write AP_POWER_STATE_REQ into property store, error: %s",
+                      writeResult.error().message().c_str());
+                return StatusCode::INTERNAL_ERROR;
+            }
+            break;
+        case toInt(VehicleApPowerStateReport::DEEP_SLEEP_ENTRY):
+            [[fallthrough]];
+        case toInt(VehicleApPowerStateReport::HIBERNATION_ENTRY):
+            [[fallthrough]];
+        case toInt(VehicleApPowerStateReport::SHUTDOWN_START):
+            // CPMS is in WAIT_FOR_FINISH state, send the FINISHED command
+            // Send back to HAL
+            // ALWAYS update status for generated property value
+            prop = createApPowerStateReq(VehicleApPowerStateReq::FINISHED);
+            if (auto writeResult =
+                        mServerSidePropStore->writeValue(std::move(prop), /*updateStatus=*/true);
+                !writeResult.ok()) {
+                ALOGE("failed to write AP_POWER_STATE_REQ into property store, error: %s",
+                      writeResult.error().message().c_str());
+                return StatusCode::INTERNAL_ERROR;
+            }
+            break;
+        default:
+            ALOGE("Unknown VehicleApPowerStateReport: %d", state);
+            break;
+    }
+    return StatusCode::OK;
+}
+
+StatusCode FakeVehicleHardware::maybeSetSpecialValue(const VehiclePropValue& value,
+                                                     bool* isSpecialValue) {
+    *isSpecialValue = false;
+    VehiclePropValuePool::RecyclableType updatedValue;
+
+    switch (value.prop) {
+        case toInt(VehicleProperty::AP_POWER_STATE_REPORT):
+            *isSpecialValue = true;
+            return setApPowerStateReport(value);
+
+#ifdef ENABLE_VENDOR_CLUSTER_PROPERTY_FOR_TESTING
+        case toInt(VehicleProperty::CLUSTER_REPORT_STATE):
+            [[fallthrough]];
+        case toInt(VehicleProperty::CLUSTER_REQUEST_DISPLAY):
+            [[fallthrough]];
+        case toInt(VehicleProperty::CLUSTER_NAVIGATION_STATE):
+            [[fallthrough]];
+        case VENDOR_CLUSTER_SWITCH_UI:
+            [[fallthrough]];
+        case VENDOR_CLUSTER_DISPLAY_STATE:
+            *isSpecialValue = true;
+            updatedValue = mValuePool->obtain(getPropType(value.prop));
+            updatedValue->prop = value.prop & ~toInt(VehiclePropertyGroup::MASK);
+            if (getPropGroup(value.prop) == VehiclePropertyGroup::SYSTEM) {
+                updatedValue->prop |= toInt(VehiclePropertyGroup::VENDOR);
+            } else {
+                updatedValue->prop |= toInt(VehiclePropertyGroup::SYSTEM);
+            }
+            updatedValue->value = value.value;
+            updatedValue->timestamp = elapsedRealtimeNano();
+            updatedValue->areaId = value.areaId;
+            if (auto writeResult = mServerSidePropStore->writeValue(std::move(updatedValue));
+                !writeResult.ok()) {
+                ALOGE("failed to write value into property store, error: %s",
+                      writeResult.error().message().c_str());
+                return StatusCode::INVALID_ARG;
+            }
+            return StatusCode::OK;
+#endif  // ENABLE_VENDOR_CLUSTER_PROPERTY_FOR_TESTING
+
+        default:
+            break;
+    }
+    return StatusCode::OK;
+}
+
 StatusCode FakeVehicleHardware::setValues(FakeVehicleHardware::SetValuesCallback&& callback,
                                           const std::vector<SetValueRequest>& requests) {
     std::vector<VehiclePropValue> updatedValues;
     std::vector<SetValueResult> results;
     for (auto& request : requests) {
-        const VehiclePropValue* value = &request.value;
-        ALOGD("setValues(%d)", value->prop);
+        const VehiclePropValue& value = request.value;
+        int propId = value.prop;
 
-        auto updatedValue = mValuePool->obtain(*value);
+        ALOGD("Set value for property ID: %d", propId);
+
+        SetValueResult setValueResult;
+        setValueResult.requestId = request.requestId;
+        setValueResult.status = StatusCode::OK;
+
+        bool isSpecialValue = false;
+        StatusCode status = maybeSetSpecialValue(value, &isSpecialValue);
+
+        if (isSpecialValue) {
+            if (status != StatusCode::OK) {
+                ALOGE("failed to set special value for property ID: %d, status: %d", propId,
+                      status);
+                setValueResult.status = status;
+            }
+
+            // Special values are already handled.
+            results.push_back(std::move(setValueResult));
+            continue;
+        }
+
+        auto updatedValue = mValuePool->obtain(value);
         int64_t timestamp = elapsedRealtimeNano();
         updatedValue->timestamp = timestamp;
 
         auto writeResult = mServerSidePropStore->writeValue(std::move(updatedValue));
-        SetValueResult setValueResult;
-        setValueResult.requestId = request.requestId;
         if (!writeResult.ok()) {
             ALOGE("failed to write value into property store, error: %s, code: %d",
                   writeResult.error().message().c_str(), writeResult.error().code());
             setValueResult.status = StatusCode::INVALID_ARG;
-        } else {
-            setValueResult.status = StatusCode::OK;
         }
         results.push_back(std::move(setValueResult));
     }
diff --git a/automotive/vehicle/aidl/impl/fake_impl/hardware/test/Android.bp b/automotive/vehicle/aidl/impl/fake_impl/hardware/test/Android.bp
index 21937b9..3399317 100644
--- a/automotive/vehicle/aidl/impl/fake_impl/hardware/test/Android.bp
+++ b/automotive/vehicle/aidl/impl/fake_impl/hardware/test/Android.bp
@@ -22,9 +22,11 @@
     name: "FakeVehicleHardwareTest",
     vendor: true,
     srcs: ["*.cpp"],
+    cflags: ["-DENABLE_VENDOR_CLUSTER_PROPERTY_FOR_TESTING"],
     header_libs: [
         "IVehicleHardware",
         "VehicleHalDefaultConfig",
+        "VehicleHalTestUtilHeaders",
     ],
     static_libs: [
         "VehicleHalUtils",
diff --git a/automotive/vehicle/aidl/impl/fake_impl/hardware/test/FakeVehicleHardwareTest.cpp b/automotive/vehicle/aidl/impl/fake_impl/hardware/test/FakeVehicleHardwareTest.cpp
index f915d69..523214c 100644
--- a/automotive/vehicle/aidl/impl/fake_impl/hardware/test/FakeVehicleHardwareTest.cpp
+++ b/automotive/vehicle/aidl/impl/fake_impl/hardware/test/FakeVehicleHardwareTest.cpp
@@ -14,9 +14,11 @@
  * limitations under the License.
  */
 
-#include <DefaultConfig.h>
 #include <FakeVehicleHardware.h>
 
+#include <DefaultConfig.h>
+#include <TestPropertyUtils.h>
+
 #include <android-base/expected.h>
 #include <android-base/file.h>
 #include <gmock/gmock.h>
@@ -25,6 +27,7 @@
 #include <utils/SystemClock.h>
 
 #include <inttypes.h>
+#include <vector>
 
 namespace android {
 namespace hardware {
@@ -39,6 +42,8 @@
 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::VehicleApPowerStateReport;
+using ::aidl::android::hardware::automotive::vehicle::VehicleApPowerStateReq;
 using ::aidl::android::hardware::automotive::vehicle::VehiclePropConfig;
 using ::aidl::android::hardware::automotive::vehicle::VehicleProperty;
 using ::aidl::android::hardware::automotive::vehicle::VehiclePropertyStatus;
@@ -47,6 +52,7 @@
 using ::android::base::unexpected;
 using ::testing::ContainerEq;
 using ::testing::Eq;
+using ::testing::IsSubsetOf;
 using ::testing::WhenSortedBy;
 
 constexpr int INVALID_PROP_ID = 0;
@@ -579,6 +585,322 @@
     ASSERT_EQ(4, result.value().value.int32Values[0]);
 }
 
+struct SetSpecialValueTestCase {
+    std::string name;
+    std::vector<VehiclePropValue> valuesToSet;
+    std::vector<VehiclePropValue> expectedValuesToGet;
+};
+
+std::vector<SetSpecialValueTestCase> setSpecialValueTestCases() {
+    return {
+            SetSpecialValueTestCase{
+                    .name = "set_ap_power_state_report_deep_sleep_exit",
+                    .valuesToSet =
+                            {
+                                    VehiclePropValue{
+                                            .prop = toInt(VehicleProperty::AP_POWER_STATE_REPORT),
+                                            .value.int32Values = {toInt(
+                                                    VehicleApPowerStateReport::DEEP_SLEEP_EXIT)},
+                                    },
+                            },
+                    .expectedValuesToGet =
+                            {
+                                    VehiclePropValue{
+                                            .prop = toInt(VehicleProperty::AP_POWER_STATE_REPORT),
+                                            .value.int32Values = {toInt(
+                                                    VehicleApPowerStateReport::DEEP_SLEEP_EXIT)},
+                                    },
+                                    VehiclePropValue{
+                                            .prop = toInt(VehicleProperty::AP_POWER_STATE_REQ),
+                                            .status = VehiclePropertyStatus::AVAILABLE,
+                                            .value.int32Values = {toInt(VehicleApPowerStateReq::ON),
+                                                                  0},
+                                    },
+                            },
+            },
+            SetSpecialValueTestCase{
+                    .name = "set_ap_power_state_report_hibernation_exit",
+                    .valuesToSet =
+                            {
+                                    VehiclePropValue{
+                                            .prop = toInt(VehicleProperty::AP_POWER_STATE_REPORT),
+                                            .value.int32Values = {toInt(
+                                                    VehicleApPowerStateReport::HIBERNATION_EXIT)},
+                                    },
+                            },
+                    .expectedValuesToGet =
+                            {
+                                    VehiclePropValue{
+                                            .prop = toInt(VehicleProperty::AP_POWER_STATE_REPORT),
+                                            .value.int32Values = {toInt(
+                                                    VehicleApPowerStateReport::HIBERNATION_EXIT)},
+                                    },
+                                    VehiclePropValue{
+                                            .prop = toInt(VehicleProperty::AP_POWER_STATE_REQ),
+                                            .status = VehiclePropertyStatus::AVAILABLE,
+                                            .value.int32Values = {toInt(VehicleApPowerStateReq::ON),
+                                                                  0},
+                                    },
+                            },
+            },
+            SetSpecialValueTestCase{
+                    .name = "set_ap_power_state_report_shutdown_cancelled",
+                    .valuesToSet =
+                            {
+                                    VehiclePropValue{
+                                            .prop = toInt(VehicleProperty::AP_POWER_STATE_REPORT),
+                                            .value.int32Values = {toInt(
+                                                    VehicleApPowerStateReport::SHUTDOWN_CANCELLED)},
+                                    },
+                            },
+                    .expectedValuesToGet =
+                            {
+                                    VehiclePropValue{
+                                            .prop = toInt(VehicleProperty::AP_POWER_STATE_REPORT),
+                                            .value.int32Values = {toInt(
+                                                    VehicleApPowerStateReport::SHUTDOWN_CANCELLED)},
+                                    },
+                                    VehiclePropValue{
+                                            .prop = toInt(VehicleProperty::AP_POWER_STATE_REQ),
+                                            .status = VehiclePropertyStatus::AVAILABLE,
+                                            .value.int32Values = {toInt(VehicleApPowerStateReq::ON),
+                                                                  0},
+                                    },
+                            },
+            },
+            SetSpecialValueTestCase{
+                    .name = "set_ap_power_state_report_wait_for_vhal",
+                    .valuesToSet =
+                            {
+                                    VehiclePropValue{
+                                            .prop = toInt(VehicleProperty::AP_POWER_STATE_REPORT),
+                                            .value.int32Values = {toInt(
+                                                    VehicleApPowerStateReport::WAIT_FOR_VHAL)},
+                                    },
+                            },
+                    .expectedValuesToGet =
+                            {
+                                    VehiclePropValue{
+                                            .prop = toInt(VehicleProperty::AP_POWER_STATE_REPORT),
+                                            .value.int32Values = {toInt(
+                                                    VehicleApPowerStateReport::WAIT_FOR_VHAL)},
+                                    },
+                                    VehiclePropValue{
+                                            .prop = toInt(VehicleProperty::AP_POWER_STATE_REQ),
+                                            .status = VehiclePropertyStatus::AVAILABLE,
+                                            .value.int32Values = {toInt(VehicleApPowerStateReq::ON),
+                                                                  0},
+                                    },
+                            },
+            },
+            SetSpecialValueTestCase{
+                    .name = "set_ap_power_state_report_deep_sleep_entry",
+                    .valuesToSet =
+                            {
+                                    VehiclePropValue{
+                                            .prop = toInt(VehicleProperty::AP_POWER_STATE_REPORT),
+                                            .value.int32Values = {toInt(
+                                                    VehicleApPowerStateReport::DEEP_SLEEP_ENTRY)},
+                                    },
+                            },
+                    .expectedValuesToGet =
+                            {
+                                    VehiclePropValue{
+                                            .prop = toInt(VehicleProperty::AP_POWER_STATE_REPORT),
+                                            .value.int32Values = {toInt(
+                                                    VehicleApPowerStateReport::DEEP_SLEEP_ENTRY)},
+                                    },
+                                    VehiclePropValue{
+                                            .prop = toInt(VehicleProperty::AP_POWER_STATE_REQ),
+                                            .status = VehiclePropertyStatus::AVAILABLE,
+                                            .value.int32Values =
+                                                    {toInt(VehicleApPowerStateReq::FINISHED), 0},
+                                    },
+                            },
+            },
+            SetSpecialValueTestCase{
+                    .name = "set_ap_power_state_report_hibernation_entry",
+                    .valuesToSet =
+                            {
+                                    VehiclePropValue{
+                                            .prop = toInt(VehicleProperty::AP_POWER_STATE_REPORT),
+                                            .value.int32Values = {toInt(
+                                                    VehicleApPowerStateReport::HIBERNATION_ENTRY)},
+                                    },
+                            },
+                    .expectedValuesToGet =
+                            {
+                                    VehiclePropValue{
+                                            .prop = toInt(VehicleProperty::AP_POWER_STATE_REPORT),
+                                            .value.int32Values = {toInt(
+                                                    VehicleApPowerStateReport::HIBERNATION_ENTRY)},
+                                    },
+                                    VehiclePropValue{
+                                            .prop = toInt(VehicleProperty::AP_POWER_STATE_REQ),
+                                            .status = VehiclePropertyStatus::AVAILABLE,
+                                            .value.int32Values =
+                                                    {toInt(VehicleApPowerStateReq::FINISHED), 0},
+                                    },
+                            },
+            },
+            SetSpecialValueTestCase{
+                    .name = "set_ap_power_state_report_shutdown_start",
+                    .valuesToSet =
+                            {
+                                    VehiclePropValue{
+                                            .prop = toInt(VehicleProperty::AP_POWER_STATE_REPORT),
+                                            .value.int32Values = {toInt(
+                                                    VehicleApPowerStateReport::SHUTDOWN_START)},
+                                    },
+                            },
+                    .expectedValuesToGet =
+                            {
+                                    VehiclePropValue{
+                                            .prop = toInt(VehicleProperty::AP_POWER_STATE_REPORT),
+                                            .value.int32Values = {toInt(
+                                                    VehicleApPowerStateReport::SHUTDOWN_START)},
+                                    },
+                                    VehiclePropValue{
+                                            .prop = toInt(VehicleProperty::AP_POWER_STATE_REQ),
+                                            .status = VehiclePropertyStatus::AVAILABLE,
+                                            .value.int32Values =
+                                                    {toInt(VehicleApPowerStateReq::FINISHED), 0},
+                                    },
+                            },
+            },
+            SetSpecialValueTestCase{
+                    .name = "cluster_report_state_to_vendor",
+                    .valuesToSet =
+                            {
+                                    VehiclePropValue{
+                                            .prop = toInt(VehicleProperty::CLUSTER_REPORT_STATE),
+                                            .value.int32Values = {1},
+                                    },
+                            },
+                    .expectedValuesToGet =
+                            {
+                                    VehiclePropValue{
+                                            .prop = VENDOR_CLUSTER_REPORT_STATE,
+                                            .value.int32Values = {1},
+                                    },
+                            },
+            },
+            SetSpecialValueTestCase{
+                    .name = "cluster_request_display_to_vendor",
+                    .valuesToSet =
+                            {
+                                    VehiclePropValue{
+                                            .prop = toInt(VehicleProperty::CLUSTER_REQUEST_DISPLAY),
+                                            .value.int32Values = {1},
+                                    },
+                            },
+                    .expectedValuesToGet =
+                            {
+                                    VehiclePropValue{
+                                            .prop = VENDOR_CLUSTER_REQUEST_DISPLAY,
+                                            .value.int32Values = {1},
+                                    },
+                            },
+            },
+            SetSpecialValueTestCase{
+                    .name = "cluster_navigation_state_to_vendor",
+                    .valuesToSet =
+                            {
+                                    VehiclePropValue{
+                                            .prop = toInt(
+                                                    VehicleProperty::CLUSTER_NAVIGATION_STATE),
+                                            .value.byteValues = {0x1},
+                                    },
+                            },
+                    .expectedValuesToGet =
+                            {
+                                    VehiclePropValue{
+                                            .prop = VENDOR_CLUSTER_NAVIGATION_STATE,
+                                            .value.byteValues = {0x1},
+                                    },
+                            },
+            },
+            SetSpecialValueTestCase{
+                    .name = "vendor_cluster_switch_ui_to_system",
+                    .valuesToSet =
+                            {
+                                    VehiclePropValue{
+                                            .prop = VENDOR_CLUSTER_SWITCH_UI,
+                                            .value.int32Values = {1},
+                                    },
+                            },
+                    .expectedValuesToGet =
+                            {
+                                    VehiclePropValue{
+                                            .prop = toInt(VehicleProperty::CLUSTER_SWITCH_UI),
+                                            .value.int32Values = {1},
+                                    },
+                            },
+            },
+            SetSpecialValueTestCase{
+                    .name = "vendor_cluster_display_state_to_system",
+                    .valuesToSet =
+                            {
+                                    VehiclePropValue{
+                                            .prop = VENDOR_CLUSTER_DISPLAY_STATE,
+                                            .value.int32Values = {1, 2},
+                                    },
+                            },
+                    .expectedValuesToGet =
+                            {
+                                    VehiclePropValue{
+                                            .prop = toInt(VehicleProperty::CLUSTER_DISPLAY_STATE),
+                                            .value.int32Values = {1, 2},
+                                    },
+                            },
+            },
+    };
+}
+
+class FakeVehicleHardwareSpecialValuesTest
+    : public FakeVehicleHardwareTest,
+      public testing::WithParamInterface<SetSpecialValueTestCase> {};
+
+TEST_P(FakeVehicleHardwareSpecialValuesTest, testSetSpecialProperties) {
+    getHardware()->registerOnPropertyChangeEvent(
+            [this](const std::vector<VehiclePropValue>& values) {
+                return onPropertyChangeEvent(values);
+            });
+
+    const SetSpecialValueTestCase& tc = GetParam();
+
+    for (const auto& value : tc.valuesToSet) {
+        ASSERT_EQ(setValue(value), StatusCode::OK) << "failed to set property " << value.prop;
+    }
+
+    std::vector<VehiclePropValue> gotValues;
+
+    for (const auto& value : tc.expectedValuesToGet) {
+        auto result = getValue(VehiclePropValue{.prop = value.prop});
+
+        ASSERT_TRUE(result.ok()) << "failed to get property " << value.prop
+                                 << " status:" << getStatus(result);
+
+        gotValues.push_back(result.value());
+        VehiclePropValue valueWithNoTimestamp = result.value();
+        valueWithNoTimestamp.timestamp = 0;
+
+        ASSERT_EQ(valueWithNoTimestamp, value);
+    }
+
+    // Some of the updated properties might be the same as default config, thus not causing
+    // a property change event. So the changed properties should be a subset of all the updated
+    // properties.
+    ASSERT_THAT(getChangedProperties(), WhenSortedBy(mPropValueCmp, IsSubsetOf(gotValues)));
+}
+
+INSTANTIATE_TEST_SUITE_P(
+        SpecialValuesTests, FakeVehicleHardwareSpecialValuesTest,
+        testing::ValuesIn(setSpecialValueTestCases()),
+        [](const testing::TestParamInfo<FakeVehicleHardwareSpecialValuesTest::ParamType>& info) {
+            return info.param.name;
+        });
+
 }  // namespace fake
 }  // namespace vehicle
 }  // namespace automotive
diff --git a/automotive/vehicle/aidl/impl/utils/test/Android.bp b/automotive/vehicle/aidl/impl/utils/test/Android.bp
index 5859151..ad9954f 100644
--- a/automotive/vehicle/aidl/impl/utils/test/Android.bp
+++ b/automotive/vehicle/aidl/impl/utils/test/Android.bp
@@ -20,6 +20,7 @@
 
 cc_library_headers {
     name: "VehicleHalTestUtilHeaders",
-    export_include_dirs: ["include"],
     vendor: true,
+    header_libs: ["VehicleHalUtilHeaders"],
+    export_include_dirs: ["include"],
 }
diff --git a/automotive/vehicle/aidl/impl/utils/test/include/TestPropertyUtils.h b/automotive/vehicle/aidl/impl/utils/test/include/TestPropertyUtils.h
index 77cf100..f80d1e6 100644
--- a/automotive/vehicle/aidl/impl/utils/test/include/TestPropertyUtils.h
+++ b/automotive/vehicle/aidl/impl/utils/test/include/TestPropertyUtils.h
@@ -29,6 +29,7 @@
 
 // These names are not part of the API since we only expose ints.
 using ::aidl::android::hardware::automotive::vehicle::VehicleArea;
+using ::aidl::android::hardware::automotive::vehicle::VehicleProperty;
 using ::aidl::android::hardware::automotive::vehicle::VehiclePropertyGroup;
 using ::aidl::android::hardware::automotive::vehicle::VehiclePropertyType;
 
@@ -44,16 +45,16 @@
 }
 
 // These properties are used for the end-to-end testing of ClusterHomeService.
-constexpr int32_t VENDOR_CLUSTER_SWITCH_UI = toVendor(
-        ::aidl::android::hardware::automotive::vehicle::VehicleProperty::CLUSTER_SWITCH_UI);
+constexpr int32_t VENDOR_CLUSTER_SWITCH_UI =
+        toVendor(testpropertyutils_impl::VehicleProperty::CLUSTER_SWITCH_UI);
 constexpr int32_t VENDOR_CLUSTER_DISPLAY_STATE =
-        toVendor(::aidl::hardware::automotive::vehicle::VehicleProperty::CLUSTER_DISPLAY_STATE);
+        toVendor(testpropertyutils_impl::VehicleProperty::CLUSTER_DISPLAY_STATE);
 constexpr int32_t VENDOR_CLUSTER_REPORT_STATE =
-        toVendor(::aidl::hardware::automotive::vehicle::VehicleProperty::CLUSTER_REPORT_STATE);
+        toVendor(testpropertyutils_impl::VehicleProperty::CLUSTER_REPORT_STATE);
 constexpr int32_t VENDOR_CLUSTER_REQUEST_DISPLAY =
-        toVendor(::aidl::hardware::automotive::vehicle::VehicleProperty::CLUSTER_REQUEST_DISPLAY);
+        toVendor(testpropertyutils_impl::VehicleProperty::CLUSTER_REQUEST_DISPLAY);
 constexpr int32_t VENDOR_CLUSTER_NAVIGATION_STATE =
-        toVendor(::aidl::hardware::automotive::vehicle::VehicleProperty::CLUSTER_NAVIGATION_STATE);
+        toVendor(testpropertyutils_impl::VehicleProperty::CLUSTER_NAVIGATION_STATE);
 #endif  // ENABLE_VENDOR_CLUSTER_PROPERTY_FOR_TESTING
 
 // These properties are placeholder properties for developers to test new features without