Support enable/disable Frontends.

Bug: 210199978
Test: atest VtsHalTvTunerTargetTest
Change-Id: I08411ef92d83be6623ed60565d65d6e9093405ad
diff --git a/tv/tuner/aidl/aidl_api/android.hardware.tv.tuner/current/android/hardware/tv/tuner/ITuner.aidl b/tv/tuner/aidl/aidl_api/android.hardware.tv.tuner/current/android/hardware/tv/tuner/ITuner.aidl
index decf5b1..0ff2da9 100644
--- a/tv/tuner/aidl/aidl_api/android.hardware.tv.tuner/current/android/hardware/tv/tuner/ITuner.aidl
+++ b/tv/tuner/aidl/aidl_api/android.hardware.tv.tuner/current/android/hardware/tv/tuner/ITuner.aidl
@@ -45,4 +45,6 @@
   android.hardware.tv.tuner.ILnb openLnbById(in int lnbId);
   android.hardware.tv.tuner.ILnb openLnbByName(in String lnbName, out int[] lnbId);
   void setLna(in boolean bEnable);
+  void setMaxNumberOfFrontends(in android.hardware.tv.tuner.FrontendType frontendType, in int maxNumber);
+  int getMaxNumberOfFrontends(in android.hardware.tv.tuner.FrontendType frontendType);
 }
diff --git a/tv/tuner/aidl/android/hardware/tv/tuner/ITuner.aidl b/tv/tuner/aidl/android/hardware/tv/tuner/ITuner.aidl
index 1fcbb06..03def33 100644
--- a/tv/tuner/aidl/android/hardware/tv/tuner/ITuner.aidl
+++ b/tv/tuner/aidl/android/hardware/tv/tuner/ITuner.aidl
@@ -18,6 +18,7 @@
 
 import android.hardware.tv.tuner.DemuxCapabilities;
 import android.hardware.tv.tuner.FrontendInfo;
+import android.hardware.tv.tuner.FrontendType;
 import android.hardware.tv.tuner.IDemux;
 import android.hardware.tv.tuner.IDescrambler;
 import android.hardware.tv.tuner.IFrontend;
@@ -127,4 +128,24 @@
      * @param bEnable true if activate LNA module; false if deactivate LNA
      */
     void setLna(in boolean bEnable);
+
+    /**
+     * Set the maximum usable frontends number of a given frontend type.
+     *
+     * It is used by the client to enable or disable frontends when cable connection status
+     * is changed by user.
+     *
+     * @param frontendType the frontend type which the maximum usable number will be set.
+     * @param maxNumber the new maximum usable number.
+     */
+    void setMaxNumberOfFrontends(in FrontendType frontendType, in int maxNumber);
+
+    /**
+     * Get the maximum usable frontends number of a given frontend type.
+     *
+     * @param frontendType the frontend type which the maximum usable number will be queried.
+     *
+     * @return the maximum usable number of the queried frontend type.
+     */
+    int getMaxNumberOfFrontends(in FrontendType frontendType);
 }
diff --git a/tv/tuner/aidl/default/Tuner.cpp b/tv/tuner/aidl/default/Tuner.cpp
index 45f3dfa..48c1b66 100644
--- a/tv/tuner/aidl/default/Tuner.cpp
+++ b/tv/tuner/aidl/default/Tuner.cpp
@@ -64,6 +64,7 @@
             FrontendStatusType::STREAM_ID_LIST,
     };
     mFrontendStatusCaps[0] = statusCaps;
+    mMaxUsableFrontends[FrontendType::ISDBS] = 1;
 
     FrontendCapabilities capsAtsc3;
     capsAtsc3.set<FrontendCapabilities::Tag::atsc3Caps>(FrontendAtsc3Capabilities());
@@ -78,6 +79,7 @@
             FrontendStatusType::BANDWIDTH,
     };
     mFrontendStatusCaps[1] = statusCaps;
+    mMaxUsableFrontends[FrontendType::ATSC3] = 1;
 
     FrontendCapabilities capsDvbc;
     capsDvbc.set<FrontendCapabilities::Tag::dvbcCaps>(FrontendDvbcCapabilities());
@@ -89,6 +91,7 @@
             FrontendStatusType::INTERLEAVINGS, FrontendStatusType::BANDWIDTH,
     };
     mFrontendStatusCaps[2] = statusCaps;
+    mMaxUsableFrontends[FrontendType::DVBC] = 1;
 
     FrontendCapabilities capsDvbs;
     capsDvbs.set<FrontendCapabilities::Tag::dvbsCaps>(FrontendDvbsCapabilities());
@@ -99,6 +102,7 @@
             FrontendStatusType::ROLL_OFF,        FrontendStatusType::IS_MISO,
     };
     mFrontendStatusCaps[3] = statusCaps;
+    mMaxUsableFrontends[FrontendType::DVBS] = 1;
 
     FrontendCapabilities capsDvbt;
     capsDvbt.set<FrontendCapabilities::Tag::dvbtCaps>(FrontendDvbtCapabilities());
@@ -115,6 +119,7 @@
             FrontendStatusType::DVBT_CELL_IDS,
     };
     mFrontendStatusCaps[4] = statusCaps;
+    mMaxUsableFrontends[FrontendType::DVBT] = 1;
 
     FrontendCapabilities capsIsdbt;
     FrontendIsdbtCapabilities isdbtCaps{
@@ -145,6 +150,7 @@
             FrontendStatusType::INTERLEAVINGS,
     };
     mFrontendStatusCaps[5] = statusCaps;
+    mMaxUsableFrontends[FrontendType::ISDBT] = 1;
 
     FrontendCapabilities capsAnalog;
     capsAnalog.set<FrontendCapabilities::Tag::analogCaps>(FrontendAnalogCapabilities());
@@ -156,6 +162,7 @@
             FrontendStatusType::TS_DATA_RATES,
     };
     mFrontendStatusCaps[6] = statusCaps;
+    mMaxUsableFrontends[FrontendType::ANALOG] = 1;
 
     FrontendCapabilities capsAtsc;
     capsAtsc.set<FrontendCapabilities::Tag::atscCaps>(FrontendAtscCapabilities());
@@ -167,6 +174,7 @@
             FrontendStatusType::IS_LINEAR,
     };
     mFrontendStatusCaps[7] = statusCaps;
+    mMaxUsableFrontends[FrontendType::ATSC] = 1;
 
     FrontendCapabilities capsIsdbs3;
     capsIsdbs3.set<FrontendCapabilities::Tag::isdbs3Caps>(FrontendIsdbs3Capabilities());
@@ -177,6 +185,7 @@
             FrontendStatusType::IS_SHORT_FRAMES, FrontendStatusType::STREAM_ID_LIST,
     };
     mFrontendStatusCaps[8] = statusCaps;
+    mMaxUsableFrontends[FrontendType::ISDBS3] = 1;
 
     FrontendCapabilities capsDtmb;
     capsDtmb.set<FrontendCapabilities::Tag::dtmbCaps>(FrontendDtmbCapabilities());
@@ -187,6 +196,7 @@
             FrontendStatusType::TRANSMISSION_MODE,
     };
     mFrontendStatusCaps[9] = statusCaps;
+    mMaxUsableFrontends[FrontendType::DTMB] = 1;
 
     mLnbs.resize(2);
     mLnbs[0] = ndk::SharedRefBase::make<Lnb>(0);
@@ -324,6 +334,25 @@
     return ::ndk::ScopedAStatus::ok();
 }
 
+::ndk::ScopedAStatus Tuner::setMaxNumberOfFrontends(FrontendType in_frontendType,
+                                                    int32_t in_maxNumber) {
+    ALOGV("%s", __FUNCTION__);
+
+    // In the default implementation, every type only has one frontend.
+    if (in_maxNumber < 0 || in_maxNumber > 1) {
+        return ::ndk::ScopedAStatus::fromServiceSpecificError(
+                static_cast<int32_t>(Result::INVALID_ARGUMENT));
+    }
+    mMaxUsableFrontends[in_frontendType] = in_maxNumber;
+    return ::ndk::ScopedAStatus::ok();
+}
+
+::ndk::ScopedAStatus Tuner::getMaxNumberOfFrontends(FrontendType in_frontendType,
+                                                    int32_t* _aidl_return) {
+    *_aidl_return = mMaxUsableFrontends[in_frontendType];
+    return ::ndk::ScopedAStatus::ok();
+}
+
 binder_status_t Tuner::dump(int fd, const char** args, uint32_t numArgs) {
     ALOGV("%s", __FUNCTION__);
     {
diff --git a/tv/tuner/aidl/default/Tuner.h b/tv/tuner/aidl/default/Tuner.h
index b33a1be..216a2b6 100644
--- a/tv/tuner/aidl/default/Tuner.h
+++ b/tv/tuner/aidl/default/Tuner.h
@@ -57,6 +57,10 @@
                                        std::vector<int32_t>* out_lnbId,
                                        std::shared_ptr<ILnb>* _aidl_return) override;
     ::ndk::ScopedAStatus setLna(bool in_bEnable) override;
+    ::ndk::ScopedAStatus setMaxNumberOfFrontends(FrontendType in_frontendType,
+                                                 int32_t in_maxNumber) override;
+    ::ndk::ScopedAStatus getMaxNumberOfFrontends(FrontendType in_frontendType,
+                                                 int32_t* _aidl_return) override;
 
     binder_status_t dump(int fd, const char** args, uint32_t numArgs) override;
 
@@ -81,6 +85,7 @@
     // First used id will be 0.
     int32_t mLastUsedId = -1;
     vector<std::shared_ptr<Lnb>> mLnbs;
+    map<FrontendType, int32_t> mMaxUsableFrontends;
 };
 
 }  // namespace tuner
diff --git a/tv/tuner/aidl/vts/functional/FrontendTests.cpp b/tv/tuner/aidl/vts/functional/FrontendTests.cpp
index 075ffad..41e98ea 100644
--- a/tv/tuner/aidl/vts/functional/FrontendTests.cpp
+++ b/tv/tuner/aidl/vts/functional/FrontendTests.cpp
@@ -14,6 +14,8 @@
  * limitations under the License.
  */
 
+#include <aidl/android/hardware/tv/tuner/Result.h>
+
 #include "FrontendTests.h"
 
 ndk::ScopedAStatus FrontendCallback::onEvent(FrontendEventType frontendEventType) {
@@ -519,6 +521,41 @@
     ASSERT_TRUE(closeFrontend());
 }
 
+void FrontendTests::maxNumberOfFrontendsTest() {
+    ASSERT_TRUE(getFrontendIds());
+    for (size_t i = 0; i < mFeIds.size(); i++) {
+        ASSERT_TRUE(getFrontendInfo(mFeIds[i]));
+        int32_t defaultMax = -1;
+        ndk::ScopedAStatus status;
+        // Check default value
+        status = mService->getMaxNumberOfFrontends(mFrontendInfo.type, &defaultMax);
+        ASSERT_TRUE(status.isOk());
+        ASSERT_TRUE(defaultMax > 0);
+        // Set to -1
+        status = mService->setMaxNumberOfFrontends(mFrontendInfo.type, -1);
+        ASSERT_TRUE(status.getServiceSpecificError() ==
+                    static_cast<int32_t>(Result::INVALID_ARGUMENT));
+        // Set to defaultMax + 1
+        status = mService->setMaxNumberOfFrontends(mFrontendInfo.type, defaultMax + 1);
+        ASSERT_TRUE(status.getServiceSpecificError() ==
+                    static_cast<int32_t>(Result::INVALID_ARGUMENT));
+        // Set to 0
+        status = mService->setMaxNumberOfFrontends(mFrontendInfo.type, 0);
+        ASSERT_TRUE(status.isOk());
+        // Check after set
+        int32_t currentMax = -1;
+        status = mService->getMaxNumberOfFrontends(mFrontendInfo.type, &currentMax);
+        ASSERT_TRUE(status.isOk());
+        ASSERT_TRUE(currentMax == 0);
+        // Reset to default
+        status = mService->setMaxNumberOfFrontends(mFrontendInfo.type, defaultMax);
+        ASSERT_TRUE(status.isOk());
+        status = mService->getMaxNumberOfFrontends(mFrontendInfo.type, &currentMax);
+        ASSERT_TRUE(status.isOk());
+        ASSERT_TRUE(defaultMax == currentMax);
+    }
+}
+
 void FrontendTests::scanTest(FrontendConfig frontendConf, FrontendScanType scanType) {
     int32_t feId;
     getFrontendIdByType(frontendConf.type, feId);
diff --git a/tv/tuner/aidl/vts/functional/FrontendTests.h b/tv/tuner/aidl/vts/functional/FrontendTests.h
index 8f769a0..1745f76 100644
--- a/tv/tuner/aidl/vts/functional/FrontendTests.h
+++ b/tv/tuner/aidl/vts/functional/FrontendTests.h
@@ -100,6 +100,7 @@
     void tuneTest(FrontendConfig frontendConf);
     void scanTest(FrontendConfig frontend, FrontendScanType type);
     void debugInfoTest(FrontendConfig frontendConf);
+    void maxNumberOfFrontendsTest();
 
     void setDvrTests(DvrTests* dvrTests) { mExternalDvrTests = dvrTests; }
     void setDemux(std::shared_ptr<IDemux> demux) { getDvrTests()->setDemux(demux); }
diff --git a/tv/tuner/aidl/vts/functional/VtsHalTvTunerTargetTest.cpp b/tv/tuner/aidl/vts/functional/VtsHalTvTunerTargetTest.cpp
index 202f83f..a042427 100644
--- a/tv/tuner/aidl/vts/functional/VtsHalTvTunerTargetTest.cpp
+++ b/tv/tuner/aidl/vts/functional/VtsHalTvTunerTargetTest.cpp
@@ -891,6 +891,14 @@
     mFrontendTests.debugInfoTest(frontendMap[live.frontendId]);
 }
 
+TEST_P(TunerFrontendAidlTest, maxNumberOfFrontends) {
+    description("Test Max Frontend number");
+    if (!live.hasFrontendConnection) {
+        return;
+    }
+    mFrontendTests.maxNumberOfFrontendsTest();
+}
+
 TEST_P(TunerBroadcastAidlTest, BroadcastDataFlowVideoFilterTest) {
     description("Test Video Filter functionality in Broadcast use case.");
     if (!live.hasFrontendConnection) {