Add TestGnssMeasurementCodeType VTS test

- add default implementation to mock reporting measurements.

Bug: 120277977
Fixes: 120277977

Test: atest VtsHalGnssV2_0TargetTest
Change-Id: I881f105874a992327551ef616860d7bd61e4bf83
diff --git a/gnss/2.0/default/Gnss.cpp b/gnss/2.0/default/Gnss.cpp
index 7f1ef9b..886a3a8 100644
--- a/gnss/2.0/default/Gnss.cpp
+++ b/gnss/2.0/default/Gnss.cpp
@@ -19,6 +19,7 @@
 #include "Gnss.h"
 #include <log/log.h>
 #include "AGnssRil.h"
+#include "GnssMeasurement.h"
 
 namespace android {
 namespace hardware {
@@ -93,8 +94,8 @@
 }
 
 Return<sp<V1_0::IGnssMeasurement>> Gnss::getExtensionGnssMeasurement() {
-    // TODO implement
-    return sp<V1_0::IGnssMeasurement>{};
+    // Not supported
+    return nullptr;
 }
 
 Return<sp<V1_0::IGnssNavigationMessage>> Gnss::getExtensionGnssNavigationMessage() {
@@ -132,7 +133,7 @@
 
     sGnssCallback_1_1 = callback;
 
-    uint32_t capabilities = 0x0;
+    uint32_t capabilities = (uint32_t)V1_0::IGnssCallback::Capabilities::MEASUREMENTS;
     auto ret = sGnssCallback_1_1->gnssSetCapabilitesCb(capabilities);
     if (!ret.isOk()) {
         ALOGE("%s: Unable to invoke callback", __func__);
@@ -167,8 +168,8 @@
 }
 
 Return<sp<V1_1::IGnssMeasurement>> Gnss::getExtensionGnssMeasurement_1_1() {
-    // TODO implement
-    return sp<V1_1::IGnssMeasurement>{};
+    ALOGD("Gnss::getExtensionGnssMeasurement_1_1");
+    return new GnssMeasurement();
 }
 
 Return<bool> Gnss::injectBestLocation(const V1_0::GnssLocation&) {
@@ -182,8 +183,8 @@
 }
 
 Return<sp<V2_0::IGnssMeasurement>> Gnss::getExtensionGnssMeasurement_2_0() {
-    // TODO implement
-    return sp<V2_0::IGnssMeasurement>{};
+    ALOGD("Gnss::getExtensionGnssMeasurement_2_0");
+    return new GnssMeasurement();
 }
 
 Return<sp<measurement_corrections::V1_0::IMeasurementCorrections>>
diff --git a/gnss/2.0/default/GnssMeasurement.cpp b/gnss/2.0/default/GnssMeasurement.cpp
index fbcdc12..dc23db3 100644
--- a/gnss/2.0/default/GnssMeasurement.cpp
+++ b/gnss/2.0/default/GnssMeasurement.cpp
@@ -13,8 +13,10 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
+#define LOG_TAG "GnssMeasurement"
 
 #include "GnssMeasurement.h"
+#include <log/log.h>
 
 namespace android {
 namespace hardware {
@@ -22,6 +24,18 @@
 namespace V2_0 {
 namespace implementation {
 
+using GnssConstellationType = V1_0::GnssConstellationType;
+using GnssMeasurementFlags = V1_0::IGnssMeasurementCallback::GnssMeasurementFlags;
+using GnssMeasurementState = V1_0::IGnssMeasurementCallback::GnssMeasurementState;
+
+sp<V2_0::IGnssMeasurementCallback> GnssMeasurement::sCallback = nullptr;
+
+GnssMeasurement::GnssMeasurement() : mMinIntervalMillis(1000) {}
+
+GnssMeasurement::~GnssMeasurement() {
+    stop();
+}
+
 // Methods from V1_0::IGnssMeasurement follow.
 Return<V1_0::IGnssMeasurement::GnssMeasurementStatus> GnssMeasurement::setCallback(
     const sp<V1_0::IGnssMeasurementCallback>&) {
@@ -30,7 +44,9 @@
 }
 
 Return<void> GnssMeasurement::close() {
-    // TODO implement
+    std::unique_lock<std::mutex> lock(mMutex);
+    stop();
+    sCallback = nullptr;
     return Void();
 }
 
@@ -43,17 +59,89 @@
 
 // Methods from V2_0::IGnssMeasurement follow.
 Return<V1_0::IGnssMeasurement::GnssMeasurementStatus> GnssMeasurement::setCallback_2_0(
-    const sp<V2_0::IGnssMeasurementCallback>&, bool) {
-    // TODO implement
-    return V1_0::IGnssMeasurement::GnssMeasurementStatus{};
+    const sp<V2_0::IGnssMeasurementCallback>& callback, bool) {
+    std::unique_lock<std::mutex> lock(mMutex);
+    sCallback = callback;
+
+    if (mIsActive) {
+        ALOGW("GnssMeasurement callback already set. Resetting the callback...");
+        stop();
+    }
+    start();
+
+    return V1_0::IGnssMeasurement::GnssMeasurementStatus::SUCCESS;
 }
 
-// Methods from ::android::hidl::base::V1_0::IBase follow.
+void GnssMeasurement::start() {
+    mIsActive = true;
+    mThread = std::thread([this]() {
+        while (mIsActive == true) {
+            auto measurement = this->getMockMeasurement();
+            this->reportMeasurement(measurement);
 
-// IGnssMeasurement* HIDL_FETCH_IGnssMeasurement(const char* /* name */) {
-// return new GnssMeasurement();
-//}
-//
+            std::this_thread::sleep_for(std::chrono::milliseconds(mMinIntervalMillis));
+        }
+    });
+}
+
+void GnssMeasurement::stop() {
+    mIsActive = false;
+    if (mThread.joinable()) {
+        mThread.join();
+    }
+}
+
+GnssData GnssMeasurement::getMockMeasurement() {
+    V1_0::IGnssMeasurementCallback::GnssMeasurement measurement_1_0 = {
+        .flags = (uint32_t)GnssMeasurementFlags::HAS_CARRIER_FREQUENCY,
+        .svid = (int16_t)6,
+        .constellation = GnssConstellationType::GLONASS,
+        .timeOffsetNs = 0.0,
+        .state = GnssMeasurementState::STATE_CODE_LOCK | GnssMeasurementState::STATE_BIT_SYNC |
+                 GnssMeasurementState::STATE_SUBFRAME_SYNC |
+                 GnssMeasurementState::STATE_TOW_DECODED |
+                 GnssMeasurementState::STATE_GLO_STRING_SYNC |
+                 GnssMeasurementState::STATE_GLO_TOD_DECODED,
+        .receivedSvTimeInNs = 8195997131077,
+        .receivedSvTimeUncertaintyInNs = 15,
+        .cN0DbHz = 30.0,
+        .pseudorangeRateMps = -484.13739013671875,
+        .pseudorangeRateUncertaintyMps = 1.0379999876022339,
+        .accumulatedDeltaRangeState = (uint32_t)
+            V1_0::IGnssMeasurementCallback::GnssAccumulatedDeltaRangeState::ADR_STATE_UNKNOWN,
+        .accumulatedDeltaRangeM = 0.0,
+        .accumulatedDeltaRangeUncertaintyM = 0.0,
+        .carrierFrequencyHz = 1.59975e+09,
+        .multipathIndicator =
+            V1_0::IGnssMeasurementCallback::GnssMultipathIndicator::INDICATOR_UNKNOWN};
+    V1_1::IGnssMeasurementCallback::GnssMeasurement measurement_1_1 = {.v1_0 = measurement_1_0};
+    V2_0::IGnssMeasurementCallback::GnssMeasurement measurement_2_0 = {
+        .v1_1 = measurement_1_1,
+        .codeType = IGnssMeasurementCallback::GnssMeasurementCodeType::CODE_TYPE_C};
+
+    hidl_vec<IGnssMeasurementCallback::GnssMeasurement> measurements(1);
+    measurements[0] = measurement_2_0;
+    V1_0::IGnssMeasurementCallback::GnssClock clock = {.timeNs = 2713545000000,
+                                                       .fullBiasNs = -1226701900521857520,
+                                                       .biasNs = 0.59689998626708984,
+                                                       .biasUncertaintyNs = 47514.989972114563,
+                                                       .driftNsps = -51.757811607455452,
+                                                       .driftUncertaintyNsps = 310.64968328491528,
+                                                       .hwClockDiscontinuityCount = 1};
+    GnssData gnssData = {.measurements = measurements, .clock = clock};
+    return gnssData;
+}
+
+void GnssMeasurement::reportMeasurement(const GnssData& data) {
+    ALOGD("reportMeasurement()");
+    std::unique_lock<std::mutex> lock(mMutex);
+    if (sCallback == nullptr) {
+        ALOGE("%s: GnssMeasurement::sCallback is null.", __func__);
+        return;
+    }
+    sCallback->gnssMeasurementCb_2_0(data);
+}
+
 }  // namespace implementation
 }  // namespace V2_0
 }  // namespace gnss
diff --git a/gnss/2.0/default/GnssMeasurement.h b/gnss/2.0/default/GnssMeasurement.h
index 8c621bb..c24c00e 100644
--- a/gnss/2.0/default/GnssMeasurement.h
+++ b/gnss/2.0/default/GnssMeasurement.h
@@ -20,6 +20,9 @@
 #include <android/hardware/gnss/2.0/IGnssMeasurement.h>
 #include <hidl/MQDescriptor.h>
 #include <hidl/Status.h>
+#include <atomic>
+#include <mutex>
+#include <thread>
 
 namespace android {
 namespace hardware {
@@ -35,7 +38,11 @@
 using ::android::hardware::Return;
 using ::android::hardware::Void;
 
+using GnssData = V2_0::IGnssMeasurementCallback::GnssData;
+
 struct GnssMeasurement : public IGnssMeasurement {
+    GnssMeasurement();
+    ~GnssMeasurement();
     // Methods from V1_0::IGnssMeasurement follow.
     Return<V1_0::IGnssMeasurement::GnssMeasurementStatus> setCallback(
         const sp<V1_0::IGnssMeasurementCallback>& callback) override;
@@ -48,6 +55,18 @@
     // Methods from V2_0::IGnssMeasurement follow.
     Return<V1_0::IGnssMeasurement::GnssMeasurementStatus> setCallback_2_0(
         const sp<V2_0::IGnssMeasurementCallback>& callback, bool enableFullTracking) override;
+
+   private:
+    void start();
+    void stop();
+    GnssData getMockMeasurement();
+    void reportMeasurement(const GnssData&);
+
+    static sp<IGnssMeasurementCallback> sCallback;
+    std::atomic<long> mMinIntervalMillis;
+    std::atomic<bool> mIsActive;
+    std::thread mThread;
+    mutable std::mutex mMutex;
 };
 
 }  // namespace implementation
diff --git a/gnss/2.0/vts/functional/gnss_hal_test.cpp b/gnss/2.0/vts/functional/gnss_hal_test.cpp
index d7101a0..3a48c9e 100644
--- a/gnss/2.0/vts/functional/gnss_hal_test.cpp
+++ b/gnss/2.0/vts/functional/gnss_hal_test.cpp
@@ -38,6 +38,13 @@
 }
 
 void GnssHalTest::TearDown() {
+    // Reset counters
+    info_called_count_ = 0;
+    capabilities_called_count_ = 0;
+    location_called_count_ = 0;
+    name_called_count_ = 0;
+    measurement_called_count_ = 0;
+
     if (gnss_hal_ != nullptr) {
         gnss_hal_->cleanup();
     }
@@ -127,3 +134,12 @@
     parent_.list_gnss_sv_status_.emplace_back(svStatus);
     return Void();
 }
+
+Return<void> GnssHalTest::GnssMeasurementCallback::gnssMeasurementCb_2_0(
+    const IGnssMeasurementCallback_2_0::GnssData& data) {
+    ALOGD("GnssMeasurement received. Size = %d", (int)data.measurements.size());
+    parent_.measurement_called_count_++;
+    parent_.last_measurement_ = data;
+    parent_.notify();
+    return Void();
+}
diff --git a/gnss/2.0/vts/functional/gnss_hal_test.h b/gnss/2.0/vts/functional/gnss_hal_test.h
index 64f3575..5649b45 100644
--- a/gnss/2.0/vts/functional/gnss_hal_test.h
+++ b/gnss/2.0/vts/functional/gnss_hal_test.h
@@ -34,6 +34,9 @@
 using android::hardware::gnss::V1_0::GnssLocationFlags;
 using android::hardware::gnss::V1_1::IGnssCallback;
 using android::hardware::gnss::V2_0::IGnss;
+using IGnssMeasurementCallback_1_0 = android::hardware::gnss::V1_0::IGnssMeasurementCallback;
+using IGnssMeasurementCallback_1_1 = android::hardware::gnss::V1_1::IGnssMeasurementCallback;
+using IGnssMeasurementCallback_2_0 = android::hardware::gnss::V2_0::IGnssMeasurementCallback;
 
 using android::sp;
 
@@ -100,6 +103,27 @@
         Return<void> gnssSvStatusCb(const IGnssCallback::GnssSvStatus& svStatus) override;
     };
 
+    /* Callback class for GnssMeasurement. */
+    class GnssMeasurementCallback : public IGnssMeasurementCallback_2_0 {
+       public:
+        GnssHalTest& parent_;
+        GnssMeasurementCallback(GnssHalTest& parent) : parent_(parent){};
+        virtual ~GnssMeasurementCallback() = default;
+
+        // Methods from V1_0::IGnssMeasurementCallback follow.
+        Return<void> GnssMeasurementCb(const IGnssMeasurementCallback_1_0::GnssData&) override {
+            return Void();
+        }
+
+        // Methods from V1_1::IGnssMeasurementCallback follow.
+        Return<void> gnssMeasurementCb(const IGnssMeasurementCallback_1_1::GnssData&) override {
+            return Void();
+        }
+
+        // Methods from V2_0::IGnssMeasurementCallback follow.
+        Return<void> gnssMeasurementCb_2_0(const IGnssMeasurementCallback_2_0::GnssData&) override;
+    };
+
     /*
      * SetUpGnssCallback:
      *   Set GnssCallback and verify the result.
@@ -113,16 +137,19 @@
      * test.)
      */
     int info_called_count_;
-    IGnssCallback::GnssSystemInfo last_info_;
-    uint32_t last_capabilities_;
     int capabilities_called_count_;
     int location_called_count_;
-    GnssLocation last_location_;
-    list<IGnssCallback::GnssSvStatus> list_gnss_sv_status_;
-
+    int measurement_called_count_;
     int name_called_count_;
+
+    IGnssCallback::GnssSystemInfo last_info_;
+    uint32_t last_capabilities_;
+    GnssLocation last_location_;
+    IGnssMeasurementCallback_2_0::GnssData last_measurement_;
     android::hardware::hidl_string last_name_;
 
+    list<IGnssCallback::GnssSvStatus> list_gnss_sv_status_;
+
    private:
     std::mutex mtx_;
     std::condition_variable cv_;
diff --git a/gnss/2.0/vts/functional/gnss_hal_test_cases.cpp b/gnss/2.0/vts/functional/gnss_hal_test_cases.cpp
index 478a4b2..c1f1393 100644
--- a/gnss/2.0/vts/functional/gnss_hal_test_cases.cpp
+++ b/gnss/2.0/vts/functional/gnss_hal_test_cases.cpp
@@ -21,9 +21,10 @@
 
 using android::hardware::hidl_vec;
 
+using IAGnssRil_2_0 = android::hardware::gnss::V2_0::IAGnssRil;
 using IGnssMeasurement_2_0 = android::hardware::gnss::V2_0::IGnssMeasurement;
 using IGnssMeasurement_1_1 = android::hardware::gnss::V1_1::IGnssMeasurement;
-using IAGnssRil_2_0 = android::hardware::gnss::V2_0::IAGnssRil;
+using IGnssMeasurement_1_0 = android::hardware::gnss::V1_0::IGnssMeasurement;
 
 /*
  * SetupTeardownCreateCleanup:
@@ -40,12 +41,17 @@
 TEST_F(GnssHalTest, TestGnssMeasurementCallback) {
     auto gnssMeasurement_2_0 = gnss_hal_->getExtensionGnssMeasurement_2_0();
     auto gnssMeasurement_1_1 = gnss_hal_->getExtensionGnssMeasurement_1_1();
-    ASSERT_TRUE(gnssMeasurement_2_0.isOk() || gnssMeasurement_1_1.isOk());
+    auto gnssMeasurement_1_0 = gnss_hal_->getExtensionGnssMeasurement();
+    ASSERT_TRUE(gnssMeasurement_2_0.isOk() || gnssMeasurement_1_1.isOk() ||
+                gnssMeasurement_1_0.isOk());
     if (last_capabilities_ & IGnssCallback::Capabilities::MEASUREMENTS) {
         sp<IGnssMeasurement_2_0> iGnssMeas_2_0 = gnssMeasurement_2_0;
         sp<IGnssMeasurement_1_1> iGnssMeas_1_1 = gnssMeasurement_1_1;
-        // Exactly one interface is non-null.
-        ASSERT_TRUE((iGnssMeas_1_1 != nullptr) != (iGnssMeas_2_0 != nullptr));
+        sp<IGnssMeasurement_1_0> iGnssMeas_1_0 = gnssMeasurement_1_0;
+        // At least one interface is non-null.
+        int numNonNull = (int)(iGnssMeas_2_0 != nullptr) + (int)(iGnssMeas_1_1 != nullptr) +
+                         (int)(iGnssMeas_1_0 != nullptr);
+        ASSERT_TRUE(numNonNull >= 1);
     }
 }
 
@@ -90,3 +96,40 @@
     ASSERT_TRUE(result.isOk());
     EXPECT_TRUE(result);
 }
+
+/*
+ * TestGnssMeasurementCodeType:
+ * Sets a GnssMeasurementCallback, waits for a measurement, and verifies the codeType is valid.
+ */
+TEST_F(GnssHalTest, TestGnssMeasurementCodeType) {
+    const int kFirstGnssMeasurementTimeoutSeconds = 10;
+
+    auto gnssMeasurement = gnss_hal_->getExtensionGnssMeasurement_2_0();
+    if (!gnssMeasurement.isOk()) {
+        return;
+    }
+
+    sp<IGnssMeasurement_2_0> iGnssMeasurement = gnssMeasurement;
+    if (iGnssMeasurement == nullptr) {
+        return;
+    }
+
+    sp<IGnssMeasurementCallback_2_0> callback = new GnssMeasurementCallback(*this);
+
+    auto result = iGnssMeasurement->setCallback_2_0(callback, /* enableFullTracking= */ true);
+    ASSERT_TRUE(result.isOk());
+    EXPECT_EQ(result, IGnssMeasurement_1_0::GnssMeasurementStatus::SUCCESS);
+
+    wait(kFirstGnssMeasurementTimeoutSeconds);
+    EXPECT_EQ(measurement_called_count_, 1);
+    ASSERT_TRUE(last_measurement_.measurements.size() > 0);
+    for (auto measurement : last_measurement_.measurements) {
+        ASSERT_TRUE(
+            (int)measurement.codeType >=
+                (int)IGnssMeasurementCallback_2_0::GnssMeasurementCodeType::CODE_TYPE_A &&
+            (int)measurement.codeType <=
+                (int)IGnssMeasurementCallback_2_0::GnssMeasurementCodeType::CODE_TYPE_CODELESS);
+    }
+
+    iGnssMeasurement->close();
+}