1 /*
2  * Copyright (C) 2018 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package android.net.wifi.rtt.cts;
18 
19 import static android.net.wifi.rtt.ResponderConfig.RESPONDER_AP;
20 
21 import static org.junit.Assert.assertArrayEquals;
22 import static org.junit.Assert.assertEquals;
23 import static org.junit.Assert.assertFalse;
24 import static org.junit.Assert.assertNotEquals;
25 import static org.junit.Assert.assertNotNull;
26 import static org.junit.Assert.assertNull;
27 import static org.junit.Assert.assertTrue;
28 import static org.junit.Assert.fail;
29 import static org.junit.Assume.assumeTrue;
30 import static org.mockito.Mockito.mock;
31 
32 import android.net.MacAddress;
33 import android.net.wifi.OuiKeyedData;
34 import android.net.wifi.ScanResult;
35 import android.net.wifi.aware.PeerHandle;
36 import android.net.wifi.cts.WifiBuildCompat;
37 import android.net.wifi.cts.WifiFeature;
38 import android.net.wifi.rtt.RangingRequest;
39 import android.net.wifi.rtt.RangingResult;
40 import android.net.wifi.rtt.ResponderConfig;
41 import android.net.wifi.rtt.ResponderLocation;
42 import android.net.wifi.rtt.WifiRttManager;
43 import android.os.Build;
44 import android.os.PersistableBundle;
45 import android.platform.test.annotations.AppModeFull;
46 import android.platform.test.annotations.RequiresFlagsEnabled;
47 
48 import androidx.test.ext.junit.runners.AndroidJUnit4;
49 import androidx.test.filters.LargeTest;
50 import androidx.test.filters.SdkSuppress;
51 
52 import com.android.compatibility.common.util.ApiTest;
53 import com.android.compatibility.common.util.DeviceReportLog;
54 import com.android.compatibility.common.util.ResultType;
55 import com.android.compatibility.common.util.ResultUnit;
56 import com.android.wifi.flags.Flags;
57 
58 import org.junit.Test;
59 import org.junit.runner.RunWith;
60 
61 import java.util.ArrayList;
62 import java.util.Arrays;
63 import java.util.List;
64 
65 /**
66  * Wi-Fi RTT CTS test: range to all available Access Points which support IEEE 802.11mc.
67  */
68 @AppModeFull(reason = "Cannot get WifiManager in instant app mode")
69 @LargeTest
70 @RunWith(AndroidJUnit4.class)
71 public class WifiRttTest extends TestBase {
72     // Number of scans to do while searching for APs supporting IEEE 802.11mc
73     private static final int NUM_SCANS_SEARCHING_FOR_IEEE80211MC_AP = 5;
74 
75     // Number of RTT measurements per AP
76     private static final int NUM_OF_RTT_ITERATIONS = 10;
77 
78     // Maximum failure rate of RTT measurements (percentage)
79     private static final int MAX_FAILURE_RATE_PERCENT = 20;
80 
81     // Maximum variation from the average measurement (measures consistency)
82     private static final int MAX_VARIATION_FROM_AVERAGE_DISTANCE_MM = 2000;
83 
84     // Maximum failure rate of one-sided RTT measurements (percentage)
85     private static final int MAX_NON11MC_FAILURE_RATE_PERCENT = 40;
86 
87     // Maximum non-8011mc variation from the average measurement (measures consistency)
88     private static final int MAX_NON11MC_VARIATION_FROM_AVERAGE_DISTANCE_MM = 4000;
89 
90     // Minimum valid RSSI value
91     private static final int MIN_VALID_RSSI = -100;
92 
93     // Valid Mac Address
94     private static final MacAddress MAC = MacAddress.fromString("00:01:02:03:04:05");
95 
96     // Interval between two ranging request.
97     private static final int INTERVAL_MS = 1000;
98 
99     /**
100      * Test Wi-Fi RTT ranging operation using ScanResults in request:
101      * - Scan for visible APs for the test AP (which is validated to support IEEE 802.11mc)
102      * - Perform N (constant) RTT operations
103      * - Validate:
104      *   - Failure ratio < threshold (constant)
105      *   - Result margin < threshold (constant)
106      */
107     @Test
testRangingToTest11mcApUsingScanResult()108     public void testRangingToTest11mcApUsingScanResult() throws InterruptedException {
109         // Scan for IEEE 802.11mc supporting APs
110         ScanResult testAp = getS11McScanResult();
111         assertNotNull(
112                 "Cannot find any test APs which support RTT / IEEE 802.11mc - please verify that "
113                         + "your test setup includes them!", testAp);
114         // Perform RTT operations
115         RangingRequest.Builder builder = new RangingRequest.Builder();
116         builder.addAccessPoint(testAp);
117 
118         if (WifiBuildCompat.isPlatformOrWifiModuleAtLeastS(getContext())) {
119             builder.setRttBurstSize(RangingRequest.getMaxRttBurstSize());
120             assertTrue(RangingRequest.getDefaultRttBurstSize()
121                     >= RangingRequest.getMinRttBurstSize());
122             assertTrue(RangingRequest.getDefaultRttBurstSize()
123                     <= RangingRequest.getMaxRttBurstSize());
124         }
125 
126         RangingRequest request = builder.build();
127         if (WifiBuildCompat.isPlatformOrWifiModuleAtLeastS(getContext())) {
128             assertEquals(1, request.getRttResponders().size());
129         }
130         range11mcApRequest(request, testAp);
131     }
132 
133     /**
134      * Test Wi-Fi RTT ranging using ResponderConfig in the single responder RangingRequest API.
135      * - Scan for visible APs for the test AP (which is validated to support IEEE 802.11mc)
136      * - Perform N (constant) RTT operations
137      * - Validate:
138      *   - Failure ratio < threshold (constant)
139      *   - Result margin < threshold (constant)
140      */
141     @Test
testRangingToTest11mcApUsingResponderConfig()142     public void testRangingToTest11mcApUsingResponderConfig() throws InterruptedException {
143         // Scan for IEEE 802.11mc supporting APs
144         ScanResult testAp = getS11McScanResult();
145         assertNotNull(
146                 "Cannot find any test APs which support RTT / IEEE 802.11mc - please verify that "
147                         + "your test setup includes them!", testAp);
148         int preamble = ResponderConfig.fromScanResult(testAp).getPreamble();
149 
150         // Create a ResponderConfig from the builder API.
151         ResponderConfig.Builder responderBuilder = new ResponderConfig.Builder();
152         ResponderConfig responder = responderBuilder
153                 .setMacAddress(MacAddress.fromString(testAp.BSSID))
154                 .set80211mcSupported(testAp.is80211mcResponder())
155                 .setChannelWidth(testAp.channelWidth)
156                 .setFrequencyMhz(testAp.frequency)
157                 .setCenterFreq0Mhz(testAp.centerFreq0)
158                 .setCenterFreq1Mhz(testAp.centerFreq1)
159                 .setPreamble(preamble)
160                 .setResponderType(RESPONDER_AP)
161                 .build();
162 
163         // Validate ResponderConfig.Builder set method arguments match getter methods.
164         assertTrue(responder.getMacAddress().toString().equalsIgnoreCase(testAp.BSSID)
165                 && responder.is80211mcSupported() == testAp.is80211mcResponder()
166                 && responder.getChannelWidth() == testAp.channelWidth
167                 && responder.getFrequencyMhz() == testAp.frequency
168                 && responder.getCenterFreq0Mhz() == testAp.centerFreq0
169                 && responder.getCenterFreq1Mhz() == testAp.centerFreq1
170                 && responder.getPreamble() == preamble
171                 && responder.getResponderType() == RESPONDER_AP);
172 
173         // Perform RTT operations
174         RangingRequest.Builder builder = new RangingRequest.Builder();
175         builder.addResponder(responder);
176 
177         if (WifiBuildCompat.isPlatformOrWifiModuleAtLeastS(getContext())) {
178             builder.setRttBurstSize(RangingRequest.getMaxRttBurstSize());
179             assertTrue(RangingRequest.getDefaultRttBurstSize()
180                     >= RangingRequest.getMinRttBurstSize());
181             assertTrue(RangingRequest.getDefaultRttBurstSize()
182                     <= RangingRequest.getMaxRttBurstSize());
183         }
184 
185         RangingRequest request = builder.build();
186 
187         if (WifiBuildCompat.isPlatformOrWifiModuleAtLeastS(getContext())) {
188             assertEquals(1, request.getRttResponders().size());
189         }
190         range11mcApRequest(request, testAp);
191     }
192 
193     /**
194      * Test Wi-Fi RTT ranging using ResponderConfig in the multi-Responder RangingRequest API.
195      * - Scan for visible APs for the test AP (which is validated to support IEEE 802.11mc)
196      * - Perform N (constant) RTT operations
197      * - Validate:
198      *   - Failure ratio < threshold (constant)
199      *   - Result margin < threshold (constant)
200      */
201     @Test
testRangingToTest11mcApUsingListResponderConfig()202     public void testRangingToTest11mcApUsingListResponderConfig() throws InterruptedException {
203         // Scan for IEEE 802.11mc supporting APs
204         ScanResult testAp = getS11McScanResult();
205         assertNotNull(
206                 "Cannot find any test APs which support RTT / IEEE 802.11mc - please verify that "
207                         + "your test setup includes them!", testAp);
208         ResponderConfig responder = ResponderConfig.fromScanResult(testAp);
209         // Perform RTT operations
210         RangingRequest.Builder builder = new RangingRequest.Builder();
211         List<ResponderConfig> responders = new ArrayList<>();
212         responders.add(responder);
213         builder.addResponders(responders);
214 
215         if (WifiBuildCompat.isPlatformOrWifiModuleAtLeastS(getContext())) {
216             builder.setRttBurstSize(RangingRequest.getMaxRttBurstSize());
217             assertTrue(RangingRequest.getDefaultRttBurstSize()
218                     >= RangingRequest.getMinRttBurstSize());
219             assertTrue(RangingRequest.getDefaultRttBurstSize()
220                     <= RangingRequest.getMaxRttBurstSize());
221         }
222 
223         RangingRequest request = builder.build();
224 
225         if (WifiBuildCompat.isPlatformOrWifiModuleAtLeastS(getContext())) {
226             assertEquals(1, request.getRttResponders().size());
227         }
228         range11mcApRequest(request, testAp);
229     }
230 
231     /**
232      * Utility method for validating 11mc ranging request.
233      *
234      * @param request the ranging request that is being tested
235      * @param testAp the original test scan result to provide feedback on failure conditions
236      */
range11mcApRequest(RangingRequest request, ScanResult testAp)237     private void range11mcApRequest(RangingRequest request, ScanResult testAp)
238             throws InterruptedException {
239         Thread.sleep(5000);
240         List<RangingResult> allResults = new ArrayList<>();
241         int numFailures = 0;
242         int distanceSum = 0;
243         int distanceMin = 0;
244         int distanceMax = 0;
245         int[] statuses = new int[NUM_OF_RTT_ITERATIONS];
246         int[] distanceMms = new int[NUM_OF_RTT_ITERATIONS];
247         int[] distanceStdDevMms = new int[NUM_OF_RTT_ITERATIONS];
248         int[] rssis = new int[NUM_OF_RTT_ITERATIONS];
249         int[] numAttempted = new int[NUM_OF_RTT_ITERATIONS];
250         int[] numSuccessful = new int[NUM_OF_RTT_ITERATIONS];
251         int[] frequencies = new int[NUM_OF_RTT_ITERATIONS];
252         int[] packetBws = new int[NUM_OF_RTT_ITERATIONS];
253         long[] timestampsMs = new long[NUM_OF_RTT_ITERATIONS];
254         byte[] lastLci = null;
255         byte[] lastLcr = null;
256         for (int i = 0; i < NUM_OF_RTT_ITERATIONS; ++i) {
257             ResultCallback callback = new ResultCallback();
258             mWifiRttManager.startRanging(request, mExecutor, callback);
259             assertTrue("Wi-Fi RTT results: no callback on iteration " + i,
260                     callback.waitForCallback());
261 
262             List<RangingResult> currentResults = callback.getResults();
263             assertNotNull("Wi-Fi RTT results: null results (onRangingFailure) on iteration " + i,
264                     currentResults);
265             assertEquals("Wi-Fi RTT results: unexpected # of results (expect 1) on iteration " + i,
266                     1, currentResults.size());
267             RangingResult result = currentResults.get(0);
268             assertEquals("Wi-Fi RTT results: invalid result (wrong BSSID) entry on iteration " + i,
269                     result.getMacAddress().toString(), testAp.BSSID);
270             assertNull("Wi-Fi RTT results: invalid result (non-null PeerHandle) entry on iteration "
271                     + i, result.getPeerHandle());
272 
273             allResults.add(result);
274             int status = result.getStatus();
275             statuses[i] = status;
276             if (status == RangingResult.STATUS_SUCCESS) {
277                 if (WifiBuildCompat.isPlatformOrWifiModuleAtLeastS(getContext())) {
278                     assertEquals(
279                             "Wi-Fi RTT results: invalid result (wrong rttBurstSize) entry on "
280                                     + "iteration "
281                                     + i,
282                             result.getNumAttemptedMeasurements(),
283                             RangingRequest.getMaxRttBurstSize());
284                     assertTrue("Wi-Fi RTT results: should be a 802.11MC measurement",
285                             result.is80211mcMeasurement());
286                 }
287                 distanceSum += result.getDistanceMm();
288                 if (i == 0) {
289                     distanceMin = result.getDistanceMm();
290                     distanceMax = result.getDistanceMm();
291                 } else {
292                     distanceMin = Math.min(distanceMin, result.getDistanceMm());
293                     distanceMax = Math.max(distanceMax, result.getDistanceMm());
294                 }
295 
296                 assertTrue("Wi-Fi RTT results: invalid RSSI on iteration " + i,
297                         result.getRssi() >= MIN_VALID_RSSI);
298 
299                 distanceMms[i - numFailures] = result.getDistanceMm();
300                 distanceStdDevMms[i - numFailures] = result.getDistanceStdDevMm();
301                 rssis[i - numFailures] = result.getRssi();
302                 numAttempted[i - numFailures] = result.getNumAttemptedMeasurements();
303                 numSuccessful[i - numFailures] = result.getNumSuccessfulMeasurements();
304                 timestampsMs[i - numFailures] = result.getRangingTimestampMillis();
305                 frequencies[i - numFailures] = result.getMeasurementChannelFrequencyMHz();
306                 packetBws[i - numFailures] = result.getMeasurementBandwidth();
307 
308                 byte[] currentLci = result.getLci();
309                 byte[] currentLcr = result.getLcr();
310                 if (i - numFailures > 0) {
311                     assertArrayEquals(
312                             "Wi-Fi RTT results: invalid result (LCI mismatch) on iteration " + i,
313                             currentLci, lastLci);
314                     assertArrayEquals(
315                             "Wi-Fi RTT results: invalid result (LCR mismatch) on iteration " + i,
316                             currentLcr, lastLcr);
317                 }
318                 lastLci = currentLci;
319                 lastLcr = currentLcr;
320             } else {
321                 numFailures++;
322             }
323             // Sleep a while to avoid stress AP.
324             Thread.sleep(INTERVAL_MS);
325         }
326 
327         // Save results to log
328         int numGoodResults = NUM_OF_RTT_ITERATIONS - numFailures;
329         DeviceReportLog reportLog = new DeviceReportLog(TAG, "testRangingToTestAp");
330         reportLog.addValues("status_codes", statuses, ResultType.NEUTRAL, ResultUnit.NONE);
331         reportLog.addValues("distance_mm", Arrays.copyOf(distanceMms, numGoodResults),
332                 ResultType.NEUTRAL, ResultUnit.NONE);
333         reportLog.addValues("distance_stddev_mm", Arrays.copyOf(distanceStdDevMms, numGoodResults),
334                 ResultType.NEUTRAL, ResultUnit.NONE);
335         reportLog.addValues("rssi_dbm", Arrays.copyOf(rssis, numGoodResults), ResultType.NEUTRAL,
336                 ResultUnit.NONE);
337         reportLog.addValues("num_attempted", Arrays.copyOf(numAttempted, numGoodResults),
338                 ResultType.NEUTRAL, ResultUnit.NONE);
339         reportLog.addValues("num_successful", Arrays.copyOf(numSuccessful, numGoodResults),
340                 ResultType.NEUTRAL, ResultUnit.NONE);
341         reportLog.addValues("timestamps", Arrays.copyOf(timestampsMs, numGoodResults),
342                 ResultType.NEUTRAL, ResultUnit.NONE);
343         reportLog.addValues("frequencies", Arrays.copyOf(frequencies, numGoodResults),
344                 ResultType.NEUTRAL, ResultUnit.NONE);
345         reportLog.addValues("packetBws", Arrays.copyOf(packetBws, numGoodResults),
346                 ResultType.NEUTRAL, ResultUnit.NONE);
347         reportLog.submit();
348 
349         // Analyze results
350         assertTrue("Wi-Fi RTT failure rate exceeds threshold: FAIL=" + numFailures + ", ITERATIONS="
351                         + NUM_OF_RTT_ITERATIONS + ", AP=" + testAp,
352                 numFailures <= NUM_OF_RTT_ITERATIONS * MAX_FAILURE_RATE_PERCENT / 100);
353         if (numFailures != NUM_OF_RTT_ITERATIONS) {
354             double distanceAvg = (double) distanceSum / (NUM_OF_RTT_ITERATIONS - numFailures);
355             assertTrue("Wi-Fi RTT: Variation (max direction) exceeds threshold, Variation ="
356                             + (distanceMax - distanceAvg),
357                     (distanceMax - distanceAvg) <= MAX_VARIATION_FROM_AVERAGE_DISTANCE_MM);
358             assertTrue("Wi-Fi RTT: Variation (min direction) exceeds threshold, Variation ="
359                             + (distanceAvg - distanceMin),
360                     (distanceAvg - distanceMin) <= MAX_VARIATION_FROM_AVERAGE_DISTANCE_MM);
361             for (int i = 0; i < numGoodResults; ++i) {
362                 assertNotEquals("Number of attempted measurements is 0", 0, numAttempted[i]);
363                 assertNotEquals("Number of successful measurements is 0", 0, numSuccessful[i]);
364             }
365         }
366     }
367 
368     /**
369      * Utility method for validating 11az ranging request.
370      *
371      * @param request the ranging request that is being tested
372      * @param testAp the original test scan result to provide feedback on failure conditions
373      */
range11azApRequest(RangingRequest request, ScanResult testAp)374     private void range11azApRequest(RangingRequest request, ScanResult testAp)
375             throws InterruptedException {
376         Thread.sleep(5000);
377         List<RangingResult> allResults = new ArrayList<>();
378         int numFailures = 0;
379         int distanceSum = 0;
380         int distanceMin = 0;
381         int distanceMax = 0;
382         int[] statuses = new int[NUM_OF_RTT_ITERATIONS];
383         int[] distanceMms = new int[NUM_OF_RTT_ITERATIONS];
384         int[] distanceStdDevMms = new int[NUM_OF_RTT_ITERATIONS];
385         int[] rssis = new int[NUM_OF_RTT_ITERATIONS];
386         int[] numAttempted = new int[NUM_OF_RTT_ITERATIONS];
387         int[] numSuccessful = new int[NUM_OF_RTT_ITERATIONS];
388         int[] frequencies = new int[NUM_OF_RTT_ITERATIONS];
389         int[] packetBws = new int[NUM_OF_RTT_ITERATIONS];
390         long[] timestampsMs = new long[NUM_OF_RTT_ITERATIONS];
391         int[] i2rTxLtfRepetitions = new int[NUM_OF_RTT_ITERATIONS];
392         int[] r2iTxLtfRepetitions = new int[NUM_OF_RTT_ITERATIONS];
393         int[] numRxSts = new int[NUM_OF_RTT_ITERATIONS];
394         int[] numTxSts = new int[NUM_OF_RTT_ITERATIONS];
395         long[] maxNtbMeasurementTime = new long[NUM_OF_RTT_ITERATIONS];
396         long[] minNtbMeasurementTime = new long[NUM_OF_RTT_ITERATIONS];
397 
398         byte[] lastLci = null;
399         byte[] lastLcr = null;
400         for (int i = 0; i < NUM_OF_RTT_ITERATIONS; ++i) {
401             ResultCallback callback = new ResultCallback();
402             mWifiRttManager.startRanging(request, mExecutor, callback);
403             assertTrue("Wi-Fi RTT results: no callback on iteration " + i,
404                     callback.waitForCallback());
405 
406             List<RangingResult> currentResults = callback.getResults();
407             assertNotNull("Wi-Fi RTT results: null results (onRangingFailure) on iteration " + i,
408                     currentResults);
409             assertEquals("Wi-Fi RTT results: unexpected # of results (expect 1) on iteration " + i,
410                     1, currentResults.size());
411             RangingResult result = currentResults.get(0);
412             assertEquals("Wi-Fi RTT results: invalid result (wrong BSSID) entry on iteration " + i,
413                     result.getMacAddress().toString(), testAp.BSSID);
414             assertNull("Wi-Fi RTT results: invalid result (non-null PeerHandle) entry on iteration "
415                     + i, result.getPeerHandle());
416 
417             allResults.add(result);
418             int status = result.getStatus();
419             statuses[i] = status;
420             if (status == RangingResult.STATUS_SUCCESS) {
421                 assertTrue("Wi-Fi RTT results: should be a 802.11az measurement",
422                         result.is80211azNtbMeasurement());
423                 distanceSum += result.getDistanceMm();
424                 if (i == 0) {
425                     distanceMin = result.getDistanceMm();
426                     distanceMax = result.getDistanceMm();
427                 } else {
428                     distanceMin = Math.min(distanceMin, result.getDistanceMm());
429                     distanceMax = Math.max(distanceMax, result.getDistanceMm());
430                 }
431 
432                 assertTrue("Wi-Fi RTT results: invalid RSSI on iteration " + i,
433                         result.getRssi() >= MIN_VALID_RSSI);
434 
435                 distanceMms[i - numFailures] = result.getDistanceMm();
436                 distanceStdDevMms[i - numFailures] = result.getDistanceStdDevMm();
437                 rssis[i - numFailures] = result.getRssi();
438                 numAttempted[i - numFailures] = result.getNumAttemptedMeasurements();
439                 numSuccessful[i - numFailures] = result.getNumSuccessfulMeasurements();
440                 timestampsMs[i - numFailures] = result.getRangingTimestampMillis();
441                 frequencies[i - numFailures] = result.getMeasurementChannelFrequencyMHz();
442                 packetBws[i - numFailures] = result.getMeasurementBandwidth();
443                 i2rTxLtfRepetitions[i - numFailures] =
444                         result.get80211azInitiatorTxLtfRepetitionsCount();
445                 r2iTxLtfRepetitions[i - numFailures] =
446                         result.get80211azResponderTxLtfRepetitionsCount();
447                 numRxSts[i - numFailures] = result.get80211azNumberOfRxSpatialStreams();
448                 numTxSts[i - numFailures] = result.get80211azNumberOfTxSpatialStreams();
449                 maxNtbMeasurementTime[i - numFailures] =
450                         result.getMaxTimeBetweenNtbMeasurementsMicros();
451                 minNtbMeasurementTime[i - numFailures] =
452                         result.getMinTimeBetweenNtbMeasurementsMicros();
453 
454                 byte[] currentLci = result.getLci();
455                 byte[] currentLcr = result.getLcr();
456                 if (i - numFailures > 0) {
457                     assertArrayEquals(
458                             "Wi-Fi RTT results: invalid result (LCI mismatch) on iteration " + i,
459                             currentLci, lastLci);
460                     assertArrayEquals(
461                             "Wi-Fi RTT results: invalid result (LCR mismatch) on iteration " + i,
462                             currentLcr, lastLcr);
463                 }
464                 lastLci = currentLci;
465                 lastLcr = currentLcr;
466             } else {
467                 numFailures++;
468             }
469             // Wait for the minimum measurement time
470             Thread.sleep(result.getMinTimeBetweenNtbMeasurementsMicros() * 1000);
471         }
472 
473         // Save results to log
474         int numGoodResults = NUM_OF_RTT_ITERATIONS - numFailures;
475         DeviceReportLog reportLog = new DeviceReportLog(TAG, "testRangingToTestAp");
476         reportLog.addValues("status_codes", statuses, ResultType.NEUTRAL, ResultUnit.NONE);
477         reportLog.addValues("distance_mm", Arrays.copyOf(distanceMms, numGoodResults),
478                 ResultType.NEUTRAL, ResultUnit.NONE);
479         reportLog.addValues("distance_stddev_mm", Arrays.copyOf(distanceStdDevMms, numGoodResults),
480                 ResultType.NEUTRAL, ResultUnit.NONE);
481         reportLog.addValues("rssi_dbm", Arrays.copyOf(rssis, numGoodResults), ResultType.NEUTRAL,
482                 ResultUnit.NONE);
483         reportLog.addValues("num_attempted", Arrays.copyOf(numAttempted, numGoodResults),
484                 ResultType.NEUTRAL, ResultUnit.NONE);
485         reportLog.addValues("num_successful", Arrays.copyOf(numSuccessful, numGoodResults),
486                 ResultType.NEUTRAL, ResultUnit.NONE);
487         reportLog.addValues("timestamps", Arrays.copyOf(timestampsMs, numGoodResults),
488                 ResultType.NEUTRAL, ResultUnit.NONE);
489         reportLog.addValues("frequencies", Arrays.copyOf(frequencies, numGoodResults),
490                 ResultType.NEUTRAL, ResultUnit.NONE);
491         reportLog.addValues("packetBws", Arrays.copyOf(packetBws, numGoodResults),
492                 ResultType.NEUTRAL, ResultUnit.NONE);
493         reportLog.addValues("i2rTxLtfRepetitions",
494                 Arrays.copyOf(i2rTxLtfRepetitions, numGoodResults),
495                 ResultType.NEUTRAL, ResultUnit.NONE);
496         reportLog.addValues("r2iTxLtfRepetitions",
497                 Arrays.copyOf(r2iTxLtfRepetitions, numGoodResults),
498                 ResultType.NEUTRAL, ResultUnit.NONE);
499         reportLog.addValues("numRxSts", Arrays.copyOf(numRxSts, numGoodResults),
500                 ResultType.NEUTRAL, ResultUnit.NONE);
501         reportLog.addValues("numTxSts", Arrays.copyOf(numRxSts, numGoodResults),
502                 ResultType.NEUTRAL, ResultUnit.NONE);
503         reportLog.addValues("maxNtbMeasurementTime",
504                 Arrays.copyOf(maxNtbMeasurementTime, numGoodResults),
505                 ResultType.NEUTRAL, ResultUnit.NONE);
506         reportLog.addValues("minNtbMeasurementTime",
507                 Arrays.copyOf(minNtbMeasurementTime, numGoodResults),
508                 ResultType.NEUTRAL, ResultUnit.NONE);
509         reportLog.submit();
510 
511         // Analyze results
512         assertTrue("Wi-Fi RTT failure rate exceeds threshold: FAIL=" + numFailures + ", ITERATIONS="
513                         + NUM_OF_RTT_ITERATIONS + ", AP=" + testAp,
514                 numFailures <= NUM_OF_RTT_ITERATIONS * MAX_FAILURE_RATE_PERCENT / 100);
515         if (numFailures != NUM_OF_RTT_ITERATIONS) {
516             double distanceAvg = (double) distanceSum / (NUM_OF_RTT_ITERATIONS - numFailures);
517             assertTrue("Wi-Fi RTT: Variation (max direction) exceeds threshold, Variation ="
518                             + (distanceMax - distanceAvg),
519                     (distanceMax - distanceAvg) <= MAX_VARIATION_FROM_AVERAGE_DISTANCE_MM);
520             assertTrue("Wi-Fi RTT: Variation (min direction) exceeds threshold, Variation ="
521                             + (distanceAvg - distanceMin),
522                     (distanceAvg - distanceMin) <= MAX_VARIATION_FROM_AVERAGE_DISTANCE_MM);
523             for (int i = 0; i < numGoodResults; ++i) {
524                 assertNotEquals("Number of attempted measurements is 0", 0, numAttempted[i]);
525                 assertNotEquals("Number of successful measurements is 0", 0, numSuccessful[i]);
526             }
527         }
528     }
529 
530     /**
531      * Validate that when a request contains more range operations than allowed (by API) that we
532      * get an exception.
533      */
534     @Test
testRequestTooLarge()535     public void testRequestTooLarge() throws InterruptedException {
536         ScanResult testAp = getS11McScanResult();
537         assertNotNull(
538                 "Cannot find any test APs which support RTT / IEEE 802.11mc - please verify that "
539                         + "your test setup includes them!", testAp);
540 
541         RangingRequest.Builder builder = new RangingRequest.Builder();
542         List<ScanResult> scanResults = new ArrayList<>();
543         for (int i = 0; i < RangingRequest.getMaxPeers() - 2; ++i) {
544             scanResults.add(testAp);
545         }
546         builder.addAccessPoints(scanResults);
547 
548         ScanResult testApNon80211mc = null;
549         if (WifiBuildCompat.isPlatformOrWifiModuleAtLeastS(getContext())) {
550             testApNon80211mc = getLegacyScanResult();
551         }
552         if (testApNon80211mc == null) {
553             builder.addAccessPoints(List.of(testAp, testAp, testAp));
554         } else {
555             builder.addNon80211mcCapableAccessPoints(List.of(testApNon80211mc, testApNon80211mc,
556                     testApNon80211mc));
557         }
558 
559         try {
560             mWifiRttManager.startRanging(builder.build(), mExecutor, new ResultCallback());
561         } catch (IllegalArgumentException e) {
562             return;
563         }
564 
565         fail("Did not receive expected IllegalArgumentException when tried to range to too "
566                 + "many peers");
567     }
568 
569     /**
570      * Verify ResponderLocation API
571      */
572     @Test
testRangingToTestApWithResponderLocation()573     public void testRangingToTestApWithResponderLocation() throws InterruptedException {
574         // Scan for IEEE 802.11mc supporting APs
575         ScanResult testAp = getS11McScanResult();
576         assertNotNull(
577                 "Cannot find any test APs which support RTT / IEEE 802.11mc - please verify that "
578                         + "your test setup includes them!", testAp);
579 
580         // Perform RTT operations
581         RangingRequest request = new RangingRequest.Builder().addAccessPoint(testAp).build();
582         ResultCallback callback = new ResultCallback();
583         mWifiRttManager.startRanging(request, mExecutor, callback);
584         assertTrue("Wi-Fi RTT results: no callback! ",
585                 callback.waitForCallback());
586 
587         RangingResult result = callback.getResults().get(0);
588         assertEquals("Ranging request not success",
589                 result.getStatus(), RangingResult.STATUS_SUCCESS);
590         ResponderLocation responderLocation = result.getUnverifiedResponderLocation();
591         if (responderLocation == null) {
592             return;
593         }
594         assertTrue("ResponderLocation is not valid", responderLocation.isLciSubelementValid());
595 
596         // Check LCI related APIs
597         int exceptionCount = 0;
598         int apiCount = 0;
599         try {
600             apiCount++;
601             responderLocation.getLatitudeUncertainty();
602         } catch (IllegalStateException e) {
603             exceptionCount++;
604         }
605         try {
606             apiCount++;
607             responderLocation.getLatitude();
608         } catch (IllegalStateException e) {
609             exceptionCount++;
610         }
611         try {
612             apiCount++;
613             responderLocation.getLongitudeUncertainty();
614         } catch (IllegalStateException e) {
615             exceptionCount++;
616         }
617         try {
618             apiCount++;
619             responderLocation.getLongitude();
620         } catch (IllegalStateException e) {
621             exceptionCount++;
622         }
623         try {
624             apiCount++;
625             responderLocation.getAltitudeType();
626         } catch (IllegalStateException e) {
627             exceptionCount++;
628         }
629         try {
630             apiCount++;
631             responderLocation.getAltitudeUncertainty();
632         } catch (IllegalStateException e) {
633             exceptionCount++;
634         }
635         try {
636             apiCount++;
637             responderLocation.getAltitude();
638         } catch (IllegalStateException e) {
639             exceptionCount++;
640         }
641         try {
642             apiCount++;
643             responderLocation.getDatum();
644         } catch (IllegalStateException e) {
645             exceptionCount++;
646         }
647         try {
648             apiCount++;
649             responderLocation.getRegisteredLocationAgreementIndication();
650         } catch (IllegalStateException e) {
651             exceptionCount++;
652         }
653         try {
654             apiCount++;
655             responderLocation.getLciVersion();
656         } catch (IllegalStateException e) {
657             exceptionCount++;
658         }
659         try {
660             apiCount++;
661             assertNotNull(responderLocation.toLocation());
662         } catch (IllegalStateException e) {
663             exceptionCount++;
664         }
665         // If LCI is not valid, all APIs should throw exception, otherwise no exception.
666         assertEquals("Exception number should equal to API number",
667                 responderLocation.isLciSubelementValid()? 0 : apiCount, exceptionCount);
668 
669         // Verify ZaxisSubelement APIs
670         apiCount = 0;
671         exceptionCount = 0;
672 
673         try {
674             apiCount++;
675             responderLocation.getExpectedToMove();
676         } catch (IllegalStateException e) {
677             exceptionCount++;
678         }
679 
680         try {
681             apiCount++;
682             responderLocation.getFloorNumber();
683         } catch (IllegalStateException e) {
684             exceptionCount++;
685         }
686 
687         try {
688             apiCount++;
689             responderLocation.getHeightAboveFloorMeters();
690         } catch (IllegalStateException e) {
691             exceptionCount++;
692         }
693 
694         try {
695             apiCount++;
696             responderLocation.getHeightAboveFloorUncertaintyMeters();
697         } catch (IllegalStateException e) {
698             exceptionCount++;
699         }
700         // If Zaxis is not valid, all APIs should throw exception, otherwise no exception.
701         assertEquals("Exception number should equal to API number",
702                 responderLocation.isZaxisSubelementValid() ? 0 : apiCount, exceptionCount);
703         // Verify civic location
704         if (responderLocation.toCivicLocationAddress() == null) {
705             assertNull(responderLocation.toCivicLocationSparseArray());
706         } else {
707             assertNotNull(responderLocation.toCivicLocationSparseArray());
708         }
709         // Verify map image
710         if (responderLocation.getMapImageUri() == null) {
711             assertNull(responderLocation.getMapImageMimeType());
712         } else {
713             assertNotNull(responderLocation.getMapImageMimeType());
714         }
715         boolean extraInfoOnAssociationIndication =
716                 responderLocation.getExtraInfoOnAssociationIndication();
717         assertNotNull("ColocatedBSSID list should be nonNull",
718                 responderLocation.getColocatedBssids());
719     }
720 
721     /**
722      * Verify ranging request with aware peer Mac address and peer handle.
723      */
724     @Test
testAwareRttWithMacAddress()725     public void testAwareRttWithMacAddress() throws InterruptedException {
726         if (!WifiFeature.isAwareSupported(getContext())) {
727             return;
728         }
729         RangingRequest request = new RangingRequest.Builder()
730                 .addWifiAwarePeer(MAC).build();
731         ResultCallback callback = new ResultCallback();
732         mWifiRttManager.startRanging(request, mExecutor, callback);
733         assertTrue("Wi-Fi RTT results: no callback",
734                 callback.waitForCallback());
735         List<RangingResult> rangingResults = callback.getResults();
736         assertNotNull("Wi-Fi RTT results: null results", rangingResults);
737         assertEquals(1, rangingResults.size());
738         assertEquals(RangingResult.STATUS_FAIL, rangingResults.get(0).getStatus());
739     }
740 
741     /**
742      * Verify ranging request with aware peer handle.
743      */
744     @Test
testAwareRttWithPeerHandle()745     public void testAwareRttWithPeerHandle() throws InterruptedException {
746         if (!WifiFeature.isAwareSupported(getContext())) {
747             return;
748         }
749         PeerHandle peerHandle = mock(PeerHandle.class);
750         RangingRequest request = new RangingRequest.Builder()
751                 .addWifiAwarePeer(peerHandle).build();
752         ResultCallback callback = new ResultCallback();
753         mWifiRttManager.startRanging(request, mExecutor, callback);
754         assertTrue("Wi-Fi RTT results: no callback",
755                 callback.waitForCallback());
756         List<RangingResult> rangingResults = callback.getResults();
757         assertNotNull("Wi-Fi RTT results: null results", rangingResults);
758         assertEquals("Invalid peerHandle should return 0 result", 0, rangingResults.size());
759     }
760 
761     /**
762      * Test Wi-Fi One-sided RTT ranging operation using ScanResult in request:
763      * - Scan for visible APs for the test AP (which do not support IEEE 802.11mc) and are operating
764      * - in the 5GHz band.
765      * - Perform N (constant) RTT operations
766      * - Remove outliers while insuring greater than 50% of the results still remain
767      * - Validate:
768      *   - Failure ratio < threshold (constant)
769      *   - Result margin < threshold (constant)
770      */
771     @Test
testRangingToTestNon11mcApUsingScanResult()772     public void testRangingToTestNon11mcApUsingScanResult() throws InterruptedException {
773         if (!WifiBuildCompat.isPlatformOrWifiModuleAtLeastS(getContext())) {
774             return;
775         }
776 
777         // Scan for Non-IEEE 802.11mc supporting APs
778         ScanResult testAp = getLegacyScanResult();
779         assertNotNull(
780                 "Cannot find any test APs which are Non-IEEE 802.11mc - please verify that"
781                         + " your test setup includes them!", testAp);
782 
783         // Perform RTT operations
784         RangingRequest.Builder builder = new RangingRequest.Builder();
785         builder.addNon80211mcCapableAccessPoint(testAp);
786         builder.setRttBurstSize(RangingRequest.getMaxRttBurstSize());
787         RangingRequest request = builder.build();
788 
789         // Perform the request
790         rangeNon11mcApRequest(request, testAp, MAX_NON11MC_VARIATION_FROM_AVERAGE_DISTANCE_MM);
791     }
792 
793     /**
794      * Test Wi-Fi one-sided RTT ranging operation using ResponderConfig in request:
795      * - Scan for visible APs for the test AP (which do not support IEEE 802.11mc) and are operating
796      * - in the 5GHz band.
797      * - Perform N (constant) RTT operations
798      * - Remove outliers while insuring greater than 50% of the results still remain
799      * - Validate:
800      *   - Failure ratio < threshold (constant)
801      *   - Result margin < threshold (constant)
802      */
803     @Test
testRangingToTestNon11mcApUsingResponderConfig()804     public void testRangingToTestNon11mcApUsingResponderConfig() throws InterruptedException {
805         if (!WifiBuildCompat.isPlatformOrWifiModuleAtLeastS(getContext())) {
806             return;
807         }
808 
809         // Scan for Non-IEEE 802.11mc supporting APs
810         ScanResult testAp = getLegacyScanResult();
811         assertNotNull(
812                 "Cannot find any test APs which are Non-IEEE 802.11mc - please verify that"
813                         + " your test setup includes them!", testAp);
814 
815         ResponderConfig responder = ResponderConfig.fromScanResult(testAp);
816 
817         // Perform RTT operations
818         RangingRequest.Builder builder = new RangingRequest.Builder();
819         builder.addResponder(responder);
820         builder.setRttBurstSize(RangingRequest.getMaxRttBurstSize());
821         RangingRequest request = builder.build();
822 
823 
824 
825         // Perform the request
826         rangeNon11mcApRequest(request, testAp, MAX_NON11MC_VARIATION_FROM_AVERAGE_DISTANCE_MM);
827     }
828 
829     /**
830      * Utility method for validating a ranging request to a non-80211mc AP.
831      *
832      * @param request the ranging request that is being tested
833      * @param testAp the original test scan result to provide feedback on failure conditions
834      */
rangeNon11mcApRequest(RangingRequest request, ScanResult testAp, int variationLimit)835     private void rangeNon11mcApRequest(RangingRequest request, ScanResult testAp,
836             int variationLimit) throws InterruptedException {
837         Thread.sleep(5000);
838         List<RangingResult> allResults = new ArrayList<>();
839         int numFailures = 0;
840         int distanceSum = 0;
841         int distanceMin = 0;
842         int distanceMax = 0;
843         int[] statuses = new int[NUM_OF_RTT_ITERATIONS];
844         int[] distanceMms = new int[NUM_OF_RTT_ITERATIONS];
845         boolean[] distanceInclusionMap = new boolean[NUM_OF_RTT_ITERATIONS];
846         int[] distanceStdDevMms = new int[NUM_OF_RTT_ITERATIONS];
847         int[] rssis = new int[NUM_OF_RTT_ITERATIONS];
848         int[] numAttempted = new int[NUM_OF_RTT_ITERATIONS];
849         int[] numSuccessful = new int[NUM_OF_RTT_ITERATIONS];
850         long[] timestampsMs = new long[NUM_OF_RTT_ITERATIONS];
851         byte[] lastLci = null;
852         byte[] lastLcr = null;
853         for (int i = 0; i < NUM_OF_RTT_ITERATIONS; ++i) {
854             ResultCallback callback = new ResultCallback();
855             mWifiRttManager.startRanging(request, mExecutor, callback);
856             assertTrue("Wi-Fi RTT results: no callback on iteration " + i,
857                     callback.waitForCallback());
858 
859             List<RangingResult> currentResults = callback.getResults();
860             assertNotNull(
861                     "Wi-Fi RTT results: null results (onRangingFailure) on iteration " + i,
862                     currentResults);
863             assertEquals(
864                     "Wi-Fi RTT results: unexpected # of results (expect 1) on iteration " + i,
865                     1, currentResults.size());
866             RangingResult result = currentResults.get(0);
867             assertEquals(
868                     "Wi-Fi RTT results: invalid result (wrong BSSID) entry on iteration " + i,
869                     result.getMacAddress().toString(), testAp.BSSID);
870 
871             assertNull(
872                     "Wi-Fi RTT results: invalid result (non-null PeerHandle) entry on iteration "
873                             + i, result.getPeerHandle());
874 
875             allResults.add(result);
876             int status = result.getStatus();
877             statuses[i] = status;
878             if (status == RangingResult.STATUS_SUCCESS) {
879                 assertFalse("Wi-Fi RTT results: should not be a 802.11MC measurement",
880                         result.is80211mcMeasurement());
881                 distanceSum += result.getDistanceMm();
882 
883                 assertTrue("Wi-Fi RTT results: invalid RSSI on iteration " + i,
884                         result.getRssi() >= MIN_VALID_RSSI);
885 
886                 distanceMms[i - numFailures] = result.getDistanceMm();
887                 distanceStdDevMms[i - numFailures] = result.getDistanceStdDevMm();
888                 rssis[i - numFailures] = result.getRssi();
889                 // For one-sided RTT the number of packets attempted in a burst is not available,
890                 // So we set the result to be the same as used in the request.
891                 numAttempted[i - numFailures] = request.getRttBurstSize();
892                 numSuccessful[i - numFailures] = result.getNumSuccessfulMeasurements();
893                 timestampsMs[i - numFailures] = result.getRangingTimestampMillis();
894 
895                 byte[] currentLci = result.getLci();
896                 byte[] currentLcr = result.getLcr();
897                 if (i - numFailures > 0) {
898                     assertArrayEquals(
899                             "Wi-Fi RTT results: invalid result (LCI mismatch) on iteration " + i,
900                             currentLci, lastLci);
901                     assertArrayEquals(
902                             "Wi-Fi RTT results: invalid result (LCR mismatch) on iteration " + i,
903                             currentLcr, lastLcr);
904                 }
905                 lastLci = currentLci;
906                 lastLcr = currentLcr;
907             } else {
908                 numFailures++;
909             }
910             // Sleep a while to avoid stress AP.
911             Thread.sleep(INTERVAL_MS);
912         }
913         // Save results to log
914         int numGoodResults = NUM_OF_RTT_ITERATIONS - numFailures;
915         DeviceReportLog reportLog = new DeviceReportLog(TAG, "testRangingToTestAp");
916         reportLog.addValues("status_codes", statuses, ResultType.NEUTRAL, ResultUnit.NONE);
917         reportLog.addValues("distance_mm", Arrays.copyOf(distanceMms, numGoodResults),
918                 ResultType.NEUTRAL, ResultUnit.NONE);
919         reportLog.addValues("distance_stddev_mm",
920                 Arrays.copyOf(distanceStdDevMms, numGoodResults),
921                 ResultType.NEUTRAL, ResultUnit.NONE);
922         reportLog.addValues("rssi_dbm", Arrays.copyOf(rssis, numGoodResults),
923                 ResultType.NEUTRAL,
924                 ResultUnit.NONE);
925         reportLog.addValues("num_attempted", Arrays.copyOf(numAttempted, numGoodResults),
926                 ResultType.NEUTRAL, ResultUnit.NONE);
927         reportLog.addValues("num_successful", Arrays.copyOf(numSuccessful, numGoodResults),
928                 ResultType.NEUTRAL, ResultUnit.NONE);
929         reportLog.addValues("timestamps", Arrays.copyOf(timestampsMs, numGoodResults),
930                 ResultType.NEUTRAL, ResultUnit.NONE);
931         reportLog.submit();
932 
933         if (mCharacteristics != null && mCharacteristics.getBoolean(WifiRttManager
934                 .CHARACTERISTICS_KEY_BOOLEAN_ONE_SIDED_RTT)) {
935             // Analyze results
936             assertTrue("Wi-Fi RTT failure rate exceeds threshold: FAIL=" + numFailures
937                             + ", ITERATIONS="
938                             + NUM_OF_RTT_ITERATIONS + ", AP=" + testAp,
939                     numFailures <= NUM_OF_RTT_ITERATIONS * MAX_NON11MC_FAILURE_RATE_PERCENT / 100);
940         }
941 
942         if (numFailures != NUM_OF_RTT_ITERATIONS) {
943             // Calculate an initial average using all measurements to determine distance outliers
944             double distanceAvg = (double) distanceSum / (NUM_OF_RTT_ITERATIONS - numFailures);
945             // Now figure out the distance outliers and mark them in the distance inclusion map
946             int validDistances = 0;
947             for (int i = 0; i < (NUM_OF_RTT_ITERATIONS - numFailures); i++) {
948                 if (distanceMms[i] - variationLimit < distanceAvg) {
949                     // Distances that are in range for the distribution are included in the map
950                     distanceInclusionMap[i] = true;
951                     validDistances++;
952                 } else {
953                     // Distances that are out of range for the distribution are excluded in the map
954                     distanceInclusionMap[i] = false;
955                 }
956             }
957 
958             assertTrue("After fails+outlier removal greater that 50% distances must remain: "
959                     + NUM_OF_RTT_ITERATIONS / 2, validDistances > NUM_OF_RTT_ITERATIONS / 2);
960 
961             // Remove the distance outliers and find the new average, min and max.
962             distanceSum = 0;
963             distanceMax = Integer.MIN_VALUE;
964             distanceMin = Integer.MAX_VALUE;
965             for (int i = 0; i < (NUM_OF_RTT_ITERATIONS - numFailures); i++) {
966                 if (distanceInclusionMap[i]) {
967                     distanceSum += distanceMms[i];
968                     distanceMin = Math.min(distanceMin, distanceMms[i]);
969                     distanceMax = Math.max(distanceMax, distanceMms[i]);
970                 }
971             }
972             distanceAvg = (double) distanceSum / validDistances;
973             assertTrue("Wi-Fi RTT: Variation (max direction) exceeds threshold, Variation ="
974                             + (distanceMax - distanceAvg),
975                     (distanceMax - distanceAvg) <= variationLimit);
976             assertTrue("Wi-Fi RTT: Variation (min direction) exceeds threshold, Variation ="
977                             + (distanceAvg - distanceMin),
978                     (distanceAvg - distanceMin) <= variationLimit);
979             for (int i = 0; i < numGoodResults; ++i) {
980                 assertNotEquals("Number of attempted measurements is 0", 0, numAttempted[i]);
981                 assertNotEquals("Number of successful measurements is 0", 0, numSuccessful[i]);
982             }
983         }
984 
985     }
986 
987     /**
988      * Test RangingResult.Builder
989      */
990     @RequiresFlagsEnabled(Flags.FLAG_ANDROID_V_WIFI_API)
991     @Test
992     @ApiTest(apis = { "android.net.wifi.rtt.RangingResult.Builder#setMacAddress",
993             "android.net.wifi.rtt.RangingResult.Builder#setPeerHandle",
994             "android.net.wifi.rtt.RangingResult.Builder#setStatus",
995             "android.net.wifi.rtt.RangingResult.Builder#setDistanceMm",
996             "android.net.wifi.rtt.RangingResult.Builder#setDistanceStdDevMm",
997             "android.net.wifi.rtt.RangingResult.Builder#setLci",
998             "android.net.wifi.rtt.RangingResult.Builder#setLcr",
999             "android.net.wifi.rtt.RangingResult.Builder#setNumAttemptedMeasurements",
1000             "android.net.wifi.rtt.RangingResult.Builder#setNumSuccessfulMeasurements",
1001             "android.net.wifi.rtt.RangingResult.Builder#setRangingTimestampMillis",
1002             "android.net.wifi.rtt.RangingResult.Builder#setRssi",
1003             "android.net.wifi.rtt.RangingResult.Builder#setMeasurementChannelFrequencyMHz",
1004             "android.net.wifi.rtt.RangingResult.Builder#setMeasurementBandwidth",
1005             "android.net.wifi.rtt.RangingResult.Builder#set80211azNtbMeasurement",
1006             "android.net.wifi.rtt.RangingResult.Builder#set80211mcMeasurement",
1007             "android.net.wifi.rtt.RangingResult.Builder#set80211azInitiatorTxLtfRepetitionsCount",
1008             "android.net.wifi.rtt.RangingResult.Builder#set80211azResponderTxLtfRepetitionsCount",
1009             "android.net.wifi.rtt.RangingResult.Builder#set80211azNumberOfRxSpatialStreams",
1010             "android.net.wifi.rtt.RangingResult.Builder#set80211azNumberOfTxSpatialStreams",
1011             "android.net.wifi.rtt.RangingResult.Builder#setMinTimeBetweenNtbMeasurementsMicros",
1012             "android.net.wifi.rtt.RangingResult.Builder#setMaxTimeBetweenNtbMeasurementsMicros",
1013             "android.net.wifi.rtt.RangingResult.Builder#setUnverifiedResponderLocation",
1014             "android.net.wifi.rtt.RangingResult#Builder"})
testRangingResultBuilder()1015     public void testRangingResultBuilder() {
1016         byte[] lci = {1, 2, 3, 4};
1017         byte[] lcr = {10, 20, 30, 40};
1018         RangingResult rangingResult = new RangingResult.Builder()
1019                 .setMacAddress(MacAddress.fromString("00:11:22:33:44:55"))
1020                 .setPeerHandle(null)
1021                 .setStatus(RangingResult.STATUS_SUCCESS)
1022                 .setDistanceMm(100)
1023                 .setDistanceStdDevMm(33)
1024                 .setLci(lci)
1025                 .setLcr(lcr)
1026                 .setNumAttemptedMeasurements(10)
1027                 .setNumSuccessfulMeasurements(5)
1028                 .setRangingTimestampMillis(12345)
1029                 .setRssi(-77)
1030                 .setMeasurementChannelFrequencyMHz(5180)
1031                 .setMeasurementBandwidth(ScanResult.CHANNEL_WIDTH_40MHZ)
1032                 .set80211azNtbMeasurement(true)
1033                 .set80211mcMeasurement(false)
1034                 .set80211azInitiatorTxLtfRepetitionsCount(2)
1035                 .set80211azResponderTxLtfRepetitionsCount(1)
1036                 .set80211azNumberOfRxSpatialStreams(2)
1037                 .set80211azNumberOfTxSpatialStreams(1)
1038                 .setMinTimeBetweenNtbMeasurementsMicros(1000)
1039                 .setMaxTimeBetweenNtbMeasurementsMicros(10000)
1040                 .setUnverifiedResponderLocation(null)
1041                 .build();
1042 
1043         assertEquals(MacAddress.fromString("00:11:22:33:44:55"), rangingResult.getMacAddress());
1044         assertEquals(null, rangingResult.getPeerHandle());
1045         assertEquals(RangingResult.STATUS_SUCCESS, rangingResult.getStatus());
1046         assertEquals(100, rangingResult.getDistanceMm());
1047         assertEquals(33, rangingResult.getDistanceStdDevMm());
1048         assertArrayEquals(lci, rangingResult.getLci());
1049         assertArrayEquals(lcr, rangingResult.getLcr());
1050         assertEquals(10, rangingResult.getNumAttemptedMeasurements());
1051         assertEquals(5, rangingResult.getNumSuccessfulMeasurements());
1052         assertEquals(12345, rangingResult.getRangingTimestampMillis());
1053         assertEquals(-77, rangingResult.getRssi());
1054         assertEquals(5180, rangingResult.getMeasurementChannelFrequencyMHz());
1055         assertEquals(ScanResult.CHANNEL_WIDTH_40MHZ, rangingResult.getMeasurementBandwidth());
1056         assertTrue(rangingResult.is80211azNtbMeasurement());
1057         assertFalse(rangingResult.is80211mcMeasurement());
1058         assertEquals(2, rangingResult.get80211azInitiatorTxLtfRepetitionsCount());
1059         assertEquals(1, rangingResult.get80211azResponderTxLtfRepetitionsCount());
1060         assertEquals(2, rangingResult.get80211azNumberOfRxSpatialStreams());
1061         assertEquals(1, rangingResult.get80211azNumberOfTxSpatialStreams());
1062         assertEquals(1000, rangingResult.getMinTimeBetweenNtbMeasurementsMicros());
1063         assertEquals(10000, rangingResult.getMaxTimeBetweenNtbMeasurementsMicros());
1064         assertEquals(null, rangingResult.getUnverifiedResponderLocation());
1065         try {
1066             rangingResult = new RangingResult.Builder()
1067                     .setStatus(RangingResult.STATUS_SUCCESS)
1068                     .setDistanceMm(100)
1069                     .setDistanceStdDevMm(33)
1070                     .build();
1071             assertEquals(RangingResult.STATUS_SUCCESS, rangingResult.getStatus());
1072             fail("RangeResult need MAC address or Peer handle");
1073         } catch (IllegalArgumentException e) {
1074 
1075         }
1076     }
1077 
1078     /**
1079      * Test Wi-Fi RTT ranging operation using ScanResults in request:
1080      * - Scan for visible APs for the test AP (which is validated to support IEEE 802.11az)
1081      * - Perform N (constant) RTT operations
1082      * - Validate:
1083      *   - Failure ratio < threshold (constant)
1084      *   - Result margin < threshold (constant)
1085      */
1086     @Test
1087     @RequiresFlagsEnabled(Flags.FLAG_ANDROID_V_WIFI_API)
testRangingToTest11azApUsingScanResult()1088     public void testRangingToTest11azApUsingScanResult() throws InterruptedException {
1089         assumeTrue(mCharacteristics != null && mCharacteristics.getBoolean(
1090                 WifiRttManager.CHARACTERISTICS_KEY_BOOLEAN_NTB_INITIATOR));
1091         ScanResult testAp = getS11AzScanResult();
1092         assertNotNull("Cannot find any test APs which support RTT / IEEE 802.11az"
1093                 + " - please verify that your test setup includes them!", testAp);
1094         RangingRequest.Builder builder = new RangingRequest.Builder();
1095         builder.addAccessPoint(testAp);
1096         RangingRequest request = builder.build();
1097         range11azApRequest(request, testAp);
1098     }
1099 
1100     /*
1101      * Test that vendor data can be set and retrieved properly in RangingRequest and RangingResult.
1102      */
1103     @RequiresFlagsEnabled(Flags.FLAG_ANDROID_V_WIFI_API)
1104     @SdkSuppress(minSdkVersion = Build.VERSION_CODES.VANILLA_ICE_CREAM,
1105             codeName = "VanillaIceCream")
1106     @Test
testRangingRequestVendorData()1107     public void testRangingRequestVendorData() {
1108         // Default value should be an empty list
1109         RangingRequest emptyRequest = new RangingRequest.Builder().build();
1110         assertNotNull(emptyRequest.getVendorData());
1111         assertTrue(emptyRequest.getVendorData().isEmpty());
1112 
1113         RangingResult emptyResult = new RangingResult.Builder().setMacAddress(MAC).build();
1114         assertNotNull(emptyResult.getVendorData());
1115         assertTrue(emptyResult.getVendorData().isEmpty());
1116 
1117         // Set and get vendor data
1118         OuiKeyedData vendorDataElement =
1119                 new OuiKeyedData.Builder(0x00aabbcc, new PersistableBundle()).build();
1120         List<OuiKeyedData> vendorData = Arrays.asList(vendorDataElement);
1121 
1122         RangingRequest requestWithData = new RangingRequest.Builder()
1123                 .setVendorData(vendorData)
1124                 .build();
1125         assertTrue(vendorData.equals(requestWithData.getVendorData()));
1126 
1127         RangingResult resultWithData = new RangingResult.Builder()
1128                 .setMacAddress(MAC)
1129                 .setVendorData(vendorData)
1130                 .build();
1131         assertTrue(vendorData.equals(resultWithData.getVendorData()));
1132     }
1133 
1134     /**
1135      * Test Wi-Fi RTT ranging using ResponderConfig in the single responder RangingRequest API.
1136      * - Scan for visible APs for the test AP (which is validated to support IEEE 802.11az)
1137      * - Perform N (constant) RTT operations
1138      * - Validate:
1139      *   - Failure ratio < threshold (constant)
1140      *   - Result margin < threshold (constant)
1141      */
1142     @Test
1143     @RequiresFlagsEnabled(Flags.FLAG_ANDROID_V_WIFI_API)
1144     @ApiTest(apis = {"android.net.wifi.rtt.ResponderConfig.Builder#set80211azNtbSupported",
1145             "android.net.wifi.rtt.ResponderConfig#is80211azNtbSupported"})
testRangingToTest11azApUsingResponderConfig()1146     public void testRangingToTest11azApUsingResponderConfig() throws InterruptedException {
1147         assumeTrue(mCharacteristics != null && mCharacteristics.getBoolean(
1148                 WifiRttManager.CHARACTERISTICS_KEY_BOOLEAN_NTB_INITIATOR));
1149         // Scan for IEEE 802.11az supporting APs
1150         ScanResult testAp = getS11AzScanResult();
1151         assertNotNull(
1152                 "Cannot find any test APs which support RTT / IEEE 802.11az - please verify that "
1153                         + "your test setup includes them!", testAp);
1154         int preamble = ResponderConfig.fromScanResult(testAp).getPreamble();
1155 
1156         // Create a ResponderConfig from the builder API.
1157         ResponderConfig.Builder responderBuilder = new ResponderConfig.Builder();
1158         ResponderConfig responder = responderBuilder
1159                 .setMacAddress(MacAddress.fromString(testAp.BSSID))
1160                 .set80211azNtbSupported(testAp.is80211azNtbResponder())
1161                 .setChannelWidth(testAp.channelWidth)
1162                 .setFrequencyMhz(testAp.frequency)
1163                 .setCenterFreq0Mhz(testAp.centerFreq0)
1164                 .setCenterFreq1Mhz(testAp.centerFreq1)
1165                 .setPreamble(preamble)
1166                 .setResponderType(RESPONDER_AP)
1167                 .build();
1168 
1169         // Validate ResponderConfig.Builder set method arguments match getter methods.
1170         assertTrue(responder.getMacAddress().toString().equalsIgnoreCase(testAp.BSSID)
1171                 && responder.is80211azNtbSupported() == testAp.is80211azNtbResponder()
1172                 && responder.getChannelWidth() == testAp.channelWidth
1173                 && responder.getFrequencyMhz() == testAp.frequency
1174                 && responder.getCenterFreq0Mhz() == testAp.centerFreq0
1175                 && responder.getCenterFreq1Mhz() == testAp.centerFreq1
1176                 && responder.getPreamble() == preamble
1177                 && responder.getResponderType() == RESPONDER_AP);
1178 
1179         // Perform RTT operations
1180         RangingRequest.Builder builder = new RangingRequest.Builder();
1181         builder.addResponder(responder);
1182 
1183         RangingRequest request = builder.build();
1184 
1185         if (WifiBuildCompat.isPlatformOrWifiModuleAtLeastS(getContext())) {
1186             assertEquals(1, request.getRttResponders().size());
1187         }
1188         range11azApRequest(request, testAp);
1189     }
1190 }
1191