Add intervalMillis to IGnssMeasurement (hardware/interfaces)

Bug: 206670536
Test: atest VtsHalGnssTargetTest
Change-Id: I911fc3c0fd6010ddb20265e1551a7cb3b75216d7
diff --git a/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/IGnssMeasurementInterface.aidl b/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/IGnssMeasurementInterface.aidl
index 24d6f9c..9c4a54b 100644
--- a/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/IGnssMeasurementInterface.aidl
+++ b/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/IGnssMeasurementInterface.aidl
@@ -36,4 +36,11 @@
 interface IGnssMeasurementInterface {
   void setCallback(in android.hardware.gnss.IGnssMeasurementCallback callback, in boolean enableFullTracking, in boolean enableCorrVecOutputs);
   void close();
+  void setCallbackWithOptions(in android.hardware.gnss.IGnssMeasurementCallback callback, in android.hardware.gnss.IGnssMeasurementInterface.Options options);
+  @VintfStability
+  parcelable Options {
+    boolean enableFullTracking;
+    boolean enableCorrVecOutputs;
+    int intervalMs;
+  }
 }
diff --git a/gnss/aidl/android/hardware/gnss/IGnssMeasurementInterface.aidl b/gnss/aidl/android/hardware/gnss/IGnssMeasurementInterface.aidl
index 08c83a4..102cdcd 100644
--- a/gnss/aidl/android/hardware/gnss/IGnssMeasurementInterface.aidl
+++ b/gnss/aidl/android/hardware/gnss/IGnssMeasurementInterface.aidl
@@ -24,6 +24,48 @@
 @VintfStability
 interface IGnssMeasurementInterface {
     /**
+     * Options specifying the GnssMeasurement request.
+     */
+    @VintfStability
+    parcelable Options {
+        /**
+         * Enable full tracking mode.
+         *
+         * If true, GNSS chipset must switch off duty cycling. In such mode no clock discontinuities
+         * are expected and, when supported, carrier phase should be continuous in good signal
+         * conditions. All non-blocklisted, healthy constellations, satellites and frequency bands
+         * that the chipset supports must be reported in this mode. The GNSS chipset is allowed to
+         * consume more power in this mode. If false, API must optimize power via duty cycling,
+         * constellations and frequency limits, etc.
+         */
+        boolean enableFullTracking;
+
+        /**
+         * Enable Correlation Vector outputs.
+         *
+         * If true, enable correlation vectors as part of the raw GNSS measurements outputs. If
+         * false, disable correlation vectors.
+         */
+        boolean enableCorrVecOutputs;
+
+        /**
+         * Time interval between the reported measurements in milliseconds.
+         *
+         * The GNSS chipset must not report measurements with a rate slower than requested. All the
+         * available measurements must be reported to the framework.
+         *
+         * For cases where concurrently serving the location and the measurement requests would not
+         * consume more power than only the measurement request, the faster rate of the 2 requests
+         * must be chosen. Otherwise, it is recommended that the GNSS chipset minimizes the power
+         * consumption with appropriate location and measurement intervals to satisfy both requests.
+         * For example, for 2-sec measurement interval request and 7-sec location interval request,
+         * the GNSS chipset is recommended to run the measurement engine with 2-sec interval and the
+         * location engine with 6-sec interval.
+         */
+        int intervalMs;
+    }
+
+    /**
      * Initializes the interface and registers the callback routines with the HAL. After a
      * successful call to 'setCallback' the HAL must begin to provide updates at an average
      * output rate of 1Hz (occasional intra-measurement time offsets in the range from 0-2000msec
@@ -39,13 +81,9 @@
      *
      * @param enableCorrVecOutputs If true, enable correlation vectors as part of the raw GNSS
      *     measurements outputs. If false, disable correlation vectors.
-     *
-     * Returns ok() if successful. Returns ERROR_ALREADY_INIT if a callback has already been
-     * registered without a corresponding call to 'close'. Returns ERROR_GENERIC for any other
-     * error. The HAL must not generate any other updates upon returning this error code.
      */
     void setCallback(in IGnssMeasurementCallback callback, in boolean enableFullTracking,
-                     in boolean enableCorrVecOutputs);
+            in boolean enableCorrVecOutputs);
 
     /**
      * Stops updates from the HAL, and unregisters the callback routines. After a call to close(),
@@ -55,4 +93,11 @@
      * no work.
      */
     void close();
-}
\ No newline at end of file
+
+    /**
+     * Initializes the interface and registers the callback routines with the HAL.
+     *
+     * @param options See Options definition.
+     */
+    void setCallbackWithOptions(in IGnssMeasurementCallback callback, in Options options);
+}
diff --git a/gnss/aidl/default/GnssMeasurementInterface.cpp b/gnss/aidl/default/GnssMeasurementInterface.cpp
index 9e4f7c7..2c7241b 100644
--- a/gnss/aidl/default/GnssMeasurementInterface.cpp
+++ b/gnss/aidl/default/GnssMeasurementInterface.cpp
@@ -56,11 +56,29 @@
     return ndk::ScopedAStatus::ok();
 }
 
+ndk::ScopedAStatus GnssMeasurementInterface::setCallbackWithOptions(
+        const std::shared_ptr<IGnssMeasurementCallback>& callback, const Options& options) {
+    ALOGD("setCallbackWithOptions: fullTracking:%d, corrVec:%d, intervalMs:%d",
+          (int)options.enableFullTracking, (int)options.enableCorrVecOutputs, options.intervalMs);
+    std::unique_lock<std::mutex> lock(mMutex);
+    sCallback = callback;
+
+    if (mIsActive) {
+        ALOGW("GnssMeasurement callback already set. Resetting the callback...");
+        stop();
+    }
+    mMinIntervalMillis = options.intervalMs;
+    start(options.enableCorrVecOutputs);
+
+    return ndk::ScopedAStatus::ok();
+}
+
 ndk::ScopedAStatus GnssMeasurementInterface::close() {
     ALOGD("close");
     stop();
     std::unique_lock<std::mutex> lock(mMutex);
     sCallback = nullptr;
+    mMinIntervalMillis = 1000;
     return ndk::ScopedAStatus::ok();
 }
 
diff --git a/gnss/aidl/default/GnssMeasurementInterface.h b/gnss/aidl/default/GnssMeasurementInterface.h
index db63515..bf77806 100644
--- a/gnss/aidl/default/GnssMeasurementInterface.h
+++ b/gnss/aidl/default/GnssMeasurementInterface.h
@@ -32,6 +32,9 @@
                                    const bool enableFullTracking,
                                    const bool enableCorrVecOutputs) override;
     ndk::ScopedAStatus close() override;
+    ndk::ScopedAStatus setCallbackWithOptions(
+            const std::shared_ptr<IGnssMeasurementCallback>& callback,
+            const Options& options) override;
 
   private:
     void start(const bool enableCorrVecOutputs);
diff --git a/gnss/aidl/vts/gnss_hal_test_cases.cpp b/gnss/aidl/vts/gnss_hal_test_cases.cpp
index 90b643c..d3cb0a0 100644
--- a/gnss/aidl/vts/gnss_hal_test_cases.cpp
+++ b/gnss/aidl/vts/gnss_hal_test_cases.cpp
@@ -903,3 +903,42 @@
     status = iGnssVisibilityControl->enableNfwLocationAccess(proxyApps);
     ASSERT_TRUE(status.isOk());
 }
+
+/*
+ * TestGnssMeasurementSetCallbackWithOptions:
+ * 1. Gets the GnssMeasurementExtension and verifies that it returns a non-null extension.
+ * 2. Sets a GnssMeasurementCallback with intervalMillis option, waits for measurements reported,
+ *    and verifies mandatory fields are valid.
+ */
+TEST_P(GnssHalTest, TestGnssMeasurementSetCallbackWithOptions) {
+    if (aidl_gnss_hal_->getInterfaceVersion() == 1) {
+        return;
+    }
+    const int kFirstGnssMeasurementTimeoutSeconds = 10;
+    const int kNumMeasurementEvents = 5;
+
+    sp<IGnssMeasurementInterface> iGnssMeasurement;
+    auto status = aidl_gnss_hal_->getExtensionGnssMeasurement(&iGnssMeasurement);
+    ASSERT_TRUE(status.isOk());
+    ASSERT_TRUE(iGnssMeasurement != nullptr);
+
+    auto callback = sp<GnssMeasurementCallbackAidl>::make();
+    IGnssMeasurementInterface::Options options;
+    options.intervalMs = 2000;
+    status = iGnssMeasurement->setCallbackWithOptions(callback, options);
+    ASSERT_TRUE(status.isOk());
+
+    for (int i = 0; i < kNumMeasurementEvents; i++) {
+        GnssData lastMeasurement;
+        ASSERT_TRUE(callback->gnss_data_cbq_.retrieve(lastMeasurement,
+                                                      kFirstGnssMeasurementTimeoutSeconds));
+        EXPECT_EQ(callback->gnss_data_cbq_.calledCount(), i + 1);
+        ASSERT_TRUE(lastMeasurement.measurements.size() > 0);
+
+        // Validity check GnssData fields
+        CheckGnssMeasurementClockFields(lastMeasurement);
+    }
+
+    status = iGnssMeasurement->close();
+    ASSERT_TRUE(status.isOk());
+}