Merge "Fix inconsistencies in VehicleArea HAL documentation" into udc-dev
diff --git a/automotive/evs/aidl/vts/VtsHalEvsTargetTest.cpp b/automotive/evs/aidl/vts/VtsHalEvsTargetTest.cpp
index 2706c49..60adf93 100644
--- a/automotive/evs/aidl/vts/VtsHalEvsTargetTest.cpp
+++ b/automotive/evs/aidl/vts/VtsHalEvsTargetTest.cpp
@@ -51,6 +51,7 @@
 #include <ui/GraphicBufferAllocator.h>
 #include <utils/Timers.h>
 
+#include <chrono>
 #include <deque>
 #include <thread>
 #include <unordered_set>
@@ -2197,6 +2198,159 @@
     }
 }
 
+/*
+ * DisplayOpen:
+ * Test both clean shut down and "aggressive open" device stealing behavior.
+ */
+TEST_P(EvsAidlTest, DisplayOpen) {
+    LOG(INFO) << "Starting DisplayOpen test";
+
+    // Request available display IDs.
+    std::vector<uint8_t> displayIds;
+    ASSERT_TRUE(mEnumerator->getDisplayIdList(&displayIds).isOk());
+    EXPECT_GT(displayIds.size(), 0);
+
+    for (const auto displayId : displayIds) {
+        std::shared_ptr<IEvsDisplay> pDisplay;
+
+        // Request exclusive access to each EVS display, then let it go.
+        ASSERT_TRUE(mEnumerator->openDisplay(displayId, &pDisplay).isOk());
+        ASSERT_NE(pDisplay, nullptr);
+
+        {
+            // Ask the display what its name is.
+            DisplayDesc desc;
+            ASSERT_TRUE(pDisplay->getDisplayInfo(&desc).isOk());
+            LOG(DEBUG) << "Found display " << desc.id;
+        }
+
+        ASSERT_TRUE(mEnumerator->closeDisplay(pDisplay).isOk());
+
+        // Ensure we can reopen the display after it has been closed.
+        ASSERT_TRUE(mEnumerator->openDisplay(displayId, &pDisplay).isOk());
+        ASSERT_NE(pDisplay, nullptr);
+
+        // Open the display while its already open -- ownership should be transferred.
+        std::shared_ptr<IEvsDisplay> pDisplay2;
+        ASSERT_TRUE(mEnumerator->openDisplay(displayId, &pDisplay2).isOk());
+        ASSERT_NE(pDisplay2, nullptr);
+
+        {
+            // Ensure the old display properly reports its assassination.
+            DisplayState badState;
+            EXPECT_TRUE(pDisplay->getDisplayState(&badState).isOk());
+            EXPECT_EQ(badState, DisplayState::DEAD);
+        }
+
+        // Close only the newest display instance -- the other should already be a zombie.
+        ASSERT_TRUE(mEnumerator->closeDisplay(pDisplay2).isOk());
+
+        // Finally, validate that we can open the display after the provoked failure above.
+        ASSERT_TRUE(mEnumerator->openDisplay(displayId, &pDisplay).isOk());
+        ASSERT_NE(pDisplay, nullptr);
+        ASSERT_TRUE(mEnumerator->closeDisplay(pDisplay).isOk());
+    }
+}
+
+/*
+ * DisplayStates:
+ * Validate that display states transition as expected and can be queried from either the display
+ * object itself or the owning enumerator.
+ */
+TEST_P(EvsAidlTest, DisplayStates) {
+    using std::literals::chrono_literals::operator""ms;
+
+    LOG(INFO) << "Starting DisplayStates test";
+
+    // Request available display IDs.
+    std::vector<uint8_t> displayIds;
+    ASSERT_TRUE(mEnumerator->getDisplayIdList(&displayIds).isOk());
+    EXPECT_GT(displayIds.size(), 0);
+
+    for (const auto displayId : displayIds) {
+        // Ensure the display starts in the expected state.
+        {
+            DisplayState state;
+            EXPECT_FALSE(mEnumerator->getDisplayState(&state).isOk());
+        }
+
+        // Scope to limit the lifetime of the pDisplay pointer, and thus the IEvsDisplay object.
+        {
+            // Request exclusive access to the EVS display.
+            std::shared_ptr<IEvsDisplay> pDisplay;
+            ASSERT_TRUE(mEnumerator->openDisplay(displayId, &pDisplay).isOk());
+            ASSERT_NE(pDisplay, nullptr);
+            {
+                DisplayState state;
+                EXPECT_TRUE(mEnumerator->getDisplayState(&state).isOk());
+                EXPECT_EQ(state, DisplayState::NOT_VISIBLE);
+            }
+
+            // Activate the display.
+            EXPECT_TRUE(pDisplay->setDisplayState(DisplayState::VISIBLE_ON_NEXT_FRAME).isOk());
+            {
+                DisplayState state;
+                EXPECT_TRUE(mEnumerator->getDisplayState(&state).isOk());
+                EXPECT_EQ(state, DisplayState::VISIBLE_ON_NEXT_FRAME);
+            }
+            {
+                DisplayState state;
+                EXPECT_TRUE(pDisplay->getDisplayState(&state).isOk());
+                EXPECT_EQ(state, DisplayState::VISIBLE_ON_NEXT_FRAME);
+            }
+
+            // Get the output buffer we'd use to display the imagery.
+            BufferDesc tgtBuffer;
+            ASSERT_TRUE(pDisplay->getTargetBuffer(&tgtBuffer).isOk());
+
+            // Send the target buffer back for display (we didn't actually fill anything).
+            EXPECT_TRUE(pDisplay->returnTargetBufferForDisplay(tgtBuffer).isOk());
+
+            // Sleep for a tenth of a second to ensure the driver has time to get the image
+            // displayed.
+            std::this_thread::sleep_for(100ms);
+            {
+                DisplayState state;
+                EXPECT_TRUE(mEnumerator->getDisplayState(&state).isOk());
+                EXPECT_EQ(state, DisplayState::VISIBLE);
+            }
+            {
+                DisplayState state;
+                EXPECT_TRUE(pDisplay->getDisplayState(&state).isOk());
+                EXPECT_EQ(state, DisplayState::VISIBLE);
+            }
+
+            // Turn off the display.
+            EXPECT_TRUE(pDisplay->setDisplayState(DisplayState::NOT_VISIBLE).isOk());
+            std::this_thread::sleep_for(100ms);
+            {
+                DisplayState state;
+                EXPECT_TRUE(mEnumerator->getDisplayState(&state).isOk());
+                EXPECT_EQ(state, DisplayState::NOT_VISIBLE);
+            }
+            {
+                DisplayState state;
+                EXPECT_TRUE(pDisplay->getDisplayState(&state).isOk());
+                EXPECT_EQ(state, DisplayState::NOT_VISIBLE);
+            }
+
+            // Close the display.
+            mEnumerator->closeDisplay(pDisplay);
+        }
+
+        // Now that the display pointer has gone out of scope, causing the IEvsDisplay interface
+        // object to be destroyed, we should be back to the "not open" state.
+        // NOTE:  If we want this to pass without the sleep above, we'd have to add the
+        //        (now recommended) closeDisplay() call instead of relying on the smarter pointer
+        //        going out of scope.  I've not done that because I want to verify that the deletion
+        //        of the object does actually clean up (eventually).
+        {
+            DisplayState state;
+            EXPECT_FALSE(mEnumerator->getDisplayState(&state).isOk());
+        }
+    }
+}
+
 GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(EvsAidlTest);
 INSTANTIATE_TEST_SUITE_P(
         PerInstance, EvsAidlTest,