Add more GnssDebug validity tests

Bug: 326293710
Test: atest VtsHalGnssTargetTest
Change-Id: Ie20d0ce369bc7d03ccfb7f7e01a4e28ed54a5d4d
diff --git a/gnss/aidl/default/Gnss.cpp b/gnss/aidl/default/Gnss.cpp
index c31f991..94d4d00 100644
--- a/gnss/aidl/default/Gnss.cpp
+++ b/gnss/aidl/default/Gnss.cpp
@@ -162,12 +162,13 @@
     return ScopedAStatus::ok();
 }
 
-void Gnss::reportLocation(const GnssLocation& location) const {
+void Gnss::reportLocation(const GnssLocation& location) {
     std::unique_lock<std::mutex> lock(mMutex);
     if (sGnssCallback == nullptr) {
         ALOGE("%s: GnssCallback is null.", __func__);
         return;
     }
+    mLastLocation = std::make_shared<GnssLocation>(location);
     auto status = sGnssCallback->gnssLocationCb(location);
     if (!status.isOk()) {
         ALOGE("%s: Unable to invoke gnssLocationCb", __func__);
@@ -359,7 +360,6 @@
 
 ndk::ScopedAStatus Gnss::getExtensionGnssDebug(std::shared_ptr<IGnssDebug>* iGnssDebug) {
     ALOGD("Gnss::getExtensionGnssDebug");
-
     *iGnssDebug = SharedRefBase::make<GnssDebug>();
     return ndk::ScopedAStatus::ok();
 }
@@ -398,4 +398,8 @@
     mGnssMeasurementIntervalMs = intervalMs;
 }
 
+std::shared_ptr<GnssLocation> Gnss::getLastLocation() const {
+    return mLastLocation;
+}
+
 }  // namespace aidl::android::hardware::gnss
diff --git a/gnss/aidl/default/Gnss.h b/gnss/aidl/default/Gnss.h
index 245d607..73085ef 100644
--- a/gnss/aidl/default/Gnss.h
+++ b/gnss/aidl/default/Gnss.h
@@ -87,18 +87,19 @@
     void reportSvStatus() const;
     void setGnssMeasurementEnabled(const bool enabled);
     void setGnssMeasurementInterval(const long intervalMs);
+    std::shared_ptr<GnssLocation> getLastLocation() const;
     std::shared_ptr<GnssConfiguration> mGnssConfiguration;
     std::shared_ptr<GnssPowerIndication> mGnssPowerIndication;
     std::shared_ptr<GnssMeasurementInterface> mGnssMeasurementInterface;
 
   private:
-    void reportLocation(const GnssLocation&) const;
+    void reportLocation(const GnssLocation&);
     void reportSvStatus(const std::vector<IGnssCallback::GnssSvInfo>& svInfoList) const;
+    void reportGnssStatusValue(const IGnssCallback::GnssStatusValue gnssStatusValue) const;
+    void reportNmea() const;
     std::vector<IGnssCallback::GnssSvInfo> filterBlocklistedSatellites(
             std::vector<IGnssCallback::GnssSvInfo> gnssSvInfoList) const;
-    void reportGnssStatusValue(const IGnssCallback::GnssStatusValue gnssStatusValue) const;
     std::unique_ptr<GnssLocation> getLocationFromHW();
-    void reportNmea() const;
 
     static std::shared_ptr<IGnssCallback> sGnssCallback;
 
@@ -109,6 +110,7 @@
     std::atomic<bool> mIsNmeaActive;
     std::atomic<bool> mFirstFixReceived;
     std::atomic<bool> mGnssMeasurementEnabled;
+    std::shared_ptr<GnssLocation> mLastLocation;
     std::thread mThread;
     ::android::hardware::gnss::common::ThreadBlocker mThreadBlocker;
 
diff --git a/gnss/aidl/default/GnssDebug.cpp b/gnss/aidl/default/GnssDebug.cpp
index f40c0bc..5ae6edd 100644
--- a/gnss/aidl/default/GnssDebug.cpp
+++ b/gnss/aidl/default/GnssDebug.cpp
@@ -18,10 +18,15 @@
 
 #include "GnssDebug.h"
 #include <log/log.h>
+#include <utils/SystemClock.h>
+#include "Constants.h"
+#include "Gnss.h"
 #include "MockLocation.h"
 
 namespace aidl::android::hardware::gnss {
 
+using ::android::hardware::gnss::common::kMockTimestamp;
+
 ndk::ScopedAStatus GnssDebug::getDebugData(DebugData* debugData) {
     ALOGD("GnssDebug::getDebugData");
 
@@ -36,10 +41,94 @@
                                    .speedAccuracyMetersPerSecond = 1,
                                    .bearingAccuracyDegrees = 90,
                                    .ageSeconds = 0.99};
-    TimeDebug timeDebug = {.timeEstimateMs = 1519930775453L,
+    TimeDebug timeDebug = {.timeEstimateMs = static_cast<int64_t>(
+                                   kMockTimestamp + ::android::elapsedRealtimeNano() / 1e6),
                            .timeUncertaintyNs = 1000,
-                           .frequencyUncertaintyNsPerSec = 5.0e4};
-    std::vector<SatelliteData> satelliteDataArrayDebug = {};
+                           .frequencyUncertaintyNsPerSec = 800};
+    SatelliteData satelliteData1 = {
+            .svid = 3,
+            .constellation = GnssConstellationType::GPS,
+            .ephemerisType = SatelliteEphemerisType::EPHEMERIS,
+            .ephemerisSource = SatellitePvt::SatelliteEphemerisSource::SERVER_LONG_TERM,
+            .ephemerisHealth = SatelliteEphemerisHealth::GOOD,
+            .ephemerisAgeSeconds = 12,
+            .serverPredictionIsAvailable = true,
+            .serverPredictionAgeSeconds = 30};
+    SatelliteData satelliteData2 = {
+            .svid = 5,
+            .constellation = GnssConstellationType::GPS,
+            .ephemerisType = SatelliteEphemerisType::EPHEMERIS,
+            .ephemerisSource = SatellitePvt::SatelliteEphemerisSource::SERVER_LONG_TERM,
+            .ephemerisHealth = SatelliteEphemerisHealth::GOOD,
+            .ephemerisAgeSeconds = 12,
+            .serverPredictionIsAvailable = true,
+            .serverPredictionAgeSeconds = 30};
+    SatelliteData satelliteData3 = {
+            .svid = 17,
+            .constellation = GnssConstellationType::GPS,
+            .ephemerisType = SatelliteEphemerisType::EPHEMERIS,
+            .ephemerisSource = SatellitePvt::SatelliteEphemerisSource::SERVER_LONG_TERM,
+            .ephemerisHealth = SatelliteEphemerisHealth::GOOD,
+            .ephemerisAgeSeconds = 12,
+            .serverPredictionIsAvailable = true,
+            .serverPredictionAgeSeconds = 30};
+    SatelliteData satelliteData4 = {
+            .svid = 26,
+            .constellation = GnssConstellationType::GPS,
+            .ephemerisType = SatelliteEphemerisType::EPHEMERIS,
+            .ephemerisSource = SatellitePvt::SatelliteEphemerisSource::SERVER_LONG_TERM,
+            .ephemerisHealth = SatelliteEphemerisHealth::GOOD,
+            .ephemerisAgeSeconds = 12,
+            .serverPredictionIsAvailable = true,
+            .serverPredictionAgeSeconds = 30};
+    SatelliteData satelliteData5 = {
+            .svid = 5,
+            .constellation = GnssConstellationType::GLONASS,
+            .ephemerisType = SatelliteEphemerisType::EPHEMERIS,
+            .ephemerisSource = SatellitePvt::SatelliteEphemerisSource::SERVER_LONG_TERM,
+            .ephemerisHealth = SatelliteEphemerisHealth::GOOD,
+            .ephemerisAgeSeconds = 12,
+            .serverPredictionIsAvailable = true,
+            .serverPredictionAgeSeconds = 30};
+    SatelliteData satelliteData6 = {
+            .svid = 17,
+            .constellation = GnssConstellationType::GLONASS,
+            .ephemerisType = SatelliteEphemerisType::EPHEMERIS,
+            .ephemerisSource = SatellitePvt::SatelliteEphemerisSource::SERVER_LONG_TERM,
+            .ephemerisHealth = SatelliteEphemerisHealth::GOOD,
+            .ephemerisAgeSeconds = 12,
+            .serverPredictionIsAvailable = true,
+            .serverPredictionAgeSeconds = 30};
+    SatelliteData satelliteData7 = {
+            .svid = 18,
+            .constellation = GnssConstellationType::GLONASS,
+            .ephemerisType = SatelliteEphemerisType::EPHEMERIS,
+            .ephemerisSource = SatellitePvt::SatelliteEphemerisSource::SERVER_LONG_TERM,
+            .ephemerisHealth = SatelliteEphemerisHealth::GOOD,
+            .ephemerisAgeSeconds = 12,
+            .serverPredictionIsAvailable = true,
+            .serverPredictionAgeSeconds = 30};
+    SatelliteData satelliteData8 = {
+            .svid = 10,
+            .constellation = GnssConstellationType::GLONASS,
+            .ephemerisType = SatelliteEphemerisType::EPHEMERIS,
+            .ephemerisSource = SatellitePvt::SatelliteEphemerisSource::SERVER_LONG_TERM,
+            .ephemerisHealth = SatelliteEphemerisHealth::GOOD,
+            .ephemerisAgeSeconds = 12,
+            .serverPredictionIsAvailable = true,
+            .serverPredictionAgeSeconds = 30};
+    SatelliteData satelliteData9 = {
+            .svid = 3,
+            .constellation = GnssConstellationType::IRNSS,
+            .ephemerisType = SatelliteEphemerisType::EPHEMERIS,
+            .ephemerisSource = SatellitePvt::SatelliteEphemerisSource::SERVER_LONG_TERM,
+            .ephemerisHealth = SatelliteEphemerisHealth::GOOD,
+            .ephemerisAgeSeconds = 12,
+            .serverPredictionIsAvailable = true,
+            .serverPredictionAgeSeconds = 30};
+    std::vector<SatelliteData> satelliteDataArrayDebug = {
+            satelliteData1, satelliteData2, satelliteData3, satelliteData4, satelliteData5,
+            satelliteData6, satelliteData7, satelliteData8, satelliteData9};
     debugData->position = positionDebug;
     debugData->time = timeDebug;
     debugData->satelliteDataArray = satelliteDataArrayDebug;
diff --git a/gnss/aidl/default/GnssDebug.h b/gnss/aidl/default/GnssDebug.h
index 001d47c..b6844b3 100644
--- a/gnss/aidl/default/GnssDebug.h
+++ b/gnss/aidl/default/GnssDebug.h
@@ -20,6 +20,8 @@
 
 namespace aidl::android::hardware::gnss {
 
+class Gnss;
+
 struct GnssDebug : public BnGnssDebug {
   public:
     ndk::ScopedAStatus getDebugData(DebugData* debugData) override;
diff --git a/gnss/aidl/vts/gnss_hal_test_cases.cpp b/gnss/aidl/vts/gnss_hal_test_cases.cpp
index 9381a0a..b8b1dae 100644
--- a/gnss/aidl/vts/gnss_hal_test_cases.cpp
+++ b/gnss/aidl/vts/gnss_hal_test_cases.cpp
@@ -1149,40 +1149,139 @@
     sp<IGnssDebug> iGnssDebug;
     auto status = aidl_gnss_hal_->getExtensionGnssDebug(&iGnssDebug);
     ASSERT_TRUE(status.isOk());
-
-    if (!IsAutomotiveDevice()) {
-        ASSERT_TRUE(iGnssDebug != nullptr);
-
-        IGnssDebug::DebugData data;
-        auto status = iGnssDebug->getDebugData(&data);
-        ASSERT_TRUE(status.isOk());
-
-        if (data.position.valid) {
-            ASSERT_TRUE(data.position.latitudeDegrees >= -90 &&
-                        data.position.latitudeDegrees <= 90);
-            ASSERT_TRUE(data.position.longitudeDegrees >= -180 &&
-                        data.position.longitudeDegrees <= 180);
-            ASSERT_TRUE(data.position.altitudeMeters >= -1000 &&  // Dead Sea: -414m
-                        data.position.altitudeMeters <= 20000);   // Mount Everest: 8850m
-            ASSERT_TRUE(data.position.speedMetersPerSec >= 0 &&
-                        data.position.speedMetersPerSec <= 600);
-            ASSERT_TRUE(data.position.bearingDegrees >= -360 &&
-                        data.position.bearingDegrees <= 360);
-            ASSERT_TRUE(data.position.horizontalAccuracyMeters > 0 &&
-                        data.position.horizontalAccuracyMeters <= 20000000);
-            ASSERT_TRUE(data.position.verticalAccuracyMeters > 0 &&
-                        data.position.verticalAccuracyMeters <= 20000);
-            ASSERT_TRUE(data.position.speedAccuracyMetersPerSecond > 0 &&
-                        data.position.speedAccuracyMetersPerSecond <= 500);
-            ASSERT_TRUE(data.position.bearingAccuracyDegrees > 0 &&
-                        data.position.bearingAccuracyDegrees <= 180);
-            ASSERT_TRUE(data.position.ageSeconds >= 0);
-        }
-        ASSERT_TRUE(data.time.timeEstimateMs >= 1483228800000);  // Jan 01 2017 00:00:00 GMT.
-        ASSERT_TRUE(data.time.timeUncertaintyNs > 0);
-        ASSERT_TRUE(data.time.frequencyUncertaintyNsPerSec > 0 &&
-                    data.time.frequencyUncertaintyNsPerSec <= 2.0e5);  // 200 ppm
+    if (IsAutomotiveDevice()) {
+        return;
     }
+    ASSERT_TRUE(iGnssDebug != nullptr);
+
+    IGnssDebug::DebugData data;
+    status = iGnssDebug->getDebugData(&data);
+    ASSERT_TRUE(status.isOk());
+    Utils::checkPositionDebug(data);
+
+    // Additional GnssDebug tests for AIDL version >= 4 (launched in Android 15(V)+)
+    if (aidl_gnss_hal_->getInterfaceVersion() <= 3) {
+        return;
+    }
+
+    // Start location and check the consistency between SvStatus and DebugData
+    aidl_gnss_cb_->location_cbq_.reset();
+    aidl_gnss_cb_->sv_info_list_cbq_.reset();
+    StartAndCheckLocations(/* count= */ 2);
+    int location_called_count = aidl_gnss_cb_->location_cbq_.calledCount();
+    ALOGD("Observed %d GnssSvStatus, while awaiting 2 locations (%d received)",
+          aidl_gnss_cb_->sv_info_list_cbq_.size(), location_called_count);
+
+    // Wait for up to kNumSvInfoLists events for kTimeoutSeconds for each event.
+    int kTimeoutSeconds = 2;
+    int kNumSvInfoLists = 4;
+    std::list<std::vector<IGnssCallback::GnssSvInfo>> sv_info_lists;
+    std::vector<IGnssCallback::GnssSvInfo> last_sv_info_list;
+
+    do {
+        EXPECT_GT(aidl_gnss_cb_->sv_info_list_cbq_.retrieve(sv_info_lists, kNumSvInfoLists,
+                                                            kTimeoutSeconds),
+                  0);
+        if (!sv_info_lists.empty()) {
+            last_sv_info_list = sv_info_lists.back();
+            ALOGD("last_sv_info size = %d", (int)last_sv_info_list.size());
+        }
+    } while (!sv_info_lists.empty() && last_sv_info_list.size() == 0);
+
+    StopAndClearLocations();
+
+    status = iGnssDebug->getDebugData(&data);
+    Utils::checkPositionDebug(data);
+
+    // Validate SatelliteEphemerisType, SatelliteEphemerisSource, SatelliteEphemerisHealth
+    for (auto sv_info : last_sv_info_list) {
+        if ((sv_info.svFlag & static_cast<int>(IGnssCallback::GnssSvFlags::USED_IN_FIX)) == 0) {
+            continue;
+        }
+        ALOGD("Found usedInFix const: %d, svid: %d", static_cast<int>(sv_info.constellation),
+              sv_info.svid);
+        bool foundDebugData = false;
+        for (auto satelliteData : data.satelliteDataArray) {
+            if (satelliteData.constellation == sv_info.constellation &&
+                satelliteData.svid == sv_info.svid) {
+                foundDebugData = true;
+                ALOGD("Found GnssDebug data for this sv.");
+                EXPECT_TRUE(satelliteData.serverPredictionIsAvailable ||
+                            satelliteData.ephemerisType ==
+                                    IGnssDebug::SatelliteEphemerisType::EPHEMERIS);
+                // for satellites with ephType=0, they need ephHealth=0 if used-in-fix
+                if (satelliteData.ephemerisType == IGnssDebug::SatelliteEphemerisType::EPHEMERIS) {
+                    EXPECT_TRUE(satelliteData.ephemerisHealth ==
+                                IGnssDebug::SatelliteEphemerisHealth::GOOD);
+                }
+                break;
+            }
+        }
+        // Every Satellite where GnssStatus says it is used-in-fix has a valid ephemeris - i.e. it's
+        // it shows either a serverPredAvail: 1, or a ephType=0
+        EXPECT_TRUE(foundDebugData);
+    }
+
+    bool hasServerPredictionAvailable = false;
+    bool hasNoneZeroServerPredictionAgeSeconds = false;
+    bool hasNoneDemodEphSource = false;
+    for (auto satelliteData : data.satelliteDataArray) {
+        // for satellites with serverPredAvail: 1, the serverPredAgeSec: is not 0 for all
+        // satellites (at least not on 2 fixes in a row - it could get lucky once)
+        if (satelliteData.serverPredictionIsAvailable) {
+            hasServerPredictionAvailable = true;
+            if (satelliteData.serverPredictionAgeSeconds != 0) {
+                hasNoneZeroServerPredictionAgeSeconds = true;
+            }
+        }
+        // for satellites with ephType=0, they need ephSource 0-3
+        if (satelliteData.ephemerisType == IGnssDebug::SatelliteEphemerisType::EPHEMERIS) {
+            EXPECT_TRUE(satelliteData.ephemerisSource >=
+                                SatellitePvt::SatelliteEphemerisSource::DEMODULATED &&
+                        satelliteData.ephemerisSource <=
+                                SatellitePvt::SatelliteEphemerisSource::OTHER);
+            if (satelliteData.ephemerisSource !=
+                SatellitePvt::SatelliteEphemerisSource::DEMODULATED) {
+                hasNoneDemodEphSource = true;
+            }
+        }
+    }
+    if (hasNoneDemodEphSource && hasServerPredictionAvailable) {
+        EXPECT_TRUE(hasNoneZeroServerPredictionAgeSeconds);
+    }
+
+    /**
+    - Gnss Location Data:: should show some valid information, ideally reasonably close (+/-1km) to
+        the Location output - at least after the 2nd valid location output (maybe in general, wait
+        for 2 good Location outputs before checking this, in case they don't update the assistance
+        until after they output the Location)
+    */
+    double distanceM =
+            Utils::distanceMeters(data.position.latitudeDegrees, data.position.longitudeDegrees,
+                                  aidl_gnss_cb_->last_location_.latitudeDegrees,
+                                  aidl_gnss_cb_->last_location_.longitudeDegrees);
+    ALOGD("distance between debug position and last position: %.2lf", distanceM);
+    EXPECT_LT(distanceM, 1000.0);  // 1km
+
+    /**
+    - Gnss Time Data:: timeEstimate should be reasonably close to the current GPS time.
+    - Gnss Time Data:: timeUncertaintyNs should always be > 0 and < 5e9 (could be large due
+        to solve-for-time type solutions)
+    - Gnss Time Data:: frequencyUncertaintyNsPerSec: should always be > 0 and < 1000 (1000 ns/s
+        corresponds to roughly a 300 m/s speed error, which should be pretty rare)
+    */
+    ALOGD("debug time: %" PRId64 ", position time: %" PRId64, data.time.timeEstimateMs,
+          aidl_gnss_cb_->last_location_.timestampMillis);
+    // Allowing 5s between the last location time and the current GPS time
+    EXPECT_LT(abs(data.time.timeEstimateMs - aidl_gnss_cb_->last_location_.timestampMillis), 5000);
+
+    ALOGD("debug time uncertainty: %f ns", data.time.timeUncertaintyNs);
+    EXPECT_GT(data.time.timeUncertaintyNs, 0);
+    EXPECT_LT(data.time.timeUncertaintyNs, 5e9);
+
+    ALOGD("debug freq uncertainty: %f ns/s", data.time.frequencyUncertaintyNsPerSec);
+    EXPECT_GT(data.time.frequencyUncertaintyNsPerSec, 0);
+    EXPECT_LT(data.time.frequencyUncertaintyNsPerSec, 1000);
 }
 
 /*
diff --git a/gnss/common/utils/vts/Utils.cpp b/gnss/common/utils/vts/Utils.cpp
index 69e2b34..e3ff0f3 100644
--- a/gnss/common/utils/vts/Utils.cpp
+++ b/gnss/common/utils/vts/Utils.cpp
@@ -20,6 +20,7 @@
 #include "gtest/gtest.h"
 
 #include <cutils/properties.h>
+#include <math.h>
 #include <utils/SystemClock.h>
 
 namespace android {
@@ -58,6 +59,31 @@
     checkElapsedRealtime(location.elapsedRealtime);
 }
 
+void Utils::checkPositionDebug(android::hardware::gnss::IGnssDebug::DebugData data) {
+    if (data.position.valid) {
+        ASSERT_TRUE(data.position.latitudeDegrees >= -90 && data.position.latitudeDegrees <= 90);
+        ASSERT_TRUE(data.position.longitudeDegrees >= -180 &&
+                    data.position.longitudeDegrees <= 180);
+        ASSERT_TRUE(data.position.altitudeMeters >= -1000 &&  // Dead Sea: -414m
+                    data.position.altitudeMeters <= 20000);   // Mount Everest: 8850m
+        ASSERT_TRUE(data.position.speedMetersPerSec >= 0 && data.position.speedMetersPerSec <= 600);
+        ASSERT_TRUE(data.position.bearingDegrees >= -360 && data.position.bearingDegrees <= 360);
+        ASSERT_TRUE(data.position.horizontalAccuracyMeters > 0 &&
+                    data.position.horizontalAccuracyMeters <= 20000000);
+        ASSERT_TRUE(data.position.verticalAccuracyMeters > 0 &&
+                    data.position.verticalAccuracyMeters <= 20000);
+        ASSERT_TRUE(data.position.speedAccuracyMetersPerSecond > 0 &&
+                    data.position.speedAccuracyMetersPerSecond <= 500);
+        ASSERT_TRUE(data.position.bearingAccuracyDegrees > 0 &&
+                    data.position.bearingAccuracyDegrees <= 180);
+        ASSERT_TRUE(data.position.ageSeconds >= 0);
+    }
+    ASSERT_TRUE(data.time.timeEstimateMs >= 1483228800000);  // Jan 01 2017 00:00:00 GMT.
+    ASSERT_TRUE(data.time.timeUncertaintyNs > 0);
+    ASSERT_TRUE(data.time.frequencyUncertaintyNsPerSec > 0 &&
+                data.time.frequencyUncertaintyNsPerSec <= 2.0e5);  // 200 ppm
+}
+
 void Utils::checkElapsedRealtime(const ElapsedRealtime& elapsedRealtime) {
     ASSERT_TRUE(elapsedRealtime.flags >= 0 &&
                 elapsedRealtime.flags <= (ElapsedRealtime::HAS_TIMESTAMP_NS |
@@ -282,6 +308,17 @@
     return strncmp(buffer, "automotive", PROPERTY_VALUE_MAX) == 0;
 }
 
+double Utils::distanceMeters(double lat1, double lon1, double lat2, double lon2) {
+    double R = 6378.137;  // Radius of earth in KM
+    double dLat = lat2 * M_PI / 180 - lat1 * M_PI / 180;
+    double dLon = lon2 * M_PI / 180 - lon1 * M_PI / 180;
+    double a = sin(dLat / 2) * sin(dLat / 2) +
+               cos(lat1 * M_PI / 180) * cos(lat2 * M_PI / 180) * sin(dLon / 2) * sin(dLon / 2);
+    double c = 2 * atan2(sqrt(a), sqrt(1 - a));
+    double d = R * c;
+    return d * 1000;  // meters
+}
+
 }  // namespace common
 }  // namespace gnss
 }  // namespace hardware
diff --git a/gnss/common/utils/vts/include/Utils.h b/gnss/common/utils/vts/include/Utils.h
index 7b89078..62d409a 100644
--- a/gnss/common/utils/vts/include/Utils.h
+++ b/gnss/common/utils/vts/include/Utils.h
@@ -43,6 +43,7 @@
 
     static void checkElapsedRealtime(
             const android::hardware::gnss::ElapsedRealtime& elapsedRealtime);
+    static void checkPositionDebug(android::hardware::gnss::IGnssDebug::DebugData data);
 
     static const android::hardware::gnss::GnssLocation getMockLocation(
             double latitudeDegrees, double longitudeDegrees, double horizontalAccuracyMeters);
@@ -57,6 +58,7 @@
             V2_0::GnssConstellationType constellation);
 
     static bool isAutomotiveDevice();
+    static double distanceMeters(double lat1, double lon1, double lat2, double lon2);
 
   private:
     template <class T>