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 package android.location.cts; 17 18 import junit.framework.Assert; 19 import android.location.GnssClock; 20 import android.location.GnssMeasurement; 21 import android.location.GnssMeasurementsEvent; 22 import android.util.Log; 23 24 import java.util.ArrayList; 25 import java.util.HashMap; 26 import java.util.List; 27 import java.util.concurrent.CountDownLatch; 28 import java.util.concurrent.TimeUnit; 29 30 /** 31 * Used for receiving GPS satellite measurements from the GPS engine. 32 * Each measurement contains raw and computed data identifying a satellite. 33 * Only counts measurement events with more than one actual Measurement in them (not just clock) 34 */ 35 class TestGnssMeasurementListener extends GnssMeasurementsEvent.Callback { 36 // When filterByEventSize flag is true, we only keep the GnssMeasurementsEvents that have at 37 // least 4 decoded GnssMeasurement in same constellation. 38 private boolean filterByEventSize = false; 39 // Timeout in sec for count down latch wait 40 private static final int STATUS_TIMEOUT_IN_SEC = 10; 41 private static final int MEAS_TIMEOUT_IN_SEC = 60; 42 private static final int TOW_DECODED_MEASUREMENT_STATE_BIT = 3; 43 private static final int C_TO_N0_THRESHOLD_DB_HZ = 18; 44 private volatile int mStatus = -1; 45 46 private final String mTag; 47 private final List<GnssMeasurementsEvent> mMeasurementsEvents; 48 private final CountDownLatch mCountDownLatch; 49 private final CountDownLatch mCountDownLatchStatus; 50 51 /** 52 * Constructor for TestGnssMeasurementListener 53 * @param tag for Logging. 54 */ 55 TestGnssMeasurementListener(String tag) { 56 this(tag, 0, false); 57 } 58 59 /** 60 * Constructor for TestGnssMeasurementListener 61 * @param tag for Logging. 62 * @param eventsToCollect wait until the number of events collected. 63 */ 64 TestGnssMeasurementListener(String tag, int eventsToCollect) { 65 this(tag, eventsToCollect, false); 66 } 67 68 /** 69 * Constructor for TestGnssMeasurementListener 70 * @param tag for Logging. 71 * @param eventsToCollect wait until the number of events collected. 72 * @param filterByEventSize whether filter the GnssMeasurementsEvents when we collect them. 73 */ 74 TestGnssMeasurementListener(String tag, int eventsToCollect, boolean filterByEventSize) { 75 mTag = tag; 76 mCountDownLatch = new CountDownLatch(eventsToCollect); 77 mCountDownLatchStatus = new CountDownLatch(1); 78 mMeasurementsEvents = new ArrayList<>(eventsToCollect); 79 this.filterByEventSize = filterByEventSize; 80 } 81 82 @Override 83 public void onGnssMeasurementsReceived(GnssMeasurementsEvent event) { 84 // Only count measurement events with more than 4 actual Measurements in same constellation 85 // with Cn0DbHz value greater than 18 86 if (event.getMeasurements().size() > 0) { 87 Log.i(mTag, "GnssMeasurementsEvent size:" + event.getMeasurements().size()); 88 if (filterByEventSize) { 89 HashMap<Integer, Integer> constellationEventCount = new HashMap<>(); 90 GnssClock gnssClock = event.getClock(); 91 if (!gnssClock.hasFullBiasNanos()) { 92 // If devices does not have FullBiasNanos yet, it will be difficult to check the quality, so await 93 // this flag as well. 94 return; 95 } 96 for (GnssMeasurement gnssMeasurement : event.getMeasurements()){ 97 int constellationType = gnssMeasurement.getConstellationType(); 98 // if the measurement's signal level is too small ignore 99 if (gnssMeasurement.getCn0DbHz() < C_TO_N0_THRESHOLD_DB_HZ || 100 (gnssMeasurement.getState() & (1L << TOW_DECODED_MEASUREMENT_STATE_BIT)) == 0) { 101 continue; 102 } 103 if (constellationEventCount.containsKey(constellationType)) { 104 constellationEventCount.put(constellationType, 105 constellationEventCount.get(constellationType) + 1); 106 } 107 else { 108 constellationEventCount.put(constellationType, 1); 109 } 110 if (constellationEventCount.get(constellationType) >= 4) { 111 synchronized(mMeasurementsEvents) { 112 mMeasurementsEvents.add(event); 113 } 114 mCountDownLatch.countDown(); 115 return; 116 } 117 } 118 } 119 else { 120 synchronized(mMeasurementsEvents) { 121 mMeasurementsEvents.add(event); 122 } 123 mCountDownLatch.countDown(); 124 } 125 } 126 } 127 128 @Override 129 public void onStatusChanged(int status) { 130 mStatus = status; 131 mCountDownLatchStatus.countDown(); 132 } 133 134 public boolean awaitStatus() throws InterruptedException { 135 return TestUtils.waitFor(mCountDownLatchStatus, STATUS_TIMEOUT_IN_SEC); 136 } 137 138 public boolean await() throws InterruptedException { 139 return TestUtils.waitFor(mCountDownLatch, MEAS_TIMEOUT_IN_SEC); 140 } 141 142 143 /** 144 * @return {@code true} if the state of the test ensures that data is expected to be collected, 145 * {@code false} otherwise. 146 */ 147 public boolean verifyStatus(boolean testIsStrict) { 148 switch (getStatus()) { 149 case GnssMeasurementsEvent.Callback.STATUS_NOT_SUPPORTED: 150 String message = "GnssMeasurements is not supported in the device:" 151 + " verifications performed by this test may be skipped on older devices."; 152 if (testIsStrict) { 153 Assert.fail(message); 154 } else { 155 SoftAssert.failAsWarning(mTag, message); 156 } 157 return false; 158 case GnssMeasurementsEvent.Callback.STATUS_READY: 159 return true; 160 case GnssMeasurementsEvent.Callback.STATUS_LOCATION_DISABLED: 161 message = "Location or GPS is disabled on the device:" 162 + " enable location to continue the test"; 163 if (testIsStrict) { 164 Assert.fail(message); 165 } else { 166 SoftAssert.failAsWarning(mTag, message); 167 } 168 return false; 169 default: 170 Assert.fail("GnssMeasurementsEvent status callback was not received."); 171 } 172 return false; 173 } 174 175 /** 176 * Get GPS Measurements Status. 177 * 178 * @return mStatus Gps Measurements Status 179 */ 180 public int getStatus() { 181 return mStatus; 182 } 183 184 /** 185 * Get the current list of GPS Measurements Events. 186 * 187 * @return the current list of GPS Measurements Events 188 */ 189 public List<GnssMeasurementsEvent> getEvents() { 190 synchronized(mMeasurementsEvents) { 191 List<GnssMeasurementsEvent> clone = new ArrayList<>(); 192 clone.addAll(mMeasurementsEvents); 193 return clone; 194 } 195 } 196 } 197