1 /*
2  * Copyright (C) 2017 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #define LOG_TAG "GnssHalTestCases"
18 
19 #include <gnss_hal_test.h>
20 
21 #include <VtsHalHidlTargetTestBase.h>
22 
23 #include <android/hardware/gnss/1.1/IGnssConfiguration.h>
24 #include <cutils/properties.h>
25 
26 using android::hardware::hidl_vec;
27 
28 using IGnssMeasurement_1_0 = android::hardware::gnss::V1_0::IGnssMeasurement;
29 using IGnssMeasurement_1_1 = android::hardware::gnss::V1_1::IGnssMeasurement;
30 
31 using android::hardware::gnss::V1_0::GnssConstellationType;
32 using android::hardware::gnss::V1_0::GnssLocation;
33 using android::hardware::gnss::V1_0::IGnssDebug;
34 using android::hardware::gnss::V1_1::IGnssConfiguration;
35 using android::hardware::gnss::V1_1::IGnssMeasurement;
36 
IsAutomotiveDevice()37 static bool IsAutomotiveDevice() {
38   char buffer[PROPERTY_VALUE_MAX] = {0};
39   property_get("ro.hardware.type", buffer, "");
40   return strncmp(buffer, "automotive", PROPERTY_VALUE_MAX) == 0;
41 }
42 
43 /*
44  * SetupTeardownCreateCleanup:
45  * Requests the gnss HAL then calls cleanup
46  *
47  * Empty test fixture to verify basic Setup & Teardown
48  */
TEST_F(GnssHalTest,SetupTeardownCreateCleanup)49 TEST_F(GnssHalTest, SetupTeardownCreateCleanup) {}
50 
51 /*
52  * TestGnssMeasurementCallback:
53  * Gets the GnssMeasurementExtension and verify that it returns an actual extension.
54  */
TEST_F(GnssHalTest,TestGnssMeasurementCallback)55 TEST_F(GnssHalTest, TestGnssMeasurementCallback) {
56     auto gnssMeasurement_1_1 = gnss_hal_->getExtensionGnssMeasurement_1_1();
57     ASSERT_TRUE(gnssMeasurement_1_1.isOk());
58     auto gnssMeasurement_1_0 = gnss_hal_->getExtensionGnssMeasurement();
59     ASSERT_TRUE(gnssMeasurement_1_0.isOk());
60     if (last_capabilities_ & IGnssCallback::Capabilities::MEASUREMENTS) {
61         sp<IGnssMeasurement_1_1> iGnssMeas_1_1 = gnssMeasurement_1_1;
62         sp<IGnssMeasurement_1_0> iGnssMeas_1_0 = gnssMeasurement_1_0;
63         // At least one interface must be non-null.
64         ASSERT_TRUE(iGnssMeas_1_1 != nullptr || iGnssMeas_1_0 != nullptr);
65     }
66 }
67 
68 /*
69  * GetLocationLowPower:
70  * Turns on location, waits for at least 5 locations allowing max of LOCATION_TIMEOUT_SUBSEQUENT_SEC
71  * between one location and the next. Also ensure that MIN_INTERVAL_MSEC is respected by waiting
72  * NO_LOCATION_PERIOD_SEC and verfiy that no location is received. Also perform validity checks on
73  * each received location.
74  */
TEST_F(GnssHalTest,GetLocationLowPower)75 TEST_F(GnssHalTest, GetLocationLowPower) {
76     if (!IsGnssHalVersion_1_1()) {
77         ALOGI("Test GetLocationLowPower skipped. GNSS HAL version is greater than 1.1.");
78         return;
79     }
80 
81     const int kMinIntervalMsec = 5000;
82     const int kLocationTimeoutSubsequentSec = (kMinIntervalMsec / 1000) * 2;
83     const int kNoLocationPeriodSec = (kMinIntervalMsec / 1000) / 2;
84     const int kLocationsToCheck = 5;
85     const bool kLowPowerMode = true;
86 
87     // Warmup period - VTS doesn't have AGPS access via GnssLocationProvider
88     StartAndCheckLocations(5);
89     StopAndClearLocations();
90 
91     // Start of Low Power Mode test
92     SetPositionMode(kMinIntervalMsec, kLowPowerMode);
93 
94     // Don't expect true - as without AGPS access
95     if (!StartAndCheckFirstLocation()) {
96         ALOGW("GetLocationLowPower test - no first low power location received.");
97     }
98 
99     for (int i = 1; i < kLocationsToCheck; i++) {
100         // Verify that kMinIntervalMsec is respected by waiting kNoLocationPeriodSec and
101         // ensure that no location is received yet
102 
103         wait(kNoLocationPeriodSec);
104         // Tolerate (ignore) one extra location right after the first one
105         // to handle startup edge case scheduling limitations in some implementations
106         if ((i == 1) && (location_called_count_ == 2)) {
107             CheckLocation(last_location_, true);
108             continue;  // restart the quiet wait period after this too-fast location
109         }
110         EXPECT_LE(location_called_count_, i);
111         if (location_called_count_ != i) {
112             ALOGW("GetLocationLowPower test - not enough locations received. %d vs. %d expected ",
113                   location_called_count_, i);
114         }
115 
116         if (std::cv_status::no_timeout !=
117             wait(kLocationTimeoutSubsequentSec - kNoLocationPeriodSec)) {
118             ALOGW("GetLocationLowPower test - timeout awaiting location %d", i);
119         } else {
120             CheckLocation(last_location_, true);
121         }
122     }
123 
124     StopAndClearLocations();
125 }
126 
127 /*
128  * FindStrongFrequentNonGpsSource:
129  *
130  * Search through a GnssSvStatus list for the strongest non-GPS satellite observed enough times
131  *
132  * returns the strongest source,
133  *         or a source with constellation == UNKNOWN if none are found sufficient times
134  */
135 
FindStrongFrequentNonGpsSource(const list<IGnssCallback::GnssSvStatus> list_gnss_sv_status,const int min_observations)136 IGnssConfiguration::BlacklistedSource FindStrongFrequentNonGpsSource(
137     const list<IGnssCallback::GnssSvStatus> list_gnss_sv_status, const int min_observations) {
138     struct ComparableBlacklistedSource {
139         IGnssConfiguration::BlacklistedSource id;
140 
141         ComparableBlacklistedSource() {
142             id.constellation = GnssConstellationType::UNKNOWN;
143             id.svid = 0;
144         }
145 
146         bool operator<(const ComparableBlacklistedSource& compare) const {
147             return ((id.svid < compare.id.svid) || ((id.svid == compare.id.svid) &&
148                                                     (id.constellation < compare.id.constellation)));
149         }
150     };
151 
152     struct SignalCounts {
153         int observations;
154         float max_cn0_dbhz;
155     };
156 
157     std::map<ComparableBlacklistedSource, SignalCounts> mapSignals;
158 
159     for (const auto& gnss_sv_status : list_gnss_sv_status) {
160         for (uint32_t iSv = 0; iSv < gnss_sv_status.numSvs; iSv++) {
161             const auto& gnss_sv = gnss_sv_status.gnssSvList[iSv];
162             if ((gnss_sv.svFlag & IGnssCallback::GnssSvFlags::USED_IN_FIX) &&
163                 (gnss_sv.constellation != GnssConstellationType::GPS)) {
164                 ComparableBlacklistedSource source;
165                 source.id.svid = gnss_sv.svid;
166                 source.id.constellation = gnss_sv.constellation;
167 
168                 const auto& itSignal = mapSignals.find(source);
169                 if (itSignal == mapSignals.end()) {
170                     SignalCounts counts;
171                     counts.observations = 1;
172                     counts.max_cn0_dbhz = gnss_sv.cN0Dbhz;
173                     mapSignals.insert(
174                         std::pair<ComparableBlacklistedSource, SignalCounts>(source, counts));
175                 } else {
176                     itSignal->second.observations++;
177                     if (itSignal->second.max_cn0_dbhz < gnss_sv.cN0Dbhz) {
178                         itSignal->second.max_cn0_dbhz = gnss_sv.cN0Dbhz;
179                     }
180                 }
181             }
182         }
183     }
184 
185     float max_cn0_dbhz_with_sufficient_count = 0.;
186     int total_observation_count = 0;
187     int blacklisted_source_count_observation = 0;
188 
189     ComparableBlacklistedSource source_to_blacklist;  // initializes to zero = UNKNOWN constellation
190     for (auto const& pairSignal : mapSignals) {
191         total_observation_count += pairSignal.second.observations;
192         if ((pairSignal.second.observations >= min_observations) &&
193             (pairSignal.second.max_cn0_dbhz > max_cn0_dbhz_with_sufficient_count)) {
194             source_to_blacklist = pairSignal.first;
195             blacklisted_source_count_observation = pairSignal.second.observations;
196             max_cn0_dbhz_with_sufficient_count = pairSignal.second.max_cn0_dbhz;
197         }
198     }
199     ALOGD(
200         "Among %d observations, chose svid %d, constellation %d, "
201         "with %d observations at %.1f max CNo",
202         total_observation_count, source_to_blacklist.id.svid,
203         (int)source_to_blacklist.id.constellation, blacklisted_source_count_observation,
204         max_cn0_dbhz_with_sufficient_count);
205 
206     return source_to_blacklist.id;
207 }
208 
209 /*
210  * BlacklistIndividualSatellites:
211  *
212  * 1) Turns on location, waits for 3 locations, ensuring they are valid, and checks corresponding
213  * GnssStatus for common satellites (strongest and one other.)
214  * 2a & b) Turns off location, and blacklists common satellites.
215  * 3) Restart location, wait for 3 locations, ensuring they are valid, and checks corresponding
216  * GnssStatus does not use those satellites.
217  * 4a & b) Turns off location, and send in empty blacklist.
218  * 5a) Restart location, wait for 3 locations, ensuring they are valid, and checks corresponding
219  * GnssStatus does re-use at least the previously strongest satellite
220  * 5b) Retry a few times, in case GNSS search strategy takes a while to reacquire even the
221  * formerly strongest satellite
222  */
TEST_F(GnssHalTest,BlacklistIndividualSatellites)223 TEST_F(GnssHalTest, BlacklistIndividualSatellites) {
224     if (!IsGnssHalVersion_1_1()) {
225         ALOGI("Test BlacklistIndividualSatellites skipped. GNSS HAL version is greater than 1.1.");
226         return;
227     }
228 
229     const int kLocationsToAwait = 3;
230     const int kRetriesToUnBlacklist = 10;
231 
232     StartAndCheckLocations(kLocationsToAwait);
233 
234     // Tolerate 1 less sv status to handle edge cases in reporting.
235     EXPECT_GE((int)list_gnss_sv_status_.size() + 1, kLocationsToAwait);
236     ALOGD("Observed %d GnssSvStatus, while awaiting %d Locations (%d received)",
237           (int)list_gnss_sv_status_.size(), kLocationsToAwait, location_called_count_);
238 
239     /*
240      * Identify strongest SV seen at least kLocationsToAwait -1 times
241      * Why -1?  To avoid test flakiness in case of (plausible) slight flakiness in strongest signal
242      * observability (one epoch RF null)
243      */
244 
245     IGnssConfiguration::BlacklistedSource source_to_blacklist =
246         FindStrongFrequentNonGpsSource(list_gnss_sv_status_, kLocationsToAwait - 1);
247 
248     if (source_to_blacklist.constellation == GnssConstellationType::UNKNOWN) {
249         // Cannot find a non-GPS satellite. Let the test pass.
250         return;
251     }
252 
253     // Stop locations, blacklist the common SV
254     StopAndClearLocations();
255 
256     auto gnss_configuration_hal_return = gnss_hal_->getExtensionGnssConfiguration_1_1();
257     ASSERT_TRUE(gnss_configuration_hal_return.isOk());
258     sp<IGnssConfiguration> gnss_configuration_hal = gnss_configuration_hal_return;
259     ASSERT_NE(gnss_configuration_hal, nullptr);
260 
261     hidl_vec<IGnssConfiguration::BlacklistedSource> sources;
262     sources.resize(1);
263     sources[0] = source_to_blacklist;
264 
265     auto result = gnss_configuration_hal->setBlacklist(sources);
266     ASSERT_TRUE(result.isOk());
267     EXPECT_TRUE(result);
268 
269     // retry and ensure satellite not used
270     list_gnss_sv_status_.clear();
271 
272     StartAndCheckLocations(kLocationsToAwait);
273 
274     // early exit if test is being run with insufficient signal
275     if (location_called_count_ == 0) {
276         ALOGE("0 Gnss locations received - ensure sufficient signal and retry");
277     }
278     ASSERT_TRUE(location_called_count_ > 0);
279 
280     // Tolerate 1 less sv status to handle edge cases in reporting.
281     EXPECT_GE((int)list_gnss_sv_status_.size() + 1, kLocationsToAwait);
282     ALOGD("Observed %d GnssSvStatus, while awaiting %d Locations (%d received)",
283           (int)list_gnss_sv_status_.size(), kLocationsToAwait, location_called_count_);
284     for (const auto& gnss_sv_status : list_gnss_sv_status_) {
285         for (uint32_t iSv = 0; iSv < gnss_sv_status.numSvs; iSv++) {
286             const auto& gnss_sv = gnss_sv_status.gnssSvList[iSv];
287             EXPECT_FALSE((gnss_sv.svid == source_to_blacklist.svid) &&
288                          (gnss_sv.constellation == source_to_blacklist.constellation) &&
289                          (gnss_sv.svFlag & IGnssCallback::GnssSvFlags::USED_IN_FIX));
290         }
291     }
292 
293     // clear blacklist and restart - this time updating the blacklist while location is still on
294     sources.resize(0);
295 
296     result = gnss_configuration_hal->setBlacklist(sources);
297     ASSERT_TRUE(result.isOk());
298     EXPECT_TRUE(result);
299 
300     bool strongest_sv_is_reobserved = false;
301     // do several loops awaiting a few locations, allowing non-immediate reacquisition strategies
302     int unblacklist_loops_remaining = kRetriesToUnBlacklist;
303     while (!strongest_sv_is_reobserved && (unblacklist_loops_remaining-- > 0)) {
304         StopAndClearLocations();
305         list_gnss_sv_status_.clear();
306 
307         StartAndCheckLocations(kLocationsToAwait);
308 
309         // early exit loop if test is being run with insufficient signal
310         if (location_called_count_ == 0) {
311             ALOGE("0 Gnss locations received - ensure sufficient signal and retry");
312         }
313         ASSERT_TRUE(location_called_count_ > 0);
314 
315         // Tolerate 1 less sv status to handle edge cases in reporting.
316         EXPECT_GE((int)list_gnss_sv_status_.size() + 1, kLocationsToAwait);
317         ALOGD(
318             "Clear blacklist, observed %d GnssSvStatus, while awaiting %d Locations"
319             ", tries remaining %d",
320             (int)list_gnss_sv_status_.size(), kLocationsToAwait, unblacklist_loops_remaining);
321 
322         for (const auto& gnss_sv_status : list_gnss_sv_status_) {
323             for (uint32_t iSv = 0; iSv < gnss_sv_status.numSvs; iSv++) {
324                 const auto& gnss_sv = gnss_sv_status.gnssSvList[iSv];
325                 if ((gnss_sv.svid == source_to_blacklist.svid) &&
326                     (gnss_sv.constellation == source_to_blacklist.constellation) &&
327                     (gnss_sv.svFlag & IGnssCallback::GnssSvFlags::USED_IN_FIX)) {
328                     strongest_sv_is_reobserved = true;
329                     break;
330                 }
331             }
332             if (strongest_sv_is_reobserved) break;
333         }
334     }
335     EXPECT_TRUE(strongest_sv_is_reobserved);
336     StopAndClearLocations();
337 }
338 
339 /*
340  * BlacklistConstellationWithLocationOff:
341  *
342  * 1) Turns on location, waits for 3 locations, ensuring they are valid, and checks corresponding
343  * GnssStatus for any non-GPS constellations.
344  * 2a & b) Turns off location, and blacklist first non-GPS constellations.
345  * 3) Restart location, wait for 3 locations, ensuring they are valid, and checks corresponding
346  * GnssStatus does not use any constellation but GPS.
347  * 4a & b) Clean up by turning off location, and send in empty blacklist.
348  */
TEST_F(GnssHalTest,BlacklistConstellationWithLocationOff)349 TEST_F(GnssHalTest, BlacklistConstellationWithLocationOff) {
350     if (!IsGnssHalVersion_1_1()) {
351         ALOGI("Test BlacklistConstellation skipped. GNSS HAL version is greater than 1.1.");
352         return;
353     }
354 
355     const int kLocationsToAwait = 3;
356     // Find first non-GPS constellation to blacklist
357     GnssConstellationType constellation_to_blacklist = startLocationAndGetNonGpsConstellation();
358 
359     // Turns off location
360     StopAndClearLocations();
361 
362     IGnssConfiguration::BlacklistedSource source_to_blacklist;
363     source_to_blacklist.constellation = constellation_to_blacklist;
364     source_to_blacklist.svid = 0;  // documented wildcard for all satellites in this constellation
365 
366     auto gnss_configuration_hal_return = gnss_hal_->getExtensionGnssConfiguration_1_1();
367     ASSERT_TRUE(gnss_configuration_hal_return.isOk());
368     sp<IGnssConfiguration> gnss_configuration_hal = gnss_configuration_hal_return;
369     ASSERT_NE(gnss_configuration_hal, nullptr);
370 
371     hidl_vec<IGnssConfiguration::BlacklistedSource> sources;
372     sources.resize(1);
373     sources[0] = source_to_blacklist;
374 
375     auto result = gnss_configuration_hal->setBlacklist(sources);
376     ASSERT_TRUE(result.isOk());
377     EXPECT_TRUE(result);
378 
379     // retry and ensure constellation not used
380     list_gnss_sv_status_.clear();
381 
382     location_called_count_ = 0;
383     StartAndCheckLocations(kLocationsToAwait);
384 
385     // Tolerate 1 less sv status to handle edge cases in reporting.
386     EXPECT_GE((int)list_gnss_sv_status_.size() + 1, kLocationsToAwait);
387     ALOGD("Observed %d GnssSvStatus, while awaiting %d Locations", (int)list_gnss_sv_status_.size(),
388           kLocationsToAwait);
389     for (const auto& gnss_sv_status : list_gnss_sv_status_) {
390         for (uint32_t iSv = 0; iSv < gnss_sv_status.numSvs; iSv++) {
391             const auto& gnss_sv = gnss_sv_status.gnssSvList[iSv];
392             EXPECT_FALSE((gnss_sv.constellation == source_to_blacklist.constellation) &&
393                          (gnss_sv.svFlag & IGnssCallback::GnssSvFlags::USED_IN_FIX));
394         }
395     }
396 
397     // clean up
398     StopAndClearLocations();
399     sources.resize(0);
400     result = gnss_configuration_hal->setBlacklist(sources);
401     ASSERT_TRUE(result.isOk());
402     EXPECT_TRUE(result);
403 }
404 
405 /*
406  * BlacklistConstellationWithLocationOn:
407  *
408  * 1) Turns on location, waits for 3 locations, ensuring they are valid, and checks corresponding
409  * GnssStatus for any non-GPS constellations.
410  * 2a & b) Blacklist first non-GPS constellations, and turns off location.
411  * 3) Restart location, wait for 3 locations, ensuring they are valid, and checks corresponding
412  * GnssStatus does not use any constellation but GPS.
413  * 4a & b) Clean up by turning off location, and send in empty blacklist.
414  */
TEST_F(GnssHalTest,BlacklistConstellationWithLocationOn)415 TEST_F(GnssHalTest, BlacklistConstellationWithLocationOn) {
416     if (!IsGnssHalVersion_1_1()) {
417         ALOGI("Test BlacklistConstellation skipped. GNSS HAL version is greater than 1.1.");
418         return;
419     }
420 
421     const int kLocationsToAwait = 3;
422     GnssConstellationType constellation_to_blacklist = startLocationAndGetNonGpsConstellation();
423 
424     IGnssConfiguration::BlacklistedSource source_to_blacklist;
425     source_to_blacklist.constellation = constellation_to_blacklist;
426     source_to_blacklist.svid = 0;  // documented wildcard for all satellites in this constellation
427 
428     auto gnss_configuration_hal_return = gnss_hal_->getExtensionGnssConfiguration_1_1();
429     ASSERT_TRUE(gnss_configuration_hal_return.isOk());
430     sp<IGnssConfiguration> gnss_configuration_hal = gnss_configuration_hal_return;
431     ASSERT_NE(gnss_configuration_hal, nullptr);
432 
433     hidl_vec<IGnssConfiguration::BlacklistedSource> sources;
434     sources.resize(1);
435     sources[0] = source_to_blacklist;
436 
437     // setBlacklist when location is on.
438     auto result = gnss_configuration_hal->setBlacklist(sources);
439     ASSERT_TRUE(result.isOk());
440     EXPECT_TRUE(result);
441 
442     // Turns off location
443     StopAndClearLocations();
444 
445     // retry and ensure constellation not used
446     list_gnss_sv_status_.clear();
447 
448     location_called_count_ = 0;
449     StartAndCheckLocations(kLocationsToAwait);
450 
451     // Tolerate 1 less sv status to handle edge cases in reporting.
452     EXPECT_GE((int)list_gnss_sv_status_.size() + 1, kLocationsToAwait);
453     ALOGD("Observed %d GnssSvStatus, while awaiting %d Locations", (int)list_gnss_sv_status_.size(),
454           kLocationsToAwait);
455     for (const auto& gnss_sv_status : list_gnss_sv_status_) {
456         for (uint32_t iSv = 0; iSv < gnss_sv_status.numSvs; iSv++) {
457             const auto& gnss_sv = gnss_sv_status.gnssSvList[iSv];
458             EXPECT_FALSE((gnss_sv.constellation == source_to_blacklist.constellation) &&
459                          (gnss_sv.svFlag & IGnssCallback::GnssSvFlags::USED_IN_FIX));
460         }
461     }
462 
463     // clean up
464     StopAndClearLocations();
465     sources.resize(0);
466     result = gnss_configuration_hal->setBlacklist(sources);
467     ASSERT_TRUE(result.isOk());
468     EXPECT_TRUE(result);
469 }
470 
471 /*
472  * InjectBestLocation
473  *
474  * Ensure successfully injecting a location.
475  */
TEST_F(GnssHalTest,InjectBestLocation)476 TEST_F(GnssHalTest, InjectBestLocation) {
477     StartAndCheckLocations(1);
478     GnssLocation gnssLocation = last_location_;
479     CheckLocation(gnssLocation, true);
480 
481     auto result = gnss_hal_->injectBestLocation(gnssLocation);
482 
483     ASSERT_TRUE(result.isOk());
484     EXPECT_TRUE(result);
485 
486     auto resultVoid = gnss_hal_->deleteAidingData(IGnss::GnssAidingData::DELETE_POSITION);
487 
488     ASSERT_TRUE(resultVoid.isOk());
489 }
490 
491 /*
492  * GnssDebugValuesSanityTest:
493  * Ensures that GnssDebug values make sense.
494  */
TEST_F(GnssHalTest,GnssDebugValuesSanityTest)495 TEST_F(GnssHalTest, GnssDebugValuesSanityTest) {
496     auto gnssDebug = gnss_hal_->getExtensionGnssDebug();
497     ASSERT_TRUE(gnssDebug.isOk());
498     if (!IsAutomotiveDevice() && info_called_count_ > 0 && last_info_.yearOfHw >= 2017) {
499         sp<IGnssDebug> iGnssDebug = gnssDebug;
500         EXPECT_NE(iGnssDebug, nullptr);
501 
502         IGnssDebug::DebugData data;
503         iGnssDebug->getDebugData(
504             [&data](const IGnssDebug::DebugData& debugData) { data = debugData; });
505 
506         if (data.position.valid) {
507             EXPECT_GE(data.position.latitudeDegrees, -90);
508             EXPECT_LE(data.position.latitudeDegrees, 90);
509 
510             EXPECT_GE(data.position.longitudeDegrees, -180);
511             EXPECT_LE(data.position.longitudeDegrees, 180);
512 
513             EXPECT_GE(data.position.altitudeMeters, -1000);  // Dead Sea: -414m
514             EXPECT_LE(data.position.altitudeMeters, 20000);  // Mount Everest: 8850m
515 
516             EXPECT_GE(data.position.speedMetersPerSec, 0);
517             EXPECT_LE(data.position.speedMetersPerSec, 600);
518 
519             EXPECT_GE(data.position.bearingDegrees, -360);
520             EXPECT_LE(data.position.bearingDegrees, 360);
521 
522             EXPECT_GT(data.position.horizontalAccuracyMeters, 0);
523             EXPECT_LE(data.position.horizontalAccuracyMeters, 20000000);
524 
525             EXPECT_GT(data.position.verticalAccuracyMeters, 0);
526             EXPECT_LE(data.position.verticalAccuracyMeters, 20000);
527 
528             EXPECT_GT(data.position.speedAccuracyMetersPerSecond, 0);
529             EXPECT_LE(data.position.speedAccuracyMetersPerSecond, 500);
530 
531             EXPECT_GT(data.position.bearingAccuracyDegrees, 0);
532             EXPECT_LE(data.position.bearingAccuracyDegrees, 180);
533 
534             EXPECT_GE(data.position.ageSeconds, 0);
535         }
536 
537         EXPECT_GE(data.time.timeEstimate, 1483228800000);  // Jan 01 2017 00:00:00 GMT.
538 
539         EXPECT_GT(data.time.timeUncertaintyNs, 0);
540 
541         EXPECT_GT(data.time.frequencyUncertaintyNsPerSec, 0);
542         EXPECT_LE(data.time.frequencyUncertaintyNsPerSec, 2.0e5);  // 200 ppm
543     }
544 }
545