1/*
2 * Copyright (C) 2015 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
17package com.android.server.wifi.scanner;
18
19import static com.android.server.wifi.ScanTestUtil.NativeScanSettingsBuilder;
20import static com.android.server.wifi.ScanTestUtil.assertScanDatasEquals;
21import static com.android.server.wifi.ScanTestUtil.createFreqSet;
22
23import static org.junit.Assert.*;
24import static org.mockito.Mockito.*;
25
26import android.net.wifi.ScanResult;
27import android.net.wifi.WifiScanner;
28import android.net.wifi.WifiSsid;
29import android.test.suitebuilder.annotation.SmallTest;
30
31import com.android.server.wifi.ScanDetail;
32import com.android.server.wifi.ScanResults;
33import com.android.server.wifi.WifiMonitor;
34import com.android.server.wifi.WifiNative;
35
36import org.junit.Before;
37import org.junit.Test;
38import org.mockito.InOrder;
39
40import java.util.ArrayList;
41import java.util.Set;
42
43/**
44 * Unit tests for {@link com.android.server.wifi.scanner.WificondScannerImpl}.
45 */
46@SmallTest
47public class WificondScannerTest extends BaseWifiScannerImplTest {
48
49    @Before
50    public void setup() throws Exception {
51        mScanner = new WificondScannerImpl(mContext, mWifiNative, mWifiMonitor,
52                mLooper.getLooper(), mClock);
53    }
54
55    @Test
56    public void backgroundScanSuccessSingleBucket() {
57        WifiNative.ScanSettings settings = new NativeScanSettingsBuilder()
58                .withBasePeriod(10000)
59                .withMaxApPerScan(10)
60                .addBucketWithBand(10000, WifiScanner.REPORT_EVENT_AFTER_EACH_SCAN,
61                        WifiScanner.WIFI_BAND_24_GHZ)
62                .build();
63
64        ScanPeriod[] expectedPeriods = new ScanPeriod[] {
65            new ScanPeriod(ScanPeriod.ReportType.RESULT,
66                    ScanResults.create(0, 2400),
67                    expectedBandScanFreqs(WifiScanner.WIFI_BAND_24_GHZ)),
68            new ScanPeriod(ScanPeriod.ReportType.RESULT,
69                    ScanResults.create(1, 2450),
70                    expectedBandScanFreqs(WifiScanner.WIFI_BAND_24_GHZ))
71        };
72
73        doSuccessfulTest(settings, expectedPeriods);
74    }
75
76    @Test
77    public void backgroundScanMaxApExceeded() {
78        WifiNative.ScanSettings settings = new NativeScanSettingsBuilder()
79                .withBasePeriod(10000)
80                .withMaxApPerScan(2)
81                .addBucketWithBand(10000,
82                        WifiScanner.REPORT_EVENT_AFTER_EACH_SCAN
83                        | WifiScanner.REPORT_EVENT_FULL_SCAN_RESULT,
84                        WifiScanner.WIFI_BAND_24_GHZ)
85                .build();
86
87        ScanPeriod[] expectedPeriods = new ScanPeriod[] {
88            new ScanPeriod(ScanPeriod.ReportType.FULL_AND_RESULT,
89                    ScanResults.createOverflowing(0, 2,
90                            new ScanDetail(WifiSsid.createFromAsciiEncoded("TEST AP 1"),
91                                    "00:00:00:00:00:00", "", -70, 2450, Long.MAX_VALUE, 0),
92                            new ScanDetail(WifiSsid.createFromAsciiEncoded("TEST AP 2"),
93                                    "AA:BB:CC:DD:EE:FF", "", -66, 2400, Long.MAX_VALUE, 0),
94                            new ScanDetail(WifiSsid.createFromAsciiEncoded("TEST AP 3"),
95                                    "00:00:00:00:00:00", "", -80, 2450, Long.MAX_VALUE, 0),
96                            new ScanDetail(WifiSsid.createFromAsciiEncoded("TEST AP 4"),
97                                    "AA:BB:CC:11:22:33", "", -65, 2450, Long.MAX_VALUE, 0)),
98                    expectedBandScanFreqs(WifiScanner.WIFI_BAND_24_GHZ))
99        };
100
101        doSuccessfulTest(settings, expectedPeriods);
102    }
103
104    @Test
105    public void backgroundScanSuccessWithFullScanResults() {
106        WifiNative.ScanSettings settings = new NativeScanSettingsBuilder()
107                .withBasePeriod(10000)
108                .withMaxApPerScan(10)
109                .addBucketWithBand(10000,
110                        WifiScanner.REPORT_EVENT_AFTER_EACH_SCAN
111                        | WifiScanner.REPORT_EVENT_FULL_SCAN_RESULT,
112                        WifiScanner.WIFI_BAND_24_GHZ)
113                .build();
114
115        ScanPeriod[] expectedPeriods = new ScanPeriod[] {
116            new ScanPeriod(ScanPeriod.ReportType.FULL_AND_RESULT,
117                    ScanResults.create(0, 2400, 2450, 2400, 2400),
118                    expectedBandScanFreqs(WifiScanner.WIFI_BAND_24_GHZ)),
119            new ScanPeriod(ScanPeriod.ReportType.FULL_AND_RESULT,
120                    ScanResults.create(1, 2450, 2400, 2450, 2400),
121                    expectedBandScanFreqs(WifiScanner.WIFI_BAND_24_GHZ))
122        };
123
124        doSuccessfulTest(settings, expectedPeriods);
125    }
126
127    @Test
128    public void backgroundScanSuccessWithMixedFullResultsAndNot() {
129        WifiNative.ScanSettings settings = new NativeScanSettingsBuilder()
130                .withBasePeriod(10000)
131                .withMaxApPerScan(10)
132                .addBucketWithBand(10000,
133                        WifiScanner.REPORT_EVENT_AFTER_EACH_SCAN,
134                        WifiScanner.WIFI_BAND_24_GHZ)
135                .addBucketWithBand(20000,
136                        WifiScanner.REPORT_EVENT_AFTER_EACH_SCAN
137                        | WifiScanner.REPORT_EVENT_FULL_SCAN_RESULT,
138                        WifiScanner.WIFI_BAND_5_GHZ)
139                .build();
140
141        ScanPeriod[] expectedPeriods = new ScanPeriod[] {
142            new ScanPeriod(ScanPeriod.ReportType.FULL_AND_RESULT,
143                    ScanResults.create(0, 2400, 2450, 2400, 5175),
144                    expectedBandScanFreqs(WifiScanner.WIFI_BAND_BOTH)),
145            new ScanPeriod(ScanPeriod.ReportType.RESULT,
146                    ScanResults.create(1, 2450, 2400, 2450, 2400),
147                    expectedBandScanFreqs(WifiScanner.WIFI_BAND_24_GHZ)),
148            new ScanPeriod(ScanPeriod.ReportType.FULL_AND_RESULT,
149                    ScanResults.create(2, 2450, 2400, 2450, 5150),
150                    expectedBandScanFreqs(WifiScanner.WIFI_BAND_BOTH))
151        };
152
153        doSuccessfulTest(settings, expectedPeriods);
154    }
155
156    @Test
157    public void backgroundScanNoBatch() {
158        WifiNative.ScanSettings settings = new NativeScanSettingsBuilder()
159                .withBasePeriod(10000)
160                .withMaxApPerScan(10)
161                .addBucketWithBand(10000,
162                        WifiScanner.REPORT_EVENT_NO_BATCH,
163                        WifiScanner.WIFI_BAND_24_GHZ)
164                .build();
165
166        ScanPeriod[] expectedPeriods = new ScanPeriod[] {
167            new ScanPeriod(ScanPeriod.ReportType.NONE,
168                    ScanResults.create(0, 2400, 2400, 2400),
169                    expectedBandScanFreqs(WifiScanner.WIFI_BAND_24_GHZ)),
170            new ScanPeriod(ScanPeriod.ReportType.NONE,
171                    ScanResults.create(1, 2400, 2400, 2450),
172                    expectedBandScanFreqs(WifiScanner.WIFI_BAND_24_GHZ)),
173            new ScanPeriod(ScanPeriod.ReportType.NONE,
174                    ScanResults.create(2, 2400, 2450, 2400),
175                    expectedBandScanFreqs(WifiScanner.WIFI_BAND_24_GHZ))
176        };
177
178        doSuccessfulTest(settings, expectedPeriods);
179    }
180
181    @Test
182    public void backgroundScanBatch() {
183        WifiNative.ScanSettings settings = new NativeScanSettingsBuilder()
184                .withBasePeriod(10000)
185                .withMaxApPerScan(10)
186                .withMaxScansToCache(3)
187                .addBucketWithBand(10000,
188                        WifiScanner.REPORT_EVENT_AFTER_BUFFER_FULL,
189                        WifiScanner.WIFI_BAND_24_GHZ)
190                .build();
191
192        ScanResults[] periodResults = new ScanResults[] {
193            ScanResults.create(0, 2400, 2400, 2400),
194            ScanResults.create(1, 2400, 2400, 2400, 2400),
195            ScanResults.create(2, 2450),
196            ScanResults.create(3, 2400, 2400),
197            ScanResults.create(4, 2400, 2450),
198            ScanResults.create(5, 2450)
199        };
200
201        ScanPeriod[] expectedPeriods = new ScanPeriod[] {
202            new ScanPeriod(ScanPeriod.ReportType.NONE,
203                    periodResults[0],
204                    expectedBandScanFreqs(WifiScanner.WIFI_BAND_24_GHZ)),
205            new ScanPeriod(ScanPeriod.ReportType.NONE,
206                    periodResults[1],
207                    expectedBandScanFreqs(WifiScanner.WIFI_BAND_24_GHZ)),
208            new ScanPeriod(ScanPeriod.ReportType.RESULT,
209                    new ScanResults[] {
210                        periodResults[0],
211                        periodResults[1],
212                        periodResults[2]
213                    },
214                    expectedBandScanFreqs(WifiScanner.WIFI_BAND_24_GHZ)),
215            new ScanPeriod(ScanPeriod.ReportType.NONE,
216                    periodResults[3],
217                    expectedBandScanFreqs(WifiScanner.WIFI_BAND_24_GHZ)),
218            new ScanPeriod(ScanPeriod.ReportType.NONE,
219                    periodResults[4],
220                    expectedBandScanFreqs(WifiScanner.WIFI_BAND_24_GHZ)),
221            new ScanPeriod(ScanPeriod.ReportType.RESULT,
222                    new ScanResults[] {
223                        periodResults[3],
224                        periodResults[4],
225                        periodResults[5]
226                    },
227                    expectedBandScanFreqs(WifiScanner.WIFI_BAND_24_GHZ))
228        };
229
230        doSuccessfulTest(settings, expectedPeriods);
231    }
232
233    @Test
234    public void backgroundScanSuccessWithMultipleBuckets() {
235        WifiNative.ScanSettings settings = new NativeScanSettingsBuilder()
236                .withBasePeriod(10000)
237                .withMaxApPerScan(10)
238                .addBucketWithBand(10000, WifiScanner.REPORT_EVENT_AFTER_EACH_SCAN,
239                        WifiScanner.WIFI_BAND_24_GHZ)
240                .addBucketWithBand(30000, WifiScanner.REPORT_EVENT_AFTER_EACH_SCAN,
241                        WifiScanner.WIFI_BAND_BOTH)
242                .addBucketWithChannels(20000, WifiScanner.REPORT_EVENT_AFTER_EACH_SCAN,
243                        5650)
244                .build();
245
246        ScanPeriod[] expectedPeriods = new ScanPeriod[] {
247            new ScanPeriod(ScanPeriod.ReportType.RESULT,
248                    ScanResults.create(0, 2400, 5175),
249                    expectedBandAndChannelScanFreqs(WifiScanner.WIFI_BAND_BOTH, 5650)),
250            new ScanPeriod(ScanPeriod.ReportType.RESULT,
251                    ScanResults.create(1, 2400),
252                    expectedBandScanFreqs(WifiScanner.WIFI_BAND_24_GHZ)),
253            new ScanPeriod(ScanPeriod.ReportType.RESULT,
254                    ScanResults.create(2, 2450, 5650),
255                    expectedBandAndChannelScanFreqs(WifiScanner.WIFI_BAND_24_GHZ, 5650)),
256            new ScanPeriod(ScanPeriod.ReportType.RESULT,
257                    ScanResults.create(3, 2450, 5175),
258                    expectedBandScanFreqs(WifiScanner.WIFI_BAND_BOTH)),
259            new ScanPeriod(ScanPeriod.ReportType.RESULT,
260                    ScanResults.create(4, new int[0]),
261                    expectedBandAndChannelScanFreqs(WifiScanner.WIFI_BAND_24_GHZ, 5650)),
262            new ScanPeriod(ScanPeriod.ReportType.RESULT,
263                    ScanResults.create(5, 2400, 2400, 2400, 2450),
264                    expectedBandScanFreqs(WifiScanner.WIFI_BAND_24_GHZ)),
265            new ScanPeriod(ScanPeriod.ReportType.RESULT,
266                    ScanResults.create(6, 5150, 5650, 5650),
267                    expectedBandAndChannelScanFreqs(WifiScanner.WIFI_BAND_BOTH, 5650))
268        };
269
270        doSuccessfulTest(settings, expectedPeriods);
271    }
272
273    @Test
274    public void backgroundScanSuccessWithMultipleBucketsWhereAPeriodDoesNotRequireAScan() {
275        WifiNative.ScanSettings settings = new NativeScanSettingsBuilder()
276                .withBasePeriod(10000)
277                .withMaxApPerScan(10)
278                .addBucketWithBand(30000, WifiScanner.REPORT_EVENT_AFTER_EACH_SCAN,
279                        WifiScanner.WIFI_BAND_BOTH)
280                .addBucketWithChannels(20000, WifiScanner.REPORT_EVENT_AFTER_EACH_SCAN,
281                        5650)
282                .build();
283
284        // expected scan frequencies
285        ScanPeriod[] expectedPeriods = new ScanPeriod[] {
286            new ScanPeriod(ScanPeriod.ReportType.RESULT,
287                    ScanResults.create(0, 2400, 5175),
288                    expectedBandAndChannelScanFreqs(WifiScanner.WIFI_BAND_BOTH, 5650)),
289            null,
290            new ScanPeriod(ScanPeriod.ReportType.RESULT,
291                    ScanResults.create(1, 5650),
292                    createFreqSet(5650)),
293            new ScanPeriod(ScanPeriod.ReportType.RESULT,
294                    ScanResults.create(2, 2450, 5175),
295                    expectedBandScanFreqs(WifiScanner.WIFI_BAND_BOTH)),
296            new ScanPeriod(ScanPeriod.ReportType.RESULT,
297                    ScanResults.create(3, 5650, 5650, 5650),
298                    createFreqSet(5650)),
299            null,
300            new ScanPeriod(ScanPeriod.ReportType.RESULT,
301                    ScanResults.create(4, 2400, 2400, 2400, 2450),
302                    expectedBandAndChannelScanFreqs(WifiScanner.WIFI_BAND_BOTH, 5650))
303        };
304
305        doSuccessfulTest(settings, expectedPeriods);
306    }
307
308    @Test
309    public void backgroundScanStartFailed() {
310        WifiNative.ScanEventHandler eventHandler = mock(WifiNative.ScanEventHandler.class);
311        WifiNative.ScanSettings settings = new NativeScanSettingsBuilder()
312                .withBasePeriod(10000)
313                .withMaxApPerScan(10)
314                .addBucketWithBand(10000, WifiScanner.REPORT_EVENT_AFTER_EACH_SCAN,
315                        WifiScanner.WIFI_BAND_24_GHZ)
316                .build();
317
318        InOrder order = inOrder(eventHandler, mWifiNative);
319
320        // All scans fail
321        when(mWifiNative.scan(any(), any(Set.class))).thenReturn(false);
322
323        // Start scan
324        mScanner.startBatchedScan(settings, eventHandler);
325
326        assertBackgroundPeriodAlarmPending();
327
328        expectFailedScanStart(order, eventHandler,
329                expectedBandScanFreqs(WifiScanner.WIFI_BAND_24_GHZ));
330
331        // Fire alarm to start next scan
332        dispatchBackgroundPeriodAlarm();
333
334        assertBackgroundPeriodAlarmPending();
335
336        expectFailedScanStart(order, eventHandler,
337                expectedBandScanFreqs(WifiScanner.WIFI_BAND_24_GHZ));
338
339        verifyNoMoreInteractions(eventHandler);
340    }
341
342
343    @Test
344    public void backgroundScanEventFailed() {
345        WifiNative.ScanEventHandler eventHandler = mock(WifiNative.ScanEventHandler.class);
346        WifiNative.ScanSettings settings = new NativeScanSettingsBuilder()
347                .withBasePeriod(10000)
348                .withMaxApPerScan(10)
349                .addBucketWithBand(10000, WifiScanner.REPORT_EVENT_AFTER_EACH_SCAN,
350                        WifiScanner.WIFI_BAND_24_GHZ)
351                .build();
352
353        InOrder order = inOrder(eventHandler, mWifiNative);
354
355        // All scan starts succeed
356        when(mWifiNative.scan(any(), any(Set.class))).thenReturn(true);
357
358        // Start scan
359        mScanner.startBatchedScan(settings, eventHandler);
360
361        assertBackgroundPeriodAlarmPending();
362
363        expectFailedEventScan(order, eventHandler,
364                expectedBandScanFreqs(WifiScanner.WIFI_BAND_24_GHZ));
365
366        // Fire alarm to start next scan
367        dispatchBackgroundPeriodAlarm();
368
369        assertBackgroundPeriodAlarmPending();
370
371        expectFailedEventScan(order, eventHandler,
372                expectedBandScanFreqs(WifiScanner.WIFI_BAND_24_GHZ));
373
374        verifyNoMoreInteractions(eventHandler);
375    }
376
377    /**
378     * Run a scan and then pause after the first scan completes, but before the next one starts
379     * Then resume the scan
380     */
381    @Test
382    public void pauseWhileWaitingToStartNextScanAndResumeScan() {
383        WifiNative.ScanEventHandler eventHandler = mock(WifiNative.ScanEventHandler.class);
384        WifiNative.ScanSettings settings = new NativeScanSettingsBuilder()
385                .withBasePeriod(10000)
386                .withMaxApPerScan(10)
387                .addBucketWithBand(10000, WifiScanner.REPORT_EVENT_AFTER_EACH_SCAN,
388                        WifiScanner.WIFI_BAND_24_GHZ)
389                .build();
390
391        ScanPeriod[] expectedPeriods = new ScanPeriod[] {
392            new ScanPeriod(ScanPeriod.ReportType.RESULT,
393                    ScanResults.create(0, 2400, 2450, 2450),
394                    expectedBandScanFreqs(WifiScanner.WIFI_BAND_24_GHZ)),
395            new ScanPeriod(ScanPeriod.ReportType.RESULT,
396                    ScanResults.create(1, 2400),
397                    expectedBandScanFreqs(WifiScanner.WIFI_BAND_24_GHZ))
398        };
399
400        InOrder order = inOrder(eventHandler, mWifiNative);
401
402        // All scan starts succeed
403        when(mWifiNative.scan(any(), any(Set.class))).thenReturn(true);
404
405        // Start scan
406        mScanner.startBatchedScan(settings, eventHandler);
407
408        assertBackgroundPeriodAlarmPending();
409
410        expectSuccessfulBackgroundScan(order, eventHandler, expectedPeriods[0], 0);
411
412        assertBackgroundPeriodAlarmPending();
413
414        mScanner.pauseBatchedScan();
415
416        // onPause callback (previous results were flushed)
417        order.verify(eventHandler).onScanPaused(new WifiScanner.ScanData[0]);
418
419        assertBackgroundPeriodAlarmNotPending();
420
421        mScanner.restartBatchedScan();
422
423        // onRestarted callback
424        order.verify(eventHandler).onScanRestarted();
425
426        expectSuccessfulBackgroundScan(order, eventHandler, expectedPeriods[1], 1);
427
428        verifyNoMoreInteractions(eventHandler);
429    }
430
431    /**
432     * Run a scan and then pause while the first scan is running
433     * Then resume the scan
434     */
435    @Test
436    public void pauseWhileScanningAndResumeScan() {
437        WifiNative.ScanEventHandler eventHandler = mock(WifiNative.ScanEventHandler.class);
438        WifiNative.ScanSettings settings = new NativeScanSettingsBuilder()
439                .withBasePeriod(10000)
440                .withMaxApPerScan(10)
441                .addBucketWithBand(10000, WifiScanner.REPORT_EVENT_AFTER_EACH_SCAN,
442                        WifiScanner.WIFI_BAND_24_GHZ)
443                .build();
444
445        ScanPeriod[] expectedPeriods = new ScanPeriod[] {
446            new ScanPeriod(ScanPeriod.ReportType.RESULT,
447                    ScanResults.create(0, 2400, 2450, 2450),
448                    expectedBandScanFreqs(WifiScanner.WIFI_BAND_24_GHZ)),
449            new ScanPeriod(ScanPeriod.ReportType.RESULT,
450                    ScanResults.create(1, 2400),
451                    expectedBandScanFreqs(WifiScanner.WIFI_BAND_24_GHZ))
452        };
453
454        InOrder order = inOrder(eventHandler, mWifiNative);
455
456        // All scan starts succeed
457        when(mWifiNative.scan(any(), any(Set.class))).thenReturn(true);
458
459        // Start scan
460        mScanner.startBatchedScan(settings, eventHandler);
461
462        assertBackgroundPeriodAlarmPending();
463
464        order.verify(mWifiNative).scan(eq(expectedPeriods[0].getScanFreqs()), any(Set.class));
465
466        mScanner.pauseBatchedScan();
467
468        // onPause callback (no pending results)
469        order.verify(eventHandler).onScanPaused(new WifiScanner.ScanData[0]);
470
471        assertBackgroundPeriodAlarmNotPending();
472
473        // Setup scan results
474        when(mWifiNative.getScanResults()).thenReturn(expectedPeriods[0]
475                .getResultsToBeDelivered()[0].getScanDetailArrayList());
476
477        // Notify scan has finished
478        mWifiMonitor.sendMessage(mWifiNative.getInterfaceName(), WifiMonitor.SCAN_RESULTS_EVENT);
479        assertEquals("dispatch message after results event", 1, mLooper.dispatchAll());
480
481        // listener should not be notified
482
483        mScanner.restartBatchedScan();
484
485        // onRestarted callback
486        order.verify(eventHandler).onScanRestarted();
487
488        expectSuccessfulBackgroundScan(order, eventHandler, expectedPeriods[1], 1);
489
490        verifyNoMoreInteractions(eventHandler);
491    }
492
493
494    /**
495     * Run a scan and then pause after the first scan completes, but before the next one starts
496     * Then schedule a new scan while still paused
497     */
498    @Test
499    public void pauseWhileWaitingToStartNextScanAndStartNewScan() {
500        WifiNative.ScanEventHandler eventHandler = mock(WifiNative.ScanEventHandler.class);
501        WifiNative.ScanSettings settings = new NativeScanSettingsBuilder()
502                .withBasePeriod(10000)
503                .withMaxApPerScan(10)
504                .addBucketWithBand(10000, WifiScanner.REPORT_EVENT_AFTER_EACH_SCAN,
505                        WifiScanner.WIFI_BAND_24_GHZ)
506                .build();
507
508        WifiNative.ScanSettings settings2 = new NativeScanSettingsBuilder()
509                .withBasePeriod(10000)
510                .withMaxApPerScan(10)
511                .addBucketWithBand(10000, WifiScanner.REPORT_EVENT_AFTER_EACH_SCAN,
512                        WifiScanner.WIFI_BAND_5_GHZ)
513                .build();
514
515        ScanPeriod[] expectedPeriods = new ScanPeriod[] {
516            new ScanPeriod(ScanPeriod.ReportType.RESULT,
517                    ScanResults.create(0, 2400, 2450, 2450),
518                    expectedBandScanFreqs(WifiScanner.WIFI_BAND_24_GHZ))
519        };
520
521        ScanPeriod[] expectedPeriods2 = new ScanPeriod[] {
522            new ScanPeriod(ScanPeriod.ReportType.RESULT,
523                    ScanResults.create(1, 5150, 5175, 5175),
524                    expectedBandScanFreqs(WifiScanner.WIFI_BAND_5_GHZ)),
525        };
526
527        InOrder order = inOrder(eventHandler, mWifiNative);
528
529        // All scan starts succeed
530        when(mWifiNative.scan(any(), any(Set.class))).thenReturn(true);
531
532        // Start scan
533        mScanner.startBatchedScan(settings, eventHandler);
534
535        assertBackgroundPeriodAlarmPending();
536
537        expectSuccessfulBackgroundScan(order, eventHandler, expectedPeriods[0], 0);
538
539        assertBackgroundPeriodAlarmPending();
540
541        mScanner.pauseBatchedScan();
542
543        // onPause callback (previous results were flushed)
544        order.verify(eventHandler).onScanPaused(new WifiScanner.ScanData[0]);
545
546        assertBackgroundPeriodAlarmNotPending();
547
548        // Start new scan
549        mScanner.startBatchedScan(settings2, eventHandler);
550
551        expectSuccessfulBackgroundScan(order, eventHandler, expectedPeriods2[0], 0);
552
553        verifyNoMoreInteractions(eventHandler);
554    }
555
556    /**
557     * Run a test with the given settings where all native scans succeed
558     * This will execute expectedPeriods.length scan periods by first
559     * starting the scan settings and then dispatching the scan period alarm to start the
560     * next scan.
561     */
562    private void doSuccessfulTest(WifiNative.ScanSettings settings, ScanPeriod[] expectedPeriods) {
563        WifiNative.ScanEventHandler eventHandler = mock(WifiNative.ScanEventHandler.class);
564
565        InOrder order = inOrder(eventHandler, mWifiNative);
566
567        // All scans succeed
568        when(mWifiNative.scan(any(), any(Set.class))).thenReturn(true);
569
570        // Start scan
571        mScanner.startBatchedScan(settings, eventHandler);
572
573        for (int i = 0; i < expectedPeriods.length; ++i) {
574            ScanPeriod period = expectedPeriods[i];
575            assertBackgroundPeriodAlarmPending();
576            if (period != null) { // scan should be scheduled
577                expectSuccessfulBackgroundScan(order, eventHandler, expectedPeriods[i], i);
578            }
579            if (i < expectedPeriods.length - 1) {
580                dispatchBackgroundPeriodAlarm();
581            }
582        }
583
584        verifyNoMoreInteractions(eventHandler);
585    }
586
587    /**
588     * Verify the state after a scan was started either through startBatchedScan or
589     * dispatching the period alarm.
590     */
591    private void expectSuccessfulBackgroundScan(InOrder order,
592            WifiNative.ScanEventHandler eventHandler, ScanPeriod period, int periodId) {
593        WifiScanner.ScanData[] scanDatas = null;
594        ArrayList<ScanDetail> nativeResults = null;
595        ScanResult[] fullResults = null;
596        if (period.getResultsToBeDelivered() != null) {
597            ScanResults lastPeriodResults = period.getResultsToBeDelivered()
598                    [period.getResultsToBeDelivered().length - 1];
599            nativeResults = lastPeriodResults.getScanDetailArrayList();
600            if (period.expectResults()) {
601                scanDatas =
602                        new WifiScanner.ScanData[period.getResultsToBeDelivered().length];
603                for (int j = 0; j < scanDatas.length; ++j) {
604                    scanDatas[j] = period.getResultsToBeDelivered()[j].getScanData();
605                }
606            }
607            if (period.expectFullResults()) {
608                fullResults = lastPeriodResults.getRawScanResults();
609            }
610        }
611        expectSuccessfulBackgroundScan(order, eventHandler, period.getScanFreqs(),
612                nativeResults, scanDatas, fullResults, periodId);
613    }
614
615    /**
616     * Verify the state after a scan was started either through startBatchedScan or
617     * dispatching the period alarm.
618     */
619    private void expectSuccessfulBackgroundScan(InOrder order,
620            WifiNative.ScanEventHandler eventHandler, Set<Integer> scanFreqs,
621            ArrayList<ScanDetail> nativeResults,
622            WifiScanner.ScanData[] expectedScanResults,
623            ScanResult[] fullResults, int periodId) {
624        // Verify scan started
625        order.verify(mWifiNative).scan(eq(scanFreqs), any(Set.class));
626
627        // Setup scan results
628        when(mWifiNative.getScanResults()).thenReturn(nativeResults);
629
630        // Notify scan has finished
631        mWifiMonitor.sendMessage(mWifiNative.getInterfaceName(), WifiMonitor.SCAN_RESULTS_EVENT);
632        assertEquals("dispatch message after results event", 1, mLooper.dispatchAll());
633
634        if (fullResults != null) {
635            for (ScanResult result : fullResults) {
636                order.verify(eventHandler).onFullScanResult(eq(result), eq(0));
637            }
638        }
639
640        if (expectedScanResults != null) {
641            // Verify scan results delivered
642            order.verify(eventHandler).onScanStatus(WifiNative.WIFI_SCAN_RESULTS_AVAILABLE);
643            assertScanDatasEquals("period[" + periodId + "].", expectedScanResults,
644                    mScanner.getLatestBatchedScanResults(true));
645        }
646    }
647
648    private void expectFailedScanStart(InOrder order, WifiNative.ScanEventHandler eventHandler,
649            Set<Integer> scanFreqs) {
650        // Verify scan started
651        order.verify(mWifiNative).scan(eq(scanFreqs), any(Set.class));
652    }
653
654    private void expectFailedEventScan(InOrder order, WifiNative.ScanEventHandler eventHandler,
655            Set<Integer> scanFreqs) {
656        // Verify scan started
657        order.verify(mWifiNative).scan(eq(scanFreqs), any(Set.class));
658
659        // Notify scan has failed
660        mWifiMonitor.sendMessage(mWifiNative.getInterfaceName(), WifiMonitor.SCAN_FAILED_EVENT);
661        assertEquals("dispatch message after results event", 1, mLooper.dispatchAll());
662
663        // TODO: verify failure event
664    }
665
666    private void assertBackgroundPeriodAlarmPending() {
667        assertTrue("background period alarm not pending",
668                mAlarmManager.isPending(WificondScannerImpl.BACKGROUND_PERIOD_ALARM_TAG));
669    }
670
671    private void assertBackgroundPeriodAlarmNotPending() {
672        assertFalse("background period alarm is pending",
673                mAlarmManager.isPending(WificondScannerImpl.BACKGROUND_PERIOD_ALARM_TAG));
674    }
675
676    private void dispatchBackgroundPeriodAlarm() {
677        assertTrue("dispatch background period alarm",
678                mAlarmManager.dispatch(WificondScannerImpl.BACKGROUND_PERIOD_ALARM_TAG));
679        mLooper.dispatchAll();
680    }
681
682    private static class ScanPeriod {
683        enum ReportType {
684            NONE(false, false),
685            RESULT(true, false),
686            FULL_AND_RESULT(true, true),
687            FULL(false, true);
688
689            public final boolean result;
690            public final boolean full;
691            ReportType(boolean result, boolean full) {
692                this.result = result;
693                this.full = full;
694            }
695        };
696        private final ReportType mReportType;
697        private final ScanResults[] mDeliveredResults;
698        private final Set<Integer> mRequestedFreqs;
699
700        ScanPeriod(ReportType reportType, ScanResults deliveredResult,
701                Set<Integer> requestedFreqs) {
702            this(reportType, new ScanResults[] {deliveredResult}, requestedFreqs);
703        }
704
705        ScanPeriod(ReportType reportType, ScanResults[] deliveredResults,
706                Set<Integer> requestedFreqs) {
707            mReportType = reportType;
708            mDeliveredResults = deliveredResults;
709            mRequestedFreqs = requestedFreqs;
710        }
711
712        public boolean expectResults() {
713            return mReportType.result;
714        }
715        public boolean expectFullResults() {
716            return mReportType.full;
717        }
718        public final ScanResults[] getResultsToBeDelivered() {
719            return mDeliveredResults;
720        }
721        public Set<Integer> getScanFreqs() {
722            return mRequestedFreqs;
723        }
724    }
725}
726