/*
 * 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.2"

#include <android-base/logging.h>
#include <android-base/properties.h>
#include <composer-vts/2.1/GraphicsComposerCallback.h>
#include <composer-vts/2.1/TestCommandReader.h>
#include <composer-vts/2.2/ComposerVts.h>
#include <gtest/gtest.h>
#include <hidl/GtestPrinter.h>
#include <hidl/ServiceManagement.h>
#include <ui/GraphicBuffer.h>

namespace android {
namespace hardware {
namespace graphics {
namespace composer {
namespace V2_2 {
namespace vts {
namespace {

using common::V1_0::BufferUsage;
using common::V1_1::ColorMode;
using common::V1_1::Dataspace;
using common::V1_1::PixelFormat;
using common::V1_1::RenderIntent;

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();

        Config config = mComposerClient->getActiveConfig(mPrimaryDisplay);
        mDisplayWidth = mComposerClient->getDisplayAttribute(mPrimaryDisplay, config,
                                                             IComposerClient::Attribute::WIDTH);
        mDisplayHeight = mComposerClient->getDisplayAttribute(mPrimaryDisplay, config,
                                                              IComposerClient::Attribute::HEIGHT);

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

        mComposerClient->getRaw()->getReadbackBufferAttributes(
                mPrimaryDisplay,
                [&](const auto& tmpError, const auto& tmpPixelFormat, const auto& tmpDataspace) {
                    mHasReadbackBuffer = tmpError == Error::NONE;
                    if (mHasReadbackBuffer) {
                        mReadbackPixelFormat = tmpPixelFormat;
                        mReadbackDataspace = tmpDataspace;
                        ASSERT_LT(static_cast<PixelFormat>(0), mReadbackPixelFormat);
                        ASSERT_NE(Dataspace::UNKNOWN, mReadbackDataspace);
                    }
                });

        mInvalidDisplayId = GetInvalidDisplayId();
    }

    void TearDown() override {
        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;
    }

    // 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;
    int32_t mDisplayWidth;
    int32_t mDisplayHeight;

    bool mHasReadbackBuffer;

    uint64_t mInvalidDisplayId;
    PixelFormat mReadbackPixelFormat;
    Dataspace mReadbackDataspace;

   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::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::getPerFrameMetadataKeys.
 */
TEST_P(GraphicsComposerHidlTest, GetPerFrameMetadataKeys) {
    std::vector<IComposerClient::PerFrameMetadataKey> keys;
    Error error = Error::NONE;
    mComposerClient->getRaw()->getPerFrameMetadataKeys(
            mPrimaryDisplay, [&](const auto& tmpError, const auto& tmpKeys) {
                error = tmpError;
                keys = tmpKeys;
            });
    if (error == Error::UNSUPPORTED) {
        GTEST_SUCCEED() << "getPerFrameMetadataKeys is not supported";
        return;
    }
    ASSERT_EQ(Error::NONE, error);
    ASSERT_TRUE(keys.size() >= 0);
}

/**
 * Test IComposerClient::createVirtualDisplay_2_2 and
 * IComposerClient::destroyVirtualDisplay.
 *
 * Test that virtual displays can be created and has the correct display type.
 */
TEST_P(GraphicsComposerHidlTest, CreateVirtualDisplay_2_2) {
    if (mComposerClient->getMaxVirtualDisplayCount() == 0) {
        GTEST_SUCCEED() << "no virtual display support";
        return;
    }

    Display display;
    PixelFormat format;
    ASSERT_NO_FATAL_FAILURE(
        display = mComposerClient->createVirtualDisplay_2_2(
            64, 64, PixelFormat::IMPLEMENTATION_DEFINED, kBufferSlotCount, &format));

    // test display type
    IComposerClient::DisplayType type = mComposerClient->getDisplayType(display);
    EXPECT_EQ(IComposerClient::DisplayType::VIRTUAL, type);

    mComposerClient->destroyVirtualDisplay(display);
}

/**
 * Test IComposerClient::getClientTargetSupport_2_2.
 *
 * Test that IComposerClient::getClientTargetSupport returns true for the
 * required client targets.
 */
TEST_P(GraphicsComposerHidlTest, GetClientTargetSupport_2_2) {
    ASSERT_NO_FATAL_FAILURE(
            mComposerClient->setPowerMode_2_2(mPrimaryDisplay, IComposerClient::PowerMode::ON));
    std::vector<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_2(
            mPrimaryDisplay, width, height, PixelFormat::RGBA_8888, Dataspace::UNKNOWN));
    }
}

/**
 * Test IComposerClient::getClientTargetSupport_2_2
 *
 * Test that IComposerClient::getClientTargetSupport_2_2 returns
 * Error::BAD_DISPLAY when passed in an invalid display handle
 */

TEST_P(GraphicsComposerHidlTest, GetClientTargetSupport_2_2BadDisplay) {
    std::vector<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_2(
            mInvalidDisplayId, width, height, PixelFormat::RGBA_8888, Dataspace::UNKNOWN);

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

/**
 * Test IComposerClient::setPowerMode_2_2.
 */
TEST_P(GraphicsComposerHidlTest, SetPowerMode_2_2) {
    std::vector<IComposerClient::PowerMode> modes;
    modes.push_back(IComposerClient::PowerMode::OFF);
    modes.push_back(IComposerClient::PowerMode::ON_SUSPEND);
    modes.push_back(IComposerClient::PowerMode::ON);

    for (auto mode : modes) {
        mComposerClient->setPowerMode_2_2(mPrimaryDisplay, mode);
    }
}

/**
 * Test IComposerClient::setPowerMode_2_2
 *
 * Test that IComposerClient::setPowerMode_2_2 succeeds for different varations
 * of PowerMode
 */
TEST_P(GraphicsComposerHidlTest, SetPowerMode_2_2Variations) {
    std::vector<IComposerClient::PowerMode> modes;

    modes.push_back(IComposerClient::PowerMode::OFF);
    modes.push_back(IComposerClient::PowerMode::OFF);

    for (auto mode : modes) {
        ASSERT_NO_FATAL_FAILURE(mComposerClient->setPowerMode_2_2(mPrimaryDisplay, mode));
    }

    modes.clear();

    modes.push_back(IComposerClient::PowerMode::ON);
    modes.push_back(IComposerClient::PowerMode::ON);

    for (auto mode : modes) {
        ASSERT_NO_FATAL_FAILURE(mComposerClient->setPowerMode_2_2(mPrimaryDisplay, mode));
    }

    modes.clear();

    modes.push_back(IComposerClient::PowerMode::ON_SUSPEND);
    modes.push_back(IComposerClient::PowerMode::ON_SUSPEND);

    for (auto mode : modes) {
        ASSERT_NO_FATAL_FAILURE(mComposerClient->setPowerMode_2_2(mPrimaryDisplay, mode));
    }

    if (mComposerClient->getDozeSupport(mPrimaryDisplay)) {
        modes.clear();

        modes.push_back(IComposerClient::PowerMode::DOZE);
        modes.push_back(IComposerClient::PowerMode::DOZE);

        for (auto mode : modes) {
            ASSERT_NO_FATAL_FAILURE(mComposerClient->setPowerMode_2_2(mPrimaryDisplay, mode));
        }

        modes.clear();

        modes.push_back(IComposerClient::PowerMode::DOZE_SUSPEND);
        modes.push_back(IComposerClient::PowerMode::DOZE_SUSPEND);

        for (auto mode : modes) {
            ASSERT_NO_FATAL_FAILURE(mComposerClient->setPowerMode_2_2(mPrimaryDisplay, mode));
        }
    }
}

/**
 * Test IComposerClient::setPowerMode_2_2
 *
 * Tests that IComposerClient::setPowerMode_2_2 returns BAD_DISPLAY when passed an
 * invalid display handle
 */
TEST_P(GraphicsComposerHidlTest, SetPowerMode_2_2BadDisplay) {
    Error error = mComposerClient->getRaw()->setPowerMode_2_2(mInvalidDisplayId,
                                                              IComposerClient::PowerMode::ON);
    ASSERT_EQ(Error::BAD_DISPLAY, error);
}

/**
 * Test IComposerClient::setPowerMode_2_2
 *
 * Test that IComposerClient::setPowerMode_2_2 returns BAD_PARAMETER when passed
 * an invalid PowerMode
 */
TEST_P(GraphicsComposerHidlTest, SetPowerMode_2_2BadParameter) {
    Error error = mComposerClient->getRaw()->setPowerMode_2_2(
        mPrimaryDisplay, static_cast<IComposerClient::PowerMode>(-1));
    ASSERT_EQ(Error::BAD_PARAMETER, error);
}

/**
 * Test IComposerClient::setPowerMode_2_2
 *
 * Test that IComposerClient::setPowerMode_2_2 returns UNSUPPORTED when passed
 * DOZE or DOZE_SUPPORT on a device that does not support these modes
 */
TEST_P(GraphicsComposerHidlTest, SetPowerMode_2_2Unsupported) {
    if (!mComposerClient->getDozeSupport(mPrimaryDisplay)) {
        Error error = mComposerClient->getRaw()->setPowerMode_2_2(mPrimaryDisplay,
                                                                  IComposerClient::PowerMode::DOZE);
        EXPECT_EQ(Error::UNSUPPORTED, error);

        error = mComposerClient->getRaw()->setPowerMode_2_2(
            mPrimaryDisplay, IComposerClient::PowerMode::DOZE_SUSPEND);
        EXPECT_EQ(Error::UNSUPPORTED, error);
    }
}

/**
 * Test IComposerClient::setReadbackBuffer
 *
 * Test IComposerClient::setReadbackBuffer
 */
TEST_P(GraphicsComposerHidlTest, SetReadbackBuffer) {
    if (!mHasReadbackBuffer) {
        return;
    }

    // BufferUsage::COMPOSER_OUTPUT is missing
    uint64_t usage =
            static_cast<uint64_t>(BufferUsage::COMPOSER_OVERLAY | BufferUsage::CPU_READ_OFTEN);

    sp<GraphicBuffer> buffer = sp<GraphicBuffer>::make(mDisplayWidth, mDisplayHeight,
                                                       (int32_t)mReadbackPixelFormat, 1, usage);
    ASSERT_EQ(STATUS_OK, buffer->initCheck());

    mComposerClient->setReadbackBuffer(mPrimaryDisplay, buffer->handle, -1);
}

/**
 * Test IComposerClient::setReadbackBuffer
 *
 * Test that IComposerClient::setReadbackBuffer returns an Error::BAD_DISPLAY
 * when passed an invalid display handle
 */
TEST_P(GraphicsComposerHidlTest, SetReadbackBufferBadDisplay) {
    if (!mHasReadbackBuffer) {
        return;
    }

    uint64_t usage =
            static_cast<uint64_t>(BufferUsage::COMPOSER_OVERLAY | BufferUsage::CPU_READ_OFTEN);

    sp<GraphicBuffer> buffer = sp<GraphicBuffer>::make(mDisplayWidth, mDisplayHeight,
                                                       (int32_t)mReadbackPixelFormat, 1, usage);
    ASSERT_EQ(STATUS_OK, buffer->initCheck());

    Error error = mComposerClient->getRaw()->setReadbackBuffer(mInvalidDisplayId, buffer->handle,
                                                               nullptr);
    ASSERT_EQ(Error::BAD_DISPLAY, error);
}

/**
 * Test IComposerClient::setReadbackBuffer
 *
 * Test that IComposerClient::setReadbackBuffer returns Error::BAD_PARAMETER
 * when passed an invalid buffer handle
 */
TEST_P(GraphicsComposerHidlTest, SetReadbackBufferBadParameter) {
    if (!mHasReadbackBuffer) {
        return;
    }

    Error error = mComposerClient->getRaw()->setReadbackBuffer(mPrimaryDisplay, nullptr, nullptr);
    ASSERT_EQ(Error::BAD_PARAMETER, error);
}

TEST_P(GraphicsComposerHidlTest, GetReadbackBufferFenceInactive) {
    if (!mHasReadbackBuffer) {
        return;
    }

    mComposerClient->getRaw()->getReadbackBufferFence(
        mPrimaryDisplay, [&](const auto& tmpError, const auto&) {
            ASSERT_EQ(Error::UNSUPPORTED, tmpError) << "readback buffer is active";
        });
}

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

    mWriter->selectDisplay(mPrimaryDisplay);
    mWriter->selectLayer(layer);
    mWriter->setLayerCompositionType(IComposerClient::Composition::SOLID_COLOR);
    mWriter->setLayerFloatColor(IComposerClient::FloatColor{1.0, 1.0, 1.0, 1.0});
    mWriter->setLayerFloatColor(IComposerClient::FloatColor{0.0, 0.0, 0.0, 0.0});
    execute();

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

    // ensure setting float color on layer with composition type that is not
    // SOLID_COLOR does not fail
    V2_1::Layer clientLayer;
    ASSERT_NO_FATAL_FAILURE(clientLayer =
                                mComposerClient->createLayer(mPrimaryDisplay, kBufferSlotCount));
    mWriter->selectDisplay(mPrimaryDisplay);
    mWriter->selectLayer(clientLayer);
    mWriter->setLayerCompositionType(IComposerClient::Composition::CLIENT);
    mWriter->setLayerFloatColor(IComposerClient::FloatColor{1.0, 1.0, 1.0, 1.0});
    execute();

    // At this point we know that this function is supported so there should be
    // no errors (checked upon TearDown)
}

/**
 * Test IComposerClient::getDataspaceSaturationMatrix.
 */
TEST_P(GraphicsComposerHidlTest, GetDataspaceSaturationMatrix) {
    auto matrix = mComposerClient->getDataspaceSaturationMatrix(Dataspace::SRGB_LINEAR);
    // the last row is known
    ASSERT_EQ(0.0f, matrix[12]);
    ASSERT_EQ(0.0f, matrix[13]);
    ASSERT_EQ(0.0f, matrix[14]);
    ASSERT_EQ(1.0f, matrix[15]);
}

/*
 * Test IComposerClient::getDataspaceSaturationMatrix
 *
 * Test that IComposerClient::getDataspaceSaturationMatrix returns
 * Error::BAD_PARAMETER when passed a dataspace other than
 * Dataspace::SRGB_LINEAR
 */
TEST_P(GraphicsComposerHidlTest, GetDataspaceSaturationMatrixBadParameter) {
    mComposerClient->getRaw()->getDataspaceSaturationMatrix(
        Dataspace::UNKNOWN,
        [&](const auto& tmpError, const auto&) { ASSERT_EQ(Error::BAD_PARAMETER, tmpError); });
}

/**
 * Test IComposerClient::getColorMode_2_2.
 */
TEST_P(GraphicsComposerHidlTest, GetColorMode_2_2) {
    std::vector<ColorMode> modes = mComposerClient->getColorModes(mPrimaryDisplay);

    auto nativeMode = std::find(modes.cbegin(), modes.cend(), ColorMode::NATIVE);
    EXPECT_NE(modes.cend(), nativeMode);
}

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

/**
 * Test IComposerClient::getRenderIntents.
 */
TEST_P(GraphicsComposerHidlTest, GetRenderIntents) {
    std::vector<ColorMode> modes = mComposerClient->getColorModes(mPrimaryDisplay);
    for (auto mode : modes) {
        std::vector<RenderIntent> intents =
            mComposerClient->getRenderIntents(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
 *
 * Test that IComposerClient::getRenderIntent returns Error::BAD_DISPLAY when
 * passed an invalid display handle
 */
TEST_P(GraphicsComposerHidlTest, GetRenderIntentsBadDisplay) {
    std::vector<ColorMode> modes = mComposerClient->getColorModes(mPrimaryDisplay);
    for (auto mode : modes) {
        mComposerClient->getRaw()->getRenderIntents(
            mInvalidDisplayId, mode,
            [&](const auto& tmpError, const auto&) { EXPECT_EQ(Error::BAD_DISPLAY, tmpError); });
    }
}

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

/**
 * Test IComposerClient::setColorMode_2_2.
 */
TEST_P(GraphicsComposerHidlTest, SetColorMode_2_2) {
    std::vector<ColorMode> modes = mComposerClient->getColorModes(mPrimaryDisplay);
    for (auto mode : modes) {
        std::vector<RenderIntent> intents =
            mComposerClient->getRenderIntents(mPrimaryDisplay, mode);
        for (auto intent : intents) {
            mComposerClient->setColorMode(mPrimaryDisplay, mode, intent);
        }
    }

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

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

    ASSERT_EQ(Error::BAD_DISPLAY, error);
}

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

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

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_2
}  // 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();
}
