Support frontend status readiness query.

The caller could use it to check whether frontend status is ready to
read or not.

Bug: 171540820
Test: atest VtsHalTvTunerTargetTest
Change-Id: I65521aacd8afe824342ad0b24f7d89006ceb5851
diff --git a/tv/tuner/aidl/aidl_api/android.hardware.tv.tuner/current/android/hardware/tv/tuner/FrontendStatusReadiness.aidl b/tv/tuner/aidl/aidl_api/android.hardware.tv.tuner/current/android/hardware/tv/tuner/FrontendStatusReadiness.aidl
new file mode 100644
index 0000000..41944ce
--- /dev/null
+++ b/tv/tuner/aidl/aidl_api/android.hardware.tv.tuner/current/android/hardware/tv/tuner/FrontendStatusReadiness.aidl
@@ -0,0 +1,43 @@
+/*
+ * Copyright 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.tv.tuner;
+/* @hide */
+@Backing(type="int") @VintfStability
+enum FrontendStatusReadiness {
+  UNDEFINED = 0,
+  UNAVAILABLE = 1,
+  UNSTABLE = 2,
+  STABLE = 3,
+  UNSUPPORTED = 4,
+}
diff --git a/tv/tuner/aidl/aidl_api/android.hardware.tv.tuner/current/android/hardware/tv/tuner/IFrontend.aidl b/tv/tuner/aidl/aidl_api/android.hardware.tv.tuner/current/android/hardware/tv/tuner/IFrontend.aidl
index e240e40..3e3ff4f 100644
--- a/tv/tuner/aidl/aidl_api/android.hardware.tv.tuner/current/android/hardware/tv/tuner/IFrontend.aidl
+++ b/tv/tuner/aidl/aidl_api/android.hardware.tv.tuner/current/android/hardware/tv/tuner/IFrontend.aidl
@@ -47,4 +47,5 @@
   void unlinkCiCam(in int ciCamId);
   String getHardwareInfo();
   void removeOutputPid(int pid);
+  android.hardware.tv.tuner.FrontendStatusReadiness[] getFrontendStatusReadiness(in android.hardware.tv.tuner.FrontendStatusType[] statusTypes);
 }
diff --git a/tv/tuner/aidl/android/hardware/tv/tuner/FrontendStatusReadiness.aidl b/tv/tuner/aidl/android/hardware/tv/tuner/FrontendStatusReadiness.aidl
new file mode 100644
index 0000000..a9e3080
--- /dev/null
+++ b/tv/tuner/aidl/android/hardware/tv/tuner/FrontendStatusReadiness.aidl
@@ -0,0 +1,54 @@
+/*
+ * Copyright 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.tv.tuner;
+
+/**
+ * FrontendStatus readiness status.
+ * @hide
+ */
+@VintfStability
+@Backing(type="int")
+enum FrontendStatusReadiness {
+    /**
+     * The FrontendStatus’ readiness status for the given FrontendStatusType is
+     * undefined.
+     */
+    UNDEFINED,
+
+    /**
+     * The FrontendStatus for the given FrontendStatusType is currently
+     * unavailable.
+     */
+    UNAVAILABLE,
+
+    /**
+     * The FrontendStatus for the given FrontendStatusType can be read, but it’s
+     * unstable.
+     */
+    UNSTABLE,
+
+    /**
+     * The FrontendStatus for the given FrontendStatusType can be ready, and it’s
+     * stable.
+     */
+    STABLE,
+
+    /**
+     * The FrontendStatus for the given FrontendStatusType is not supported.
+     */
+    UNSUPPORTED,
+}
diff --git a/tv/tuner/aidl/android/hardware/tv/tuner/IFrontend.aidl b/tv/tuner/aidl/android/hardware/tv/tuner/IFrontend.aidl
index f8248e6..12f2692 100644
--- a/tv/tuner/aidl/android/hardware/tv/tuner/IFrontend.aidl
+++ b/tv/tuner/aidl/android/hardware/tv/tuner/IFrontend.aidl
@@ -19,6 +19,7 @@
 import android.hardware.tv.tuner.FrontendScanType;
 import android.hardware.tv.tuner.FrontendSettings;
 import android.hardware.tv.tuner.FrontendStatus;
+import android.hardware.tv.tuner.FrontendStatusReadiness;
 import android.hardware.tv.tuner.FrontendStatusType;
 import android.hardware.tv.tuner.IFrontendCallback;
 
@@ -155,4 +156,14 @@
      * @return UNAVAILABLE if the frontend doesn’t support PID filtering out.
      */
     void removeOutputPid(int pid);
+
+    /**
+     * Gets FrontendStatus’ readiness statuses for given status types.
+     *
+     * @param statusTypes an array of status types.
+     *
+     * @return an array of current readiness statuses. The ith readiness status in
+     *         the array presents fronted type statusTypes[i]’s readiness status.
+     */
+    FrontendStatusReadiness[] getFrontendStatusReadiness(in FrontendStatusType[] statusTypes);
 }
diff --git a/tv/tuner/aidl/default/Frontend.cpp b/tv/tuner/aidl/default/Frontend.cpp
index f0bf001..056d014 100644
--- a/tv/tuner/aidl/default/Frontend.cpp
+++ b/tv/tuner/aidl/default/Frontend.cpp
@@ -34,6 +34,140 @@
     mTuner = tuner;
     // Init callback to nullptr
     mCallback = nullptr;
+
+    switch (mType) {
+        case FrontendType::ISDBS: {
+            mFrontendCaps.set<FrontendCapabilities::Tag::isdbsCaps>(FrontendIsdbsCapabilities());
+            mFrontendStatusCaps = {
+                    FrontendStatusType::DEMOD_LOCK,
+                    FrontendStatusType::SNR,
+                    FrontendStatusType::FEC,
+                    FrontendStatusType::MODULATION,
+                    FrontendStatusType::MODULATIONS,
+                    FrontendStatusType::ROLL_OFF,
+                    FrontendStatusType::STREAM_ID_LIST,
+            };
+            break;
+        }
+        case FrontendType::ATSC3: {
+            mFrontendCaps.set<FrontendCapabilities::Tag::atsc3Caps>(FrontendAtsc3Capabilities());
+            mFrontendStatusCaps = {
+                    FrontendStatusType::BER,
+                    FrontendStatusType::PER,
+                    FrontendStatusType::ATSC3_PLP_INFO,
+                    FrontendStatusType::MODULATIONS,
+                    FrontendStatusType::BERS,
+                    FrontendStatusType::INTERLEAVINGS,
+                    FrontendStatusType::BANDWIDTH,
+                    FrontendStatusType::ATSC3_ALL_PLP_INFO,
+            };
+            break;
+        }
+        case FrontendType::DVBC: {
+            mFrontendCaps.set<FrontendCapabilities::Tag::dvbcCaps>(FrontendDvbcCapabilities());
+            mFrontendStatusCaps = {
+                    FrontendStatusType::PRE_BER,       FrontendStatusType::SIGNAL_QUALITY,
+                    FrontendStatusType::MODULATION,    FrontendStatusType::SPECTRAL,
+                    FrontendStatusType::MODULATIONS,   FrontendStatusType::CODERATES,
+                    FrontendStatusType::INTERLEAVINGS, FrontendStatusType::BANDWIDTH,
+            };
+            break;
+        }
+        case FrontendType::DVBS: {
+            mFrontendCaps.set<FrontendCapabilities::Tag::dvbsCaps>(FrontendDvbsCapabilities());
+            mFrontendStatusCaps = {
+                    FrontendStatusType::SIGNAL_STRENGTH, FrontendStatusType::SYMBOL_RATE,
+                    FrontendStatusType::MODULATION,      FrontendStatusType::MODULATIONS,
+                    FrontendStatusType::ROLL_OFF,        FrontendStatusType::IS_MISO,
+            };
+            break;
+        }
+        case FrontendType::DVBT: {
+            mFrontendCaps.set<FrontendCapabilities::Tag::dvbtCaps>(FrontendDvbtCapabilities());
+            mFrontendStatusCaps = {
+                    FrontendStatusType::EWBS,
+                    FrontendStatusType::PLP_ID,
+                    FrontendStatusType::HIERARCHY,
+                    FrontendStatusType::MODULATIONS,
+                    FrontendStatusType::BANDWIDTH,
+                    FrontendStatusType::GUARD_INTERVAL,
+                    FrontendStatusType::TRANSMISSION_MODE,
+                    FrontendStatusType::T2_SYSTEM_ID,
+                    FrontendStatusType::DVBT_CELL_IDS,
+            };
+            break;
+        }
+        case FrontendType::ISDBT: {
+            FrontendIsdbtCapabilities isdbtCaps{
+                    .modeCap = (int)FrontendIsdbtMode::MODE_1 | (int)FrontendIsdbtMode::MODE_2,
+                    .bandwidthCap = (int)FrontendIsdbtBandwidth::BANDWIDTH_6MHZ,
+                    .modulationCap = (int)FrontendIsdbtModulation::MOD_16QAM,
+                    .coderateCap = (int)FrontendIsdbtCoderate::CODERATE_4_5 |
+                                   (int)FrontendIsdbtCoderate::CODERATE_6_7,
+                    .guardIntervalCap = (int)FrontendIsdbtGuardInterval::INTERVAL_1_128,
+                    .timeInterleaveCap = (int)FrontendIsdbtTimeInterleaveMode::AUTO |
+                                         (int)FrontendIsdbtTimeInterleaveMode::INTERLEAVE_1_0,
+                    .isSegmentAuto = true,
+                    .isFullSegment = true,
+            };
+            mFrontendCaps.set<FrontendCapabilities::Tag::isdbtCaps>(isdbtCaps);
+            mFrontendStatusCaps = {
+                    FrontendStatusType::AGC,
+                    FrontendStatusType::LNA,
+                    FrontendStatusType::MODULATION,
+                    FrontendStatusType::MODULATIONS,
+                    FrontendStatusType::BANDWIDTH,
+                    FrontendStatusType::GUARD_INTERVAL,
+                    FrontendStatusType::TRANSMISSION_MODE,
+                    FrontendStatusType::ISDBT_SEGMENTS,
+                    FrontendStatusType::ISDBT_MODE,
+                    FrontendStatusType::ISDBT_PARTIAL_RECEPTION_FLAG,
+                    FrontendStatusType::INTERLEAVINGS,
+            };
+            break;
+        }
+        case FrontendType::ANALOG: {
+            mFrontendCaps.set<FrontendCapabilities::Tag::analogCaps>(FrontendAnalogCapabilities());
+            mFrontendStatusCaps = {
+                    FrontendStatusType::LAYER_ERROR,
+                    FrontendStatusType::MER,
+                    FrontendStatusType::UEC,
+                    FrontendStatusType::TS_DATA_RATES,
+            };
+            break;
+        }
+        case FrontendType::ATSC: {
+            mFrontendCaps.set<FrontendCapabilities::Tag::atscCaps>(FrontendAtscCapabilities());
+            mFrontendStatusCaps = {
+                    FrontendStatusType::FREQ_OFFSET,
+                    FrontendStatusType::RF_LOCK,
+                    FrontendStatusType::MODULATIONS,
+                    FrontendStatusType::IS_LINEAR,
+            };
+            break;
+        }
+        case FrontendType::ISDBS3: {
+            mFrontendCaps.set<FrontendCapabilities::Tag::isdbs3Caps>(FrontendIsdbs3Capabilities());
+            mFrontendStatusCaps = {
+                    FrontendStatusType::DEMOD_LOCK,      FrontendStatusType::MODULATION,
+                    FrontendStatusType::MODULATIONS,     FrontendStatusType::ROLL_OFF,
+                    FrontendStatusType::IS_SHORT_FRAMES, FrontendStatusType::STREAM_ID_LIST,
+            };
+            break;
+        }
+        case FrontendType::DTMB: {
+            mFrontendCaps.set<FrontendCapabilities::Tag::dtmbCaps>(FrontendDtmbCapabilities());
+            mFrontendStatusCaps = {
+                    FrontendStatusType::MODULATIONS,       FrontendStatusType::INTERLEAVINGS,
+                    FrontendStatusType::BANDWIDTH,         FrontendStatusType::GUARD_INTERVAL,
+                    FrontendStatusType::TRANSMISSION_MODE,
+            };
+            break;
+        }
+        default: {
+            break;
+        }
+    }
 }
 
 Frontend::~Frontend() {}
@@ -763,6 +897,10 @@
     dprintf(fd, "    mType: %d\n", mType);
     dprintf(fd, "    mIsLocked: %d\n", mIsLocked);
     dprintf(fd, "    mCiCamId: %d\n", mCiCamId);
+    dprintf(fd, "    mFrontendStatusCaps:");
+    for (int i = 0; i < mFrontendStatusCaps.size(); i++) {
+        dprintf(fd, "        %d\n", mFrontendStatusCaps[i]);
+    }
     return STATUS_OK;
 }
 
@@ -780,6 +918,29 @@
             static_cast<int32_t>(Result::UNAVAILABLE));
 }
 
+::ndk::ScopedAStatus Frontend::getFrontendStatusReadiness(
+        const std::vector<FrontendStatusType>& in_statusTypes,
+        std::vector<FrontendStatusReadiness>* _aidl_return) {
+    ALOGV("%s", __FUNCTION__);
+
+    _aidl_return->resize(in_statusTypes.size());
+    for (int i = 0; i < in_statusTypes.size(); i++) {
+        int j = 0;
+        while (j < mFrontendStatusCaps.size()) {
+            if (in_statusTypes[i] == mFrontendStatusCaps[j]) {
+                (*_aidl_return)[i] = FrontendStatusReadiness::STABLE;
+                break;
+            }
+            j++;
+        }
+        if (j >= mFrontendStatusCaps.size()) {
+            (*_aidl_return)[i] = FrontendStatusReadiness::UNSUPPORTED;
+        }
+    }
+
+    return ::ndk::ScopedAStatus::ok();
+}
+
 FrontendType Frontend::getFrontendType() {
     return mType;
 }
@@ -797,6 +958,21 @@
     return mIsLocked;
 }
 
+void Frontend::getFrontendInfo(FrontendInfo* _aidl_return) {
+    // assign randomly selected values for testing.
+    *_aidl_return = {
+            .type = mType,
+            .minFrequency = 139000000,
+            .maxFrequency = 1139000000,
+            .minSymbolRate = 45,
+            .maxSymbolRate = 1145,
+            .acquireRange = 30,
+            .exclusiveGroupId = 57,
+            .statusCaps = mFrontendStatusCaps,
+            .frontendCaps = mFrontendCaps,
+    };
+}
+
 }  // namespace tuner
 }  // namespace tv
 }  // namespace hardware
diff --git a/tv/tuner/aidl/default/Frontend.h b/tv/tuner/aidl/default/Frontend.h
index 3df1aa1..1d9ab53 100644
--- a/tv/tuner/aidl/default/Frontend.h
+++ b/tv/tuner/aidl/default/Frontend.h
@@ -51,6 +51,9 @@
     ::ndk::ScopedAStatus unlinkCiCam(int32_t in_ciCamId) override;
     ::ndk::ScopedAStatus getHardwareInfo(std::string* _aidl_return) override;
     ::ndk::ScopedAStatus removeOutputPid(int32_t in_pid) override;
+    ::ndk::ScopedAStatus getFrontendStatusReadiness(
+            const std::vector<FrontendStatusType>& in_statusTypes,
+            std::vector<FrontendStatusReadiness>* _aidl_return) override;
 
     binder_status_t dump(int fd, const char** args, uint32_t numArgs) override;
 
@@ -58,6 +61,7 @@
     int32_t getFrontendId();
     string getSourceFile();
     bool isLocked();
+    void getFrontendInfo(FrontendInfo* _aidl_return);
 
   private:
     virtual ~Frontend();
@@ -74,6 +78,8 @@
     FrontendSettings mFrontendSettings;
     FrontendScanType mFrontendScanType;
     std::ifstream mFrontendData;
+    FrontendCapabilities mFrontendCaps;
+    vector<FrontendStatusType> mFrontendStatusCaps;
 };
 
 }  // namespace tuner
diff --git a/tv/tuner/aidl/default/Tuner.cpp b/tv/tuner/aidl/default/Tuner.cpp
index 7a5fa6e..fa74288 100644
--- a/tv/tuner/aidl/default/Tuner.cpp
+++ b/tv/tuner/aidl/default/Tuner.cpp
@@ -49,154 +49,15 @@
     mFrontends[8] = ndk::SharedRefBase::make<Frontend>(FrontendType::ISDBS3, 8, this->ref<Tuner>());
     mFrontends[9] = ndk::SharedRefBase::make<Frontend>(FrontendType::DTMB, 9, this->ref<Tuner>());
 
-    vector<FrontendStatusType> statusCaps;
-
-    FrontendCapabilities capsIsdbs;
-    capsIsdbs.set<FrontendCapabilities::Tag::isdbsCaps>(FrontendIsdbsCapabilities());
-    mFrontendCaps[0] = capsIsdbs;
-    statusCaps = {
-            FrontendStatusType::DEMOD_LOCK,
-            FrontendStatusType::SNR,
-            FrontendStatusType::FEC,
-            FrontendStatusType::MODULATION,
-            FrontendStatusType::MODULATIONS,
-            FrontendStatusType::ROLL_OFF,
-            FrontendStatusType::STREAM_ID_LIST,
-    };
-    mFrontendStatusCaps[0] = statusCaps;
     mMaxUsableFrontends[FrontendType::ISDBS] = 1;
-
-    FrontendCapabilities capsAtsc3;
-    capsAtsc3.set<FrontendCapabilities::Tag::atsc3Caps>(FrontendAtsc3Capabilities());
-    mFrontendCaps[1] = capsAtsc3;
-    statusCaps = {
-            FrontendStatusType::BER,
-            FrontendStatusType::PER,
-            FrontendStatusType::ATSC3_PLP_INFO,
-            FrontendStatusType::MODULATIONS,
-            FrontendStatusType::BERS,
-            FrontendStatusType::INTERLEAVINGS,
-            FrontendStatusType::BANDWIDTH,
-            FrontendStatusType::ATSC3_ALL_PLP_INFO,
-    };
-    mFrontendStatusCaps[1] = statusCaps;
     mMaxUsableFrontends[FrontendType::ATSC3] = 1;
-
-    FrontendCapabilities capsDvbc;
-    capsDvbc.set<FrontendCapabilities::Tag::dvbcCaps>(FrontendDvbcCapabilities());
-    mFrontendCaps[2] = capsDvbc;
-    statusCaps = {
-            FrontendStatusType::PRE_BER,       FrontendStatusType::SIGNAL_QUALITY,
-            FrontendStatusType::MODULATION,    FrontendStatusType::SPECTRAL,
-            FrontendStatusType::MODULATIONS,   FrontendStatusType::CODERATES,
-            FrontendStatusType::INTERLEAVINGS, FrontendStatusType::BANDWIDTH,
-    };
-    mFrontendStatusCaps[2] = statusCaps;
     mMaxUsableFrontends[FrontendType::DVBC] = 1;
-
-    FrontendCapabilities capsDvbs;
-    capsDvbs.set<FrontendCapabilities::Tag::dvbsCaps>(FrontendDvbsCapabilities());
-    mFrontendCaps[3] = capsDvbs;
-    statusCaps = {
-            FrontendStatusType::SIGNAL_STRENGTH, FrontendStatusType::SYMBOL_RATE,
-            FrontendStatusType::MODULATION,      FrontendStatusType::MODULATIONS,
-            FrontendStatusType::ROLL_OFF,        FrontendStatusType::IS_MISO,
-    };
-    mFrontendStatusCaps[3] = statusCaps;
     mMaxUsableFrontends[FrontendType::DVBS] = 1;
-
-    FrontendCapabilities capsDvbt;
-    capsDvbt.set<FrontendCapabilities::Tag::dvbtCaps>(FrontendDvbtCapabilities());
-    mFrontendCaps[4] = capsDvbt;
-    statusCaps = {
-            FrontendStatusType::EWBS,
-            FrontendStatusType::PLP_ID,
-            FrontendStatusType::HIERARCHY,
-            FrontendStatusType::MODULATIONS,
-            FrontendStatusType::BANDWIDTH,
-            FrontendStatusType::GUARD_INTERVAL,
-            FrontendStatusType::TRANSMISSION_MODE,
-            FrontendStatusType::T2_SYSTEM_ID,
-            FrontendStatusType::DVBT_CELL_IDS,
-    };
-    mFrontendStatusCaps[4] = statusCaps;
     mMaxUsableFrontends[FrontendType::DVBT] = 1;
-
-    FrontendCapabilities capsIsdbt;
-    FrontendIsdbtCapabilities isdbtCaps{
-            .modeCap = (int)FrontendIsdbtMode::MODE_1 | (int)FrontendIsdbtMode::MODE_2,
-            .bandwidthCap = (int)FrontendIsdbtBandwidth::BANDWIDTH_6MHZ,
-            .modulationCap = (int)FrontendIsdbtModulation::MOD_16QAM,
-            .coderateCap = (int)FrontendIsdbtCoderate::CODERATE_4_5 |
-                           (int)FrontendIsdbtCoderate::CODERATE_6_7,
-            .guardIntervalCap = (int)FrontendIsdbtGuardInterval::INTERVAL_1_128,
-            .timeInterleaveCap = (int)FrontendIsdbtTimeInterleaveMode::AUTO |
-                                 (int)FrontendIsdbtTimeInterleaveMode::INTERLEAVE_1_0,
-            .isSegmentAuto = true,
-            .isFullSegment = true,
-    };
-    capsIsdbt.set<FrontendCapabilities::Tag::isdbtCaps>(isdbtCaps);
-    mFrontendCaps[5] = capsIsdbt;
-    statusCaps = {
-            FrontendStatusType::AGC,
-            FrontendStatusType::LNA,
-            FrontendStatusType::MODULATION,
-            FrontendStatusType::MODULATIONS,
-            FrontendStatusType::BANDWIDTH,
-            FrontendStatusType::GUARD_INTERVAL,
-            FrontendStatusType::TRANSMISSION_MODE,
-            FrontendStatusType::ISDBT_SEGMENTS,
-            FrontendStatusType::ISDBT_MODE,
-            FrontendStatusType::ISDBT_PARTIAL_RECEPTION_FLAG,
-            FrontendStatusType::INTERLEAVINGS,
-    };
-    mFrontendStatusCaps[5] = statusCaps;
     mMaxUsableFrontends[FrontendType::ISDBT] = 1;
-
-    FrontendCapabilities capsAnalog;
-    capsAnalog.set<FrontendCapabilities::Tag::analogCaps>(FrontendAnalogCapabilities());
-    mFrontendCaps[6] = capsAnalog;
-    statusCaps = {
-            FrontendStatusType::LAYER_ERROR,
-            FrontendStatusType::MER,
-            FrontendStatusType::UEC,
-            FrontendStatusType::TS_DATA_RATES,
-    };
-    mFrontendStatusCaps[6] = statusCaps;
     mMaxUsableFrontends[FrontendType::ANALOG] = 1;
-
-    FrontendCapabilities capsAtsc;
-    capsAtsc.set<FrontendCapabilities::Tag::atscCaps>(FrontendAtscCapabilities());
-    mFrontendCaps[7] = capsAtsc;
-    statusCaps = {
-            FrontendStatusType::FREQ_OFFSET,
-            FrontendStatusType::RF_LOCK,
-            FrontendStatusType::MODULATIONS,
-            FrontendStatusType::IS_LINEAR,
-    };
-    mFrontendStatusCaps[7] = statusCaps;
     mMaxUsableFrontends[FrontendType::ATSC] = 1;
-
-    FrontendCapabilities capsIsdbs3;
-    capsIsdbs3.set<FrontendCapabilities::Tag::isdbs3Caps>(FrontendIsdbs3Capabilities());
-    mFrontendCaps[8] = capsIsdbs3;
-    statusCaps = {
-            FrontendStatusType::DEMOD_LOCK,      FrontendStatusType::MODULATION,
-            FrontendStatusType::MODULATIONS,     FrontendStatusType::ROLL_OFF,
-            FrontendStatusType::IS_SHORT_FRAMES, FrontendStatusType::STREAM_ID_LIST,
-    };
-    mFrontendStatusCaps[8] = statusCaps;
     mMaxUsableFrontends[FrontendType::ISDBS3] = 1;
-
-    FrontendCapabilities capsDtmb;
-    capsDtmb.set<FrontendCapabilities::Tag::dtmbCaps>(FrontendDtmbCapabilities());
-    mFrontendCaps[9] = capsDtmb;
-    statusCaps = {
-            FrontendStatusType::MODULATIONS,       FrontendStatusType::INTERLEAVINGS,
-            FrontendStatusType::BANDWIDTH,         FrontendStatusType::GUARD_INTERVAL,
-            FrontendStatusType::TRANSMISSION_MODE,
-    };
-    mFrontendStatusCaps[9] = statusCaps;
     mMaxUsableFrontends[FrontendType::DTMB] = 1;
 
     mLnbs.resize(2);
@@ -267,24 +128,12 @@
 ::ndk::ScopedAStatus Tuner::getFrontendInfo(int32_t in_frontendId, FrontendInfo* _aidl_return) {
     ALOGV("%s", __FUNCTION__);
 
-    if (in_frontendId >= mFrontendSize) {
+    if (in_frontendId < 0 || in_frontendId >= mFrontendSize) {
         return ::ndk::ScopedAStatus::fromServiceSpecificError(
                 static_cast<int32_t>(Result::INVALID_ARGUMENT));
     }
 
-    // assign randomly selected values for testing.
-    *_aidl_return = {
-            .type = mFrontends[in_frontendId]->getFrontendType(),
-            .minFrequency = 139000000,
-            .maxFrequency = 1139000000,
-            .minSymbolRate = 45,
-            .maxSymbolRate = 1145,
-            .acquireRange = 30,
-            .exclusiveGroupId = 57,
-            .statusCaps = mFrontendStatusCaps[in_frontendId],
-            .frontendCaps = mFrontendCaps[in_frontendId],
-    };
-
+    mFrontends[in_frontendId]->getFrontendInfo(_aidl_return);
     return ::ndk::ScopedAStatus::ok();
 }
 
@@ -360,9 +209,6 @@
         dprintf(fd, "Frontends:\n");
         for (int i = 0; i < mFrontendSize; i++) {
             mFrontends[i]->dump(fd, args, numArgs);
-            for (int j = 0; j < mFrontendStatusCaps[i].size(); j++) {
-                dprintf(fd, "    statusCap: %d\n", mFrontendStatusCaps[i][j]);
-            }
         }
     }
     {
diff --git a/tv/tuner/aidl/default/Tuner.h b/tv/tuner/aidl/default/Tuner.h
index 216a2b6..ad73003 100644
--- a/tv/tuner/aidl/default/Tuner.h
+++ b/tv/tuner/aidl/default/Tuner.h
@@ -75,8 +75,6 @@
   private:
     // Static mFrontends array to maintain local frontends information
     map<int32_t, std::shared_ptr<Frontend>> mFrontends;
-    map<int32_t, FrontendCapabilities> mFrontendCaps;
-    map<int32_t, vector<FrontendStatusType>> mFrontendStatusCaps;
     map<int32_t, int32_t> mFrontendToDemux;
     map<int32_t, std::shared_ptr<Demux>> mDemuxes;
     // To maintain how many Frontends we have
diff --git a/tv/tuner/aidl/vts/functional/FrontendTests.cpp b/tv/tuner/aidl/vts/functional/FrontendTests.cpp
index 62d9b74..a1f51df 100644
--- a/tv/tuner/aidl/vts/functional/FrontendTests.cpp
+++ b/tv/tuner/aidl/vts/functional/FrontendTests.cpp
@@ -581,3 +581,47 @@
     ASSERT_TRUE(stopScanFrontend());
     ASSERT_TRUE(closeFrontend());
 }
+
+void FrontendTests::statusReadinessTest(FrontendConfig frontendConf) {
+    int32_t feId;
+    vector<FrontendStatusType> allTypes;
+    vector<FrontendStatusReadiness> readiness;
+    getFrontendIdByType(frontendConf.type, feId);
+    ASSERT_TRUE(feId != INVALID_ID);
+    ASSERT_TRUE(openFrontendById(feId));
+    ASSERT_TRUE(setFrontendCallback());
+    if (frontendConf.canConnectToCiCam) {
+        ASSERT_TRUE(linkCiCam(frontendConf.ciCamId));
+        ASSERT_TRUE(removeOutputPid(frontendConf.removePid));
+        ASSERT_TRUE(unlinkCiCam(frontendConf.ciCamId));
+    }
+    ASSERT_TRUE(getFrontendInfo(feId));
+    ASSERT_TRUE(tuneFrontend(frontendConf, false /*testWithDemux*/));
+
+    // TODO: find a better way to push all frontend status types
+    for (int32_t i = 0; i < static_cast<int32_t>(FrontendStatusType::ATSC3_ALL_PLP_INFO); i++) {
+        allTypes.push_back(static_cast<FrontendStatusType>(i));
+    }
+    ndk::ScopedAStatus status = mFrontend->getFrontendStatusReadiness(allTypes, &readiness);
+    ASSERT_TRUE(status.isOk());
+    ASSERT_TRUE(readiness.size() == allTypes.size());
+    for (int32_t i = 0; i < readiness.size(); i++) {
+        int32_t j = 0;
+        while (j < mFrontendInfo.statusCaps.size()) {
+            if (allTypes[i] == mFrontendInfo.statusCaps[j]) {
+                ASSERT_TRUE(readiness[i] == FrontendStatusReadiness::UNAVAILABLE ||
+                            readiness[i] == FrontendStatusReadiness::UNSTABLE ||
+                            readiness[i] == FrontendStatusReadiness::STABLE);
+                break;
+            }
+            j++;
+        }
+
+        if (j >= mFrontendInfo.statusCaps.size()) {
+            ASSERT_TRUE(readiness[i] == FrontendStatusReadiness::UNSUPPORTED);
+        }
+    }
+
+    ASSERT_TRUE(stopTuneFrontend(false /*testWithDemux*/));
+    ASSERT_TRUE(closeFrontend());
+}
diff --git a/tv/tuner/aidl/vts/functional/FrontendTests.h b/tv/tuner/aidl/vts/functional/FrontendTests.h
index 537c419..1746c8e 100644
--- a/tv/tuner/aidl/vts/functional/FrontendTests.h
+++ b/tv/tuner/aidl/vts/functional/FrontendTests.h
@@ -102,6 +102,7 @@
     void scanTest(FrontendConfig frontend, FrontendScanType type);
     void debugInfoTest(FrontendConfig frontendConf);
     void maxNumberOfFrontendsTest();
+    void statusReadinessTest(FrontendConfig frontendConf);
 
     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 0566089..c99da41 100644
--- a/tv/tuner/aidl/vts/functional/VtsHalTvTunerTargetTest.cpp
+++ b/tv/tuner/aidl/vts/functional/VtsHalTvTunerTargetTest.cpp
@@ -907,6 +907,14 @@
     mFrontendTests.maxNumberOfFrontendsTest();
 }
 
+TEST_P(TunerFrontendAidlTest, statusReadinessTest) {
+    description("Test Max Frontend status readiness");
+    if (!live.hasFrontendConnection) {
+        return;
+    }
+    mFrontendTests.statusReadinessTest(frontendMap[live.frontendId]);
+}
+
 TEST_P(TunerBroadcastAidlTest, BroadcastDataFlowVideoFilterTest) {
     description("Test Video Filter functionality in Broadcast use case.");
     if (!live.hasFrontendConnection) {