GNSS HAL & VTS for Duty Cycling & Low Power APIs.

Defintions for 2 GNSS Android P features:
- The Duty Cycling OFF API to enable high accuracy applications development
- The Low Power Mode GNSS API to save power when indoor

VTS tests for both features.

Bug: 64009176
Test: hidl-gen/compile/build checks, no functional tests yet
Change-Id: I4a41757e4ad6747f22a7e9ae1e0024f083c5fbfb
diff --git a/gnss/1.1/Android.bp b/gnss/1.1/Android.bp
index 09f65a4..6909807 100644
--- a/gnss/1.1/Android.bp
+++ b/gnss/1.1/Android.bp
@@ -9,6 +9,7 @@
     srcs: [
         "IGnss.hal",
         "IGnssCallback.hal",
+        "IGnssMeasurement.hal",
     ],
     interfaces: [
         "android.hardware.gnss@1.0",
diff --git a/gnss/1.1/IGnss.hal b/gnss/1.1/IGnss.hal
index f26d47c..d5e0c3e 100644
--- a/gnss/1.1/IGnss.hal
+++ b/gnss/1.1/IGnss.hal
@@ -18,17 +18,56 @@
 
 import @1.0::IGnss;
 
+import IGnssMeasurement;
 import IGnssCallback;
 
 /** Represents the standard GNSS (Global Navigation Satellite System) interface. */
 interface IGnss extends @1.0::IGnss {
     /**
-     * Opens the interface and provides the callback routines
-     * to the implementation of this interface.
+     * Opens the interface and provides the callback routines to the implementation of this
+     * interface.
      *
      * @param callback Callback interface for IGnss.
      *
      * @return success Returns true on success.
      */
     setCallback_1_1(IGnssCallback callback) generates (bool success);
+
+    /**
+     * Sets the GnssPositionMode parameter, its associated recurrence value,
+     * the time between fixes, requested fix accuracy, time to first fix.
+     *
+     * @param mode Parameter must be one of MS_BASED or STANDALONE. It is allowed by the platform
+     *     (and it is recommended) to fallback to MS_BASED if MS_ASSISTED is passed in, and MS_BASED
+     *     is supported.
+     * @param recurrence GNSS postion recurrence value, either periodic or single.
+     * @param minIntervalMs Represents the time between fixes in milliseconds.
+     * @param preferredAccuracyMeters Represents the requested fix accuracy in meters.
+     * @param preferredTimeMs Represents the requested time to first fix in milliseconds.
+     * @param lowPowerMode When true, HAL must make strong tradeoffs to substantially restrict power
+     *     use. Specifically, in the case of a several second long minIntervalMs, the GNSS chipset
+     *     must not, on average, run power hungry operations like RF and signal searches for more
+     *     than one second per interval, and must make exactly one call to gnssSvStatusCb(), and
+     *     either zero or one call to GnssLocationCb() at each interval. When false, HAL must
+     *     operate in the nominal mode (similar to V1.0 where this flag wasn't present) and is
+     *     expected to make power and performance tradoffs such as duty-cycling when signal
+     *     conditions are good and more active searches to reacquire GNSS signals when no signals
+     *     are present.
+     *
+     * @return success Returns true if successful.
+     */
+    setPositionMode_1_1(GnssPositionMode mode,
+                        GnssPositionRecurrence recurrence,
+                        uint32_t minIntervalMs,
+                        uint32_t preferredAccuracyMeters,
+                        uint32_t preferredTimeMs,
+                        bool lowPowerMode)
+             generates (bool success);
+
+   /**
+    * This method returns the IGnssMeasurement interface.
+    *
+    * @return gnssMeasurementIface Handle to the IGnssMeasurement interface.
+    */
+    getExtensionGnssMeasurement_1_1() generates (IGnssMeasurement gnssMeasurementIface);
 };
\ No newline at end of file
diff --git a/gnss/1.1/IGnssMeasurement.hal b/gnss/1.1/IGnssMeasurement.hal
new file mode 100644
index 0000000..75df5a8
--- /dev/null
+++ b/gnss/1.1/IGnssMeasurement.hal
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.gnss@1.1;
+
+import @1.0::IGnssMeasurement;
+import @1.0::IGnssMeasurementCallback;
+
+/**
+ * Extended interface for GNSS Measurements support.
+ */
+interface IGnssMeasurement extends @1.0::IGnssMeasurement {
+
+    /**
+     * Initializes the interface and registers the callback routines with the HAL. After a
+     * successful call to 'setCallback_1_1' 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
+     * can be tolerated.)
+     *
+     * @param callback Handle to GnssMeasurement callback interface.
+     * @param enableFullTracking 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 constellations 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 behave as in HAL V1_0, optimizing power via
+     *     duty cycling, constellations and frequency limits, etc.
+     *
+     * @return initRet Returns SUCCESS 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.
+     */
+    setCallback_1_1(IGnssMeasurementCallback callback, bool enableFullTracking)
+         generates (GnssMeasurementStatus initRet);
+
+};
diff --git a/gnss/1.1/vts/functional/gnss_hal_test.cpp b/gnss/1.1/vts/functional/gnss_hal_test.cpp
index 40fd71b..2f4dd93 100644
--- a/gnss/1.1/vts/functional/gnss_hal_test.cpp
+++ b/gnss/1.1/vts/functional/gnss_hal_test.cpp
@@ -22,7 +22,12 @@
 #include <chrono>
 
 // Implementations for the main test class for GNSS HAL
-GnssHalTest::GnssHalTest() : info_called_count_(0), name_called_count_(0), notify_count_(0) {}
+GnssHalTest::GnssHalTest()
+    : info_called_count_(0),
+      capabilities_called_count_(0),
+      location_called_count_(0),
+      name_called_count_(0),
+      notify_count_(0) {}
 
 void GnssHalTest::SetUp() {
     gnss_hal_ = ::testing::VtsHalHidlTargetTestBase::getService<IGnss>();
@@ -56,7 +61,6 @@
     return status;
 }
 
-// Actual (test) callback handlers
 Return<void> GnssHalTest::GnssCallback::gnssSetSystemInfoCb(
     const IGnssCallback::GnssSystemInfo& info) {
     ALOGI("Info received, year %d", info.yearOfHw);
@@ -66,11 +70,26 @@
     return Void();
 }
 
-// Actual (test) callback handlers
+Return<void> GnssHalTest::GnssCallback::gnssSetCapabilitesCb(uint32_t capabilities) {
+    ALOGI("Capabilities received %d", capabilities);
+    parent_.capabilities_called_count_++;
+    parent_.last_capabilities_ = capabilities;
+    parent_.notify();
+    return Void();
+}
+
 Return<void> GnssHalTest::GnssCallback::gnssNameCb(const android::hardware::hidl_string& name) {
     ALOGI("Name received: %s", name.c_str());
     parent_.name_called_count_++;
     parent_.last_name_ = name;
     parent_.notify();
     return Void();
-}
\ No newline at end of file
+}
+
+Return<void> GnssHalTest::GnssCallback::gnssLocationCb(const GnssLocation& location) {
+    ALOGI("Location received");
+    parent_.location_called_count_++;
+    parent_.last_location_ = location;
+    parent_.notify();
+    return Void();
+}
diff --git a/gnss/1.1/vts/functional/gnss_hal_test.h b/gnss/1.1/vts/functional/gnss_hal_test.h
index 05cb4ab..bbc8d9f 100644
--- a/gnss/1.1/vts/functional/gnss_hal_test.h
+++ b/gnss/1.1/vts/functional/gnss_hal_test.h
@@ -31,8 +31,9 @@
 
 using android::hardware::gnss::V1_1::IGnss;
 using android::hardware::gnss::V1_1::IGnssCallback;
-
+using android::hardware::gnss::V1_0::GnssLocationFlags;
 using android::sp;
+#define TIMEOUT_SEC 2  // for basic commands/responses
 
 // The main test class for GNSS HAL.
 class GnssHalTest : public ::testing::VtsHalHidlTargetTestBase {
@@ -72,13 +73,134 @@
         Return<void> gnssAcquireWakelockCb() override { return Void(); }
         Return<void> gnssReleaseWakelockCb() override { return Void(); }
         Return<void> gnssRequestTimeCb() override { return Void(); }
-        Return<void> gnssLocationCb(const GnssLocation& /* location */) override { return Void(); }
-        Return<void> gnssSetCapabilitesCb(uint32_t /* capabilities */) override { return Void(); }
         // Actual (test) callback handlers
+        Return<void> gnssLocationCb(const GnssLocation& location) override;
+        Return<void> gnssSetCapabilitesCb(uint32_t capabilities) override;
         Return<void> gnssSetSystemInfoCb(const IGnssCallback::GnssSystemInfo& info) override;
         Return<void> gnssNameCb(const android::hardware::hidl_string& name) override;
     };
 
+    /*
+     * StartAndGetSingleLocation:
+     * Helper function to get one Location and check fields
+     *
+     * returns  true if a location was successfully generated
+     */
+    bool StartAndGetSingleLocation(bool checkAccuracies) {
+        auto result = gnss_hal_->start();
+
+        EXPECT_TRUE(result.isOk());
+        EXPECT_TRUE(result);
+
+        /*
+         * GPS signals initially optional for this test, so don't expect fast fix,
+         * or no timeout, unless signal is present
+         */
+        int firstGnssLocationTimeoutSeconds = 15;
+
+        wait(firstGnssLocationTimeoutSeconds);
+        EXPECT_EQ(location_called_count_, 1);
+
+        if (location_called_count_ > 0) {
+            // don't require speed on first fix
+            CheckLocation(last_location_, checkAccuracies, false);
+            return true;
+        }
+        return false;
+    }
+
+    /*
+     * CheckLocation:
+     *   Helper function to vet Location fields when calling setPositionMode_1_1()
+     */
+    void CheckLocation(GnssLocation& location, bool checkAccuracies, bool checkSpeed) {
+        EXPECT_TRUE(location.gnssLocationFlags & GnssLocationFlags::HAS_LAT_LONG);
+        EXPECT_TRUE(location.gnssLocationFlags & GnssLocationFlags::HAS_ALTITUDE);
+        if (checkSpeed) {
+            EXPECT_TRUE(location.gnssLocationFlags & GnssLocationFlags::HAS_SPEED);
+        }
+        EXPECT_TRUE(location.gnssLocationFlags & GnssLocationFlags::HAS_HORIZONTAL_ACCURACY);
+        // New uncertainties available in O must be provided,
+        // at least when paired with modern hardware (2017+)
+        if (checkAccuracies) {
+            EXPECT_TRUE(location.gnssLocationFlags & GnssLocationFlags::HAS_VERTICAL_ACCURACY);
+            if (checkSpeed) {
+                EXPECT_TRUE(location.gnssLocationFlags & GnssLocationFlags::HAS_SPEED_ACCURACY);
+                if (location.gnssLocationFlags & GnssLocationFlags::HAS_BEARING) {
+                    EXPECT_TRUE(location.gnssLocationFlags &
+                                GnssLocationFlags::HAS_BEARING_ACCURACY);
+                }
+            }
+        }
+        EXPECT_GE(location.latitudeDegrees, -90.0);
+        EXPECT_LE(location.latitudeDegrees, 90.0);
+        EXPECT_GE(location.longitudeDegrees, -180.0);
+        EXPECT_LE(location.longitudeDegrees, 180.0);
+        EXPECT_GE(location.altitudeMeters, -1000.0);
+        EXPECT_LE(location.altitudeMeters, 30000.0);
+        if (checkSpeed) {
+            EXPECT_GE(location.speedMetersPerSec, 0.0);
+            EXPECT_LE(location.speedMetersPerSec, 5.0);  // VTS tests are stationary.
+
+            // Non-zero speeds must be reported with an associated bearing
+            if (location.speedMetersPerSec > 0.0) {
+                EXPECT_TRUE(location.gnssLocationFlags & GnssLocationFlags::HAS_BEARING);
+            }
+        }
+
+        /*
+         * Tolerating some especially high values for accuracy estimate, in case of
+         * first fix with especially poor geometry (happens occasionally)
+         */
+        EXPECT_GT(location.horizontalAccuracyMeters, 0.0);
+        EXPECT_LE(location.horizontalAccuracyMeters, 250.0);
+
+        /*
+         * Some devices may define bearing as -180 to +180, others as 0 to 360.
+         * Both are okay & understandable.
+         */
+        if (location.gnssLocationFlags & GnssLocationFlags::HAS_BEARING) {
+            EXPECT_GE(location.bearingDegrees, -180.0);
+            EXPECT_LE(location.bearingDegrees, 360.0);
+        }
+        if (location.gnssLocationFlags & GnssLocationFlags::HAS_VERTICAL_ACCURACY) {
+            EXPECT_GT(location.verticalAccuracyMeters, 0.0);
+            EXPECT_LE(location.verticalAccuracyMeters, 500.0);
+        }
+        if (location.gnssLocationFlags & GnssLocationFlags::HAS_SPEED_ACCURACY) {
+            EXPECT_GT(location.speedAccuracyMetersPerSecond, 0.0);
+            EXPECT_LE(location.speedAccuracyMetersPerSecond, 50.0);
+        }
+        if (location.gnssLocationFlags & GnssLocationFlags::HAS_BEARING_ACCURACY) {
+            EXPECT_GT(location.bearingAccuracyDegrees, 0.0);
+            EXPECT_LE(location.bearingAccuracyDegrees, 360.0);
+        }
+
+        // Check timestamp > 1.48e12 (47 years in msec - 1970->2017+)
+        EXPECT_GT(location.timestamp, 1.48e12);
+    }
+
+    /*
+     * StopAndClearLocations:
+     * Helper function to stop locations
+     *
+     * returns  true if a location was successfully generated
+     */
+    void StopAndClearLocations() {
+        auto result = gnss_hal_->stop();
+
+        EXPECT_TRUE(result.isOk());
+        EXPECT_TRUE(result);
+
+        /*
+         * Clear notify/waiting counter, allowing up till the timeout after
+         * the last reply for final startup messages to arrive (esp. system
+         * info.)
+         */
+        while (wait(TIMEOUT_SEC) == std::cv_status::no_timeout) {
+        }
+    }
+
     sp<IGnss> gnss_hal_;         // GNSS HAL to call into
     sp<IGnssCallback> gnss_cb_;  // Primary callback interface
 
@@ -87,6 +209,10 @@
      */
     int info_called_count_;
     IGnssCallback::GnssSystemInfo last_info_;
+    uint32_t last_capabilities_;
+    int capabilities_called_count_;
+    int location_called_count_;
+    GnssLocation last_location_;
 
     int name_called_count_;
     android::hardware::hidl_string last_name_;
diff --git a/gnss/1.1/vts/functional/gnss_hal_test_cases.cpp b/gnss/1.1/vts/functional/gnss_hal_test_cases.cpp
index 075940c..47bad34 100644
--- a/gnss/1.1/vts/functional/gnss_hal_test_cases.cpp
+++ b/gnss/1.1/vts/functional/gnss_hal_test_cases.cpp
@@ -18,7 +18,7 @@
 
 #include <VtsHalHidlTargetTestBase.h>
 
-#define TIMEOUT_SEC 2  // for basic commands/responses
+using android::hardware::gnss::V1_1::IGnssMeasurement;
 
 /*
  * SetupTeardownCreateCleanup:
@@ -30,7 +30,7 @@
 
 /*
  * SetCallbackResponses:
- * Sets up the callback, awaits the info & name
+ * Sets up the callback, awaits the capability, info & name
  */
 TEST_F(GnssHalTest, SetCallbackResponses) {
     gnss_cb_ = new GnssCallback(*this);
@@ -45,11 +45,68 @@
     ASSERT_TRUE(result);
 
     /*
-     * Both name and systemInfo callbacks should trigger
+     * All capabilities, name and systemInfo callbacks should trigger
      */
     EXPECT_EQ(std::cv_status::no_timeout, wait(TIMEOUT_SEC));
     EXPECT_EQ(std::cv_status::no_timeout, wait(TIMEOUT_SEC));
+    EXPECT_EQ(std::cv_status::no_timeout, wait(TIMEOUT_SEC));
 
+    EXPECT_EQ(capabilities_called_count_, 1);
     EXPECT_EQ(info_called_count_, 1);
     EXPECT_EQ(name_called_count_, 1);
+}
+
+/*
+ * TestGnssMeasurementCallback:
+ * Gets the GnssMeasurementExtension and verify that it returns an actual extension.
+ */
+TEST_F(GnssHalTest, TestGnssMeasurementCallback) {
+    auto gnssMeasurement = gnss_hal_->getExtensionGnssMeasurement_1_1();
+    ASSERT_TRUE(gnssMeasurement.isOk());
+    if (last_capabilities_ & IGnssCallback::Capabilities::MEASUREMENTS) {
+        sp<IGnssMeasurement> iGnssMeas = gnssMeasurement;
+        EXPECT_NE(iGnssMeas, nullptr);
+    }
+}
+
+/*
+ * GetLocation:
+ * Turns on location, waits for at least 5 locations allowing max of LOCATION_TIMEOUT_SUBSEQUENT_SEC
+ * between one location and the next. Also ensure that MIN_INTERVAL_MSEC is respected by waiting
+ * NO_LOCATION_PERIOD_SEC and verfiy that no location is received. Also perform validity checks on
+ * each received location.
+ */
+TEST_F(GnssHalTest, GetLocationLowPower) {
+#define MIN_INTERVAL_MSEC 5000
+#define PREFERRED_ACCURACY 0   // Ideally perfect (matches GnssLocationProvider)
+#define PREFERRED_TIME_MSEC 0  // Ideally immediate
+
+#define LOCATION_TIMEOUT_SUBSEQUENT_SEC (MIN_INTERVAL_MSEC + 1000) / 1000
+#define NO_LOCATION_PERIOD_SEC 2
+#define LOCATIONS_TO_CHECK 5
+#define LOW_POWER_MODE true
+
+    bool checkMoreAccuracies = (info_called_count_ > 0 && last_info_.yearOfHw >= 2017);
+
+    auto result = gnss_hal_->setPositionMode_1_1(
+        IGnss::GnssPositionMode::MS_BASED, IGnss::GnssPositionRecurrence::RECURRENCE_PERIODIC,
+        MIN_INTERVAL_MSEC, PREFERRED_ACCURACY, PREFERRED_TIME_MSEC, LOW_POWER_MODE);
+
+    ASSERT_TRUE(result.isOk());
+    EXPECT_TRUE(result);
+
+    EXPECT_TRUE(StartAndGetSingleLocation(checkMoreAccuracies));
+
+    for (int i = 1; i < LOCATIONS_TO_CHECK; i++) {
+        // Verify that MIN_INTERVAL_MSEC is respected by waiting NO_LOCATION_PERIOD_SEC and
+        // ensure that no location is received yet
+        wait(NO_LOCATION_PERIOD_SEC);
+        EXPECT_EQ(location_called_count_, i);
+        EXPECT_EQ(std::cv_status::no_timeout,
+                  wait(LOCATION_TIMEOUT_SUBSEQUENT_SEC - NO_LOCATION_PERIOD_SEC));
+        EXPECT_EQ(location_called_count_, i + 1);
+        CheckLocation(last_location_, checkMoreAccuracies, true);
+    }
+
+    StopAndClearLocations();
 }
\ No newline at end of file