Merge "Add Scrambling Status Monitor merchanism in Tuner 1.1"
diff --git a/tv/tuner/1.1/IFilter.hal b/tv/tuner/1.1/IFilter.hal
index 3ea4209..df736aa 100644
--- a/tv/tuner/1.1/IFilter.hal
+++ b/tv/tuner/1.1/IFilter.hal
@@ -81,4 +81,21 @@
      *         UNKNOWN_ERROR if failed for other reasons.
      */
     configureAvStreamType(AvStreamType avStreamType) generates (Result result);
+
+    /**
+     * Configure the filter to monitor specific Scrambling Status.
+     *
+     * Scrambling Status should be sent through the filer callback at the following two scenarios:
+     *   1. When this method is called, the first detected scrambling status should be sent.
+     *   2. When the filter transits into the monitored statuses configured through this method,
+     *      event should be sent.
+     *
+     * @param statuses Scrambling Statuses to monitor. Set corresponding bit to monitor. Reset to
+     *        stop monitoring.
+     * @return result Result status of the operation.
+     *         SUCCESS if successful,
+     *         INVALID_STATE if configure can't be applied,
+     *         UNKNOWN_ERROR if failed for other reasons.
+     */
+    configureScramblingEvent(bitfield<ScramblingStatus> statuses) generates (Result result);
 };
diff --git a/tv/tuner/1.1/default/Filter.cpp b/tv/tuner/1.1/default/Filter.cpp
index 54d515b..4c37729 100644
--- a/tv/tuner/1.1/default/Filter.cpp
+++ b/tv/tuner/1.1/default/Filter.cpp
@@ -249,6 +249,28 @@
     return Result::SUCCESS;
 }
 
+Return<Result> Filter::configureScramblingEvent(uint32_t statuses) {
+    ALOGV("%s", __FUNCTION__);
+
+    mStatuses = statuses;
+    if (mCallback_1_1 != nullptr) {
+        // Assuming current status is always NOT_SCRAMBLED
+        V1_1::DemuxFilterEventExt filterEventExt;
+        V1_1::DemuxFilterEventExt::Event event;
+        event.scramblingStatus(V1_1::ScramblingStatus::NOT_SCRAMBLED);
+        int size = filterEventExt.events.size();
+        filterEventExt.events.resize(size + 1);
+        filterEventExt.events[size] = event;
+        DemuxFilterEvent emptyFilterEvent;
+
+        mCallback_1_1->onFilterEvent_1_1(emptyFilterEvent, filterEventExt);
+        mFilterEventExt.events.resize(0);
+    } else {
+        return Result::INVALID_STATE;
+    }
+    return Result::SUCCESS;
+}
+
 bool Filter::createFilterMQ() {
     ALOGV("%s", __FUNCTION__);
 
diff --git a/tv/tuner/1.1/default/Filter.h b/tv/tuner/1.1/default/Filter.h
index f8b9a65..522db35 100644
--- a/tv/tuner/1.1/default/Filter.h
+++ b/tv/tuner/1.1/default/Filter.h
@@ -84,6 +84,8 @@
 
     virtual Return<Result> configureAvStreamType(const V1_1::AvStreamType& avStreamType) override;
 
+    virtual Return<Result> configureScramblingEvent(uint32_t statuses) override;
+
     /**
      * To create a FilterMQ and its Event Flag.
      *
@@ -230,6 +232,9 @@
 
     uint32_t mAudioStreamType;
     uint32_t mVideoStreamType;
+
+    // Scrambling status to be monitored
+    uint32_t mStatuses = 0;
 };
 
 }  // namespace implementation
diff --git a/tv/tuner/1.1/types.hal b/tv/tuner/1.1/types.hal
index 4e677b5..defc99b 100644
--- a/tv/tuner/1.1/types.hal
+++ b/tv/tuner/1.1/types.hal
@@ -125,6 +125,8 @@
         DemuxFilterRecordEventExt tsRecord;
 
         DemuxFilterRecordEventExt mmtpRecord;
+
+        ScramblingStatus scramblingStatus;
     };
 
     /**
@@ -133,6 +135,25 @@
     vec<Event> events;
 };
 
+/**
+ * Scrambling Status Type.
+ */
+@export
+enum ScramblingStatus : uint32_t {
+    /**
+     * Content’s scrambling status is unknown
+     */
+    UNKNOWN = 1 << 0,
+    /**
+     * Content is not scrambled.
+     */
+    NOT_SCRAMBLED = 1 << 1,
+    /**
+     * Content is scrambled.
+     */
+    SCRAMBLED = 1 << 2,
+};
+
 typedef FrontendDvbcSpectralInversion FrontendSpectralInversion;
 
 /**
diff --git a/tv/tuner/1.1/vts/functional/FilterTests.cpp b/tv/tuner/1.1/vts/functional/FilterTests.cpp
index f4ac8bf..f114a66 100644
--- a/tv/tuner/1.1/vts/functional/FilterTests.cpp
+++ b/tv/tuner/1.1/vts/functional/FilterTests.cpp
@@ -28,6 +28,18 @@
     ALOGW("[vts] pass and stop");
 }
 
+void FilterCallback::testFilterScramblingEvent() {
+    android::Mutex::Autolock autoLock(mMsgLock);
+    while (mScramblingStatusEvent < 1) {
+        if (-ETIMEDOUT == mMsgCondition.waitRelative(mMsgLock, WAIT_TIMEOUT)) {
+            EXPECT_TRUE(false) << "scrambling event does not output within timeout";
+            return;
+        }
+    }
+    mScramblingStatusEvent = 0;
+    ALOGW("[vts] pass and stop");
+}
+
 void FilterCallback::readFilterEventData() {
     ALOGW("[vts] reading filter event");
     // todo separate filter handlers
@@ -56,6 +68,9 @@
                       eventExt.mmtpRecord().pts, eventExt.mmtpRecord().firstMbInSlice,
                       eventExt.mmtpRecord().mpuSequenceNumber);
                 break;
+            case DemuxFilterEventExt::Event::hidl_discriminator::scramblingStatus:
+                mScramblingStatusEvent++;
+                break;
             default:
                 break;
         }
@@ -240,3 +255,19 @@
     }
     return AssertionResult(status == Result::SUCCESS);
 }
+
+AssertionResult FilterTests::configureScramblingEvent(uint64_t filterId, uint32_t statuses) {
+    EXPECT_TRUE(mFilters[filterId]) << "Test with getNewlyOpenedFilterId first.";
+    Result status;
+
+    sp<android::hardware::tv::tuner::V1_1::IFilter> filter_v1_1 =
+            android::hardware::tv::tuner::V1_1::IFilter::castFrom(mFilters[filterId]);
+    if (filter_v1_1 != NULL) {
+        status = filter_v1_1->configureScramblingEvent(statuses);
+        mFilterCallbacks[filterId]->testFilterScramblingEvent();
+    } else {
+        ALOGW("[vts] Can't cast IFilter into v1_1.");
+        return failure();
+    }
+    return AssertionResult(status == Result::SUCCESS);
+}
diff --git a/tv/tuner/1.1/vts/functional/FilterTests.h b/tv/tuner/1.1/vts/functional/FilterTests.h
index 3472e4e..d88f171 100644
--- a/tv/tuner/1.1/vts/functional/FilterTests.h
+++ b/tv/tuner/1.1/vts/functional/FilterTests.h
@@ -117,6 +117,7 @@
     void setMemSize(uint64_t size) { mAvSharedMemSize = size; }
 
     void testFilterDataOutput();
+    void testFilterScramblingEvent();
 
     void readFilterEventData();
     bool dumpAvData(DemuxFilterMediaEvent event);
@@ -136,6 +137,7 @@
     android::Condition mMsgCondition;
 
     int mPidFilterOutputCount = 0;
+    int mScramblingStatusEvent = 0;
 };
 
 class FilterTests {
@@ -153,6 +155,7 @@
     AssertionResult configFilter(DemuxFilterSettings setting, uint64_t filterId);
     AssertionResult configAvFilterStreamType(AvStreamType type, uint64_t filterId);
     AssertionResult configIpFilterCid(uint32_t ipCid, uint64_t filterId);
+    AssertionResult configureScramblingEvent(uint64_t filterId, uint32_t statuses);
     AssertionResult getFilterMQDescriptor(uint64_t filterId);
     AssertionResult startFilter(uint64_t filterId);
     AssertionResult stopFilter(uint64_t filterId);
diff --git a/tv/tuner/1.1/vts/functional/VtsHalTvTunerV1_1TargetTest.cpp b/tv/tuner/1.1/vts/functional/VtsHalTvTunerV1_1TargetTest.cpp
index 2185920..17abf49 100644
--- a/tv/tuner/1.1/vts/functional/VtsHalTvTunerV1_1TargetTest.cpp
+++ b/tv/tuner/1.1/vts/functional/VtsHalTvTunerV1_1TargetTest.cpp
@@ -46,6 +46,9 @@
     if (filterConf.type.mainType == DemuxFilterMainType::IP) {
         ASSERT_TRUE(mFilterTests.configIpFilterCid(filterConf.ipCid, filterId));
     }
+    if (filterConf.statuses > 0) {
+        ASSERT_TRUE(mFilterTests.configureScramblingEvent(filterId, filterConf.statuses));
+    }
     ASSERT_TRUE(mFilterTests.getFilterMQDescriptor(filterId));
     ASSERT_TRUE(mFilterTests.startFilter(filterId));
     ASSERT_TRUE(mFilterTests.stopFilter(filterId));
diff --git a/tv/tuner/1.1/vts/functional/VtsHalTvTunerV1_1TestConfigurations.h b/tv/tuner/1.1/vts/functional/VtsHalTvTunerV1_1TestConfigurations.h
index 911d984..76bf765 100644
--- a/tv/tuner/1.1/vts/functional/VtsHalTvTunerV1_1TestConfigurations.h
+++ b/tv/tuner/1.1/vts/functional/VtsHalTvTunerV1_1TestConfigurations.h
@@ -96,6 +96,7 @@
     DemuxFilterSettings settings;
     AvStreamType streamType;
     uint32_t ipCid;
+    uint32_t statuses;
 
     bool operator<(const FilterConfig& /*c*/) const { return false; }
 };
@@ -187,6 +188,7 @@
     filterArray[TS_VIDEO0].bufferSize = FMQ_SIZE_16M;
     filterArray[TS_VIDEO0].settings.ts().tpid = 256;
     filterArray[TS_VIDEO0].settings.ts().filterSettings.av({.isPassthrough = false});
+    filterArray[TS_VIDEO0].statuses = 1;
     filterArray[TS_VIDEO1].type.mainType = DemuxFilterMainType::TS;
     filterArray[TS_VIDEO1].type.subType.tsFilterType(DemuxTsFilterType::VIDEO);
     filterArray[TS_VIDEO1].bufferSize = FMQ_SIZE_16M;