Add APIs to allow sending a picture profile down to Composer HAL

Bug: 337330263
Test: atest GraphicsComposerAidlCommandV3Test
Change-Id: Icf82d7eaa856df13a8d96b52811be5225026604e
diff --git a/graphics/composer/aidl/vts/VtsComposerClient.cpp b/graphics/composer/aidl/vts/VtsComposerClient.cpp
index 89ba2e6..9b6a005 100644
--- a/graphics/composer/aidl/vts/VtsComposerClient.cpp
+++ b/graphics/composer/aidl/vts/VtsComposerClient.cpp
@@ -690,4 +690,10 @@
     mDisplayResources.clear();
     return true;
 }
+
+std::pair<ScopedAStatus, int32_t> VtsComposerClient::getMaxLayerPictureProfiles(int64_t display) {
+    int32_t outMaxProfiles = 0;
+    return {mComposerClient->getMaxLayerPictureProfiles(display, &outMaxProfiles), outMaxProfiles};
+}
+
 }  // namespace aidl::android::hardware::graphics::composer3::vts
diff --git a/graphics/composer/aidl/vts/VtsComposerClient.h b/graphics/composer/aidl/vts/VtsComposerClient.h
index da6116f..53f5fae 100644
--- a/graphics/composer/aidl/vts/VtsComposerClient.h
+++ b/graphics/composer/aidl/vts/VtsComposerClient.h
@@ -198,6 +198,8 @@
 
     std::vector<RefreshRateChangedDebugData> takeListOfRefreshRateChangedDebugData();
 
+    std::pair<ScopedAStatus, int32_t> getMaxLayerPictureProfiles(int64_t display);
+
     static constexpr int32_t kMaxFrameIntervalNs = 50000000;  // 20fps
     static constexpr int32_t kNoFrameIntervalNs = 0;
 
diff --git a/graphics/composer/aidl/vts/VtsHalGraphicsComposer3_TargetTest.cpp b/graphics/composer/aidl/vts/VtsHalGraphicsComposer3_TargetTest.cpp
index eaf23b5..106941e 100644
--- a/graphics/composer/aidl/vts/VtsHalGraphicsComposer3_TargetTest.cpp
+++ b/graphics/composer/aidl/vts/VtsHalGraphicsComposer3_TargetTest.cpp
@@ -31,6 +31,7 @@
 #include <gtest/gtest.h>
 #include <ui/Fence.h>
 #include <ui/GraphicBuffer.h>
+#include <ui/PictureProfileHandle.h>
 #include <ui/PixelFormat.h>
 #include <algorithm>
 #include <iterator>
@@ -118,6 +119,15 @@
                 [&](const Capability& activeCapability) { return activeCapability == capability; });
     }
 
+    bool hasDisplayCapability(int64_t displayId, DisplayCapability capability) {
+        const auto& [status, capabilities] = mComposerClient->getDisplayCapabilities(displayId);
+        EXPECT_TRUE(status.isOk());
+        return std::any_of(capabilities.begin(), capabilities.end(),
+                           [&](const DisplayCapability& activeCapability) {
+                               return activeCapability == capability;
+                           });
+    }
+
     int getInterfaceVersion() {
         const auto& [versionStatus, version] = mComposerClient->getInterfaceVersion();
         EXPECT_TRUE(versionStatus.isOk());
@@ -1388,6 +1398,14 @@
     }
 }
 
+TEST_P(GraphicsComposerAidlV3Test, GetMaxLayerPictureProfiles) {
+    for (const auto& display : mDisplays) {
+        const auto& [status, maxPorfiles] =
+                mComposerClient->getMaxLayerPictureProfiles(display.getDisplayId());
+        EXPECT_TRUE(status.isOk());
+    }
+}
+
 // Tests for Command.
 class GraphicsComposerAidlCommandTest : public GraphicsComposerAidlTest {
   protected:
@@ -2048,6 +2066,7 @@
     EXPECT_TRUE(layerStatus.isOk());
     writer.setLayerBuffer(getPrimaryDisplayId(), layer, /*slot*/ 0, handle, /*acquireFence*/ -1);
     execute();
+    ASSERT_TRUE(mReader.takeErrors().empty());
 }
 
 TEST_P(GraphicsComposerAidlCommandTest, SetLayerBufferMultipleTimes) {
@@ -3219,6 +3238,92 @@
     });
 }
 
+TEST_P(GraphicsComposerAidlCommandV3Test, getMaxLayerPictureProfiles_success) {
+    for (auto& display : mDisplays) {
+        int64_t displayId = display.getDisplayId();
+        if (!hasDisplayCapability(displayId, DisplayCapability::PICTURE_PROCESSING)) {
+            continue;
+        }
+        const auto& [status, maxProfiles] =
+                mComposerClient->getMaxLayerPictureProfiles(getPrimaryDisplayId());
+        EXPECT_TRUE(status.isOk());
+    }
+}
+
+TEST_P(GraphicsComposerAidlCommandV3Test, setDisplayPictureProfileId_success) {
+    for (auto& display : mDisplays) {
+        int64_t displayId = display.getDisplayId();
+        if (!hasDisplayCapability(displayId, DisplayCapability::PICTURE_PROCESSING)) {
+            continue;
+        }
+
+        auto& writer = getWriter(displayId);
+        const auto layer = createOnScreenLayer(display);
+        const auto buffer = allocate(::android::PIXEL_FORMAT_RGBA_8888);
+        ASSERT_NE(nullptr, buffer->handle);
+        // TODO(b/337330263): Lookup profile IDs from PictureProfileService
+        writer.setDisplayPictureProfileId(displayId, PictureProfileId(1));
+        writer.setLayerBuffer(displayId, layer, /*slot*/ 0, buffer->handle,
+                              /*acquireFence*/ -1);
+        execute();
+        ASSERT_TRUE(mReader.takeErrors().empty());
+    }
+}
+
+TEST_P(GraphicsComposerAidlCommandV3Test, setLayerPictureProfileId_success) {
+    for (auto& display : mDisplays) {
+        int64_t displayId = display.getDisplayId();
+        if (!hasDisplayCapability(displayId, DisplayCapability::PICTURE_PROCESSING)) {
+            continue;
+        }
+        const auto& [status, maxProfiles] = mComposerClient->getMaxLayerPictureProfiles(displayId);
+        EXPECT_TRUE(status.isOk());
+        if (maxProfiles == 0) {
+            continue;
+        }
+
+        auto& writer = getWriter(displayId);
+        const auto layer = createOnScreenLayer(display);
+        const auto buffer = allocate(::android::PIXEL_FORMAT_RGBA_8888);
+        ASSERT_NE(nullptr, buffer->handle);
+        writer.setLayerBuffer(displayId, layer, /*slot*/ 0, buffer->handle,
+                              /*acquireFence*/ -1);
+        // TODO(b/337330263): Lookup profile IDs from PictureProfileService
+        writer.setLayerPictureProfileId(displayId, layer, PictureProfileId(1));
+        execute();
+        ASSERT_TRUE(mReader.takeErrors().empty());
+    }
+}
+
+TEST_P(GraphicsComposerAidlCommandV3Test, setLayerPictureProfileId_failsWithTooManyProfiles) {
+    for (auto& display : mDisplays) {
+        int64_t displayId = display.getDisplayId();
+        if (!hasDisplayCapability(displayId, DisplayCapability::PICTURE_PROCESSING)) {
+            continue;
+        }
+        const auto& [status, maxProfiles] = mComposerClient->getMaxLayerPictureProfiles(displayId);
+        EXPECT_TRUE(status.isOk());
+        if (maxProfiles == 0) {
+            continue;
+        }
+
+        auto& writer = getWriter(displayId);
+        for (int profileId = 1; profileId <= maxProfiles + 1; ++profileId) {
+            const auto layer = createOnScreenLayer(display);
+            const auto buffer = allocate(::android::PIXEL_FORMAT_RGBA_8888);
+            ASSERT_NE(nullptr, buffer->handle);
+            writer.setLayerBuffer(displayId, layer, /*slot*/ 0, buffer->handle,
+                                  /*acquireFence*/ -1);
+            // TODO(b/337330263): Lookup profile IDs from PictureProfileService
+            writer.setLayerPictureProfileId(displayId, layer, PictureProfileId(profileId));
+        }
+        execute();
+        const auto errors = mReader.takeErrors();
+        ASSERT_TRUE(errors.size() == 1 &&
+                    errors[0].errorCode == IComposerClient::EX_PICTURE_PROFILE_MAX_EXCEEDED);
+    }
+}
+
 GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(GraphicsComposerAidlCommandTest);
 INSTANTIATE_TEST_SUITE_P(
         PerInstance, GraphicsComposerAidlCommandTest,