Implement regional configuration fetching.

Bug: 69958423
Test: VTS
Change-Id: I7c184191b4f4999bd03b06bd3b2283e028694918
diff --git a/broadcastradio/2.0/default/Android.bp b/broadcastradio/2.0/default/Android.bp
index 6d4effb..900454e 100644
--- a/broadcastradio/2.0/default/Android.bp
+++ b/broadcastradio/2.0/default/Android.bp
@@ -24,6 +24,9 @@
         "-Wextra",
         "-Werror",
     ],
+    cppflags: [
+        "-std=c++1z",
+    ],
     srcs: [
         "BroadcastRadio.cpp",
         "TunerSession.cpp",
diff --git a/broadcastradio/2.0/default/BroadcastRadio.cpp b/broadcastradio/2.0/default/BroadcastRadio.cpp
index 5ab517d..5dde8a7 100644
--- a/broadcastradio/2.0/default/BroadcastRadio.cpp
+++ b/broadcastradio/2.0/default/BroadcastRadio.cpp
@@ -33,6 +33,16 @@
 using std::mutex;
 using std::vector;
 
+static const AmFmRegionConfig gDefaultAmFmConfig = {  //
+    {
+        {87500, 108000, 100, 100},  // FM
+        {153, 282, 3, 9},           // AM LW
+        {531, 1620, 9, 9},          // AM MW
+        {1600, 30000, 1, 5},        // AM SW
+    },
+    static_cast<uint32_t>(Deemphasis::D50),
+    static_cast<uint32_t>(Rds::RDS)};
+
 static Properties initProperties(const VirtualRadio& virtualRadio) {
     Properties prop = {};
 
@@ -51,7 +61,9 @@
 }
 
 BroadcastRadio::BroadcastRadio(const VirtualRadio& virtualRadio)
-    : mVirtualRadio(virtualRadio), mProperties(initProperties(virtualRadio)) {}
+    : mVirtualRadio(virtualRadio),
+      mProperties(initProperties(virtualRadio)),
+      mAmFmConfig(gDefaultAmFmConfig) {}
 
 Return<void> BroadcastRadio::getProperties(getProperties_cb _hidl_cb) {
     ALOGV("%s", __func__);
@@ -59,6 +71,44 @@
     return {};
 }
 
+AmFmRegionConfig BroadcastRadio::getAmFmConfig() const {
+    lock_guard<mutex> lk(mMut);
+    return mAmFmConfig;
+}
+
+Return<void> BroadcastRadio::getAmFmRegionConfig(bool full, getAmFmRegionConfig_cb _hidl_cb) {
+    ALOGV("%s(%d)", __func__, full);
+
+    if (full) {
+        AmFmRegionConfig config = {};
+        config.ranges = hidl_vec<AmFmBandRange>({
+            {65000, 108000, 10, 0},  // FM
+            {150, 30000, 1, 0},      // AM
+        });
+        config.fmDeemphasis = Deemphasis::D50 | Deemphasis::D75;
+        config.fmRds = Rds::RDS | Rds::RBDS;
+        _hidl_cb(Result::OK, config);
+        return {};
+    } else {
+        _hidl_cb(Result::OK, getAmFmConfig());
+        return {};
+    }
+}
+
+Return<void> BroadcastRadio::getDabRegionConfig(getDabRegionConfig_cb _hidl_cb) {
+    ALOGV("%s", __func__);
+
+    hidl_vec<DabTableEntry> config = {
+        {"5A", 174928},  {"7D", 194064},  {"8A", 195936},  {"8B", 197648},  {"9A", 202928},
+        {"9B", 204640},  {"9C", 206352},  {"10B", 211648}, {"10C", 213360}, {"10D", 215072},
+        {"11A", 216928}, {"11B", 218640}, {"11C", 220352}, {"11D", 222064}, {"12A", 223936},
+        {"12B", 225648}, {"12C", 227360}, {"12D", 229072},
+    };
+
+    _hidl_cb(Result::OK, config);
+    return {};
+}
+
 Return<void> BroadcastRadio::openSession(const sp<ITunerCallback>& callback,
                                          openSession_cb _hidl_cb) {
     ALOGV("%s", __func__);
diff --git a/broadcastradio/2.0/default/BroadcastRadio.h b/broadcastradio/2.0/default/BroadcastRadio.h
index fcf0615..733cadf 100644
--- a/broadcastradio/2.0/default/BroadcastRadio.h
+++ b/broadcastradio/2.0/default/BroadcastRadio.h
@@ -32,14 +32,19 @@
 
     // V2_0::IBroadcastRadio methods
     Return<void> getProperties(getProperties_cb _hidl_cb) override;
+    Return<void> getAmFmRegionConfig(bool full, getAmFmRegionConfig_cb _hidl_cb);
+    Return<void> getDabRegionConfig(getDabRegionConfig_cb _hidl_cb);
     Return<void> openSession(const sp<ITunerCallback>& callback, openSession_cb _hidl_cb) override;
     Return<void> getImage(uint32_t id, getImage_cb _hidl_cb);
 
     std::reference_wrapper<const VirtualRadio> mVirtualRadio;
     Properties mProperties;
 
+    AmFmRegionConfig getAmFmConfig() const;
+
    private:
-    std::mutex mMut;
+    mutable std::mutex mMut;
+    AmFmRegionConfig mAmFmConfig;
     wp<TunerSession> mSession;
 };
 
diff --git a/broadcastradio/2.0/default/TunerSession.cpp b/broadcastradio/2.0/default/TunerSession.cpp
index 244544a..3166d86 100644
--- a/broadcastradio/2.0/default/TunerSession.cpp
+++ b/broadcastradio/2.0/default/TunerSession.cpp
@@ -77,8 +77,12 @@
     mCallback->onCurrentProgramInfoChanged(programInfo);
 }
 
+const BroadcastRadio& TunerSession::module() const {
+    return mModule.get();
+}
+
 const VirtualRadio& TunerSession::virtualRadio() const {
-    return mModule.get().mVirtualRadio;
+    return module().mVirtualRadio;
 }
 
 Return<Result> TunerSession::tune(const ProgramSelector& sel) {
@@ -86,7 +90,7 @@
     lock_guard<mutex> lk(mMut);
     if (mIsClosed) return Result::INVALID_STATE;
 
-    if (!utils::isSupported(mModule.get().mProperties, sel)) {
+    if (!utils::isSupported(module().mProperties, sel)) {
         ALOGW("Selector not supported");
         return Result::NOT_SUPPORTED;
     }
@@ -170,23 +174,19 @@
     mIsTuneCompleted = false;
 
     auto stepTo = utils::getId(mCurrentProgram, IdentifierType::AMFM_FREQUENCY);
-#if 0
-    // TODO(b/69958423): handle regions
-    if (directionUp) {
-        stepTo += mAmfmConfig.spacings[0];
-    } else {
-        stepTo -= mAmfmConfig.spacings[0];
+    auto range = getAmFmRangeLocked();
+    if (!range) {
+        ALOGE("Can't find current band");
+        return Result::INTERNAL_ERROR;
     }
 
-    if (stepTo > mAmfmConfig.upperLimit) stepTo = mAmfmConfig.lowerLimit;
-    if (stepTo < mAmfmConfig.lowerLimit) stepTo = mAmfmConfig.upperLimit;
-#else
     if (directionUp) {
-        stepTo += 100;
+        stepTo += range->spacing;
     } else {
-        stepTo -= 100;
+        stepTo -= range->spacing;
     }
-#endif
+    if (stepTo > range->upperBound) stepTo = range->lowerBound;
+    if (stepTo < range->lowerBound) stepTo = range->upperBound;
 
     auto task = [this, stepTo]() {
         ALOGI("Performing step to %s", std::to_string(stepTo).c_str());
@@ -280,6 +280,18 @@
     return {};
 }
 
+std::optional<AmFmBandRange> TunerSession::getAmFmRangeLocked() const {
+    if (!mIsTuneCompleted) return {};
+    if (!utils::hasId(mCurrentProgram, IdentifierType::AMFM_FREQUENCY)) return {};
+
+    auto freq = utils::getId(mCurrentProgram, IdentifierType::AMFM_FREQUENCY);
+    for (auto&& range : module().getAmFmConfig().ranges) {
+        if (range.lowerBound <= freq && range.upperBound >= freq) return range;
+    }
+
+    return {};
+}
+
 }  // namespace implementation
 }  // namespace V2_0
 }  // namespace broadcastradio
diff --git a/broadcastradio/2.0/default/TunerSession.h b/broadcastradio/2.0/default/TunerSession.h
index a58aa19..5d27b1e 100644
--- a/broadcastradio/2.0/default/TunerSession.h
+++ b/broadcastradio/2.0/default/TunerSession.h
@@ -22,6 +22,8 @@
 #include <android/hardware/broadcastradio/2.0/ITunerSession.h>
 #include <broadcastradio-utils/WorkerThread.h>
 
+#include <optional>
+
 namespace android {
 namespace hardware {
 namespace broadcastradio {
@@ -48,6 +50,8 @@
                                        getParameters_cb _hidl_cb) override;
     virtual Return<void> close() override;
 
+    std::optional<AmFmBandRange> getAmFmRangeLocked() const;
+
    private:
     std::mutex mMut;
     WorkerThread mThread;
@@ -61,6 +65,7 @@
 
     void tuneInternalLocked(const ProgramSelector& sel);
     const VirtualRadio& virtualRadio() const;
+    const BroadcastRadio& module() const;
 };
 
 }  // namespace implementation