Merge "Revert "Revert "Add monitor for ip cid change"""
diff --git a/tv/tuner/1.1/IFilter.hal b/tv/tuner/1.1/IFilter.hal
index 1c6c33f..1e94114 100644
--- a/tv/tuner/1.1/IFilter.hal
+++ b/tv/tuner/1.1/IFilter.hal
@@ -85,19 +85,23 @@
     configureAvStreamType(AvStreamType avStreamType) generates (Result result);
 
     /**
-     * Configure the filter to monitor specific Scrambling Status.
+     * Configure the monitor event.
      *
-     * Scrambling Status should be sent through the filer callback at the following two scenarios:
+     * The event for Scrambling Status should be sent 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.
+     *   2. When the Scrambling status transits into different status, event should be sent.
      *
-     * @param statuses Scrambling Statuses to monitor. Set corresponding bit to monitor. Reset to
-     *        stop monitoring.
+     * The event for IP CID change should be sent at the following two scenarios:
+     *   1. When this method is called, the first detected CID for the IP should be sent.
+     *   2. When the CID is changed to different value for the IP filter, event should be sent.
+     *
+     * @param monitorEventypes the events to monitor. Set corresponding bit of the event 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.
+     *                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);
+    configureMonitorEvent(bitfield<DemuxFilterMonitorEventType> monitorEventTypes)
+            generates (Result result);
 };
diff --git a/tv/tuner/1.1/default/Filter.cpp b/tv/tuner/1.1/default/Filter.cpp
index e766a8a..4fa1746 100644
--- a/tv/tuner/1.1/default/Filter.cpp
+++ b/tv/tuner/1.1/default/Filter.cpp
@@ -250,25 +250,49 @@
     return Result::SUCCESS;
 }
 
-Return<Result> Filter::configureScramblingEvent(uint32_t statuses) {
+Return<Result> Filter::configureMonitorEvent(uint32_t monitorEventTypes) {
     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;
+    DemuxFilterEvent emptyFilterEvent;
+    V1_1::DemuxFilterMonitorEvent monitorEvent;
+    V1_1::DemuxFilterEventExt eventExt;
 
-        mCallback_1_1->onFilterEvent_1_1(emptyFilterEvent, filterEventExt);
-        mFilterEventExt.events.resize(0);
-    } else {
-        return Result::INVALID_STATE;
+    uint32_t newScramblingStatus =
+            monitorEventTypes & V1_1::DemuxFilterMonitorEventType::SCRAMBLING_STATUS;
+    uint32_t newIpCid = monitorEventTypes & V1_1::DemuxFilterMonitorEventType::IP_CID_CHANGE;
+
+    // if scrambling status monitoring flipped, record the new state and send msg on enabling
+    if (newScramblingStatus ^ mScramblingStatusMonitored) {
+        mScramblingStatusMonitored = newScramblingStatus;
+        if (mScramblingStatusMonitored) {
+            if (mCallback_1_1 != nullptr) {
+                // Assuming current status is always NOT_SCRAMBLED
+                monitorEvent.scramblingStatus(V1_1::ScramblingStatus::NOT_SCRAMBLED);
+                eventExt.events.resize(1);
+                eventExt.events[0].monitorEvent(monitorEvent);
+                mCallback_1_1->onFilterEvent_1_1(emptyFilterEvent, eventExt);
+            } else {
+                return Result::INVALID_STATE;
+            }
+        }
     }
+
+    // if ip cid monitoring flipped, record the new state and send msg on enabling
+    if (newIpCid ^ mIpCidMonitored) {
+        mIpCidMonitored = newIpCid;
+        if (mIpCidMonitored) {
+            if (mCallback_1_1 != nullptr) {
+                // Return random cid
+                monitorEvent.cid(1);
+                eventExt.events.resize(1);
+                eventExt.events[0].monitorEvent(monitorEvent);
+                mCallback_1_1->onFilterEvent_1_1(emptyFilterEvent, eventExt);
+            } else {
+                return Result::INVALID_STATE;
+            }
+        }
+    }
+
     return Result::SUCCESS;
 }
 
diff --git a/tv/tuner/1.1/default/Filter.h b/tv/tuner/1.1/default/Filter.h
index 1ebc135..3a4246e 100644
--- a/tv/tuner/1.1/default/Filter.h
+++ b/tv/tuner/1.1/default/Filter.h
@@ -84,7 +84,7 @@
 
     virtual Return<Result> configureAvStreamType(const V1_1::AvStreamType& avStreamType) override;
 
-    virtual Return<Result> configureScramblingEvent(uint32_t statuses) override;
+    virtual Return<Result> configureMonitorEvent(uint32_t monitorEventTypes) override;
 
     /**
      * To create a FilterMQ and its Event Flag.
@@ -238,6 +238,8 @@
 
     bool mConfigured = false;
     int mStartId = 0;
+    uint8_t mScramblingStatusMonitored = 0;
+    uint8_t mIpCidMonitored = 0;
 };
 
 }  // namespace implementation
diff --git a/tv/tuner/1.1/types.hal b/tv/tuner/1.1/types.hal
index 09b87f2..938cb6e 100644
--- a/tv/tuner/1.1/types.hal
+++ b/tv/tuner/1.1/types.hal
@@ -151,22 +151,42 @@
 struct DemuxFilterEventExt {
     safe_union Event {
         /**
-         * No extended record filter Event. This is used by the tsRecord or mmtpRecord filter event
-         * that does not contain the DemuxFilterTs/MmtpRecordEventExt information.
+         * No extended filter Event.
          */
         Monostate noinit;
 
+        /**
+         * Extended TS Record event sent along with @1.0::DemuxFilterEvent::Event::tsRecord.
+         * DemuxFilterEventExt.events[i] is corresponding to @1.0::DemuxFilterEvent.events[i]. If
+         * @1.0::DemuxFilterEvent.events[i] does not have extended event,
+         * DemuxFilterEventExt.events[i] should use Monostate.
+         */
         DemuxFilterTsRecordEventExt tsRecord;
 
+        /**
+         * Extended MMTP Record event sent along with @1.0::DemuxFilterEvent::Event::mmtpRecord.
+         * DemuxFilterEventExt.events[i] is corresponding to @1.0::DemuxFilterEvent.events[i]. If
+         * @1.0::DemuxFilterEvent.events[i] does not have extended event,
+         * DemuxFilterEventExt.events[i] should use Monostate.
+         */
         DemuxFilterMmtpRecordEventExt mmtpRecord;
 
-        ScramblingStatus scramblingStatus;
+        /**
+         * Monitor event to notify monitored status change.
+         *
+         * When sending monitorEvent, DemuxFilterEventExt.events should only contain one
+         * monitorEvent. MonitorEvent should be sent with an empty @1.0::DemuxFilterEvent.
+         */
+        DemuxFilterMonitorEvent monitorEvent;
 
         /**
          * An unique ID to mark the start point of receiving the valid filter events after
          * reconfiguring the filter. It must be sent at least once in the first event after the
          * filter is restarted. 0 is reserved for the newly opened filter's first start, which is
          * optional for HAL to send.
+         *
+         * When sending starId, DemuxFilterEventExt.events should only contain one startId event.
+         * StardId event should be sent with an empty @1.0::DemuxFilterEvent.
          */
         uint32_t startId;
     };
@@ -196,6 +216,24 @@
     SCRAMBLED = 1 << 2,
 };
 
+@export
+enum DemuxFilterMonitorEventType : uint32_t {
+    SCRAMBLING_STATUS = 1 << 0,
+    IP_CID_CHANGE = 1 << 1,
+};
+
+safe_union DemuxFilterMonitorEvent {
+    /**
+     * New scrambling status.
+     */
+    ScramblingStatus scramblingStatus;
+
+    /**
+     * New cid for the IP filter.
+     */
+    uint32_t cid;
+};
+
 typedef FrontendDvbcSpectralInversion FrontendSpectralInversion;
 
 /**
diff --git a/tv/tuner/1.1/vts/functional/FilterTests.cpp b/tv/tuner/1.1/vts/functional/FilterTests.cpp
index cdf3b69..d8fad3d 100644
--- a/tv/tuner/1.1/vts/functional/FilterTests.cpp
+++ b/tv/tuner/1.1/vts/functional/FilterTests.cpp
@@ -40,6 +40,18 @@
     ALOGW("[vts] pass and stop");
 }
 
+void FilterCallback::testFilterIpCidEvent() {
+    android::Mutex::Autolock autoLock(mMsgLock);
+    while (mIpCidEvent < 1) {
+        if (-ETIMEDOUT == mMsgCondition.waitRelative(mMsgLock, WAIT_TIMEOUT)) {
+            EXPECT_TRUE(false) << "ip cid change event does not output within timeout";
+            return;
+        }
+    }
+    mIpCidEvent = 0;
+    ALOGW("[vts] pass and stop");
+}
+
 void FilterCallback::testStartIdAfterReconfigure() {
     android::Mutex::Autolock autoLock(mMsgLock);
     while (!mStartIdReceived) {
@@ -80,8 +92,17 @@
                       eventExt.mmtpRecord().pts, eventExt.mmtpRecord().firstMbInSlice,
                       eventExt.mmtpRecord().mpuSequenceNumber, eventExt.mmtpRecord().tsIndexMask);
                 break;
-            case DemuxFilterEventExt::Event::hidl_discriminator::scramblingStatus:
-                mScramblingStatusEvent++;
+            case DemuxFilterEventExt::Event::hidl_discriminator::monitorEvent:
+                switch (eventExt.monitorEvent().getDiscriminator()) {
+                    case DemuxFilterMonitorEvent::hidl_discriminator::scramblingStatus:
+                        mScramblingStatusEvent++;
+                        break;
+                    case DemuxFilterMonitorEvent::hidl_discriminator::cid:
+                        mIpCidEvent++;
+                        break;
+                    default:
+                        break;
+                }
                 break;
             case DemuxFilterEventExt::Event::hidl_discriminator::startId:
                 ALOGD("[vts] Extended restart filter event, startId=%d", eventExt.startId());
@@ -272,15 +293,16 @@
     return AssertionResult(status == Result::SUCCESS);
 }
 
-AssertionResult FilterTests::configureScramblingEvent(uint64_t filterId, uint32_t statuses) {
+AssertionResult FilterTests::configureMonitorEvent(uint64_t filterId, uint32_t monitorEventTypes) {
     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);
+        status = filter_v1_1->configureMonitorEvent(monitorEventTypes);
         mFilterCallbacks[filterId]->testFilterScramblingEvent();
+        mFilterCallbacks[filterId]->testFilterIpCidEvent();
     } else {
         ALOGW("[vts] Can't cast IFilter into v1_1.");
         return failure();
diff --git a/tv/tuner/1.1/vts/functional/FilterTests.h b/tv/tuner/1.1/vts/functional/FilterTests.h
index ae57659..6749265 100644
--- a/tv/tuner/1.1/vts/functional/FilterTests.h
+++ b/tv/tuner/1.1/vts/functional/FilterTests.h
@@ -56,6 +56,7 @@
 using android::hardware::tv::tuner::V1_0::Result;
 using android::hardware::tv::tuner::V1_1::AvStreamType;
 using android::hardware::tv::tuner::V1_1::DemuxFilterEventExt;
+using android::hardware::tv::tuner::V1_1::DemuxFilterMonitorEvent;
 using android::hardware::tv::tuner::V1_1::IFilterCallback;
 using android::hardware::tv::tuner::V1_1::ITuner;
 
@@ -118,6 +119,7 @@
 
     void testFilterDataOutput();
     void testFilterScramblingEvent();
+    void testFilterIpCidEvent();
     void testStartIdAfterReconfigure();
 
     void readFilterEventData();
@@ -139,6 +141,7 @@
 
     int mPidFilterOutputCount = 0;
     int mScramblingStatusEvent = 0;
+    int mIpCidEvent = 0;
     bool mStartIdReceived = false;
 };
 
@@ -157,7 +160,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 configureMonitorEvent(uint64_t filterId, uint32_t monitorEventTypes);
     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 dda8b60..e872762 100644
--- a/tv/tuner/1.1/vts/functional/VtsHalTvTunerV1_1TargetTest.cpp
+++ b/tv/tuner/1.1/vts/functional/VtsHalTvTunerV1_1TargetTest.cpp
@@ -46,8 +46,8 @@
     if (filterConf.type.mainType == DemuxFilterMainType::IP) {
         ASSERT_TRUE(mFilterTests.configIpFilterCid(filterConf.ipCid, filterId));
     }
-    if (filterConf.statuses > 0) {
-        ASSERT_TRUE(mFilterTests.configureScramblingEvent(filterId, filterConf.statuses));
+    if (filterConf.monitorEventTypes > 0) {
+        ASSERT_TRUE(mFilterTests.configureMonitorEvent(filterId, filterConf.monitorEventTypes));
     }
     ASSERT_TRUE(mFilterTests.getFilterMQDescriptor(filterId));
     ASSERT_TRUE(mFilterTests.startFilter(filterId));
diff --git a/tv/tuner/1.1/vts/functional/VtsHalTvTunerV1_1TestConfigurations.h b/tv/tuner/1.1/vts/functional/VtsHalTvTunerV1_1TestConfigurations.h
index 76bf765..beae223 100644
--- a/tv/tuner/1.1/vts/functional/VtsHalTvTunerV1_1TestConfigurations.h
+++ b/tv/tuner/1.1/vts/functional/VtsHalTvTunerV1_1TestConfigurations.h
@@ -96,7 +96,7 @@
     DemuxFilterSettings settings;
     AvStreamType streamType;
     uint32_t ipCid;
-    uint32_t statuses;
+    uint32_t monitorEventTypes;
 
     bool operator<(const FilterConfig& /*c*/) const { return false; }
 };
@@ -188,7 +188,9 @@
     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_VIDEO0].monitorEventTypes =
+            android::hardware::tv::tuner::V1_1::DemuxFilterMonitorEventType::SCRAMBLING_STATUS |
+            android::hardware::tv::tuner::V1_1::DemuxFilterMonitorEventType::IP_CID_CHANGE;
     filterArray[TS_VIDEO1].type.mainType = DemuxFilterMainType::TS;
     filterArray[TS_VIDEO1].type.subType.tsFilterType(DemuxTsFilterType::VIDEO);
     filterArray[TS_VIDEO1].bufferSize = FMQ_SIZE_16M;