/*
 * Copyright (C) 2018 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.
 */

#define LOG_TAG "graphics_composer_hidl_hal_test@2.3"

#include <algorithm>
#include <numeric>

#include <android-base/logging.h>
#include <android-base/properties.h>
#include <composer-command-buffer/2.3/ComposerCommandBuffer.h>
#include <composer-vts/2.1/GraphicsComposerCallback.h>
#include <composer-vts/2.1/TestCommandReader.h>
#include <composer-vts/2.3/ComposerVts.h>
#include <gtest/gtest.h>
#include <hidl/GtestPrinter.h>
#include <hidl/ServiceManagement.h>

namespace android {
namespace hardware {
namespace graphics {
namespace composer {
namespace V2_3 {
namespace vts {
namespace {

using common::V1_1::RenderIntent;
using common::V1_2::ColorMode;
using common::V1_2::Dataspace;
using common::V1_2::PixelFormat;

class GraphicsComposerHidlTest : public ::testing::TestWithParam<std::string> {
  protected:
    void SetUp() override {
        ASSERT_NO_FATAL_FAILURE(
                mComposer = std::make_unique<Composer>(IComposer::getService(GetParam())));
        ASSERT_NO_FATAL_FAILURE(mComposerClient = mComposer->createClient());

        mComposerCallback = new V2_1::vts::GraphicsComposerCallback;
        mComposerClient->registerCallback(mComposerCallback);

        // assume the first display is primary and is never removed
        mPrimaryDisplay = waitForFirstDisplay();

        mInvalidDisplayId = GetInvalidDisplayId();

        // explicitly disable vsync
        mComposerClient->setVsyncEnabled(mPrimaryDisplay, false);
        mComposerCallback->setVsyncAllowed(false);

        mWriter = std::make_unique<CommandWriterBase>(1024);
        mReader = std::make_unique<V2_1::vts::TestCommandReader>();
    }

    void TearDown() override {
        ASSERT_EQ(0, mReader->mErrors.size());
        ASSERT_EQ(0, mReader->mCompositionChanges.size());
        if (mComposerCallback != nullptr) {
            EXPECT_EQ(0, mComposerCallback->getInvalidHotplugCount());
            EXPECT_EQ(0, mComposerCallback->getInvalidRefreshCount());
            EXPECT_EQ(0, mComposerCallback->getInvalidVsyncCount());
        }
    }

    // returns an invalid display id (one that has not been registered to a
    // display.  Currently assuming that a device will never have close to
    // std::numeric_limit<uint64_t>::max() displays registered while running tests
    Display GetInvalidDisplayId() {
        std::vector<Display> validDisplays = mComposerCallback->getDisplays();
        uint64_t id = std::numeric_limits<uint64_t>::max();
        while (id > 0) {
            if (std::find(validDisplays.begin(), validDisplays.end(), id) == validDisplays.end()) {
                return id;
            }
            id--;
        }

        return 0;
    }

    void execute() { mComposerClient->execute(mReader.get(), mWriter.get()); }

    // use the slot count usually set by SF
    static constexpr uint32_t kBufferSlotCount = 64;

    std::unique_ptr<Composer> mComposer;
    std::unique_ptr<ComposerClient> mComposerClient;
    sp<V2_1::vts::GraphicsComposerCallback> mComposerCallback;
    // the first display and is assumed never to be removed
    Display mPrimaryDisplay;
    Display mInvalidDisplayId;
    std::unique_ptr<CommandWriterBase> mWriter;
    std::unique_ptr<V2_1::vts::TestCommandReader> mReader;

   private:
    Display waitForFirstDisplay() {
        while (true) {
            std::vector<Display> displays = mComposerCallback->getDisplays();
            if (displays.empty()) {
                usleep(5 * 1000);
                continue;
            }

            return displays[0];
        }
    }
};

// Tests for IComposerClient::Command.
class GraphicsComposerHidlCommandTest : public GraphicsComposerHidlTest {
   protected:
    void SetUp() override {
        ASSERT_NO_FATAL_FAILURE(GraphicsComposerHidlTest::SetUp());

        mWriter = std::make_unique<CommandWriterBase>(1024);
        mReader = std::make_unique<V2_1::vts::TestCommandReader>();
    }

    void TearDown() override {
        ASSERT_EQ(0, mReader->mErrors.size());
        ASSERT_NO_FATAL_FAILURE(GraphicsComposerHidlTest::TearDown());
    }

    void execute() { mComposerClient->execute(mReader.get(), mWriter.get()); }

    std::unique_ptr<CommandWriterBase> mWriter;
    std::unique_ptr<V2_1::vts::TestCommandReader> mReader;
};

/**
 * Test IComposerClient::getDisplayIdentificationData.
 *
 * TODO: Check that ports are unique for multiple displays.
 */
TEST_P(GraphicsComposerHidlTest, GetDisplayIdentificationData) {
    uint8_t port0;
    std::vector<uint8_t> data0;

    if (!mComposerClient->getDisplayIdentificationData(mPrimaryDisplay, &port0, &data0)) {
        return;
    }

    ASSERT_FALSE(data0.empty());
    constexpr size_t kEdidBlockSize = 128;
    ASSERT_TRUE(data0.size() % kEdidBlockSize == 0)
            << "EDID blob length is not a multiple of " << kEdidBlockSize;

    const uint8_t kEdidHeader[] = {0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00};
    ASSERT_TRUE(std::equal(std::begin(kEdidHeader), std::end(kEdidHeader), data0.begin()))
            << "EDID blob doesn't start with the fixed EDID header";
    ASSERT_EQ(0, std::accumulate(data0.begin(), data0.begin() + kEdidBlockSize,
                                 static_cast<uint8_t>(0)))
            << "EDID base block doesn't checksum";

    uint8_t port1;
    std::vector<uint8_t> data1;
    ASSERT_TRUE(mComposerClient->getDisplayIdentificationData(mPrimaryDisplay, &port1, &data1));

    ASSERT_EQ(port0, port1) << "ports are not stable";
    ASSERT_TRUE(data0.size() == data1.size() &&
                std::equal(data0.begin(), data0.end(), data1.begin()))
            << "data is not stable";
}

/**
 * Test IComposerClient::Command::SET_LAYER_PER_FRAME_METADATA.
 */
TEST_P(GraphicsComposerHidlCommandTest, SET_LAYER_PER_FRAME_METADATA) {
    Layer layer;
    ASSERT_NO_FATAL_FAILURE(layer =
                                mComposerClient->createLayer(mPrimaryDisplay, kBufferSlotCount));

    mWriter->selectDisplay(mPrimaryDisplay);
    mWriter->selectLayer(layer);

    /**
     * DISPLAY_P3 is a color space that uses the DCI_P3 primaries,
     * the D65 white point and the SRGB transfer functions.
     * Rendering Intent: Colorimetric
     * Primaries:
     *                  x       y
     *  green           0.265   0.690
     *  blue            0.150   0.060
     *  red             0.680   0.320
     *  white (D65)     0.3127  0.3290
     */

    std::vector<IComposerClient::PerFrameMetadata> hidlMetadata;
    hidlMetadata.push_back({IComposerClient::PerFrameMetadataKey::DISPLAY_RED_PRIMARY_X, 0.680});
    hidlMetadata.push_back({IComposerClient::PerFrameMetadataKey::DISPLAY_RED_PRIMARY_Y, 0.320});
    hidlMetadata.push_back({IComposerClient::PerFrameMetadataKey::DISPLAY_GREEN_PRIMARY_X, 0.265});
    hidlMetadata.push_back({IComposerClient::PerFrameMetadataKey::DISPLAY_GREEN_PRIMARY_Y, 0.690});
    hidlMetadata.push_back({IComposerClient::PerFrameMetadataKey::DISPLAY_BLUE_PRIMARY_X, 0.150});
    hidlMetadata.push_back({IComposerClient::PerFrameMetadataKey::DISPLAY_BLUE_PRIMARY_Y, 0.060});
    hidlMetadata.push_back({IComposerClient::PerFrameMetadataKey::WHITE_POINT_X, 0.3127});
    hidlMetadata.push_back({IComposerClient::PerFrameMetadataKey::WHITE_POINT_Y, 0.3290});
    hidlMetadata.push_back({IComposerClient::PerFrameMetadataKey::MAX_LUMINANCE, 100.0});
    hidlMetadata.push_back({IComposerClient::PerFrameMetadataKey::MIN_LUMINANCE, 0.1});
    hidlMetadata.push_back({IComposerClient::PerFrameMetadataKey::MAX_CONTENT_LIGHT_LEVEL, 78.0});
    hidlMetadata.push_back(
        {IComposerClient::PerFrameMetadataKey::MAX_FRAME_AVERAGE_LIGHT_LEVEL, 62.0});
    mWriter->setLayerPerFrameMetadata(hidlMetadata);
    execute();

    if (mReader->mErrors.size() == 1 &&
        static_cast<Error>(mReader->mErrors[0].second) == Error::UNSUPPORTED) {
        mReader->mErrors.clear();
        GTEST_SUCCEED() << "SetLayerPerFrameMetadata is not supported";
        ASSERT_NO_FATAL_FAILURE(mComposerClient->destroyLayer(mPrimaryDisplay, layer));
        return;
    }

    ASSERT_NO_FATAL_FAILURE(mComposerClient->destroyLayer(mPrimaryDisplay, layer));
}

/**
 * Test IComposerClient::getHdrCapabilities_2_3
 */
TEST_P(GraphicsComposerHidlTest, GetHdrCapabilities_2_3) {
    float maxLuminance;
    float maxAverageLuminance;
    float minLuminance;
    ASSERT_NO_FATAL_FAILURE(mComposerClient->getHdrCapabilities_2_3(
        mPrimaryDisplay, &maxLuminance, &maxAverageLuminance, &minLuminance));
    ASSERT_TRUE(maxLuminance >= minLuminance);
}

/**
 * Test IComposerClient::getPerFrameMetadataKeys_2_3
 */
TEST_P(GraphicsComposerHidlTest, GetPerFrameMetadataKeys_2_3) {
    std::vector<IComposerClient::PerFrameMetadataKey> keys;
    mComposerClient->getRaw()->getPerFrameMetadataKeys_2_3(
        mPrimaryDisplay, [&](const auto tmpError, const auto outKeys) {
            if (tmpError != Error::UNSUPPORTED) {
                ASSERT_EQ(Error::NONE, tmpError);
                keys = outKeys;
            }
        });
}

/**
 * TestIComposerClient::getReadbackBufferAttributes_2_3
 */
TEST_P(GraphicsComposerHidlTest, GetReadbackBufferAttributes_2_3) {
    Dataspace dataspace;
    PixelFormat pixelFormat;

    mComposerClient->getRaw()->getReadbackBufferAttributes_2_3(
        mPrimaryDisplay,
        [&](const auto tmpError, const auto outPixelFormat, const auto outDataspace) {
            if (tmpError != Error::UNSUPPORTED) {
                ASSERT_EQ(Error::NONE, tmpError);
                dataspace = outDataspace;
                pixelFormat = outPixelFormat;
            }
        });
}

/**
 * Test IComposerClient::getClientTargetSupport_2_3
 */
TEST_P(GraphicsComposerHidlTest, GetClientTargetSupport_2_3) {
    ASSERT_NO_FATAL_FAILURE(
            mComposerClient->setPowerMode_2_2(mPrimaryDisplay, IComposerClient::PowerMode::ON));
    std::vector<V2_1::Config> configs = mComposerClient->getDisplayConfigs(mPrimaryDisplay);
    for (auto config : configs) {
        int32_t width = mComposerClient->getDisplayAttribute(mPrimaryDisplay, config,
                                                             IComposerClient::Attribute::WIDTH);
        int32_t height = mComposerClient->getDisplayAttribute(mPrimaryDisplay, config,
                                                              IComposerClient::Attribute::HEIGHT);
        ASSERT_LT(0, width);
        ASSERT_LT(0, height);

        mComposerClient->setActiveConfig(mPrimaryDisplay, config);

        ASSERT_TRUE(mComposerClient->getClientTargetSupport_2_3(
            mPrimaryDisplay, width, height, PixelFormat::RGBA_8888, Dataspace::UNKNOWN));
    }
}
/**
 * Test IComposerClient::getClientTargetSupport_2_3
 *
 * Test that IComposerClient::getClientTargetSupport_2_3 returns
 * Error::BAD_DISPLAY when passed in an invalid display handle
 */

TEST_P(GraphicsComposerHidlTest, GetClientTargetSupport_2_3BadDisplay) {
    std::vector<V2_1::Config> configs = mComposerClient->getDisplayConfigs(mPrimaryDisplay);
    for (auto config : configs) {
        int32_t width = mComposerClient->getDisplayAttribute(mPrimaryDisplay, config,
                                                             IComposerClient::Attribute::WIDTH);
        int32_t height = mComposerClient->getDisplayAttribute(mPrimaryDisplay, config,
                                                              IComposerClient::Attribute::HEIGHT);
        ASSERT_LT(0, width);
        ASSERT_LT(0, height);

        mComposerClient->setActiveConfig(mPrimaryDisplay, config);

        Error error = mComposerClient->getRaw()->getClientTargetSupport_2_3(
            mInvalidDisplayId, width, height, PixelFormat::RGBA_8888, Dataspace::UNKNOWN);

        EXPECT_EQ(Error::BAD_DISPLAY, error);
    }
}

/**
 * Test IComposerClient::getRenderIntents_2_3
 */
TEST_P(GraphicsComposerHidlTest, GetRenderIntents_2_3) {
    std::vector<ColorMode> modes = mComposerClient->getColorModes_2_3(mPrimaryDisplay);
    for (auto mode : modes) {
        std::vector<RenderIntent> intents =
            mComposerClient->getRenderIntents_2_3(mPrimaryDisplay, mode);

        bool isHdr;
        switch (mode) {
            case ColorMode::BT2100_PQ:
            case ColorMode::BT2100_HLG:
                isHdr = true;
                break;
            default:
                isHdr = false;
                break;
        }
        RenderIntent requiredIntent =
            isHdr ? RenderIntent::TONE_MAP_COLORIMETRIC : RenderIntent::COLORIMETRIC;

        auto iter = std::find(intents.cbegin(), intents.cend(), requiredIntent);
        EXPECT_NE(intents.cend(), iter);
    }
}

/*
 * Test IComposerClient::getRenderIntents_2_3
 *
 * Test that IComposerClient::getRenderIntents_2_3 returns Error::BAD_DISPLAY when
 * passed an invalid display handle
 */
TEST_P(GraphicsComposerHidlTest, GetRenderIntents_2_3BadDisplay) {
    std::vector<ColorMode> modes = mComposerClient->getColorModes_2_3(mPrimaryDisplay);
    for (auto mode : modes) {
        mComposerClient->getRaw()->getRenderIntents_2_3(
            mInvalidDisplayId, mode,
            [&](const auto& tmpError, const auto&) { EXPECT_EQ(Error::BAD_DISPLAY, tmpError); });
    }
}

/*
 * Test IComposerClient::getRenderIntents_2_3
 *
 * Test that IComposerClient::getRenderIntents_2_3 returns Error::BAD_PARAMETER when
 * pased either an invalid Color mode or an invalid Render Intent
 */
TEST_P(GraphicsComposerHidlTest, GetRenderIntents_2_3BadParameter) {
    mComposerClient->getRaw()->getRenderIntents_2_3(
        mPrimaryDisplay, static_cast<ColorMode>(-1),
        [&](const auto& tmpError, const auto&) { EXPECT_EQ(Error::BAD_PARAMETER, tmpError); });
}

/**
 * IComposerClient::getColorModes_2_3
 */
TEST_P(GraphicsComposerHidlTest, GetColorModes_2_3) {
    std::vector<ColorMode> colorModes = mComposerClient->getColorModes_2_3(mPrimaryDisplay);

    auto native = std::find(colorModes.cbegin(), colorModes.cend(), ColorMode::NATIVE);
    ASSERT_NE(colorModes.cend(), native);
}

/*
 * Test IComposerClient::getColorModes_2_3
 *
 * Test that IComposerClient::getColorModes_2_3 returns Error::BAD_DISPLAY when
 * passed an invalid display handle
 */
TEST_P(GraphicsComposerHidlTest, GetColorMode_2_3BadDisplay) {
    mComposerClient->getRaw()->getColorModes_2_3(
        mInvalidDisplayId,
        [&](const auto& tmpError, const auto&) { ASSERT_EQ(Error::BAD_DISPLAY, tmpError); });
}

/**
 * IComposerClient::setColorMode_2_3
 */
TEST_P(GraphicsComposerHidlTest, SetColorMode_2_3) {
    std::vector<ColorMode> colorModes = mComposerClient->getColorModes_2_3(mPrimaryDisplay);
    for (auto mode : colorModes) {
        std::vector<RenderIntent> intents =
            mComposerClient->getRenderIntents_2_3(mPrimaryDisplay, mode);
        for (auto intent : intents) {
            ASSERT_NO_FATAL_FAILURE(
                mComposerClient->setColorMode_2_3(mPrimaryDisplay, mode, intent));
        }
    }

    ASSERT_NO_FATAL_FAILURE(mComposerClient->setColorMode_2_3(mPrimaryDisplay, ColorMode::NATIVE,
                                                              RenderIntent::COLORIMETRIC));
}

/*
 * Test IComposerClient::setColorMode_2_3
 *
 * Test that IComposerClient::setColorMode_2_3 returns an Error::BAD_DISPLAY
 * when passed an invalid display handle
 */
TEST_P(GraphicsComposerHidlTest, SetColorMode_2_3BadDisplay) {
    Error error = mComposerClient->getRaw()->setColorMode_2_3(mInvalidDisplayId, ColorMode::NATIVE,
                                                              RenderIntent::COLORIMETRIC);

    ASSERT_EQ(Error::BAD_DISPLAY, error);
}

/*
 * Test IComposerClient::setColorMode_2_3
 *
 * Test that IComposerClient::setColorMode_2_3 returns Error::BAD_PARAMETER when
 * passed an invalid Color mode or an invalid render intent
 */
TEST_P(GraphicsComposerHidlTest, SetColorMode_2_3BadParameter) {
    Error colorModeError = mComposerClient->getRaw()->setColorMode_2_3(
        mPrimaryDisplay, static_cast<ColorMode>(-1), RenderIntent::COLORIMETRIC);
    EXPECT_EQ(Error::BAD_PARAMETER, colorModeError);

    Error renderIntentError = mComposerClient->getRaw()->setColorMode_2_3(
        mPrimaryDisplay, ColorMode::NATIVE, static_cast<RenderIntent>(-1));
    EXPECT_EQ(Error::BAD_PARAMETER, renderIntentError);
}

/**
 * Test IComposerClient::Command::SET_LAYER_COLOR_TRANSFORM.
 * TODO Add color to the layer, use matrix to keep only red component,
 * and check.
 */
TEST_P(GraphicsComposerHidlTest, SetLayerColorTransform) {
    Layer layer;
    ASSERT_NO_FATAL_FAILURE(layer =
                                mComposerClient->createLayer(mPrimaryDisplay, kBufferSlotCount));
    mWriter->selectDisplay(mPrimaryDisplay);
    mWriter->selectLayer(layer);

    // clang-format off
    const std::array<float, 16> matrix = {{
        1.0f, 0.0f, 0.0f, 0.0f,
        0.0f, 1.0f, 0.0f, 0.0f,
        0.0f, 0.0f, 1.0f, 0.0f,
        0.0f, 0.0f, 0.0f, 1.0f,
    }};
    // clang-format on

    mWriter->setLayerColorTransform(matrix.data());
    execute();

    if (mReader->mErrors.size() == 1 &&
        static_cast<Error>(mReader->mErrors[0].second) == Error::UNSUPPORTED) {
        mReader->mErrors.clear();
        GTEST_SUCCEED() << "setLayerColorTransform is not supported";
        return;
    }
}

TEST_P(GraphicsComposerHidlTest, GetDisplayedContentSamplingAttributes) {
    int constexpr invalid = -1;
    auto format = static_cast<PixelFormat>(invalid);
    auto dataspace = static_cast<Dataspace>(invalid);
    auto componentMask = static_cast<hidl_bitfield<IComposerClient::FormatColorComponent>>(invalid);
    auto error = mComposerClient->getDisplayedContentSamplingAttributes(mPrimaryDisplay, format,
                                                                        dataspace, componentMask);

    if (error == Error::UNSUPPORTED) {
        SUCCEED() << "Device does not support optional extension. Test skipped";
        return;
    }

    EXPECT_EQ(error, Error::NONE);
    EXPECT_NE(format, static_cast<PixelFormat>(invalid));
    EXPECT_NE(dataspace, static_cast<Dataspace>(invalid));
    EXPECT_NE(componentMask,
              static_cast<hidl_bitfield<IComposerClient::FormatColorComponent>>(invalid));
};

TEST_P(GraphicsComposerHidlTest, SetDisplayedContentSamplingEnabled) {
    auto const maxFrames = 10;
    auto const enableAllComponents = 0;
    auto error = mComposerClient->setDisplayedContentSamplingEnabled(
        mPrimaryDisplay, IComposerClient::DisplayedContentSampling::ENABLE, enableAllComponents,
        maxFrames);
    if (error == Error::UNSUPPORTED) {
        SUCCEED() << "Device does not support optional extension. Test skipped";
        return;
    }
    EXPECT_EQ(error, Error::NONE);

    error = mComposerClient->setDisplayedContentSamplingEnabled(
        mPrimaryDisplay, IComposerClient::DisplayedContentSampling::DISABLE, enableAllComponents,
        maxFrames);
    EXPECT_EQ(error, Error::NONE);
}

TEST_P(GraphicsComposerHidlTest, GetDisplayedContentSample) {
    int constexpr invalid = -1;
    auto format = static_cast<PixelFormat>(invalid);
    auto dataspace = static_cast<Dataspace>(invalid);
    auto componentMask = static_cast<hidl_bitfield<IComposerClient::FormatColorComponent>>(invalid);
    auto error = mComposerClient->getDisplayedContentSamplingAttributes(mPrimaryDisplay, format,
                                                                        dataspace, componentMask);

    uint64_t maxFrames = 10;
    uint64_t timestamp = 0;
    uint64_t frameCount = 0;
    hidl_array<hidl_vec<uint64_t>, 4> histogram;
    error = mComposerClient->getDisplayedContentSample(mPrimaryDisplay, maxFrames, timestamp,
                                                       frameCount, histogram[0], histogram[1],
                                                       histogram[2], histogram[3]);
    if (error == Error::UNSUPPORTED) {
        SUCCEED() << "Device does not support optional extension. Test skipped";
        return;
    }

    EXPECT_EQ(error, Error::NONE);
    EXPECT_LE(frameCount, maxFrames);
    for (auto i = 0; i < histogram.size(); i++) {
        if (componentMask & (1 << i)) {
            EXPECT_NE(histogram[i].size(), 0);
        } else {
            EXPECT_EQ(histogram[i].size(), 0);
        }
    }
}

/*
 * getDisplayCapabilities is required in composer 2.3
 * Test some constraints.
 */
TEST_P(GraphicsComposerHidlTest, getDisplayCapabilitiesBasic) {
    std::vector<IComposerClient::DisplayCapability> capabilities;
    const auto error = mComposerClient->getDisplayCapabilities(mPrimaryDisplay, &capabilities);
    ASSERT_EQ(Error::NONE, error);
    const bool hasDozeSupport =
            std::find(capabilities.begin(), capabilities.end(),
                      IComposerClient::DisplayCapability::DOZE) != capabilities.end();
    EXPECT_EQ(mComposerClient->getDozeSupport(mPrimaryDisplay), hasDozeSupport);
    bool hasBrightnessSupport =
            std::find(capabilities.begin(), capabilities.end(),
                      IComposerClient::DisplayCapability::BRIGHTNESS) != capabilities.end();
    EXPECT_EQ(mComposerClient->getDisplayBrightnessSupport(mPrimaryDisplay), hasBrightnessSupport);
}

TEST_P(GraphicsComposerHidlTest, getDisplayCapabilitiesBadDisplay) {
    std::vector<IComposerClient::DisplayCapability> capabilities;
    const auto error = mComposerClient->getDisplayCapabilities(mInvalidDisplayId, &capabilities);
    EXPECT_EQ(Error::BAD_DISPLAY, error);
}

TEST_P(GraphicsComposerHidlTest, SetLayerPerFrameMetadataBlobs) {
    Layer layer;
    ASSERT_NO_FATAL_FAILURE(layer =
                                mComposerClient->createLayer(mPrimaryDisplay, kBufferSlotCount));

    mWriter->selectDisplay(mPrimaryDisplay);
    mWriter->selectLayer(layer);

    std::vector<IComposerClient::PerFrameMetadataBlob> metadata;
    metadata.push_back(
        {IComposerClient::PerFrameMetadataKey::HDR10_PLUS_SEI, std::vector<uint8_t>(1, 0xff)});

    mWriter->setLayerPerFrameMetadataBlobs(metadata);
    execute();

    if (mReader->mErrors.size() == 1 &&
        static_cast<Error>(mReader->mErrors[0].second) == Error::UNSUPPORTED) {
        mReader->mErrors.clear();
        GTEST_SUCCEED() << "setLayerDynamicPerFrameMetadata is not supported";
        return;
    }
}

/*
 * Test that if brightness operations are supported, setDisplayBrightness works as expected.
 */
TEST_P(GraphicsComposerHidlTest, setDisplayBrightness) {
    std::vector<IComposerClient::DisplayCapability> capabilities;
    const auto error = mComposerClient->getDisplayCapabilities(mPrimaryDisplay, &capabilities);
    ASSERT_EQ(Error::NONE, error);
    bool brightnessSupport =
            std::find(capabilities.begin(), capabilities.end(),
                      IComposerClient::DisplayCapability::BRIGHTNESS) != capabilities.end();
    if (!brightnessSupport) {
        EXPECT_EQ(mComposerClient->getRaw()->setDisplayBrightness(mPrimaryDisplay, 0.5f),
                  Error::UNSUPPORTED);
        GTEST_SUCCEED() << "Brightness operations are not supported";
        return;
    }

    EXPECT_EQ(mComposerClient->setDisplayBrightness(mPrimaryDisplay, 0.0f), Error::NONE);
    EXPECT_EQ(mComposerClient->setDisplayBrightness(mPrimaryDisplay, 0.5f), Error::NONE);
    EXPECT_EQ(mComposerClient->setDisplayBrightness(mPrimaryDisplay, 1.0f), Error::NONE);
    EXPECT_EQ(mComposerClient->setDisplayBrightness(mPrimaryDisplay, -1.0f), Error::NONE);

    EXPECT_EQ(mComposerClient->setDisplayBrightness(mPrimaryDisplay, +2.0f), Error::BAD_PARAMETER);
    EXPECT_EQ(mComposerClient->setDisplayBrightness(mPrimaryDisplay, -2.0f), Error::BAD_PARAMETER);
}

GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(GraphicsComposerHidlTest);
INSTANTIATE_TEST_SUITE_P(
        PerInstance, GraphicsComposerHidlTest,
        testing::ValuesIn(android::hardware::getAllHalInstanceNames(IComposer::descriptor)),
        android::hardware::PrintInstanceNameToString);

GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(GraphicsComposerHidlCommandTest);
INSTANTIATE_TEST_SUITE_P(
        PerInstance, GraphicsComposerHidlCommandTest,
        testing::ValuesIn(android::hardware::getAllHalInstanceNames(IComposer::descriptor)),
        android::hardware::PrintInstanceNameToString);

}  // namespace
}  // namespace vts
}  // namespace V2_3
}  // namespace composer
}  // namespace graphics
}  // namespace hardware
}  // namespace android

int main(int argc, char** argv) {
    ::testing::InitGoogleTest(&argc, argv);

    using namespace std::chrono_literals;
    if (!android::base::WaitForProperty("init.svc.surfaceflinger", "stopped", 10s)) {
        ALOGE("Failed to stop init.svc.surfaceflinger");
        return -1;
    }

    return RUN_ALL_TESTS();
}