Make virtual radio space generic, not only FM-exclusive.

Bug: b/36864090
Test: VTS, instrumentalization
Change-Id: I2764d09f56a397a1b80914a2634d6bad4b3bd3d2
diff --git a/broadcastradio/1.1/default/BroadcastRadio.cpp b/broadcastradio/1.1/default/BroadcastRadio.cpp
index 7916407..17ec780 100644
--- a/broadcastradio/1.1/default/BroadcastRadio.cpp
+++ b/broadcastradio/1.1/default/BroadcastRadio.cpp
@@ -143,7 +143,7 @@
         mTuner = nullptr;
     }
 
-    sp<Tuner> newTuner = new Tuner(callback);
+    sp<Tuner> newTuner = new Tuner(mClassId, callback);
     mTuner = newTuner;
     if (mClassId == Class::AM_FM) {
         auto ret = newTuner->setConfiguration(config);
diff --git a/broadcastradio/1.1/default/Tuner.cpp b/broadcastradio/1.1/default/Tuner.cpp
index 2af221e..f48a8db 100644
--- a/broadcastradio/1.1/default/Tuner.cpp
+++ b/broadcastradio/1.1/default/Tuner.cpp
@@ -33,6 +33,7 @@
 
 using V1_0::Band;
 using V1_0::BandConfig;
+using V1_0::Class;
 using V1_0::Direction;
 using utils::HalRevision;
 
@@ -50,10 +51,11 @@
     milliseconds tune = 150ms;
 } gDefaultDelay;
 
-Tuner::Tuner(const sp<V1_0::ITunerCallback>& callback)
-    : mCallback(callback),
+Tuner::Tuner(V1_0::Class classId, const sp<V1_0::ITunerCallback>& callback)
+    : mClassId(classId),
+      mCallback(callback),
       mCallback1_1(ITunerCallback::castFrom(callback).withDefault(nullptr)),
-      mVirtualFm(make_fm_radio()),
+      mVirtualRadio(getRadio(classId)),
       mIsAnalogForced(false) {}
 
 void Tuner::forceClose() {
@@ -66,6 +68,10 @@
     ALOGV("%s", __func__);
     lock_guard<mutex> lk(mMut);
     if (mIsClosed) return Result::NOT_INITIALIZED;
+    if (mClassId != Class::AM_FM) {
+        ALOGE("Can't set AM/FM configuration on SAT/DT radio tuner");
+        return Result::INVALID_STATE;
+    }
 
     if (config.lowerLimit >= config.upperLimit) return Result::INVALID_ARGUMENTS;
 
@@ -77,6 +83,12 @@
         mAmfmConfig.antennaConnected = true;
         mCurrentProgram = utils::make_selector(mAmfmConfig.type, mAmfmConfig.lowerLimit);
 
+        if (mAmfmConfig.type == Band::FM_HD || mAmfmConfig.type == Band::FM) {
+            mVirtualRadio = std::ref(getFmRadio());
+        } else {
+            mVirtualRadio = std::ref(getAmRadio());
+        }
+
         mIsAmfmConfigSet = true;
         mCallback->configChange(Result::OK, mAmfmConfig);
     };
@@ -117,19 +129,9 @@
     }
 }
 
-bool Tuner::isFmLocked() {
-    if (!utils::isAmFm(utils::getType(mCurrentProgram))) return false;
-    return mAmfmConfig.type == Band::FM_HD || mAmfmConfig.type == Band::FM;
-}
-
 void Tuner::tuneInternalLocked(const ProgramSelector& sel) {
-    VirtualRadio* virtualRadio = nullptr;
-    if (isFmLocked()) {
-        virtualRadio = &mVirtualFm;
-    }
-
     VirtualProgram virtualProgram;
-    if (virtualRadio != nullptr && virtualRadio->getProgram(sel, virtualProgram)) {
+    if (mVirtualRadio.get().getProgram(sel, virtualProgram)) {
         mCurrentProgram = virtualProgram.selector;
         mCurrentProgramInfo = virtualProgram.getProgramInfo(getHalRev());
     } else {
@@ -150,11 +152,7 @@
     lock_guard<mutex> lk(mMut);
     if (mIsClosed) return Result::NOT_INITIALIZED;
 
-    vector<VirtualProgram> list;
-
-    if (isFmLocked()) {
-        list = mVirtualFm.getProgramList();
-    }
+    auto list = mVirtualRadio.get().getProgramList();
 
     if (list.empty()) {
         mIsTuneCompleted = false;
@@ -332,14 +330,7 @@
         return {};
     }
 
-    auto& virtualRadio = mVirtualFm;
-    if (!isFmLocked()) {
-        ALOGI("bands other than FM are not supported yet");
-        _hidl_cb(ProgramListResult::OK, {});
-        return {};
-    }
-
-    auto list = virtualRadio.getProgramList();
+    auto list = mVirtualRadio.get().getProgramList();
     ALOGD("returning a list of %zu programs", list.size());
     _hidl_cb(ProgramListResult::OK, getProgramInfoVector(list, getHalRev()));
     return {};
diff --git a/broadcastradio/1.1/default/Tuner.h b/broadcastradio/1.1/default/Tuner.h
index af19ec0..c4efe6e 100644
--- a/broadcastradio/1.1/default/Tuner.h
+++ b/broadcastradio/1.1/default/Tuner.h
@@ -29,7 +29,7 @@
 namespace implementation {
 
 struct Tuner : public ITuner {
-    Tuner(const sp<V1_0::ITunerCallback>& callback);
+    Tuner(V1_0::Class classId, const sp<V1_0::ITunerCallback>& callback);
 
     void forceClose();
 
@@ -55,11 +55,11 @@
     WorkerThread mThread;
     bool mIsClosed = false;
 
+    V1_0::Class mClassId;
     const sp<V1_0::ITunerCallback> mCallback;
     const sp<V1_1::ITunerCallback> mCallback1_1;
 
-    VirtualRadio mVirtualFm;
-
+    std::reference_wrapper<VirtualRadio> mVirtualRadio;
     bool mIsAmfmConfigSet = false;
     V1_0::BandConfig mAmfmConfig;
     bool mIsTuneCompleted = false;
@@ -69,7 +69,6 @@
 
     utils::HalRevision getHalRev() const;
     void tuneInternalLocked(const ProgramSelector& sel);
-    bool isFmLocked();  // TODO(b/36864090): make it generic, not FM only
 };
 
 }  // namespace implementation
diff --git a/broadcastradio/1.1/default/VirtualProgram.h b/broadcastradio/1.1/default/VirtualProgram.h
index 33ec292..a14830d 100644
--- a/broadcastradio/1.1/default/VirtualProgram.h
+++ b/broadcastradio/1.1/default/VirtualProgram.h
@@ -25,6 +25,12 @@
 namespace V1_1 {
 namespace implementation {
 
+/**
+ * A radio program mock.
+ *
+ * This represents broadcast waves flying over the air,
+ * not an entry for a captured station in the radio tuner memory.
+ */
 struct VirtualProgram {
     ProgramSelector selector;
 
diff --git a/broadcastradio/1.1/default/VirtualRadio.cpp b/broadcastradio/1.1/default/VirtualRadio.cpp
index 692e7bc..36d47a9 100644
--- a/broadcastradio/1.1/default/VirtualRadio.cpp
+++ b/broadcastradio/1.1/default/VirtualRadio.cpp
@@ -13,9 +13,13 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
+#define LOG_TAG "BroadcastRadioDefault.VirtualRadio"
+//#define LOG_NDEBUG 0
+
 #include "VirtualRadio.h"
 
 #include <broadcastradio-utils/Utils.h>
+#include <log/log.h>
 
 namespace android {
 namespace hardware {
@@ -24,6 +28,7 @@
 namespace implementation {
 
 using V1_0::Band;
+using V1_0::Class;
 
 using std::lock_guard;
 using std::move;
@@ -32,7 +37,7 @@
 
 using utils::make_selector;
 
-const vector<VirtualProgram> gInitialFmPrograms{
+static const vector<VirtualProgram> gInitialFmPrograms{
     {make_selector(Band::FM, 94900), "Wild 94.9", "Drake ft. Rihanna", "Too Good"},
     {make_selector(Band::FM, 96500), "KOIT", "Celine Dion", "All By Myself"},
     {make_selector(Band::FM, 97300), "Alice@97.3", "Drops of Jupiter", "Train"},
@@ -42,7 +47,8 @@
     {make_selector(Band::FM, 106100), "106 KMEL", "Drake", "Marvins Room"},
 };
 
-VirtualRadio::VirtualRadio(VirtualRadio&& o) : mPrograms(move(o.mPrograms)) {}
+static VirtualRadio gEmptyRadio({});
+static VirtualRadio gFmRadio(gInitialFmPrograms);
 
 VirtualRadio::VirtualRadio(const vector<VirtualProgram> initialList) : mPrograms(initialList) {}
 
@@ -62,8 +68,34 @@
     return false;
 }
 
-VirtualRadio make_fm_radio() {
-    return VirtualRadio(gInitialFmPrograms);
+VirtualRadio& getRadio(V1_0::Class classId) {
+    switch (classId) {
+        case Class::AM_FM:
+            return getFmRadio();
+        case Class::SAT:
+            return getSatRadio();
+        case Class::DT:
+            return getDigitalRadio();
+        default:
+            ALOGE("Invalid class ID");
+            return gEmptyRadio;
+    }
+}
+
+VirtualRadio& getAmRadio() {
+    return gEmptyRadio;
+}
+
+VirtualRadio& getFmRadio() {
+    return gFmRadio;
+}
+
+VirtualRadio& getSatRadio() {
+    return gEmptyRadio;
+}
+
+VirtualRadio& getDigitalRadio() {
+    return gEmptyRadio;
 }
 
 }  // namespace implementation
diff --git a/broadcastradio/1.1/default/VirtualRadio.h b/broadcastradio/1.1/default/VirtualRadio.h
index 4cdc72f..3c7ae5c 100644
--- a/broadcastradio/1.1/default/VirtualRadio.h
+++ b/broadcastradio/1.1/default/VirtualRadio.h
@@ -27,9 +27,16 @@
 namespace V1_1 {
 namespace implementation {
 
+/**
+ * A radio frequency space mock.
+ *
+ * This represents all broadcast waves in the air for a given radio technology,
+ * not a captured station list in the radio tuner memory.
+ *
+ * It's meant to abstract out radio content from default tuner implementation.
+ */
 class VirtualRadio {
    public:
-    VirtualRadio(VirtualRadio&& o);
     VirtualRadio(const std::vector<VirtualProgram> initialList);
 
     std::vector<VirtualProgram> getProgramList();
@@ -40,7 +47,29 @@
     std::vector<VirtualProgram> mPrograms;
 };
 
-VirtualRadio make_fm_radio();
+/**
+ * Get virtual radio space for a given radio class.
+ *
+ * As a space, each virtual radio always exists. For example, DAB frequencies
+ * exists in US, but contains no programs.
+ *
+ * The lifetime of the virtual radio space is virtually infinite, but for the
+ * needs of default implementation, it's bound with the lifetime of default
+ * implementation process.
+ *
+ * Internally, it's a static object, so trying to access the reference during
+ * default implementation library unloading may result in segmentation fault.
+ * It's unlikely for testing purposes.
+ *
+ * @param classId A class of radio technology.
+ * @return A reference to virtual radio space for a given technology.
+ */
+VirtualRadio& getRadio(V1_0::Class classId);
+
+VirtualRadio& getAmRadio();
+VirtualRadio& getFmRadio();
+VirtualRadio& getSatRadio();
+VirtualRadio& getDigitalRadio();
 
 }  // namespace implementation
 }  // namespace V1_1