Implement program list fetching.

Bug: 69860743
Test: VTS
Change-Id: I04eb43c1e0e1bb7bad86e123594a473454eed983
diff --git a/broadcastradio/2.0/vts/functional/VtsHalBroadcastradioV2_0TargetTest.cpp b/broadcastradio/2.0/vts/functional/VtsHalBroadcastradioV2_0TargetTest.cpp
index d0e4144..46b3f19 100644
--- a/broadcastradio/2.0/vts/functional/VtsHalBroadcastradioV2_0TargetTest.cpp
+++ b/broadcastradio/2.0/vts/functional/VtsHalBroadcastradioV2_0TargetTest.cpp
@@ -38,6 +38,7 @@
 
 using namespace std::chrono_literals;
 
+using std::unordered_set;
 using std::vector;
 using testing::_;
 using testing::AnyNumber;
@@ -54,6 +55,7 @@
 namespace timeout {
 
 static constexpr auto tune = 30s;
+static constexpr auto programListScan = 5min;
 
 }  // namespace timeout
 
@@ -63,16 +65,20 @@
     ConfigFlag::DAB_HARD_LINKING, ConfigFlag::DAB_SOFT_LINKING,
 };
 
-struct TunerCallbackMock : public ITunerCallback {
-    TunerCallbackMock() {
-        // we expect the antenna is connected through the whole test
-        EXPECT_CALL(*this, onAntennaStateChange(false)).Times(0);
-    }
+class TunerCallbackMock : public ITunerCallback {
+   public:
+    TunerCallbackMock();
 
     MOCK_METHOD2(onTuneFailed, Return<void>(Result, const ProgramSelector&));
     MOCK_TIMEOUT_METHOD1(onCurrentProgramInfoChanged, Return<void>(const ProgramInfo&));
+    Return<void> onProgramListUpdated(const ProgramListChunk& chunk);
     MOCK_METHOD1(onAntennaStateChange, Return<void>(bool connected));
     MOCK_METHOD1(onParametersUpdated, Return<void>(const hidl_vec<VendorKeyValue>& parameters));
+
+    MOCK_TIMEOUT_METHOD0(onProgramListReady, void());
+
+    std::mutex mLock;
+    utils::ProgramInfoSet mProgramList;
 };
 
 class BroadcastRadioHalTest : public ::testing::VtsHalHidlTargetTestBase {
@@ -88,6 +94,25 @@
     sp<TunerCallbackMock> mCallback = new TunerCallbackMock();
 };
 
+static void printSkipped(std::string msg) {
+    std::cout << "[  SKIPPED ] " << msg << std::endl;
+}
+
+TunerCallbackMock::TunerCallbackMock() {
+    // we expect the antenna is connected through the whole test
+    EXPECT_CALL(*this, onAntennaStateChange(false)).Times(0);
+}
+
+Return<void> TunerCallbackMock::onProgramListUpdated(const ProgramListChunk& chunk) {
+    std::lock_guard<std::mutex> lk(mLock);
+
+    updateProgramList(mProgramList, chunk);
+
+    if (chunk.complete) onProgramListReady();
+
+    return {};
+}
+
 void BroadcastRadioHalTest::SetUp() {
     EXPECT_EQ(nullptr, mModule.get()) << "Module is already open";
 
@@ -463,6 +488,32 @@
     }
 }
 
+/**
+ * Test getting program list.
+ *
+ * Verifies that:
+ * - startProgramListUpdates either succeeds or returns NOT_SUPPORTED;
+ * - the complete list is fetched within timeout::programListScan;
+ * - stopProgramListUpdates does not crash.
+ */
+TEST_F(BroadcastRadioHalTest, GetProgramList) {
+    ASSERT_TRUE(openSession());
+
+    EXPECT_TIMEOUT_CALL(*mCallback, onProgramListReady).Times(AnyNumber());
+
+    auto startResult = mSession->startProgramListUpdates({});
+    if (startResult == Result::NOT_SUPPORTED) {
+        printSkipped("Program list not supported");
+        return;
+    }
+    ASSERT_EQ(Result::OK, startResult);
+
+    EXPECT_TIMEOUT_CALL_WAIT(*mCallback, onProgramListReady, timeout::programListScan);
+
+    auto stopResult = mSession->stopProgramListUpdates();
+    EXPECT_TRUE(stopResult.isOk());
+}
+
 }  // namespace vts
 }  // namespace V2_0
 }  // namespace broadcastradio