1 /*
2  * Copyright (C) 2015 Google Inc.
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 package android.location.cts;
18 
19 import com.android.compatibility.common.util.ApiLevelUtil;
20 
21 import android.content.Context;
22 import android.content.pm.PackageManager;
23 import android.location.GnssClock;
24 import android.location.GnssMeasurement;
25 import android.location.GnssNavigationMessage;
26 import android.location.GnssStatus;
27 import android.location.LocationManager;
28 import android.os.Build;
29 import android.util.Log;
30 
31 import junit.framework.Assert;
32 
33 import java.util.Arrays;
34 import java.util.HashSet;
35 import java.util.List;
36 import java.util.concurrent.TimeUnit;
37 import java.util.Set;
38 
39 /**
40  * Helper class for GnssMeasurement Tests.
41  */
42 public final class TestMeasurementUtil {
43 
44     private static final String TAG = "TestMeasurementUtil";
45 
46     private static final long NSEC_IN_SEC = 1000_000_000L;
47     // Generally carrier phase quality prr's have uncertainties around 0.001-0.05 m/s, vs.
48     // doppler energy quality prr's closer to 0.25-10 m/s.  Threshold is chosen between those
49     // typical ranges.
50     private static final float THRESHOLD_FOR_CARRIER_PRR_UNC_METERS_PER_SEC = 0.15F;
51 
52     // For gpsTimeInNs >= 1.14 * 10^18 (year 2016+)
53     private static final long GPS_TIME_YEAR_2016_IN_NSEC = 1_140_000_000L * NSEC_IN_SEC;
54 
55     // Error message for GnssMeasurements Registration.
56     public static final String REGISTRATION_ERROR_MESSAGE = "Registration of GnssMeasurements" +
57             " listener has failed, this indicates a platform bug. Please report the issue with" +
58             " a full bugreport.";
59 
60     private static final int YEAR_2016 = 2016;
61 
62     // The valid Gnss navigation message type as listed in
63     // android/hardware/libhardware/include/hardware/gps.h
64     public static final Set<Integer> GNSS_NAVIGATION_MESSAGE_TYPE =
65         new HashSet<Integer>(Arrays.asList(
66             GnssNavigationMessage.TYPE_GPS_L1CA,
67             GnssNavigationMessage.TYPE_GPS_L2CNAV,
68             GnssNavigationMessage.TYPE_GPS_L5CNAV,
69             GnssNavigationMessage.TYPE_GPS_CNAV2,
70             GnssNavigationMessage.TYPE_GLO_L1CA,
71             GnssNavigationMessage.TYPE_BDS_D1,
72             GnssNavigationMessage.TYPE_BDS_D2,
73             GnssNavigationMessage.TYPE_GAL_I,
74             GnssNavigationMessage.TYPE_GAL_F
75         ));
76 
77     /**
78      * Check if test can be run on the current device.
79      *
80      * @param  testLocationManager TestLocationManager
81      * @return true if Build.VERSION &gt;=  Build.VERSION_CODES.N and Location GPS present on
82      *         device.
83      */
canTestRunOnCurrentDevice(TestLocationManager testLocationManager, String testTag, int minHardwareYear, boolean isCtsVerifier)84     public static boolean canTestRunOnCurrentDevice(TestLocationManager testLocationManager,
85                                                     String testTag,
86                                                     int minHardwareYear,
87                                                     boolean isCtsVerifier) {
88        if (ApiLevelUtil.isBefore(Build.VERSION_CODES.N)) {
89             Log.i(TAG, "This test is designed to work on N or newer. " +
90                     "Test is being skipped because the platform version is being run in " +
91                     ApiLevelUtil.getApiLevel());
92             return false;
93         }
94 
95         // If device does not have a GPS, skip the test.
96         PackageManager pm = testLocationManager.getContext().getPackageManager();
97         if (!pm.hasSystemFeature(PackageManager.FEATURE_LOCATION_GPS)) {
98           Log.w(testTag, "GPS feature not present on device, skipping GPS test.");
99           return false;
100         }
101 
102         // If device has a GPS, but it's turned off in settings, and this is CTS verifier,
103         // fail the test now, because there's no point in going further.
104         // If this is CTS only,we'll warn instead, and quickly pass the test.
105         // (Cts non-verifier deep-indoors-forgiveness happens later, *if* needed)
106         boolean gpsProviderEnabled = testLocationManager.getLocationManager()
107                 .isProviderEnabled(LocationManager.GPS_PROVIDER);
108         SoftAssert.failOrWarning(isCtsVerifier, " GPS location disabled on the device. " +
109                 "Enable location in settings to continue test.", gpsProviderEnabled);
110         // If CTS only, allow an early exit pass
111         if (!isCtsVerifier && !gpsProviderEnabled) {
112             return false;
113         }
114 
115         // TODO - add this to the test info page
116         int gnssYearOfHardware = testLocationManager.getLocationManager().getGnssYearOfHardware();
117         Log.i(testTag, "This device is reporting GNSS hardware from year "
118                 + (gnssYearOfHardware == 0 ? "2015 or earlier" : gnssYearOfHardware) + ". "
119                 + "Devices " + (gnssYearOfHardware >= minHardwareYear ? "like this one " : "")
120                 + "from year " + minHardwareYear + " or newer provide GnssMeasurement support." );
121 
122         return true;
123     }
124 
125     /**
126      * Check if pseudorange rate uncertainty in Gnss Measurement is in the expected range.
127      * See field description in {@code gps.h}.
128      *
129      * @param measurement GnssMeasurement
130      * @return true if this measurement has prr uncertainty in a range indicative of carrier phase
131      */
gnssMeasurementHasCarrierPhasePrr(GnssMeasurement measurement)132     public static boolean gnssMeasurementHasCarrierPhasePrr(GnssMeasurement measurement) {
133       return (measurement.getPseudorangeRateUncertaintyMetersPerSecond() <
134               THRESHOLD_FOR_CARRIER_PRR_UNC_METERS_PER_SEC);
135     }
136 
137     /**
138      * Assert all mandatory fields in Gnss Clock are in expected range.
139      * See mandatory fields in {@code gps.h}.
140      *
141      * @param clock       GnssClock
142      * @param softAssert  custom SoftAssert
143      * @param timeInNs    event time in ns
144      */
assertGnssClockFields(GnssClock clock, SoftAssert softAssert, long timeInNs)145     public static void assertGnssClockFields(GnssClock clock,
146                                              SoftAssert softAssert,
147                                              long timeInNs) {
148         softAssert.assertTrue("time_ns: clock value",
149                 timeInNs,
150                 "X >= 0",
151                 String.valueOf(timeInNs),
152                 timeInNs >= 0L);
153 
154         // If full bias is valid and accurate within one sec. verify its sign & magnitude
155         if (clock.hasFullBiasNanos() &&
156                 ((!clock.hasBiasUncertaintyNanos()) ||
157                         (clock.getBiasUncertaintyNanos() < NSEC_IN_SEC))) {
158             long gpsTimeInNs = timeInNs - clock.getFullBiasNanos();
159             softAssert.assertTrue("TimeNanos - FullBiasNanos = GpsTimeNanos: clock value",
160                     gpsTimeInNs,
161                     "gpsTimeInNs >= 1.14 * 10^18 (year 2016+)",
162                     String.valueOf(gpsTimeInNs),
163                     gpsTimeInNs >= GPS_TIME_YEAR_2016_IN_NSEC);
164         }
165 
166     }
167 
168     /**
169      * Assert all mandatory fields in Gnss Measurement are in expected range.
170      * See mandatory fields in {@code gps.h}.
171      *
172      * @param measurement GnssMeasurement
173      * @param softAssert  custom SoftAssert
174      * @param timeInNs    event time in ns
175      */
assertAllGnssMeasurementMandatoryFields(GnssMeasurement measurement, SoftAssert softAssert, long timeInNs)176     public static void assertAllGnssMeasurementMandatoryFields(GnssMeasurement measurement,
177         SoftAssert softAssert, long timeInNs) {
178 
179         verifySvid(measurement, softAssert, timeInNs);
180         verifyReceivedSatelliteVehicleTimeInNs(measurement, softAssert, timeInNs);
181         verifyAccumulatedDeltaRanges(measurement, softAssert, timeInNs);
182 
183         int state = measurement.getState();
184         softAssert.assertTrue("state: Satellite code sync state",
185                 timeInNs,
186                 "X >= 0",
187                 String.valueOf(state),
188                 state >= 0);
189 
190         // Check received_gps_tow_uncertainty_ns
191         softAssert.assertTrueAsWarning("received_gps_tow_uncertainty_ns:" +
192                         " Uncertainty of received GPS Time-of-Week in ns",
193                 timeInNs,
194                 "X > 0",
195                 String.valueOf(measurement.getReceivedSvTimeUncertaintyNanos()),
196                 measurement.getReceivedSvTimeUncertaintyNanos() > 0L);
197 
198         long timeOffsetInSec = TimeUnit.NANOSECONDS.toSeconds(
199                 (long) measurement.getTimeOffsetNanos());
200         softAssert.assertTrue("time_offset_ns: Time offset",
201                 timeInNs,
202                 "-100 seconds < X < +10 seconds",
203                 String.valueOf(measurement.getTimeOffsetNanos()),
204                 (-100 < timeOffsetInSec) && (timeOffsetInSec < 10));
205 
206         softAssert.assertTrue("c_n0_dbhz: Carrier-to-noise density",
207                 timeInNs,
208                 "0.0 >= X <=63",
209                 String.valueOf(measurement.getCn0DbHz()),
210                 measurement.getCn0DbHz() >= 0.0 &&
211                         measurement.getCn0DbHz() <= 63.0);
212 
213         softAssert.assertTrue("pseudorange_rate_uncertainty_mps: " +
214                         "Pseudorange Rate Uncertainty in m/s",
215                 timeInNs,
216                 "X > 0.0",
217                 String.valueOf(
218                         measurement.getPseudorangeRateUncertaintyMetersPerSecond()),
219                 measurement.getPseudorangeRateUncertaintyMetersPerSecond() > 0.0);
220 
221         // Check carrier_frequency_hz.
222         if (measurement.hasCarrierFrequencyHz()) {
223             softAssert.assertTrue("carrier_frequency_hz: Carrier frequency in hz",
224                     timeInNs,
225                     "X > 0.0",
226                     String.valueOf(measurement.getCarrierFrequencyHz()),
227                     measurement.getCarrierFrequencyHz() > 0.0);
228         }
229 
230         // Check carrier_phase.
231         if (measurement.hasCarrierPhase()) {
232             softAssert.assertTrue("carrier_phase: Carrier phase",
233                     timeInNs,
234                     "0.0 >= X <= 1.0",
235                     String.valueOf(measurement.getCarrierPhase()),
236                     measurement.getCarrierPhase() >= 0.0 && measurement.getCarrierPhase() <= 1.0);
237         }
238 
239         // Check carrier_phase_uncertainty..
240         if (measurement.hasCarrierPhaseUncertainty()) {
241             softAssert.assertTrue("carrier_phase_uncertainty: 1-Sigma uncertainty of the " +
242                             "carrier-phase",
243                     timeInNs,
244                     "X > 0.0",
245                     String.valueOf(measurement.getCarrierPhaseUncertainty()),
246                     measurement.getCarrierPhaseUncertainty() > 0.0);
247         }
248 
249         // Check GNSS Measurement's multipath_indicator.
250         softAssert.assertTrue("multipath_indicator: GNSS Measurement's multipath indicator",
251                 timeInNs,
252                 "0 >= X <= 2",
253                 String.valueOf(measurement.getMultipathIndicator()),
254                 measurement.getMultipathIndicator() >= 0
255                         && measurement.getMultipathIndicator() <= 2);
256 
257 
258         // Check Signal-to-Noise ratio (SNR).
259         if (measurement.hasSnrInDb()) {
260             softAssert.assertTrue("snr: Signal-to-Noise ratio (SNR) in dB",
261                     timeInNs,
262                     "0.0 >= X <= 63",
263                     String.valueOf(measurement.getSnrInDb()),
264                     measurement.getSnrInDb() >= 0.0 && measurement.getSnrInDb() <= 63);
265         }
266 
267         // Check Automatic Gain Control level in dB.
268         if (measurement.hasAutomaticGainControlLevelDb()) {
269             softAssert.assertTrue("Automatic Gain Control level in dB",
270                 timeInNs,
271                 "-100 >= X <= 100",
272                 String.valueOf(measurement.getAutomaticGainControlLevelDb()),
273                 measurement.getAutomaticGainControlLevelDb() >= -100
274                     && measurement.getAutomaticGainControlLevelDb() <= 100);
275         }
276 
277     }
278 
279     /**
280      * Verify accumulated delta ranges are in expected range.
281      *
282      * @param measurement GnssMeasurement
283      * @param softAssert  custom SoftAssert
284      * @param timeInNs    event time in ns
285      */
verifyAccumulatedDeltaRanges(GnssMeasurement measurement, SoftAssert softAssert, long timeInNs)286     private static void verifyAccumulatedDeltaRanges(GnssMeasurement measurement,
287         SoftAssert softAssert, long timeInNs) {
288 
289         int accumulatedDeltaRangeState = measurement.getAccumulatedDeltaRangeState();
290         softAssert.assertTrue("accumulated_delta_range_state: " +
291                         "Accumulated delta range state",
292                 timeInNs,
293                 "0 <= X <= 7",
294                 String.valueOf(accumulatedDeltaRangeState),
295                 accumulatedDeltaRangeState >= 0 && accumulatedDeltaRangeState <= 7);
296         if (accumulatedDeltaRangeState > 0) {
297             double accumulatedDeltaRangeInMeters =
298                     measurement.getAccumulatedDeltaRangeMeters();
299             softAssert.assertTrue("accumulated_delta_range_m: " +
300                             "Accumulated delta range in meter",
301                     timeInNs,
302                     "X != 0.0",
303                     String.valueOf(accumulatedDeltaRangeInMeters),
304                     accumulatedDeltaRangeInMeters != 0.0);
305             double accumulatedDeltaRangeUncertainty =
306                     measurement.getAccumulatedDeltaRangeUncertaintyMeters();
307             softAssert.assertTrue("accumulated_delta_range_uncertainty_m: " +
308                             "Accumulated delta range uncertainty in meter",
309                     timeInNs,
310                     "X > 0.0",
311                     String.valueOf(accumulatedDeltaRangeUncertainty),
312                     accumulatedDeltaRangeUncertainty > 0.0);
313         }
314     }
315 
316     /**
317      * Verify svid's are in expected range.
318      *
319      * @param measurement GnssMeasurement
320      * @param softAssert  custom SoftAssert
321      * @param timeInNs    event time in ns
322      */
verifySvid(GnssMeasurement measurement, SoftAssert softAssert, long timeInNs)323     private static void verifySvid(GnssMeasurement measurement, SoftAssert softAssert,
324         long timeInNs) {
325 
326         String svidLogMessageFormat = "svid: Space Vehicle ID. Constellation type = %s";
327         int constellationType = measurement.getConstellationType();
328         int svid = measurement.getSvid();
329         validateSvidSub(softAssert, timeInNs, constellationType, svid);
330     }
331 
validateSvidSub(SoftAssert softAssert, Long timeInNs, int constellationType, int svid)332     public static void validateSvidSub(SoftAssert softAssert, Long timeInNs,
333         int constellationType, int svid) {
334 
335         String svidValue = String.valueOf(svid);
336 
337         switch (constellationType) {
338             case GnssStatus.CONSTELLATION_GPS:
339                 softAssert.assertTrue("svid: Space Vehicle ID. Constellation type " +
340                                 "= CONSTELLATION_GPS",
341                         timeInNs,
342                         "[1, 32]",
343                         svidValue,
344                         svid > 0 && svid <= 32);
345                 break;
346             case GnssStatus.CONSTELLATION_SBAS:
347                 softAssert.assertTrue("svid: Space Vehicle ID. Constellation type " +
348                                 "= CONSTELLATION_SBAS",
349                         timeInNs,
350                         "120 <= X <= 192",
351                         svidValue,
352                         svid >= 120 && svid <= 192);
353                 break;
354             case GnssStatus.CONSTELLATION_GLONASS:
355                 // Check Upper 8 bit, signed
356                 int freq = (svid >> 8);
357                 softAssert.assertTrue("svid: upper 8 bits, frequency number. Constellation type " +
358                                 "= CONSTELLATION_GLONASS",
359                         timeInNs,
360                         "freq == -127 || -7 <= freq <= 6",
361                         svidValue,
362                         // future proof check allowing a change in definition under discussion
363                         (freq == -127) || (freq >= -7 && freq <= 6) || (freq >= 93 && freq <= 106));
364                 // Check lower 8 bits, signed
365                 byte slot = (byte) svid;
366                 softAssert.assertTrue("svid: lower 8 bits, slot. Constellation type " +
367                                 "= CONSTELLATION_GLONASS",
368                         timeInNs,
369                         "slot == -127 || 1 <= slot <= 24",
370                         svidValue,
371                         // future proof check allowingn a change in definition under discussion
372                         (slot == -127) || (slot >= 1 && slot <= 24) || (slot >= 93 && slot <= 106));
373                 softAssert.assertTrue("svid: one of slot or freq is set (not -127). " +
374                                 "ConstellationType = CONSTELLATION_GLONASS,",
375                         timeInNs,
376                         "slot != -127 || freq != -127",
377                         svidValue,
378                         (slot != -127) || (freq != -127));
379                 break;
380             case GnssStatus.CONSTELLATION_QZSS:
381                 softAssert.assertTrue("svid: Space Vehicle ID. Constellation type " +
382                                 "= CONSTELLATION_QZSS",
383                         timeInNs,
384                         "193 <= X <= 200",
385                         svidValue,
386                         svid >= 193 && svid <= 200);
387                 break;
388             case GnssStatus.CONSTELLATION_BEIDOU:
389                 softAssert.assertTrue("svid: Space Vehicle ID. Constellation type " +
390                                 "= CONSTELLATION_BEIDOU",
391                         timeInNs,
392                         "1 <= X <= 36",
393                         svidValue,
394                         svid >= 1 && svid <= 36);
395                 break;
396             case GnssStatus.CONSTELLATION_GALILEO:
397                 softAssert.assertTrue("svid: Space Vehicle ID. Constellation type " +
398                                 "= CONSTELLATION_GALILEO",
399                         timeInNs,
400                         "1 <= X <= 37",
401                         String.valueOf(svid),
402                         svid >= 1 && svid <= 37);
403                 break;
404             default:
405                 // Explicit fail if did not receive valid constellation type.
406                 softAssert.assertTrue("svid: Space Vehicle ID. Did not receive any valid " +
407                                 "constellation type.",
408                         timeInNs,
409                         "Valid constellation type.",
410                         svidValue,
411                         false);
412                 break;
413         }
414     }
415 
416     /**
417      * Verify sv times are in expected range.
418      *
419      * @param measurement GnssMeasurement
420      * @param softAssert  custom SoftAssert
421      * @param timeInNs    event time in ns
422      * */
verifyReceivedSatelliteVehicleTimeInNs(GnssMeasurement measurement, SoftAssert softAssert, long timeInNs)423     private static void verifyReceivedSatelliteVehicleTimeInNs(GnssMeasurement measurement,
424         SoftAssert softAssert, long timeInNs) {
425 
426         int constellationType = measurement.getConstellationType();
427         int state = measurement.getState();
428         long received_sv_time_ns = measurement.getReceivedSvTimeNanos();
429         double sv_time_ms = TimeUnit.NANOSECONDS.toMillis(received_sv_time_ns);
430         double sv_time_sec = TimeUnit.NANOSECONDS.toSeconds(received_sv_time_ns);
431         double sv_time_days = TimeUnit.NANOSECONDS.toDays(received_sv_time_ns);
432 
433         // Check ranges for received_sv_time_ns for given Gps State
434         if (state == 0) {
435             softAssert.assertTrue("received_sv_time_ns:" +
436                             " Received SV Time-of-Week in ns." +
437                             " GNSS_MEASUREMENT_STATE_UNKNOWN.",
438                     timeInNs,
439                     "X == 0",
440                     String.valueOf(received_sv_time_ns),
441                     sv_time_ms == 0);
442         }
443 
444         switch (constellationType) {
445             case GnssStatus.CONSTELLATION_GPS:
446                 verifyGpsQzssSvTimes(measurement, softAssert, timeInNs, state, "CONSTELLATION_GPS");
447                 break;
448             case GnssStatus.CONSTELLATION_QZSS:
449                 verifyGpsQzssSvTimes(measurement, softAssert, timeInNs, state,
450                         "CONSTELLATION_QZSS");
451                 break;
452             case GnssStatus.CONSTELLATION_SBAS:
453                 if ((state | GnssMeasurement.STATE_SBAS_SYNC)
454                         == GnssMeasurement.STATE_SBAS_SYNC) {
455                     softAssert.assertTrue(getReceivedSvTimeNsLogMessage(
456                                     "GNSS_MEASUREMENT_STATE_SBAS_SYNC",
457                                     "GnssStatus.CONSTELLATION_SBAS"),
458                             timeInNs,
459                             "0s >= X <= 1s",
460                             String.valueOf(sv_time_sec),
461                             sv_time_sec >= 0 && sv_time_sec <= 1);
462                 } else if ((state | GnssMeasurement.STATE_SYMBOL_SYNC)
463                         == GnssMeasurement.STATE_SYMBOL_SYNC) {
464                     softAssert.assertTrue(getReceivedSvTimeNsLogMessage(
465                                     "GNSS_MEASUREMENT_STATE_SYMBOL_SYNC",
466                                     "GnssStatus.CONSTELLATION_SBAS"),
467                             timeInNs,
468                             "0ms >= X <= 2ms",
469                             String.valueOf(sv_time_ms),
470                             sv_time_ms >= 0 && sv_time_ms <= 2);
471                 } else if ((state | GnssMeasurement.STATE_CODE_LOCK)
472                         == GnssMeasurement.STATE_CODE_LOCK) {
473                     softAssert.assertTrue(getReceivedSvTimeNsLogMessage(
474                                     "GNSS_MEASUREMENT_STATE_CODE_LOCK",
475                                     "GnssStatus.CONSTELLATION_SBAS"),
476                             timeInNs,
477                             "0ms >= X <= 1ms",
478                             String.valueOf(sv_time_ms),
479                             sv_time_ms >= 0 && sv_time_ms <= 1);
480                 }
481                 break;
482             case GnssStatus.CONSTELLATION_GLONASS:
483                 if ((state | GnssMeasurement.STATE_GLO_TOD_DECODED)
484                         == GnssMeasurement.STATE_GLO_TOD_DECODED) {
485                     softAssert.assertTrue(getReceivedSvTimeNsLogMessage(
486                                     "GNSS_MEASUREMENT_STATE_GLO_TOD_DECODED",
487                                     "GnssStatus.CONSTELLATION_GLONASS"),
488                             timeInNs,
489                             "0 day >= X <= 1 day",
490                             String.valueOf(sv_time_days),
491                             sv_time_days >= 0 && sv_time_days <= 1);
492                 } else if ((state | GnssMeasurement.STATE_GLO_TOD_KNOWN)
493                          == GnssMeasurement.STATE_GLO_TOD_KNOWN) {
494                     softAssert.assertTrue(getReceivedSvTimeNsLogMessage(
495                                     "GNSS_MEASUREMENT_STATE_GLO_TOD_KNOWN",
496                                     "GnssStatus.CONSTELLATION_GLONASS"),
497                             timeInNs,
498                             "0 day >= X <= 1 day",
499                             String.valueOf(sv_time_days),
500                             sv_time_days >= 0 && sv_time_days <= 1);
501                 } else if ((state | GnssMeasurement.STATE_GLO_STRING_SYNC)
502                         == GnssMeasurement.STATE_GLO_STRING_SYNC) {
503                     softAssert.assertTrue(getReceivedSvTimeNsLogMessage(
504                                     "GNSS_MEASUREMENT_STATE_GLO_STRING_SYNC",
505                                     "GnssStatus.CONSTELLATION_GLONASS"),
506                             timeInNs,
507                             "0s >= X <= 2s",
508                             String.valueOf(sv_time_sec),
509                             sv_time_sec >= 0 && sv_time_sec <= 2);
510                 } else if ((state | GnssMeasurement.STATE_BIT_SYNC)
511                         == GnssMeasurement.STATE_BIT_SYNC) {
512                     softAssert.assertTrue(getReceivedSvTimeNsLogMessage(
513                                     "GNSS_MEASUREMENT_STATE_BIT_SYNC",
514                                     "GnssStatus.CONSTELLATION_GLONASS"),
515                             timeInNs,
516                             "0ms >= X <= 20ms",
517                             String.valueOf(sv_time_ms),
518                             sv_time_ms >= 0 && sv_time_ms <= 20);
519                 } else if ((state | GnssMeasurement.STATE_SYMBOL_SYNC)
520                         == GnssMeasurement.STATE_SYMBOL_SYNC) {
521                     softAssert.assertTrue(getReceivedSvTimeNsLogMessage(
522                                     "GNSS_MEASUREMENT_STATE_SYMBOL_SYNC",
523                                     "GnssStatus.CONSTELLATION_GLONASS"),
524                             timeInNs,
525                             "0ms >= X <= 10ms",
526                             String.valueOf(sv_time_ms),
527                             sv_time_ms >= 0 && sv_time_ms <= 10);
528                 } else if ((state | GnssMeasurement.STATE_CODE_LOCK)
529                         == GnssMeasurement.STATE_CODE_LOCK) {
530                     softAssert.assertTrue(getReceivedSvTimeNsLogMessage(
531                                     "GNSS_MEASUREMENT_STATE_CODE_LOCK",
532                                     "GnssStatus.CONSTELLATION_GLONASS"),
533                             timeInNs,
534                             "0ms >= X <= 1ms",
535                             String.valueOf(sv_time_ms),
536                             sv_time_ms >= 0 && sv_time_ms <= 1);
537                 }
538                 break;
539             case GnssStatus.CONSTELLATION_GALILEO:
540                 if ((state | GnssMeasurement.STATE_TOW_DECODED)
541                         == GnssMeasurement.STATE_TOW_DECODED) {
542                     softAssert.assertTrue(getReceivedSvTimeNsLogMessage(
543                                     "GNSS_MEASUREMENT_STATE_TOW_DECODED",
544                                     "GnssStatus.CONSTELLATION_GALILEO"),
545                             timeInNs,
546                             "0 >= X <= 7 days",
547                             String.valueOf(sv_time_days),
548                             sv_time_days >= 0 && sv_time_days <= 7);
549                 } else if ((state | GnssMeasurement.STATE_TOW_KNOWN)
550                               == GnssMeasurement.STATE_TOW_KNOWN) {
551                     softAssert.assertTrue(getReceivedSvTimeNsLogMessage(
552                                     "GNSS_MEASUREMENT_STATE_TOW_DECODED",
553                                     "GnssStatus.CONSTELLATION_GALILEO"),
554                         timeInNs,
555                         "0 >= X <= 7 days",
556                         String.valueOf(sv_time_days),
557                         sv_time_days >= 0 && sv_time_days <= 7);
558                 } else if ((state | GnssMeasurement.STATE_GAL_E1B_PAGE_SYNC)
559                         == GnssMeasurement.STATE_GAL_E1B_PAGE_SYNC) {
560                     softAssert.assertTrue(getReceivedSvTimeNsLogMessage(
561                                     "GNSS_MEASUREMENT_STATE_GAL_E1B_PAGE_SYNC",
562                                     "GnssStatus.CONSTELLATION_GALILEO"),
563                             timeInNs,
564                             "0s >= X <= 2s",
565                             String.valueOf(sv_time_sec),
566                             sv_time_sec >= 0 && sv_time_sec <= 2);
567                 } else if ((state | GnssMeasurement.STATE_GAL_E1C_2ND_CODE_LOCK)
568                         == GnssMeasurement.STATE_GAL_E1C_2ND_CODE_LOCK) {
569                     softAssert.assertTrue(getReceivedSvTimeNsLogMessage(
570                                     "GNSS_MEASUREMENT_STATE_GAL_E1C_2ND_CODE_LOCK",
571                                     "GnssStatus.CONSTELLATION_GALILEO"),
572                             timeInNs,
573                             "0ms >= X <= 100ms",
574                             String.valueOf(sv_time_ms),
575                             sv_time_ms >= 0 && sv_time_ms <= 100);
576                 } else if ((state | GnssMeasurement.STATE_GAL_E1BC_CODE_LOCK)
577                         == GnssMeasurement.STATE_GAL_E1BC_CODE_LOCK) {
578                     softAssert.assertTrue(getReceivedSvTimeNsLogMessage(
579                                     "GNSS_MEASUREMENT_STATE_GAL_E1BC_CODE_LOCK",
580                                     "GnssStatus.CONSTELLATION_GALILEO"),
581                             timeInNs,
582                             "0ms >= X <= 4ms",
583                             String.valueOf(sv_time_ms),
584                             sv_time_ms >= 0 && sv_time_ms <= 4);
585                 }
586                 break;
587             case GnssStatus.CONSTELLATION_BEIDOU:
588                 if ((state | GnssMeasurement.STATE_TOW_DECODED)
589                         == GnssMeasurement.STATE_TOW_DECODED) {
590                     softAssert.assertTrue(getReceivedSvTimeNsLogMessage(
591                                     "GNSS_MEASUREMENT_STATE_TOW_DECODED",
592                                     "GnssStatus.CONSTELLATION_BEIDOU"),
593                             timeInNs,
594                             "0 >= X <= 7 days",
595                             String.valueOf(sv_time_days),
596                             sv_time_days >= 0 && sv_time_days <= 7);
597                 } else if ((state | GnssMeasurement.STATE_SUBFRAME_SYNC)
598                         == GnssMeasurement.STATE_SUBFRAME_SYNC) {
599                     softAssert.assertTrue(getReceivedSvTimeNsLogMessage(
600                                     "GNSS_MEASUREMENT_STATE_SUBFRAME_SYNC",
601                                     "GnssStatus.CONSTELLATION_BEIDOU"),
602                             timeInNs,
603                             "0s >= X <= 6s",
604                             String.valueOf(sv_time_sec),
605                             sv_time_sec >= 0 && sv_time_sec <= 6);
606                 } else if ((state | GnssMeasurement.STATE_BDS_D2_SUBFRAME_SYNC)
607                         == GnssMeasurement.STATE_BDS_D2_SUBFRAME_SYNC) {
608                     softAssert.assertTrue(getReceivedSvTimeNsLogMessage(
609                                     "GNSS_MEASUREMENT_STATE_BDS_D2_SUBFRAME_SYNC",
610                                     "GnssStatus.CONSTELLATION_BEIDOU"),
611                             timeInNs,
612                             "0ms >= X <= 600ms (0.6sec)",
613                             String.valueOf(sv_time_ms),
614                             sv_time_ms >= 0 && sv_time_ms <= 600);
615                 } else if ((state | GnssMeasurement.STATE_BIT_SYNC)
616                         == GnssMeasurement.STATE_BIT_SYNC) {
617                     softAssert.assertTrue(getReceivedSvTimeNsLogMessage(
618                                     "GNSS_MEASUREMENT_STATE_BIT_SYNC",
619                                     "GnssStatus.CONSTELLATION_BEIDOU"),
620                             timeInNs,
621                             "0ms >= X <= 20ms",
622                             String.valueOf(sv_time_ms),
623                             sv_time_ms >= 0 && sv_time_ms <= 20);
624                 } else if ((state | GnssMeasurement.STATE_BDS_D2_BIT_SYNC)
625                         == GnssMeasurement.STATE_BDS_D2_BIT_SYNC) {
626                     softAssert.assertTrue(getReceivedSvTimeNsLogMessage(
627                                     "GNSS_MEASUREMENT_STATE_BDS_D2_BIT_SYNC",
628                                     "GnssStatus.CONSTELLATION_BEIDOU"),
629                             timeInNs,
630                             "0ms >= X <= 2ms",
631                             String.valueOf(sv_time_ms),
632                             sv_time_ms >= 0 && sv_time_ms <= 2);
633                 } else if ((state | GnssMeasurement.STATE_CODE_LOCK)
634                         == GnssMeasurement.STATE_CODE_LOCK) {
635                     softAssert.assertTrue(getReceivedSvTimeNsLogMessage(
636                                     "GNSS_MEASUREMENT_STATE_CODE_LOCK",
637                                     "GnssStatus.CONSTELLATION_BEIDOU"),
638                             timeInNs,
639                             "0ms >= X <= 1ms",
640                             String.valueOf(sv_time_ms),
641                             sv_time_ms >= 0 && sv_time_ms <= 1);
642                 }
643                 break;
644         }
645     }
646 
getReceivedSvTimeNsLogMessage(String constellationType, String state)647     private static String getReceivedSvTimeNsLogMessage(String constellationType, String state) {
648         return "received_sv_time_ns: Received SV Time-of-Week in ns. Constellation type = "
649                 + constellationType + ". State = " + state;
650     }
651 
652     /**
653      * Verify sv times are in expected range for given constellation type.
654      * This is common check for CONSTELLATION_GPS & CONSTELLATION_QZSS.
655      *
656      * @param measurement GnssMeasurement
657      * @param softAssert  custom SoftAssert
658      * @param timeInNs    event time in ns
659      * @param state       GnssMeasurement State
660      * @param constellationType Gnss Constellation type
661      */
verifyGpsQzssSvTimes(GnssMeasurement measurement, SoftAssert softAssert, long timeInNs, int state, String constellationType)662     private static void verifyGpsQzssSvTimes(GnssMeasurement measurement,
663         SoftAssert softAssert, long timeInNs, int state, String constellationType) {
664 
665         long received_sv_time_ns = measurement.getReceivedSvTimeNanos();
666         double sv_time_ms = TimeUnit.NANOSECONDS.toMillis(received_sv_time_ns);
667         double sv_time_sec = TimeUnit.NANOSECONDS.toSeconds(received_sv_time_ns);
668         double sv_time_days = TimeUnit.NANOSECONDS.toDays(received_sv_time_ns);
669 
670         if ((state | GnssMeasurement.STATE_TOW_DECODED)
671                 == GnssMeasurement.STATE_TOW_DECODED) {
672             softAssert.assertTrue(getReceivedSvTimeNsLogMessage(
673                             "GNSS_MEASUREMENT_STATE_TOW_DECODED",
674                             constellationType),
675                     timeInNs,
676                     "0 >= X <= 7 days",
677                     String.valueOf(sv_time_days),
678                     sv_time_days >= 0 && sv_time_days <= 7);
679         } else if ((state | GnssMeasurement.STATE_SUBFRAME_SYNC)
680                 == GnssMeasurement.STATE_SUBFRAME_SYNC) {
681             softAssert.assertTrue(getReceivedSvTimeNsLogMessage(
682                             "GNSS_MEASUREMENT_STATE_SUBFRAME_SYNC",
683                             constellationType),
684                     timeInNs,
685                     "0s >= X <= 6s",
686                     String.valueOf(sv_time_sec),
687                     sv_time_sec >= 0 && sv_time_sec <= 6);
688         } else if ((state | GnssMeasurement.STATE_BIT_SYNC)
689                 == GnssMeasurement.STATE_BIT_SYNC) {
690             softAssert.assertTrue(getReceivedSvTimeNsLogMessage(
691                             "GNSS_MEASUREMENT_STATE_BIT_SYNC",
692                             constellationType),
693                     timeInNs,
694                     "0ms >= X <= 20ms",
695                     String.valueOf(sv_time_ms),
696                     sv_time_ms >= 0 && sv_time_ms <= 20);
697 
698         } else if ((state | GnssMeasurement.STATE_CODE_LOCK)
699                 == GnssMeasurement.STATE_CODE_LOCK) {
700             softAssert.assertTrue(getReceivedSvTimeNsLogMessage(
701                             "GNSS_MEASUREMENT_STATE_CODE_LOCK",
702                             constellationType),
703                     timeInNs,
704                     "0ms >= X <= 1ms",
705                     String.valueOf(sv_time_ms),
706                     sv_time_ms >= 0 && sv_time_ms <= 1);
707         }
708     }
709 
710     /**
711      * Assert all mandatory fields in Gnss Navigation Message are in expected range.
712      * See mandatory fields in {@code gps.h}.
713      *
714      * @param testLocationManager TestLocationManager
715      * @param events GnssNavigationMessageEvents
716      */
verifyGnssNavMessageMandatoryField(TestLocationManager testLocationManager, List<GnssNavigationMessage> events)717     public static void verifyGnssNavMessageMandatoryField(TestLocationManager testLocationManager,
718                                                           List<GnssNavigationMessage> events) {
719         // Verify mandatory GnssNavigationMessage field values.
720         SoftAssert softAssert = new SoftAssert(TAG);
721         for (GnssNavigationMessage message : events) {
722             int type = message.getType();
723             softAssert.assertTrue("Gnss Navigation Message Type:expected [" +
724                 getGnssNavMessageTypes() + "] actual = " + type,
725                     GNSS_NAVIGATION_MESSAGE_TYPE.contains(type));
726 
727             int gnssYearOfHardware = testLocationManager.getLocationManager().getGnssYearOfHardware();
728             if (gnssYearOfHardware >= YEAR_2016) {
729                 softAssert.assertTrue("Message ID cannot be 0", message.getMessageId() != 0);
730                 softAssert.assertTrue("Sub Message ID cannot be 0", message.getSubmessageId() != 0);
731             }
732 
733             // if message type == TYPE_L1CA, verify PRN & Data Size.
734             int messageType = message.getType();
735             if (messageType == GnssNavigationMessage.TYPE_GPS_L1CA) {
736                 int svid = message.getSvid();
737                 softAssert.assertTrue("Space Vehicle ID : expected = [1, 32], actual = " +
738                                 svid,
739                         svid >= 1 && svid <= 32);
740                 int dataSize = message.getData().length;
741                 softAssert.assertTrue("Data size: expected = 40, actual = " + dataSize,
742                         dataSize == 40);
743             } else {
744                 Log.i(TAG, "GnssNavigationMessage (type = " + messageType
745                         + ") skipped for verification.");
746             }
747         }
748         softAssert.assertAll();
749     }
750 
getGnssNavMessageTypes()751     private static String getGnssNavMessageTypes() {
752         StringBuilder typesStr = new StringBuilder();
753         for (int type : GNSS_NAVIGATION_MESSAGE_TYPE) {
754             typesStr.append(String.format("0x%04X", type));
755             typesStr.append(", ");
756         }
757 
758         return typesStr.length() > 2 ? typesStr.substring(0, typesStr.length() - 2) : "";
759     }
760 }
761