1 package android.location.cts.gnss;
2 
3 import android.location.cts.common.GnssTestCase;
4 import android.location.cts.common.SoftAssert;
5 import android.location.cts.common.TestGnssStatusCallback;
6 import android.location.cts.common.TestLocationListener;
7 import android.location.cts.common.TestLocationManager;
8 import android.location.cts.common.TestMeasurementUtil;
9 import android.location.cts.common.TestUtils;
10 import android.net.ConnectivityManager;
11 import android.net.NetworkInfo;
12 import android.os.SystemClock;
13 import android.platform.test.annotations.AppModeFull;
14 import android.telephony.TelephonyManager;
15 import android.util.Log;
16 
17 import com.android.compatibility.common.util.CddTest;
18 
19 import java.util.concurrent.TimeUnit;
20 
21 /**
22  * Tests for the ttff (time to the first fix) validating whether TTFF is
23  * below the expected thresholds in different scenario
24  */
25 public class GnssTtffTests extends GnssTestCase {
26 
27   private static final String TAG = "GnssTtffTests";
28   private static final int LOCATION_TO_COLLECT_COUNT = 1;
29   private static final int STATUS_TO_COLLECT_COUNT = 3;
30   private static final int AIDING_DATA_RESET_DELAY_SECS = 10;
31   // Threshold values
32   private static final int TTFF_HOT_TH_SECS = 5;
33   private static final int TTFF_WITH_WIFI_CELLUAR_COLD_TH_SECS = 10;
34   // The worst case we saw in the Nexus 6p device is 15sec,
35   // adding 20% margin to the threshold
36   private static final int TTFF_WITH_WIFI_ONLY_COLD_TH_SECS = 18;
37 
38   @Override
setUp()39   protected void setUp() throws Exception {
40     super.setUp();
41     mTestLocationManager = new TestLocationManager(getContext());
42   }
43 
44   /**
45    * Test the TTFF in the case where there is a network connection for both cold and hot start TTFF
46    * cases.
47    * We first test the "COLD" start where different TTFF thresholds are chosen based on network
48    * connection (cellular vs Wifi). Then we test the "HOT" start where the type of network
49    * connection should not matter hence one threshold is used.
50    * @throws Exception
51    */
52   @CddTest(requirement="7.3.3")
53   @AppModeFull(reason = "permission ACCESS_LOCATION_EXTRA_COMMANDS not available to instant apps")
testTtffWithNetwork()54   public void testTtffWithNetwork() throws Exception {
55     if (!TestUtils.deviceHasGpsFeature(getContext())) {
56       return;
57     }
58 
59     // Network connection isn't required for automotive devices.
60     if (TestMeasurementUtil.isAutomotiveDevice(getContext())) {
61       return;
62     }
63 
64     ensureNetworkStatus();
65     if (hasCellularData()) {
66       checkTtffColdWithWifiOn(TTFF_WITH_WIFI_CELLUAR_COLD_TH_SECS);
67     }
68     else {
69       checkTtffColdWithWifiOn(TTFF_WITH_WIFI_ONLY_COLD_TH_SECS);
70     }
71     checkTtffHotWithWifiOn(TTFF_HOT_TH_SECS);
72   }
73 
74   /**
75    * Test Scenario 1
76    * Check whether TTFF is below the threshold on the cold start with Wifi ON
77    * 1) Delete the aiding data.
78    * 2) Get GPS, check the TTFF value
79    * @param threshold, the threshold for the TTFF value
80    */
checkTtffColdWithWifiOn(long threshold)81   private void checkTtffColdWithWifiOn(long threshold) throws Exception {
82     SoftAssert softAssert = new SoftAssert(TAG);
83     mTestLocationManager.sendExtraCommand("delete_aiding_data");
84     Thread.sleep(TimeUnit.SECONDS.toMillis(AIDING_DATA_RESET_DELAY_SECS));
85     checkTtffByThreshold("checkTtffColdWithWifiOn",
86         TimeUnit.SECONDS.toMillis(threshold), softAssert);
87     softAssert.assertAll();
88   }
89 
90   /**
91    * Test Scenario 2
92    * Check whether TTFF is below the threhold on the hot start with wifi ON
93    * TODO(tccyp): to test the hot case with network connection off
94    * @param threshold, the threshold for the TTFF value
95    */
checkTtffHotWithWifiOn(long threshold)96   private void checkTtffHotWithWifiOn(long threshold) throws Exception {
97     SoftAssert softAssert = new SoftAssert(TAG);
98     checkTtffByThreshold("checkTtffHotWithWifiOn",
99         TimeUnit.SECONDS.toMillis(threshold), softAssert);
100     softAssert.assertAll();
101   }
102 
103   /**
104    * Make sure the device has either wifi data or cellular connection
105    */
ensureNetworkStatus()106   private void ensureNetworkStatus(){
107     assertTrue("Device has to connect to Wifi or Cellular to complete this test.",
108         TestUtils.isConnectedToWifiOrCellular(getContext()));
109 
110   }
111 
hasCellularData()112   private boolean hasCellularData() {
113     ConnectivityManager connManager = TestUtils.getConnectivityManager(getContext());
114     NetworkInfo cellularNetworkInfo = connManager.getNetworkInfo(ConnectivityManager.TYPE_MOBILE);
115     // check whether the cellular data is ON if the device has cellular capability
116     if (cellularNetworkInfo == null) {
117       Log.i(TAG, "This is a wifi only device.");
118       return false;
119     }
120     TelephonyManager telephonyManager = (TelephonyManager) getContext().getApplicationContext()
121         .getSystemService(getContext().TELEPHONY_SERVICE);
122     if (!telephonyManager.isDataEnabled()) {
123       Log.i(TAG, "Device doesn't have cellular data.");
124       return false;
125     }
126     return true;
127   }
128 
129   /*
130    * Check whether TTFF is below the threshold
131    * @param testName
132    * @param threshold, the threshold for the TTFF value
133    */
checkTtffByThreshold(String testName, long threshold, SoftAssert softAssert)134   private void checkTtffByThreshold(String testName,
135       long threshold, SoftAssert softAssert) throws Exception {
136     TestLocationListener networkLocationListener
137         = new TestLocationListener(LOCATION_TO_COLLECT_COUNT);
138     // fetch the networklocation first to make sure the ttff is not flaky
139     if (mTestLocationManager.requestNetworkLocationUpdates(networkLocationListener)) {
140         networkLocationListener.await();
141     }
142 
143     TestGnssStatusCallback testGnssStatusCallback =
144         new TestGnssStatusCallback(TAG, STATUS_TO_COLLECT_COUNT);
145     mTestLocationManager.registerGnssStatusCallback(testGnssStatusCallback);
146 
147     TestLocationListener locationListener = new TestLocationListener(LOCATION_TO_COLLECT_COUNT);
148     mTestLocationManager.requestLocationUpdates(locationListener);
149 
150 
151     long startTimeMillis = SystemClock.elapsedRealtime();
152     boolean success = testGnssStatusCallback.awaitTtff();
153     long ttffTimeMillis = SystemClock.elapsedRealtime() - startTimeMillis;
154 
155     softAssert.assertTrue(
156             "Test case:" + testName
157             + ". Threshold exceeded without getting a location."
158             + " Possibly, the test has been run deep indoors."
159             + " Consider retrying test outdoors.",
160         success);
161     mTestLocationManager.removeLocationUpdates(locationListener);
162     mTestLocationManager.unregisterGnssStatusCallback(testGnssStatusCallback);
163     softAssert.assertTrue("Test case: " + testName +", TTFF should be less than " + threshold
164         + " . In current test, TTFF value is: " + ttffTimeMillis, ttffTimeMillis < threshold);
165   }
166 }
167