Home | History | Annotate | Download | only in cts
      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      */
     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      */
    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      */
    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      */
    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      */
    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      */
    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 
    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      * */
    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 
    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      */
    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      */
    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 
    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