1 /*
2  * Copyright (C) 2016 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;
18 
19 import static org.junit.Assert.assertArrayEquals;
20 import static org.junit.Assert.assertEquals;
21 import static org.junit.Assert.assertFalse;
22 import static org.junit.Assert.assertNotNull;
23 import static org.junit.Assert.assertThrows;
24 import static org.junit.Assert.assertTrue;
25 import static org.junit.Assert.fail;
26 import static org.junit.Assume.assumeTrue;
27 import static org.mockito.ArgumentMatchers.any;
28 import static org.mockito.ArgumentMatchers.eq;
29 import static org.mockito.Mockito.doAnswer;
30 import static org.mockito.Mockito.mock;
31 import static org.mockito.Mockito.never;
32 import static org.mockito.Mockito.spy;
33 import static org.mockito.Mockito.times;
34 import static org.mockito.Mockito.validateMockitoUsage;
35 import static org.mockito.Mockito.verify;
36 import static org.mockito.Mockito.when;
37 
38 import android.app.test.MockAnswerUtil;
39 import android.content.Context;
40 import android.net.wifi.WifiScanner.PnoSettings;
41 import android.net.wifi.WifiScanner.PnoSettings.PnoNetwork;
42 import android.net.wifi.WifiScanner.ScanData;
43 import android.net.wifi.WifiScanner.ScanListener;
44 import android.net.wifi.WifiScanner.ScanSettings;
45 import android.os.Handler;
46 import android.os.Parcel;
47 import android.os.WorkSource;
48 import android.os.test.TestLooper;
49 
50 import androidx.test.filters.SmallTest;
51 
52 import com.android.modules.utils.build.SdkLevel;
53 
54 import org.junit.After;
55 import org.junit.Before;
56 import org.junit.Test;
57 import org.mockito.ArgumentCaptor;
58 import org.mockito.Mock;
59 import org.mockito.MockitoAnnotations;
60 import org.mockito.Spy;
61 
62 import java.util.ArrayList;
63 import java.util.Arrays;
64 import java.util.List;
65 import java.util.concurrent.Executor;
66 
67 /**
68  * Unit tests for {@link android.net.wifi.WifiScanner}.
69  */
70 @SmallTest
71 public class WifiScannerTest {
72     @Mock
73     private Context mContext;
74     @Mock
75     private IWifiScanner mService;
76     @Spy
77     private Executor mExecutor = new SynchronousExecutor();
78     @Mock
79     private ScanListener mScanListener;
80     @Mock
81     private WifiScanner.ParcelableScanData mParcelableScanData;
82     private ScanData[] mScanData = {};
83 
84     private static final boolean TEST_PNOSETTINGS_IS_CONNECTED = false;
85     private static final int TEST_PNOSETTINGS_MIN_5GHZ_RSSI = -60;
86     private static final int TEST_PNOSETTINGS_MIN_2GHZ_RSSI = -70;
87     private static final int TEST_PNOSETTINGS_MIN_6GHZ_RSSI = -55;
88     private static final String TEST_SSID_1 = "TEST1";
89     private static final String TEST_SSID_2 = "TEST2";
90     private static final int[] TEST_FREQUENCIES_1 = {};
91     private static final int[] TEST_FREQUENCIES_2 = {2500, 5124, 6245};
92     private static final String DESCRIPTION_NOT_AUTHORIZED = "Not authorized";
93     private static final String TEST_PACKAGE_NAME = "com.test.123";
94     private static final String TEST_FEATURE_ID = "test.feature";
95 
96     private WifiScanner mWifiScanner;
97     private TestLooper mLooper;
98     private Handler mHandler;
99 
100     /**
101      * Setup before tests.
102      */
103     @Before
setUp()104     public void setUp() throws Exception {
105         MockitoAnnotations.initMocks(this);
106         mLooper = new TestLooper();
107         mHandler = spy(new Handler(mLooper.getLooper()));
108         mWifiScanner = new WifiScanner(mContext, mService, mLooper.getLooper());
109         mLooper.dispatchAll();
110         when(mParcelableScanData.getResults()).thenReturn(mScanData);
111         when(mContext.getOpPackageName()).thenReturn(TEST_PACKAGE_NAME);
112         when(mContext.getPackageName()).thenReturn(TEST_PACKAGE_NAME);
113         when(mContext.getAttributionTag()).thenReturn(TEST_FEATURE_ID);
114     }
115 
116     /**
117      * Clean up after tests.
118      */
119     @After
cleanup()120     public void cleanup() {
121         validateMockitoUsage();
122     }
123 
124     /**
125      * Verify parcel read/write for ScanSettings.
126      */
127     @Test
verifyScanSettingsParcelWithBand()128     public void verifyScanSettingsParcelWithBand() throws Exception {
129         ScanSettings writeSettings = new ScanSettings();
130         writeSettings.type = WifiScanner.SCAN_TYPE_LOW_POWER;
131         writeSettings.band = WifiScanner.WIFI_BAND_BOTH_WITH_DFS;
132 
133         ScanSettings readSettings = parcelWriteRead(writeSettings);
134         assertEquals(readSettings.type, writeSettings.type);
135         assertEquals(readSettings.band, writeSettings.band);
136         assertEquals(0, readSettings.channels.length);
137     }
138 
139     /**
140      * Verify parcel read/write for ScanSettings.
141      */
142     @Test
verifyScanSettingsParcelWithChannels()143     public void verifyScanSettingsParcelWithChannels() throws Exception {
144         ScanSettings writeSettings = new ScanSettings();
145         writeSettings.type = WifiScanner.SCAN_TYPE_HIGH_ACCURACY;
146         writeSettings.band = WifiScanner.WIFI_BAND_UNSPECIFIED;
147         writeSettings.channels = new WifiScanner.ChannelSpec[] {
148                 new WifiScanner.ChannelSpec(5),
149                 new WifiScanner.ChannelSpec(7)
150         };
151 
152         ScanSettings readSettings = parcelWriteRead(writeSettings);
153         assertEquals(writeSettings.type, readSettings.type);
154         assertEquals(writeSettings.band, readSettings.band);
155         assertEquals(2, readSettings.channels.length);
156         assertEquals(5, readSettings.channels[0].frequency);
157         assertEquals(7, readSettings.channels[1].frequency);
158     }
159 
160     /**
161      * Write the provided {@link ScanSettings} to a parcel and deserialize it.
162      */
parcelWriteRead(ScanSettings writeSettings)163     private static ScanSettings parcelWriteRead(ScanSettings writeSettings) throws Exception {
164         Parcel parcel = Parcel.obtain();
165         writeSettings.writeToParcel(parcel, 0);
166         parcel.setDataPosition(0);    // Rewind data position back to the beginning for read.
167         return ScanSettings.CREATOR.createFromParcel(parcel);
168     }
169 
170     /**
171      *  PnoSettings object can be serialized and deserialized, while keeping the
172      *  values unchanged.
173      */
174     @Test
canSerializeAndDeserializePnoSettings()175     public void canSerializeAndDeserializePnoSettings() throws Exception {
176 
177         PnoSettings pnoSettings = new PnoSettings();
178 
179         PnoNetwork pnoNetwork1 = new PnoNetwork(TEST_SSID_1);
180         PnoNetwork pnoNetwork2 = new PnoNetwork(TEST_SSID_2);
181         pnoNetwork1.frequencies = TEST_FREQUENCIES_1;
182         pnoNetwork2.frequencies = TEST_FREQUENCIES_2;
183 
184         pnoSettings.networkList = new PnoNetwork[]{pnoNetwork1, pnoNetwork2};
185         pnoSettings.isConnected = TEST_PNOSETTINGS_IS_CONNECTED;
186         pnoSettings.min5GHzRssi = TEST_PNOSETTINGS_MIN_5GHZ_RSSI;
187         pnoSettings.min24GHzRssi = TEST_PNOSETTINGS_MIN_2GHZ_RSSI;
188         pnoSettings.min6GHzRssi = TEST_PNOSETTINGS_MIN_6GHZ_RSSI;
189 
190         Parcel parcel = Parcel.obtain();
191         pnoSettings.writeToParcel(parcel, 0);
192         // Rewind the pointer to the head of the parcel.
193         parcel.setDataPosition(0);
194         PnoSettings pnoSettingsDeserialized =
195                 pnoSettings.CREATOR.createFromParcel(parcel);
196 
197         assertNotNull(pnoSettingsDeserialized);
198         assertEquals(TEST_PNOSETTINGS_IS_CONNECTED, pnoSettingsDeserialized.isConnected);
199         assertEquals(TEST_PNOSETTINGS_MIN_5GHZ_RSSI, pnoSettingsDeserialized.min5GHzRssi);
200         assertEquals(TEST_PNOSETTINGS_MIN_2GHZ_RSSI, pnoSettingsDeserialized.min24GHzRssi);
201         assertEquals(TEST_PNOSETTINGS_MIN_6GHZ_RSSI, pnoSettingsDeserialized.min6GHzRssi);
202 
203         // Test parsing of PnoNetwork
204         assertEquals(pnoSettings.networkList.length, pnoSettingsDeserialized.networkList.length);
205         for (int i = 0; i < pnoSettings.networkList.length; i++) {
206             PnoNetwork expected = pnoSettings.networkList[i];
207             PnoNetwork actual = pnoSettingsDeserialized.networkList[i];
208             assertEquals(expected.ssid, actual.ssid);
209             assertEquals(expected.flags, actual.flags);
210             assertEquals(expected.authBitField, actual.authBitField);
211             assertTrue(Arrays.equals(expected.frequencies, actual.frequencies));
212         }
213     }
214 
215     /**
216      *  Make sure that frequencies is not null by default.
217      */
218     @Test
pnoNetworkFrequencyIsNotNull()219     public void pnoNetworkFrequencyIsNotNull() throws Exception {
220         PnoNetwork pnoNetwork = new PnoNetwork(TEST_SSID_1);
221         assertNotNull(pnoNetwork.frequencies);
222     }
223 
224     /**
225      * Verify parcel read/write for ScanData.
226      */
227     @Test
verifyScanDataParcel()228     public void verifyScanDataParcel() throws Exception {
229         ScanData writeScanData = new ScanData(2, 0, 3,
230                 WifiScanner.WIFI_BAND_BOTH_WITH_DFS, new ScanResult[0]);
231 
232         ScanData readScanData = parcelWriteRead(writeScanData);
233         assertEquals(writeScanData.getId(), readScanData.getId());
234         assertEquals(writeScanData.getFlags(), readScanData.getFlags());
235         assertEquals(writeScanData.getBucketsScanned(), readScanData.getBucketsScanned());
236         assertEquals(writeScanData.getScannedBandsInternal(),
237                 readScanData.getScannedBandsInternal());
238         assertArrayEquals(writeScanData.getResults(), readScanData.getResults());
239     }
240 
241     /**
242      * Write the provided {@link ScanData} to a parcel and deserialize it.
243      */
parcelWriteRead(ScanData writeScanData)244     private static ScanData parcelWriteRead(ScanData writeScanData) throws Exception {
245         Parcel parcel = Parcel.obtain();
246         writeScanData.writeToParcel(parcel, 0);
247         parcel.setDataPosition(0);    // Rewind data position back to the beginning for read.
248         return ScanData.CREATOR.createFromParcel(parcel);
249     }
250 
251     /**
252      * Verify #setRnrSetting with valid and invalid inputs.
253      */
254     @Test
testSetRnrSetting()255     public void testSetRnrSetting() throws Exception {
256         // First verify IllegalArgumentException if an invalid input is passed in.
257         assumeTrue(SdkLevel.isAtLeastS());
258         try {
259             WifiScanner.ScanSettings scanSettings = new WifiScanner.ScanSettings();
260             scanSettings.setRnrSetting(-1);
261             fail("Excepted IllegalArgumentException");
262         } catch (IllegalArgumentException e) {
263         }
264 
265         // Then verify calling the API with a valid input.
266         WifiScanner.ScanSettings scanSettings = new WifiScanner.ScanSettings();
267         scanSettings.setRnrSetting(WifiScanner.WIFI_RNR_NOT_NEEDED);
268         assertEquals(WifiScanner.WIFI_RNR_NOT_NEEDED, scanSettings.getRnrSetting());
269     }
270 
271     @Test
testIsScanning()272     public void testIsScanning() throws Exception {
273         mWifiScanner.isScanning();
274         verify(mService).isScanning();
275     }
276 
277     /**
278      * Test behavior of {@link WifiScanner#startScan(ScanSettings, ScanListener)}
279      * @throws Exception
280      */
281     @Test
testStartScan()282     public void testStartScan() throws Exception {
283         ScanSettings scanSettings = new ScanSettings();
284         ScanListener scanListener = mock(ScanListener.class);
285 
286         mWifiScanner.startScan(scanSettings, scanListener);
287         mLooper.dispatchAll();
288 
289         verify(mService).startScan(any(), eq(scanSettings),
290                 any(), eq(TEST_PACKAGE_NAME), eq(TEST_FEATURE_ID));
291     }
292 
293     /**
294      * Test behavior of {@link WifiScanner#getSingleScanResults()}.
295      */
296     @Test
testGetSingleScanResults()297     public void testGetSingleScanResults() throws Exception {
298         ScanResult scanResult = new ScanResult();
299         scanResult.SSID = TEST_SSID_1;
300         ScanResult[] scanResults = {scanResult};
301 
302         doAnswer(new MockAnswerUtil.AnswerWithArguments() {
303             public List<ScanResult> answer(String packageName, String featureId) {
304                 return new ArrayList<>(Arrays.asList(scanResults));
305             }
306         }).when(mService).getSingleScanResults(any(), any());
307 
308         List<ScanResult> results = mWifiScanner.getSingleScanResults();
309         assertEquals(1, results.size());
310         assertEquals(TEST_SSID_1, results.get(0).SSID);
311     }
312 
313     /**
314      * Test behavior of {@link WifiScanner#getSingleScanResults()} with an incorrect response from
315      * the server.
316      */
317     @Test
testGetSingleScanResultsIncorrectResponse()318     public void testGetSingleScanResultsIncorrectResponse() throws Exception {
319         doAnswer(new MockAnswerUtil.AnswerWithArguments() {
320             public List<ScanResult> answer(String packageName, String featureId) {
321                 return new ArrayList<>();
322             }
323         }).when(mService).getSingleScanResults(any(), any());
324         List<ScanResult> results = mWifiScanner.getSingleScanResults();
325         verify(mService).getSingleScanResults(eq(TEST_PACKAGE_NAME), eq(TEST_FEATURE_ID));
326         assertEquals(0, results.size());
327     }
328 
329     /**
330      * Test behavior of {@link WifiScanner#stopScan(ScanListener)}
331      * @throws Exception
332      */
333     @Test
testStopScan()334     public void testStopScan() throws Exception {
335         ScanSettings scanSettings = new ScanSettings();
336         ScanListener scanListener = mock(ScanListener.class);
337 
338         mWifiScanner.startScan(scanSettings, scanListener);
339         mLooper.dispatchAll();
340 
341         mWifiScanner.stopScan(scanListener);
342         mLooper.dispatchAll();
343 
344         verify(mService, times(1)).startScan(any(),
345                 eq(scanSettings), any(), eq(TEST_PACKAGE_NAME), eq(TEST_FEATURE_ID));
346         verify(mService, times(1)).stopScan(any(),
347                 eq(TEST_PACKAGE_NAME), eq(TEST_FEATURE_ID));
348     }
349 
350     /**
351      * Test behavior of {@link WifiScanner#startScan(ScanSettings, ScanListener)}
352      * @throws Exception
353      */
354     @Test
testStartScanListenerOnSuccess()355     public void testStartScanListenerOnSuccess() throws Exception {
356         ScanSettings scanSettings = new ScanSettings();
357         ScanListener scanListener = mock(ScanListener.class);
358 
359         doAnswer(new MockAnswerUtil.AnswerWithArguments() {
360             public void answer(IWifiScannerListener listener, WifiScanner.ScanSettings settings,
361                     WorkSource workSource, String packageName, String featureId) throws Exception {
362                     listener.onSuccess();
363             }
364         }).when(mService).startScan(any(), any(), any(), any(), any());
365         mWifiScanner.startScan(scanSettings, scanListener);
366         mLooper.dispatchAll();
367 
368         verify(mService, times(1)).startScan(any(),
369                 eq(scanSettings), any(), eq(TEST_PACKAGE_NAME), eq(TEST_FEATURE_ID));
370         verify(scanListener).onSuccess();
371     }
372 
373     /**
374      * Test behavior of {@link WifiScanner#startScan(ScanSettings, ScanListener)}
375      * @throws Exception
376      */
377     @Test
testStartScanListenerOnResults()378     public void testStartScanListenerOnResults() throws Exception {
379         ScanSettings scanSettings = new ScanSettings();
380         ScanListener scanListener = mock(ScanListener.class);
381         ScanResult scanResult = new ScanResult();
382         ScanData[] scanDatas = new ScanData[]{
383                 new ScanData(0, 0, new ScanResult[]{scanResult})};
384 
385         doAnswer(new MockAnswerUtil.AnswerWithArguments() {
386             public void answer(IWifiScannerListener listener, WifiScanner.ScanSettings settings,
387                     WorkSource workSource, String packageName, String featureId) throws Exception {
388                 listener.onSuccess();
389                 listener.onResults(scanDatas);
390             }
391         }).when(mService).startScan(any(), any(), any(), any(), any());
392         mWifiScanner.startScan(scanSettings, scanListener);
393         mLooper.dispatchAll();
394         verify(mService).startScan(any(), eq(scanSettings),
395                 any(), eq(TEST_PACKAGE_NAME), eq(TEST_FEATURE_ID));
396         mLooper.dispatchAll();
397         verify(scanListener).onResults(eq(scanDatas));
398     }
399 
400     /**
401      * Test behavior of {@link WifiScanner#startDisconnectedPnoScan(ScanSettings, PnoSettings,
402      * Executor, WifiScanner.PnoScanListener)}
403      * @throws Exception
404      */
405     @Test
testStartDisconnectedPnoScan()406     public void testStartDisconnectedPnoScan() throws Exception {
407         ScanSettings scanSettings = new ScanSettings();
408         PnoSettings pnoSettings = new PnoSettings();
409         WifiScanner.PnoScanListener pnoScanListener = mock(WifiScanner.PnoScanListener.class);
410 
411         mWifiScanner.startDisconnectedPnoScan(
412                 scanSettings, pnoSettings, mock(Executor.class), pnoScanListener);
413         mLooper.dispatchAll();
414         verify(mService).startPnoScan(any(),
415                 eq(scanSettings), eq(pnoSettings),
416                 eq(TEST_PACKAGE_NAME), eq(TEST_FEATURE_ID));
417     }
418 
419     /**
420      * Test behavior of {@link WifiScanner#startConnectedPnoScan(ScanSettings, PnoSettings,
421      * Executor, WifiScanner.PnoScanListener)}
422      * @throws Exception
423      */
424     @Test
testStartConnectedPnoScan()425     public void testStartConnectedPnoScan() throws Exception {
426         ScanSettings scanSettings = new ScanSettings();
427         PnoSettings pnoSettings = new PnoSettings();
428         WifiScanner.PnoScanListener pnoScanListener = mock(WifiScanner.PnoScanListener.class);
429 
430         mWifiScanner.startConnectedPnoScan(
431                 scanSettings, pnoSettings, mock(Executor.class), pnoScanListener);
432         verify(mService).startPnoScan(any(), eq(scanSettings), eq(pnoSettings), any(), any());
433         assertTrue(scanSettings.isPnoScan);
434         assertTrue(pnoSettings.isConnected);
435     }
436 
437     /**
438      * Test behavior of {@link WifiScanner#stopPnoScan(ScanListener)}
439      * Executor, WifiScanner.PnoScanListener)}
440      * @throws Exception
441      */
442     @Test
testStopPnoScan()443     public void testStopPnoScan() throws Exception {
444         ScanSettings scanSettings = new ScanSettings();
445         PnoSettings pnoSettings = new PnoSettings();
446         WifiScanner.PnoScanListener pnoScanListener = mock(WifiScanner.PnoScanListener.class);
447 
448         mWifiScanner.startDisconnectedPnoScan(
449                 scanSettings, pnoSettings, mock(Executor.class), pnoScanListener);
450         mWifiScanner.stopPnoScan(pnoScanListener);
451 
452         verify(mService, times(1)).stopPnoScan(any(),
453                 eq(TEST_PACKAGE_NAME), eq(TEST_FEATURE_ID));
454     }
455 
456     @Test
testScanDataAddResults()457     public void testScanDataAddResults() throws Exception {
458         ScanResult scanResult1 = new ScanResult();
459         scanResult1.SSID = TEST_SSID_1;
460         ScanData scanData = new ScanData(0, 0, new ScanResult[]{scanResult1});
461 
462         ScanResult scanResult2 = new ScanResult();
463         scanResult2.SSID = TEST_SSID_2;
464         scanData.addResults(new ScanResult[]{scanResult2});
465 
466         ScanResult[] consolidatedScanResults = scanData.getResults();
467         assertEquals(2, consolidatedScanResults.length);
468         assertEquals(TEST_SSID_1, consolidatedScanResults[0].SSID);
469         assertEquals(TEST_SSID_2, consolidatedScanResults[1].SSID);
470     }
471 
472     @Test
testScanDataParcel()473     public void testScanDataParcel() throws Exception {
474         ScanResult scanResult1 = new ScanResult();
475         scanResult1.SSID = TEST_SSID_1;
476         ScanData scanData = new ScanData(5, 4, new ScanResult[]{scanResult1});
477 
478         Parcel parcel = Parcel.obtain();
479         scanData.writeToParcel(parcel, 0);
480         parcel.setDataPosition(0);    // Rewind data position back to the beginning for read.
481         ScanData readScanData = ScanData.CREATOR.createFromParcel(parcel);
482 
483         assertEquals(scanData.getId(), readScanData.getId());
484         assertEquals(scanData.getFlags(), readScanData.getFlags());
485         assertEquals(scanData.getResults().length, readScanData.getResults().length);
486         assertEquals(scanData.getResults()[0].SSID, readScanData.getResults()[0].SSID);
487     }
488 
489     /** Tests that upon registration success, {@link ScanListener#onSuccess()} is called. */
490     @Test
testRegisterScanListenerSuccess()491     public void testRegisterScanListenerSuccess() throws Exception {
492         doAnswer(new MockAnswerUtil.AnswerWithArguments() {
493             public void answer(IWifiScannerListener listener, String packageName, String featureId)
494                     throws Exception {
495                 listener.onSuccess();
496             }
497         }).when(mService).registerScanListener(any(), any(), any());
498         mWifiScanner.registerScanListener(mExecutor, mScanListener);
499         mLooper.dispatchAll();
500         verify(mService).registerScanListener(any(), eq(TEST_PACKAGE_NAME), eq(TEST_FEATURE_ID));
501         verify(mScanListener).onSuccess();
502     }
503 
504     /**
505      * Tests that upon registration failed, {@link ScanListener#onFailure(int, String)} is called.
506      */
507     @Test
testRegisterScanListenerFailed()508     public void testRegisterScanListenerFailed() throws Exception {
509         doAnswer(new MockAnswerUtil.AnswerWithArguments() {
510             public void answer(IWifiScannerListener listener, String packageName, String featureId)
511                     throws Exception {
512                 listener.onFailure(WifiScanner.REASON_NOT_AUTHORIZED, DESCRIPTION_NOT_AUTHORIZED);
513             }
514         }).when(mService).registerScanListener(any(), any(), any());
515         mWifiScanner.registerScanListener(mExecutor, mScanListener);
516         mLooper.dispatchAll();
517         verify(mService).registerScanListener(any(), eq(TEST_PACKAGE_NAME), eq(TEST_FEATURE_ID));
518         verify(mScanListener).onFailure(WifiScanner.REASON_NOT_AUTHORIZED,
519                 DESCRIPTION_NOT_AUTHORIZED);
520     }
521 
522     /**
523      * Tests that when the ScanListener is triggered, {@link ScanListener#onResults(ScanData[])}
524      * is called.
525      */
526     @Test
testRegisterScanListenerReceiveScanResults()527     public void testRegisterScanListenerReceiveScanResults() throws Exception {
528         ArgumentCaptor<IWifiScannerListener> listenerArgumentCaptor = ArgumentCaptor.forClass(
529                 IWifiScannerListener.class);
530         doAnswer(new MockAnswerUtil.AnswerWithArguments() {
531             public void answer(IWifiScannerListener listener, String packageName, String featureId)
532                     throws Exception {
533                 listener.onSuccess();
534             }
535         }).when(mService).registerScanListener(any(), any(), any());
536         mWifiScanner.registerScanListener(mExecutor, mScanListener);
537         verify(mService).registerScanListener(listenerArgumentCaptor.capture(),
538                 eq(TEST_PACKAGE_NAME), eq(TEST_FEATURE_ID));
539         verify(mExecutor, times(1)).execute(any());
540         verify(mScanListener).onSuccess();
541 
542         doAnswer(new MockAnswerUtil.AnswerWithArguments() {
543             public void answer(IWifiScannerListener listener, WifiScanner.ScanSettings settings,
544                     WorkSource workSource, String packageName, String featureId) throws Exception {
545                 listener.onResults(mScanData);
546                 listenerArgumentCaptor.getValue().onResults(mScanData);
547             }
548         }).when(mService).startScan(any(), any(), any(), any(), any());
549         ScanSettings scanSettings = new ScanSettings();
550         mWifiScanner.startScan(scanSettings, mock(ScanListener.class));
551         verify(mExecutor, times(2)).execute(any());
552         verify(mScanListener).onResults(mScanData);
553     }
554 
555     /**
556      * Tests that after unregistering a scan listener, {@link ScanListener#onResults(ScanData[])}
557      * is not called.
558      */
559     @Test
testUnregisterScanListener()560     public void testUnregisterScanListener() throws Exception {
561         doAnswer(new MockAnswerUtil.AnswerWithArguments() {
562             public void answer(IWifiScannerListener listener, String packageName, String featureId)
563                     throws Exception {
564                 listener.onSuccess();
565             }
566         }).when(mService).unregisterScanListener(any(), any(), any());
567 
568         mWifiScanner.registerScanListener(mExecutor, mScanListener);
569         mWifiScanner.unregisterScanListener(mScanListener);
570         verify(mService).registerScanListener(any(), eq(TEST_PACKAGE_NAME), eq(TEST_FEATURE_ID));
571         verify(mService).unregisterScanListener(any(), eq(TEST_PACKAGE_NAME), eq(TEST_FEATURE_ID));
572         verify(mScanListener).onSuccess();
573         verify(mScanListener, never()).onResults(mScanData);
574     }
575 
576     /**
577      * Tests isFullBandScan() method with and without DFS check
578      */
579     @Test
testIsFullBandScan()580     public void testIsFullBandScan() throws Exception {
581         assertFalse(WifiScanner.isFullBandScan(WifiScanner.WIFI_BAND_24_GHZ, true));
582         assertFalse(WifiScanner.isFullBandScan(WifiScanner.WIFI_BAND_5_GHZ, true));
583         assertFalse(WifiScanner.isFullBandScan(WifiScanner.WIFI_BAND_6_GHZ, true));
584         assertFalse(WifiScanner.isFullBandScan(
585                 WifiScanner.WIFI_BAND_6_GHZ | WifiScanner.WIFI_BAND_5_GHZ, true));
586         assertTrue(WifiScanner.isFullBandScan(
587                 WifiScanner.WIFI_BAND_24_GHZ | WifiScanner.WIFI_BAND_5_GHZ, true));
588         assertFalse(WifiScanner.isFullBandScan(
589                 WifiScanner.WIFI_BAND_24_GHZ | WifiScanner.WIFI_BAND_5_GHZ, false));
590         assertTrue(WifiScanner.isFullBandScan(WifiScanner.WIFI_BAND_BOTH_WITH_DFS, true));
591         assertTrue(WifiScanner.isFullBandScan(WifiScanner.WIFI_BAND_BOTH_WITH_DFS, false));
592     }
593 
594     /**
595      * Tests creating WifiScanner in multi threads, with async channel disconnects.
596      */
597     @Test
testWifiScannerConcurrentServiceStart()598     public void testWifiScannerConcurrentServiceStart() {
599         WifiScanner wifiScanner = new WifiScanner(
600                 mContext, mService, WifiFrameworkInitializer.getInstanceLooper());
601 
602         Thread thread1 = new Thread(() -> {
603             try {
604                 WifiScanner wifiScanner1 = new WifiScanner(
605                         mContext, mService, WifiFrameworkInitializer.getInstanceLooper());
606             }  catch (NullPointerException e) {
607                 fail("WifiScanner can't be initialized! " + e);
608             }
609         });
610 
611         thread1.start();
612         try {
613             thread1.join();
614         } catch (InterruptedException e) {
615             fail("WifiScanner can't be initialized!" + e);
616         }
617     }
618 
619     /**
620      * Verify #setVendorIes with valid and invalid inputs
621      */
622     @Test
testSetVendorIes()623     public void testSetVendorIes() throws Exception {
624         assumeTrue(SdkLevel.isAtLeastU());
625         WifiScanner.ScanSettings scanSettings = new WifiScanner.ScanSettings();
626         List<ScanResult.InformationElement> vendorIesList = new ArrayList<>();
627         ScanResult.InformationElement vendorIe1 = new ScanResult.InformationElement(221, 0,
628                 new byte[]{0x00, 0x50, (byte) 0xf2, 0x08, 0x11, 0x22, 0x33});
629         ScanResult.InformationElement vendorIe2 = new ScanResult.InformationElement(255, 0,
630                 new byte[]{0x00, 0x50, (byte) 0xf2, 0x08, (byte) 0xaa, (byte) 0xbb, (byte) 0xcc});
631         ScanResult.InformationElement vendorIe3 = new ScanResult.InformationElement(221, 0,
632                 new byte[0]);
633         vendorIe3.bytes = null;
634         ScanResult.InformationElement vendorIe4 = new ScanResult.InformationElement(221, 0,
635                 new byte[256]);
636         ScanResult.InformationElement vendorIe5 = new ScanResult.InformationElement(221, 0,
637                 new byte[256]);
638 
639         vendorIesList.add(vendorIe2);
640         assertThrows(IllegalArgumentException.class,
641                 () -> scanSettings.setVendorIes(vendorIesList));
642 
643         vendorIesList.remove(vendorIe2);
644         vendorIesList.add(vendorIe3);
645         assertThrows(IllegalArgumentException.class,
646                 () -> scanSettings.setVendorIes(vendorIesList));
647 
648         vendorIesList.remove(vendorIe3);
649         vendorIesList.add(vendorIe4);
650         assertThrows(IllegalArgumentException.class,
651                 () -> scanSettings.setVendorIes(vendorIesList));
652 
653         vendorIesList.add(vendorIe5);
654         assertThrows(IllegalArgumentException.class,
655                 () -> scanSettings.setVendorIes(vendorIesList));
656 
657         vendorIesList.remove(vendorIe4);
658         vendorIesList.remove(vendorIe5);
659         vendorIesList.add(vendorIe1);
660         scanSettings.setVendorIes(vendorIesList);
661         assertEquals(vendorIesList, scanSettings.getVendorIes());
662     }
663 }
664