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