1 /*
2  * Copyright (C) 2023 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 com.android.systemui.statusbar.pipeline.wifi.data.repository.prod
18 
19 import android.net.wifi.ScanResult
20 import android.net.wifi.WifiManager
21 import android.net.wifi.WifiManager.UNKNOWN_SSID
22 import android.net.wifi.sharedconnectivity.app.NetworkProviderInfo
23 import android.telephony.SubscriptionManager.INVALID_SUBSCRIPTION_ID
24 import android.testing.TestableLooper
25 import androidx.test.filters.SmallTest
26 import com.android.systemui.SysuiTestCase
27 import com.android.systemui.coroutines.collectLastValue
28 import com.android.systemui.flags.FakeFeatureFlags
29 import com.android.systemui.flags.Flags
30 import com.android.systemui.log.LogBuffer
31 import com.android.systemui.log.table.TableLogBuffer
32 import com.android.systemui.statusbar.connectivity.WifiPickerTrackerFactory
33 import com.android.systemui.statusbar.pipeline.shared.data.model.DataActivityModel
34 import com.android.systemui.statusbar.pipeline.wifi.data.repository.prod.WifiRepositoryImpl.Companion.WIFI_NETWORK_DEFAULT
35 import com.android.systemui.statusbar.pipeline.wifi.shared.model.WifiNetworkModel
36 import com.android.systemui.statusbar.pipeline.wifi.shared.model.WifiScanEntry
37 import com.android.systemui.util.concurrency.FakeExecutor
38 import com.android.systemui.util.mockito.any
39 import com.android.systemui.util.mockito.argumentCaptor
40 import com.android.systemui.util.mockito.capture
41 import com.android.systemui.util.mockito.mock
42 import com.android.systemui.util.mockito.whenever
43 import com.android.systemui.util.time.FakeSystemClock
44 import com.android.wifitrackerlib.HotspotNetworkEntry
45 import com.android.wifitrackerlib.HotspotNetworkEntry.DeviceType
46 import com.android.wifitrackerlib.MergedCarrierEntry
47 import com.android.wifitrackerlib.WifiEntry
48 import com.android.wifitrackerlib.WifiEntry.WIFI_LEVEL_MAX
49 import com.android.wifitrackerlib.WifiEntry.WIFI_LEVEL_MIN
50 import com.android.wifitrackerlib.WifiEntry.WIFI_LEVEL_UNREACHABLE
51 import com.android.wifitrackerlib.WifiPickerTracker
52 import com.google.common.truth.Truth.assertThat
53 import kotlinx.coroutines.ExperimentalCoroutinesApi
54 import kotlinx.coroutines.test.StandardTestDispatcher
55 import kotlinx.coroutines.test.TestScope
56 import kotlinx.coroutines.test.runCurrent
57 import kotlinx.coroutines.test.runTest
58 import org.junit.Before
59 import org.junit.Test
60 import org.mockito.Mockito.verify
61 
62 /**
63  * Note: Most of these tests are duplicates of [WifiRepositoryImplTest] tests.
64  *
65  * Any new tests added here may also need to be added to [WifiRepositoryImplTest].
66  */
67 @Suppress("EXPERIMENTAL_IS_NOT_ENABLED")
68 @OptIn(ExperimentalCoroutinesApi::class)
69 @SmallTest
70 @TestableLooper.RunWithLooper(setAsMainLooper = true)
71 class WifiRepositoryViaTrackerLibTest : SysuiTestCase() {
72 
73     // Using lazy means that the class will only be constructed once it's fetched. Because the
74     // repository internally sets some values on construction, we need to set up some test
75     // parameters (like feature flags) *before* construction. Using lazy allows us to do that setup
76     // inside each test case without needing to manually recreate the repository.
77     private val underTest: WifiRepositoryViaTrackerLib by lazy {
78         WifiRepositoryViaTrackerLib(
79             featureFlags,
80             testScope.backgroundScope,
81             executor,
82             dispatcher,
83             wifiPickerTrackerFactory,
84             wifiManager,
85             logger,
86             tableLogger,
87         )
88     }
89 
90     private val executor = FakeExecutor(FakeSystemClock())
91     private val logger = LogBuffer("name", maxSize = 100, logcatEchoTracker = mock())
92     private val featureFlags = FakeFeatureFlags()
93     private val tableLogger = mock<TableLogBuffer>()
94     private val wifiManager =
95         mock<WifiManager>().apply { whenever(this.maxSignalLevel).thenReturn(10) }
96     private val wifiPickerTrackerFactory = mock<WifiPickerTrackerFactory>()
97     private val wifiPickerTracker = mock<WifiPickerTracker>()
98 
99     private val callbackCaptor = argumentCaptor<WifiPickerTracker.WifiPickerTrackerCallback>()
100 
101     private val dispatcher = StandardTestDispatcher()
102     private val testScope = TestScope(dispatcher)
103 
104     @Before
105     fun setUp() {
106         featureFlags.set(Flags.INSTANT_TETHER, false)
107         featureFlags.set(Flags.WIFI_SECONDARY_NETWORKS, false)
108         whenever(wifiPickerTrackerFactory.create(any(), capture(callbackCaptor)))
109             .thenReturn(wifiPickerTracker)
110     }
111 
112     @Test
113     fun wifiPickerTrackerCreation_scansDisabled() =
114         testScope.runTest {
115             collectLastValue(underTest.wifiNetwork)
116             testScope.runCurrent()
117 
118             verify(wifiPickerTracker).disableScanning()
119         }
120 
121     @Test
122     fun isWifiEnabled_enabled_true() =
123         testScope.runTest {
124             val latest by collectLastValue(underTest.isWifiEnabled)
125 
126             whenever(wifiPickerTracker.wifiState).thenReturn(WifiManager.WIFI_STATE_ENABLED)
127             getCallback().onWifiStateChanged()
128 
129             assertThat(latest).isTrue()
130         }
131 
132     @Test
133     fun isWifiEnabled_enabling_false() =
134         testScope.runTest {
135             val latest by collectLastValue(underTest.isWifiEnabled)
136 
137             whenever(wifiPickerTracker.wifiState).thenReturn(WifiManager.WIFI_STATE_ENABLING)
138             getCallback().onWifiStateChanged()
139 
140             assertThat(latest).isFalse()
141         }
142 
143     @Test
144     fun isWifiEnabled_disabling_true() =
145         testScope.runTest {
146             val latest by collectLastValue(underTest.isWifiEnabled)
147 
148             whenever(wifiPickerTracker.wifiState).thenReturn(WifiManager.WIFI_STATE_DISABLING)
149             getCallback().onWifiStateChanged()
150 
151             assertThat(latest).isFalse()
152         }
153 
154     @Test
155     fun isWifiEnabled_disabled_false() =
156         testScope.runTest {
157             val latest by collectLastValue(underTest.isWifiEnabled)
158 
159             whenever(wifiPickerTracker.wifiState).thenReturn(WifiManager.WIFI_STATE_DISABLED)
160             getCallback().onWifiStateChanged()
161 
162             assertThat(latest).isFalse()
163         }
164 
165     @Test
166     fun isWifiEnabled_respondsToUpdates() =
167         testScope.runTest {
168             val latest by collectLastValue(underTest.isWifiEnabled)
169             executor.runAllReady()
170 
171             whenever(wifiPickerTracker.wifiState).thenReturn(WifiManager.WIFI_STATE_ENABLED)
172             getCallback().onWifiStateChanged()
173 
174             assertThat(latest).isTrue()
175 
176             whenever(wifiPickerTracker.wifiState).thenReturn(WifiManager.WIFI_STATE_DISABLED)
177             getCallback().onWifiStateChanged()
178 
179             assertThat(latest).isFalse()
180         }
181 
182     @Test
183     fun isWifiDefault_initiallyGetsDefault() =
184         testScope.runTest { assertThat(underTest.isWifiDefault.value).isFalse() }
185 
186     @Test
187     fun isWifiDefault_wifiNetwork_isTrue() =
188         testScope.runTest {
189             val latest by collectLastValue(underTest.isWifiDefault)
190 
191             val wifiEntry =
192                 mock<WifiEntry>().apply { whenever(this.isDefaultNetwork).thenReturn(true) }
193             whenever(wifiPickerTracker.connectedWifiEntry).thenReturn(wifiEntry)
194             getCallback().onWifiEntriesChanged()
195 
196             assertThat(latest).isTrue()
197         }
198 
199     @Test
200     fun isWifiDefault_carrierMerged_isTrue() =
201         testScope.runTest {
202             val latest by collectLastValue(underTest.isWifiDefault)
203 
204             val wifiEntry =
205                 mock<MergedCarrierEntry>().apply {
206                     whenever(this.isDefaultNetwork).thenReturn(true)
207                 }
208             whenever(wifiPickerTracker.connectedWifiEntry).thenReturn(wifiEntry)
209             getCallback().onWifiEntriesChanged()
210 
211             assertThat(latest).isTrue()
212         }
213 
214     @Test
215     fun isWifiDefault_wifiNetworkNotDefault_isFalse() =
216         testScope.runTest {
217             val latest by collectLastValue(underTest.isWifiDefault)
218 
219             val wifiEntry =
220                 mock<WifiEntry>().apply { whenever(this.isDefaultNetwork).thenReturn(false) }
221             whenever(wifiPickerTracker.connectedWifiEntry).thenReturn(wifiEntry)
222             getCallback().onWifiEntriesChanged()
223 
224             assertThat(latest).isFalse()
225         }
226 
227     @Test
228     fun isWifiDefault_carrierMergedNotDefault_isFalse() =
229         testScope.runTest {
230             val latest by collectLastValue(underTest.isWifiDefault)
231 
232             val wifiEntry =
233                 mock<MergedCarrierEntry>().apply {
234                     whenever(this.isDefaultNetwork).thenReturn(false)
235                 }
236             whenever(wifiPickerTracker.connectedWifiEntry).thenReturn(wifiEntry)
237             getCallback().onWifiEntriesChanged()
238 
239             assertThat(latest).isFalse()
240         }
241 
242     @Test
243     fun isWifiDefault_noWifiNetwork_isFalse() =
244         testScope.runTest {
245             val latest by collectLastValue(underTest.isWifiDefault)
246 
247             // First, add a network
248             val wifiEntry =
249                 mock<WifiEntry>().apply { whenever(this.isDefaultNetwork).thenReturn(true) }
250             whenever(wifiPickerTracker.connectedWifiEntry).thenReturn(wifiEntry)
251             getCallback().onWifiEntriesChanged()
252 
253             assertThat(latest).isTrue()
254 
255             // WHEN the network is lost
256             whenever(wifiPickerTracker.connectedWifiEntry).thenReturn(null)
257             getCallback().onWifiEntriesChanged()
258 
259             // THEN we update to false
260             assertThat(latest).isFalse()
261         }
262 
263     @Test
264     fun wifiNetwork_initiallyGetsDefault() =
265         testScope.runTest {
266             val latest by collectLastValue(underTest.wifiNetwork)
267 
268             assertThat(latest).isEqualTo(WIFI_NETWORK_DEFAULT)
269         }
270 
271     @Test
272     fun wifiNetwork_primaryWifiNetworkAdded_flowHasNetwork() =
273         testScope.runTest {
274             val latest by collectLastValue(underTest.wifiNetwork)
275 
276             val wifiEntry =
277                 mock<WifiEntry>().apply {
278                     whenever(this.isPrimaryNetwork).thenReturn(true)
279                     whenever(this.level).thenReturn(3)
280                     whenever(this.title).thenReturn(TITLE)
281                 }
282             whenever(wifiPickerTracker.connectedWifiEntry).thenReturn(wifiEntry)
283             getCallback().onWifiEntriesChanged()
284 
285             assertThat(latest is WifiNetworkModel.Active).isTrue()
286             val latestActive = latest as WifiNetworkModel.Active
287             assertThat(latestActive.level).isEqualTo(3)
288             assertThat(latestActive.ssid).isEqualTo(TITLE)
289         }
290 
291     @Test
292     fun accessPointInfo_alwaysFalse() =
293         testScope.runTest {
294             val latest by collectLastValue(underTest.wifiNetwork)
295 
296             val wifiEntry =
297                 mock<WifiEntry>().apply {
298                     whenever(this.isPrimaryNetwork).thenReturn(true)
299                     whenever(this.level).thenReturn(3)
300                     whenever(this.title).thenReturn(TITLE)
301                 }
302             whenever(wifiPickerTracker.connectedWifiEntry).thenReturn(wifiEntry)
303             getCallback().onWifiEntriesChanged()
304 
305             assertThat(latest is WifiNetworkModel.Active).isTrue()
306             val latestActive = latest as WifiNetworkModel.Active
307             assertThat(latestActive.isPasspointAccessPoint).isFalse()
308             assertThat(latestActive.isOnlineSignUpForPasspointAccessPoint).isFalse()
309             assertThat(latestActive.passpointProviderFriendlyName).isNull()
310         }
311 
312     @Test
313     fun wifiNetwork_unreachableLevel_inactiveNetwork() =
314         testScope.runTest {
315             val latest by collectLastValue(underTest.wifiNetwork)
316 
317             val wifiEntry =
318                 mock<WifiEntry>().apply {
319                     whenever(this.isPrimaryNetwork).thenReturn(true)
320                     whenever(this.level).thenReturn(WIFI_LEVEL_UNREACHABLE)
321                 }
322             whenever(wifiPickerTracker.connectedWifiEntry).thenReturn(wifiEntry)
323             getCallback().onWifiEntriesChanged()
324 
325             assertThat(latest).isEqualTo(WifiNetworkModel.Inactive)
326         }
327 
328     @Test
329     fun wifiNetwork_levelTooHigh_inactiveNetwork() =
330         testScope.runTest {
331             val latest by collectLastValue(underTest.wifiNetwork)
332 
333             val wifiEntry =
334                 mock<WifiEntry>().apply {
335                     whenever(this.isPrimaryNetwork).thenReturn(true)
336                     whenever(this.level).thenReturn(WIFI_LEVEL_MAX + 1)
337                 }
338             whenever(wifiPickerTracker.connectedWifiEntry).thenReturn(wifiEntry)
339             getCallback().onWifiEntriesChanged()
340 
341             assertThat(latest).isEqualTo(WifiNetworkModel.Inactive)
342         }
343 
344     @Test
345     fun wifiNetwork_levelTooLow_inactiveNetwork() =
346         testScope.runTest {
347             val latest by collectLastValue(underTest.wifiNetwork)
348 
349             val wifiEntry =
350                 mock<WifiEntry>().apply {
351                     whenever(this.isPrimaryNetwork).thenReturn(true)
352                     whenever(this.level).thenReturn(WIFI_LEVEL_MIN - 1)
353                 }
354             whenever(wifiPickerTracker.connectedWifiEntry).thenReturn(wifiEntry)
355             getCallback().onWifiEntriesChanged()
356 
357             assertThat(latest).isEqualTo(WifiNetworkModel.Inactive)
358         }
359 
360     @Test
361     fun wifiNetwork_levelIsMax_activeNetworkWithMaxLevel() =
362         testScope.runTest {
363             val latest by collectLastValue(underTest.wifiNetwork)
364 
365             val wifiEntry =
366                 mock<WifiEntry>().apply {
367                     whenever(this.isPrimaryNetwork).thenReturn(true)
368                     whenever(this.level).thenReturn(WIFI_LEVEL_MAX)
369                 }
370             whenever(wifiPickerTracker.connectedWifiEntry).thenReturn(wifiEntry)
371             getCallback().onWifiEntriesChanged()
372 
373             assertThat(latest).isInstanceOf(WifiNetworkModel.Active::class.java)
374             assertThat((latest as WifiNetworkModel.Active).level).isEqualTo(WIFI_LEVEL_MAX)
375         }
376 
377     @Test
378     fun wifiNetwork_levelIsMin_activeNetworkWithMinLevel() =
379         testScope.runTest {
380             val latest by collectLastValue(underTest.wifiNetwork)
381 
382             val wifiEntry =
383                 mock<WifiEntry>().apply {
384                     whenever(this.isPrimaryNetwork).thenReturn(true)
385                     whenever(this.level).thenReturn(WIFI_LEVEL_MIN)
386                 }
387             whenever(wifiPickerTracker.connectedWifiEntry).thenReturn(wifiEntry)
388             getCallback().onWifiEntriesChanged()
389 
390             assertThat(latest).isInstanceOf(WifiNetworkModel.Active::class.java)
391             assertThat((latest as WifiNetworkModel.Active).level).isEqualTo(WIFI_LEVEL_MIN)
392         }
393 
394     @Test
395     fun wifiNetwork_notHotspot_none() =
396         testScope.runTest {
397             featureFlags.set(Flags.INSTANT_TETHER, true)
398             val latest by collectLastValue(underTest.wifiNetwork)
399 
400             val wifiEntry =
401                 mock<WifiEntry>().apply { whenever(this.isPrimaryNetwork).thenReturn(true) }
402             whenever(wifiPickerTracker.connectedWifiEntry).thenReturn(wifiEntry)
403             getCallback().onWifiEntriesChanged()
404 
405             assertThat((latest as WifiNetworkModel.Active).hotspotDeviceType)
406                 .isEqualTo(WifiNetworkModel.HotspotDeviceType.NONE)
407         }
408 
409     @Test
410     fun wifiNetwork_hotspot_unknown() =
411         testScope.runTest {
412             featureFlags.set(Flags.INSTANT_TETHER, true)
413             val latest by collectLastValue(underTest.wifiNetwork)
414 
415             val wifiEntry = createHotspotWithType(NetworkProviderInfo.DEVICE_TYPE_UNKNOWN)
416             whenever(wifiPickerTracker.connectedWifiEntry).thenReturn(wifiEntry)
417             getCallback().onWifiEntriesChanged()
418 
419             assertThat((latest as WifiNetworkModel.Active).hotspotDeviceType)
420                 .isEqualTo(WifiNetworkModel.HotspotDeviceType.UNKNOWN)
421         }
422 
423     @Test
424     fun wifiNetwork_hotspot_phone() =
425         testScope.runTest {
426             featureFlags.set(Flags.INSTANT_TETHER, true)
427             val latest by collectLastValue(underTest.wifiNetwork)
428 
429             val wifiEntry = createHotspotWithType(NetworkProviderInfo.DEVICE_TYPE_PHONE)
430             whenever(wifiPickerTracker.connectedWifiEntry).thenReturn(wifiEntry)
431             getCallback().onWifiEntriesChanged()
432 
433             assertThat((latest as WifiNetworkModel.Active).hotspotDeviceType)
434                 .isEqualTo(WifiNetworkModel.HotspotDeviceType.PHONE)
435         }
436 
437     @Test
438     fun wifiNetwork_hotspot_tablet() =
439         testScope.runTest {
440             featureFlags.set(Flags.INSTANT_TETHER, true)
441             val latest by collectLastValue(underTest.wifiNetwork)
442 
443             val wifiEntry = createHotspotWithType(NetworkProviderInfo.DEVICE_TYPE_TABLET)
444             whenever(wifiPickerTracker.connectedWifiEntry).thenReturn(wifiEntry)
445             getCallback().onWifiEntriesChanged()
446 
447             assertThat((latest as WifiNetworkModel.Active).hotspotDeviceType)
448                 .isEqualTo(WifiNetworkModel.HotspotDeviceType.TABLET)
449         }
450 
451     @Test
452     fun wifiNetwork_hotspot_laptop() =
453         testScope.runTest {
454             featureFlags.set(Flags.INSTANT_TETHER, true)
455             val latest by collectLastValue(underTest.wifiNetwork)
456 
457             val wifiEntry = createHotspotWithType(NetworkProviderInfo.DEVICE_TYPE_LAPTOP)
458             whenever(wifiPickerTracker.connectedWifiEntry).thenReturn(wifiEntry)
459             getCallback().onWifiEntriesChanged()
460 
461             assertThat((latest as WifiNetworkModel.Active).hotspotDeviceType)
462                 .isEqualTo(WifiNetworkModel.HotspotDeviceType.LAPTOP)
463         }
464 
465     @Test
466     fun wifiNetwork_hotspot_watch() =
467         testScope.runTest {
468             featureFlags.set(Flags.INSTANT_TETHER, true)
469             val latest by collectLastValue(underTest.wifiNetwork)
470 
471             val wifiEntry = createHotspotWithType(NetworkProviderInfo.DEVICE_TYPE_WATCH)
472             whenever(wifiPickerTracker.connectedWifiEntry).thenReturn(wifiEntry)
473             getCallback().onWifiEntriesChanged()
474 
475             assertThat((latest as WifiNetworkModel.Active).hotspotDeviceType)
476                 .isEqualTo(WifiNetworkModel.HotspotDeviceType.WATCH)
477         }
478 
479     @Test
480     fun wifiNetwork_hotspot_auto() =
481         testScope.runTest {
482             featureFlags.set(Flags.INSTANT_TETHER, true)
483             val latest by collectLastValue(underTest.wifiNetwork)
484 
485             val wifiEntry = createHotspotWithType(NetworkProviderInfo.DEVICE_TYPE_AUTO)
486             whenever(wifiPickerTracker.connectedWifiEntry).thenReturn(wifiEntry)
487             getCallback().onWifiEntriesChanged()
488 
489             assertThat((latest as WifiNetworkModel.Active).hotspotDeviceType)
490                 .isEqualTo(WifiNetworkModel.HotspotDeviceType.AUTO)
491         }
492 
493     @Test
494     fun wifiNetwork_hotspot_invalid() =
495         testScope.runTest {
496             featureFlags.set(Flags.INSTANT_TETHER, true)
497             val latest by collectLastValue(underTest.wifiNetwork)
498 
499             val wifiEntry = createHotspotWithType(1234)
500             whenever(wifiPickerTracker.connectedWifiEntry).thenReturn(wifiEntry)
501             getCallback().onWifiEntriesChanged()
502 
503             assertThat((latest as WifiNetworkModel.Active).hotspotDeviceType)
504                 .isEqualTo(WifiNetworkModel.HotspotDeviceType.INVALID)
505         }
506 
507     @Test
508     fun wifiNetwork_hotspot_flagOff_valueNotUsed() =
509         testScope.runTest {
510             // WHEN the flag is off
511             featureFlags.set(Flags.INSTANT_TETHER, false)
512 
513             val latest by collectLastValue(underTest.wifiNetwork)
514 
515             val wifiEntry = createHotspotWithType(NetworkProviderInfo.DEVICE_TYPE_WATCH)
516             whenever(wifiPickerTracker.connectedWifiEntry).thenReturn(wifiEntry)
517             getCallback().onWifiEntriesChanged()
518 
519             // THEN NONE is always used, even if the wifi entry does have a hotspot device type
520             assertThat((latest as WifiNetworkModel.Active).hotspotDeviceType)
521                 .isEqualTo(WifiNetworkModel.HotspotDeviceType.NONE)
522         }
523 
524     @Test
525     fun wifiNetwork_isCarrierMerged_flowHasCarrierMerged() =
526         testScope.runTest {
527             val latest by collectLastValue(underTest.wifiNetwork)
528 
529             val wifiEntry =
530                 mock<MergedCarrierEntry>().apply {
531                     whenever(this.isPrimaryNetwork).thenReturn(true)
532                     whenever(this.level).thenReturn(3)
533                     whenever(this.subscriptionId).thenReturn(567)
534                 }
535             whenever(wifiPickerTracker.connectedWifiEntry).thenReturn(wifiEntry)
536             getCallback().onWifiEntriesChanged()
537 
538             assertThat(latest is WifiNetworkModel.CarrierMerged).isTrue()
539             val latestMerged = latest as WifiNetworkModel.CarrierMerged
540             assertThat(latestMerged.level).isEqualTo(3)
541             assertThat(latestMerged.subscriptionId).isEqualTo(567)
542         }
543 
544     @Test
545     fun wifiNetwork_isCarrierMerged_getsMaxSignalLevel() =
546         testScope.runTest {
547             val latest by collectLastValue(underTest.wifiNetwork)
548 
549             val wifiEntry =
550                 mock<MergedCarrierEntry>().apply {
551                     whenever(this.isPrimaryNetwork).thenReturn(true)
552                 }
553             whenever(wifiPickerTracker.connectedWifiEntry).thenReturn(wifiEntry)
554             whenever(wifiManager.maxSignalLevel).thenReturn(5)
555 
556             getCallback().onWifiEntriesChanged()
557 
558             assertThat(latest is WifiNetworkModel.CarrierMerged).isTrue()
559             val latestMerged = latest as WifiNetworkModel.CarrierMerged
560             // numberOfLevels = maxSignalLevel + 1
561             assertThat(latestMerged.numberOfLevels).isEqualTo(6)
562         }
563 
564     @Test
565     fun wifiNetwork_carrierMergedButInvalidSubId_flowHasInvalid() =
566         testScope.runTest {
567             val latest by collectLastValue(underTest.wifiNetwork)
568 
569             val wifiEntry =
570                 mock<MergedCarrierEntry>().apply {
571                     whenever(this.isPrimaryNetwork).thenReturn(true)
572                     whenever(this.subscriptionId).thenReturn(INVALID_SUBSCRIPTION_ID)
573                 }
574             whenever(wifiPickerTracker.connectedWifiEntry).thenReturn(wifiEntry)
575 
576             getCallback().onWifiEntriesChanged()
577 
578             assertThat(latest).isInstanceOf(WifiNetworkModel.Invalid::class.java)
579         }
580 
581     @Test
582     fun wifiNetwork_notValidated_networkNotValidated() =
583         testScope.runTest {
584             val latest by collectLastValue(underTest.wifiNetwork)
585 
586             val wifiEntry =
587                 mock<WifiEntry>().apply {
588                     whenever(this.isPrimaryNetwork).thenReturn(true)
589                     whenever(this.hasInternetAccess()).thenReturn(false)
590                 }
591             whenever(wifiPickerTracker.connectedWifiEntry).thenReturn(wifiEntry)
592             getCallback().onWifiEntriesChanged()
593 
594             assertThat((latest as WifiNetworkModel.Active).isValidated).isFalse()
595         }
596 
597     @Test
598     fun wifiNetwork_validated_networkValidated() =
599         testScope.runTest {
600             val latest by collectLastValue(underTest.wifiNetwork)
601 
602             val wifiEntry =
603                 mock<WifiEntry>().apply {
604                     whenever(this.isPrimaryNetwork).thenReturn(true)
605                     whenever(this.hasInternetAccess()).thenReturn(true)
606                 }
607             whenever(wifiPickerTracker.connectedWifiEntry).thenReturn(wifiEntry)
608             getCallback().onWifiEntriesChanged()
609 
610             assertThat((latest as WifiNetworkModel.Active).isValidated).isTrue()
611         }
612 
613     @Test
614     fun wifiNetwork_nonPrimaryWifiNetworkAdded_flowHasNoNetwork() =
615         testScope.runTest {
616             val latest by collectLastValue(underTest.wifiNetwork)
617 
618             val wifiEntry =
619                 mock<WifiEntry>().apply { whenever(this.isPrimaryNetwork).thenReturn(false) }
620             whenever(wifiPickerTracker.connectedWifiEntry).thenReturn(wifiEntry)
621             getCallback().onWifiEntriesChanged()
622 
623             assertThat(latest).isEqualTo(WifiNetworkModel.Inactive)
624         }
625 
626     @Test
627     fun wifiNetwork_nonPrimaryCarrierMergedNetworkAdded_flowHasNoNetwork() =
628         testScope.runTest {
629             val latest by collectLastValue(underTest.wifiNetwork)
630 
631             val wifiEntry =
632                 mock<MergedCarrierEntry>().apply {
633                     whenever(this.isPrimaryNetwork).thenReturn(false)
634                 }
635             whenever(wifiPickerTracker.connectedWifiEntry).thenReturn(wifiEntry)
636             getCallback().onWifiEntriesChanged()
637 
638             assertThat(latest).isEqualTo(WifiNetworkModel.Inactive)
639         }
640 
641     @Test
642     fun wifiNetwork_newPrimaryWifiNetwork_flowHasNewNetwork() =
643         testScope.runTest {
644             val latest by collectLastValue(underTest.wifiNetwork)
645 
646             // Start with the original network
647             val wifiEntry =
648                 mock<WifiEntry>().apply {
649                     whenever(this.isPrimaryNetwork).thenReturn(true)
650                     whenever(this.level).thenReturn(3)
651                     whenever(this.title).thenReturn("AB")
652                 }
653             whenever(wifiPickerTracker.connectedWifiEntry).thenReturn(wifiEntry)
654             getCallback().onWifiEntriesChanged()
655 
656             assertThat(latest is WifiNetworkModel.Active).isTrue()
657             var latestActive = latest as WifiNetworkModel.Active
658             assertThat(latestActive.level).isEqualTo(3)
659             assertThat(latestActive.ssid).isEqualTo("AB")
660 
661             // WHEN we update to a new primary network
662             val newWifiEntry =
663                 mock<WifiEntry>().apply {
664                     whenever(this.isPrimaryNetwork).thenReturn(true)
665                     whenever(this.level).thenReturn(4)
666                     whenever(this.title).thenReturn("CD")
667                 }
668             whenever(wifiPickerTracker.connectedWifiEntry).thenReturn(newWifiEntry)
669             getCallback().onWifiEntriesChanged()
670 
671             // THEN we use the new network
672             assertThat(latest is WifiNetworkModel.Active).isTrue()
673             latestActive = latest as WifiNetworkModel.Active
674             assertThat(latestActive.level).isEqualTo(4)
675             assertThat(latestActive.ssid).isEqualTo("CD")
676         }
677 
678     @Test
679     fun wifiNetwork_noCurrentNetwork_networkLost_flowHasNoNetwork() =
680         testScope.runTest {
681             val latest by collectLastValue(underTest.wifiNetwork)
682 
683             // WHEN we receive a null network without any networks beforehand
684             whenever(wifiPickerTracker.connectedWifiEntry).thenReturn(null)
685             getCallback().onWifiEntriesChanged()
686 
687             // THEN there's no crash and we still have no network
688             assertThat(latest is WifiNetworkModel.Inactive).isTrue()
689         }
690 
691     @Test
692     fun wifiNetwork_currentActiveNetworkLost_flowHasNoNetwork() =
693         testScope.runTest {
694             val latest by collectLastValue(underTest.wifiNetwork)
695 
696             val wifiEntry =
697                 mock<WifiEntry>().apply {
698                     whenever(this.isPrimaryNetwork).thenReturn(true)
699                     whenever(this.title).thenReturn(TITLE)
700                 }
701             whenever(wifiPickerTracker.connectedWifiEntry).thenReturn(wifiEntry)
702             getCallback().onWifiEntriesChanged()
703 
704             assertThat((latest as WifiNetworkModel.Active).ssid).isEqualTo(TITLE)
705 
706             // WHEN we lose our current network
707             whenever(wifiPickerTracker.connectedWifiEntry).thenReturn(null)
708             getCallback().onWifiEntriesChanged()
709 
710             // THEN we update to no network
711             assertThat(latest is WifiNetworkModel.Inactive).isTrue()
712         }
713 
714     /** Possible regression test for b/278618530. */
715     @Test
716     fun wifiNetwork_currentCarrierMergedNetworkLost_flowHasNoNetwork() =
717         testScope.runTest {
718             val latest by collectLastValue(underTest.wifiNetwork)
719 
720             val wifiEntry =
721                 mock<MergedCarrierEntry>().apply {
722                     whenever(this.isPrimaryNetwork).thenReturn(true)
723                     whenever(this.level).thenReturn(3)
724                 }
725             whenever(wifiPickerTracker.connectedWifiEntry).thenReturn(wifiEntry)
726             getCallback().onWifiEntriesChanged()
727 
728             assertThat(latest is WifiNetworkModel.CarrierMerged).isTrue()
729             assertThat((latest as WifiNetworkModel.CarrierMerged).level).isEqualTo(3)
730 
731             // WHEN we lose our current network
732             whenever(wifiPickerTracker.connectedWifiEntry).thenReturn(null)
733             getCallback().onWifiEntriesChanged()
734 
735             // THEN we update to no network
736             assertThat(latest is WifiNetworkModel.Inactive).isTrue()
737         }
738 
739     /** Regression test for b/244173280. */
740     @Test
741     fun wifiNetwork_multipleSubscribers_newSubscribersGetCurrentValue() =
742         testScope.runTest {
743             val latest1 by collectLastValue(underTest.wifiNetwork)
744 
745             val wifiEntry =
746                 mock<WifiEntry>().apply {
747                     whenever(this.isPrimaryNetwork).thenReturn(true)
748                     whenever(this.level).thenReturn(1)
749                     whenever(this.title).thenReturn(TITLE)
750                 }
751             whenever(wifiPickerTracker.connectedWifiEntry).thenReturn(wifiEntry)
752             getCallback().onWifiEntriesChanged()
753 
754             assertThat(latest1 is WifiNetworkModel.Active).isTrue()
755             val latest1Active = latest1 as WifiNetworkModel.Active
756             assertThat(latest1Active.level).isEqualTo(1)
757             assertThat(latest1Active.ssid).isEqualTo(TITLE)
758 
759             // WHEN we add a second subscriber after having already emitted a value
760             val latest2 by collectLastValue(underTest.wifiNetwork)
761 
762             // THEN the second subscribe receives the already-emitted value
763             assertThat(latest2 is WifiNetworkModel.Active).isTrue()
764             val latest2Active = latest2 as WifiNetworkModel.Active
765             assertThat(latest2Active.level).isEqualTo(1)
766             assertThat(latest2Active.ssid).isEqualTo(TITLE)
767         }
768 
769     @Test
770     fun secondaryNetworks_activeEntriesEmpty_isEmpty() =
771         testScope.runTest {
772             featureFlags.set(Flags.WIFI_SECONDARY_NETWORKS, true)
773             val latest by collectLastValue(underTest.secondaryNetworks)
774 
775             whenever(wifiPickerTracker.activeWifiEntries).thenReturn(listOf())
776 
777             getCallback().onWifiEntriesChanged()
778 
779             assertThat(latest).isEmpty()
780         }
781 
782     @Test
783     fun secondaryNetworks_oneActiveEntry_hasOne() =
784         testScope.runTest {
785             featureFlags.set(Flags.WIFI_SECONDARY_NETWORKS, true)
786             val latest by collectLastValue(underTest.secondaryNetworks)
787 
788             val wifiEntry = mock<WifiEntry>()
789             whenever(wifiPickerTracker.activeWifiEntries).thenReturn(listOf(wifiEntry))
790 
791             getCallback().onWifiEntriesChanged()
792 
793             assertThat(latest).hasSize(1)
794         }
795 
796     @Test
797     fun secondaryNetworks_multipleActiveEntries_hasMultiple() =
798         testScope.runTest {
799             featureFlags.set(Flags.WIFI_SECONDARY_NETWORKS, true)
800             val latest by collectLastValue(underTest.secondaryNetworks)
801 
802             val wifiEntry1 = mock<WifiEntry>()
803             val wifiEntry2 = mock<WifiEntry>()
804             whenever(wifiPickerTracker.activeWifiEntries).thenReturn(listOf(wifiEntry1, wifiEntry2))
805 
806             getCallback().onWifiEntriesChanged()
807 
808             assertThat(latest).hasSize(2)
809         }
810 
811     @Test
812     fun secondaryNetworks_mapsToInactive() =
813         testScope.runTest {
814             featureFlags.set(Flags.WIFI_SECONDARY_NETWORKS, true)
815             val latest by collectLastValue(underTest.secondaryNetworks)
816 
817             val inactiveEntry =
818                 mock<WifiEntry>().apply { whenever(this.level).thenReturn(WIFI_LEVEL_UNREACHABLE) }
819             whenever(wifiPickerTracker.activeWifiEntries).thenReturn(listOf(inactiveEntry))
820 
821             getCallback().onWifiEntriesChanged()
822 
823             assertThat(latest).hasSize(1)
824             assertThat(latest!![0]).isInstanceOf(WifiNetworkModel.Inactive::class.java)
825         }
826 
827     @Test
828     fun secondaryNetworks_mapsToActive() =
829         testScope.runTest {
830             featureFlags.set(Flags.WIFI_SECONDARY_NETWORKS, true)
831             val latest by collectLastValue(underTest.secondaryNetworks)
832 
833             val activeEntry = mock<WifiEntry>().apply { whenever(this.level).thenReturn(2) }
834             whenever(wifiPickerTracker.activeWifiEntries).thenReturn(listOf(activeEntry))
835 
836             getCallback().onWifiEntriesChanged()
837 
838             assertThat(latest).hasSize(1)
839             assertThat(latest!![0]).isInstanceOf(WifiNetworkModel.Active::class.java)
840             assertThat((latest!![0] as WifiNetworkModel.Active).level).isEqualTo(2)
841         }
842 
843     @Test
844     fun secondaryNetworks_mapsToCarrierMerged() =
845         testScope.runTest {
846             featureFlags.set(Flags.WIFI_SECONDARY_NETWORKS, true)
847             val latest by collectLastValue(underTest.secondaryNetworks)
848 
849             val carrierMergedEntry =
850                 mock<MergedCarrierEntry>().apply { whenever(this.level).thenReturn(3) }
851             whenever(wifiPickerTracker.activeWifiEntries).thenReturn(listOf(carrierMergedEntry))
852 
853             getCallback().onWifiEntriesChanged()
854 
855             assertThat(latest).hasSize(1)
856             assertThat(latest!![0]).isInstanceOf(WifiNetworkModel.CarrierMerged::class.java)
857             assertThat((latest!![0] as WifiNetworkModel.CarrierMerged).level).isEqualTo(3)
858         }
859 
860     @Test
861     fun secondaryNetworks_mapsMultipleInOrder() =
862         testScope.runTest {
863             featureFlags.set(Flags.WIFI_SECONDARY_NETWORKS, true)
864             val latest by collectLastValue(underTest.secondaryNetworks)
865 
866             val activeEntry = mock<WifiEntry>().apply { whenever(this.level).thenReturn(2) }
867             val carrierMergedEntry =
868                 mock<MergedCarrierEntry>().apply { whenever(this.level).thenReturn(3) }
869             whenever(wifiPickerTracker.activeWifiEntries)
870                 .thenReturn(listOf(activeEntry, carrierMergedEntry))
871 
872             getCallback().onWifiEntriesChanged()
873 
874             assertThat(latest!![0]).isInstanceOf(WifiNetworkModel.Active::class.java)
875             assertThat((latest!![0] as WifiNetworkModel.Active).level).isEqualTo(2)
876             assertThat(latest!![1]).isInstanceOf(WifiNetworkModel.CarrierMerged::class.java)
877             assertThat((latest!![1] as WifiNetworkModel.CarrierMerged).level).isEqualTo(3)
878         }
879 
880     @Test
881     fun secondaryNetworks_filtersOutConnectedEntry() =
882         testScope.runTest {
883             featureFlags.set(Flags.WIFI_SECONDARY_NETWORKS, true)
884             val latest by collectLastValue(underTest.secondaryNetworks)
885 
886             val connectedEntry = mock<WifiEntry>().apply { whenever(this.level).thenReturn(1) }
887             val secondaryEntry1 = mock<WifiEntry>().apply { whenever(this.level).thenReturn(2) }
888             val secondaryEntry2 = mock<WifiEntry>().apply { whenever(this.level).thenReturn(3) }
889             // WHEN the active list has both a primary and secondary networks
890             whenever(wifiPickerTracker.activeWifiEntries)
891                 .thenReturn(listOf(connectedEntry, secondaryEntry1, secondaryEntry2))
892             whenever(wifiPickerTracker.connectedWifiEntry).thenReturn(connectedEntry)
893 
894             getCallback().onWifiEntriesChanged()
895 
896             // THEN only the secondary networks are included
897             assertThat(latest).hasSize(2)
898             assertThat((latest!![0] as WifiNetworkModel.Active).level).isEqualTo(2)
899             assertThat((latest!![1] as WifiNetworkModel.Active).level).isEqualTo(3)
900         }
901 
902     @Test
903     fun secondaryNetworks_noConnectedEntry_hasAllActiveEntries() =
904         testScope.runTest {
905             featureFlags.set(Flags.WIFI_SECONDARY_NETWORKS, true)
906             val latest by collectLastValue(underTest.secondaryNetworks)
907 
908             val secondaryEntry1 = mock<WifiEntry>().apply { whenever(this.level).thenReturn(2) }
909             val secondaryEntry2 = mock<WifiEntry>().apply { whenever(this.level).thenReturn(3) }
910             whenever(wifiPickerTracker.activeWifiEntries)
911                 .thenReturn(listOf(secondaryEntry1, secondaryEntry2))
912             whenever(wifiPickerTracker.connectedWifiEntry).thenReturn(null)
913 
914             getCallback().onWifiEntriesChanged()
915 
916             assertThat(latest).hasSize(2)
917             assertThat((latest!![0] as WifiNetworkModel.Active).level).isEqualTo(2)
918             assertThat((latest!![1] as WifiNetworkModel.Active).level).isEqualTo(3)
919         }
920 
921     @Test
922     fun secondaryNetworks_filtersOutPrimaryNetwork() =
923         testScope.runTest {
924             featureFlags.set(Flags.WIFI_SECONDARY_NETWORKS, true)
925             val latest by collectLastValue(underTest.secondaryNetworks)
926 
927             val primaryEntry =
928                 mock<WifiEntry>().apply {
929                     whenever(this.isPrimaryNetwork).thenReturn(true)
930                     whenever(this.level).thenReturn(1)
931                 }
932             val secondaryEntry1 = mock<WifiEntry>().apply { whenever(this.level).thenReturn(2) }
933             val secondaryEntry2 = mock<WifiEntry>().apply { whenever(this.level).thenReturn(3) }
934             // WHEN the active list has both a primary and secondary networks
935             whenever(wifiPickerTracker.activeWifiEntries)
936                 .thenReturn(listOf(secondaryEntry1, primaryEntry, secondaryEntry2))
937 
938             getCallback().onWifiEntriesChanged()
939 
940             // THEN only the secondary networks are included
941             assertThat(latest).hasSize(2)
942             assertThat((latest!![0] as WifiNetworkModel.Active).level).isEqualTo(2)
943             assertThat((latest!![1] as WifiNetworkModel.Active).level).isEqualTo(3)
944         }
945 
946     @Test
947     fun secondaryNetworks_flagOff_noNetworks() =
948         testScope.runTest {
949             featureFlags.set(Flags.WIFI_SECONDARY_NETWORKS, false)
950             val latest by collectLastValue(underTest.secondaryNetworks)
951 
952             val wifiEntry = mock<WifiEntry>()
953             whenever(wifiPickerTracker.activeWifiEntries).thenReturn(listOf(wifiEntry))
954 
955             getCallback().onWifiEntriesChanged()
956 
957             assertThat(latest).isEmpty()
958         }
959 
960     @Test
961     fun isWifiConnectedWithValidSsid_inactiveNetwork_false() =
962         testScope.runTest {
963             collectLastValue(underTest.wifiNetwork)
964 
965             whenever(wifiPickerTracker.connectedWifiEntry).thenReturn(null)
966             getCallback().onWifiEntriesChanged()
967 
968             assertThat(underTest.isWifiConnectedWithValidSsid()).isFalse()
969         }
970 
971     @Test
972     fun isWifiConnectedWithValidSsid_nonPrimaryNetwork_false() =
973         testScope.runTest {
974             collectLastValue(underTest.wifiNetwork)
975 
976             val wifiEntry =
977                 mock<WifiEntry>().apply { whenever(this.isPrimaryNetwork).thenReturn(false) }
978             whenever(wifiPickerTracker.connectedWifiEntry).thenReturn(wifiEntry)
979             getCallback().onWifiEntriesChanged()
980             testScope.runCurrent()
981 
982             assertThat(underTest.isWifiConnectedWithValidSsid()).isFalse()
983         }
984 
985     @Test
986     fun isWifiConnectedWithValidSsid_carrierMergedNetwork_false() =
987         testScope.runTest {
988             collectLastValue(underTest.wifiNetwork)
989 
990             val wifiEntry =
991                 mock<MergedCarrierEntry>().apply {
992                     whenever(this.isPrimaryNetwork).thenReturn(true)
993                 }
994             whenever(wifiPickerTracker.connectedWifiEntry).thenReturn(wifiEntry)
995             getCallback().onWifiEntriesChanged()
996             testScope.runCurrent()
997 
998             assertThat(underTest.isWifiConnectedWithValidSsid()).isFalse()
999         }
1000 
1001     @Test
1002     fun isWifiConnectedWithValidSsid_invalidNetwork_false() =
1003         testScope.runTest {
1004             collectLastValue(underTest.wifiNetwork)
1005 
1006             val wifiEntry =
1007                 mock<MergedCarrierEntry>().apply {
1008                     whenever(this.isPrimaryNetwork).thenReturn(true)
1009                     whenever(this.subscriptionId).thenReturn(INVALID_SUBSCRIPTION_ID)
1010                 }
1011             whenever(wifiPickerTracker.connectedWifiEntry).thenReturn(wifiEntry)
1012             getCallback().onWifiEntriesChanged()
1013             testScope.runCurrent()
1014 
1015             assertThat(underTest.isWifiConnectedWithValidSsid()).isFalse()
1016         }
1017 
1018     @Test
1019     fun isWifiConnectedWithValidSsid_activeNetwork_nullTitle_false() =
1020         testScope.runTest {
1021             collectLastValue(underTest.wifiNetwork)
1022 
1023             val wifiEntry =
1024                 mock<WifiEntry>().apply {
1025                     whenever(this.isPrimaryNetwork).thenReturn(true)
1026                     whenever(this.title).thenReturn(null)
1027                 }
1028             whenever(wifiPickerTracker.connectedWifiEntry).thenReturn(wifiEntry)
1029             getCallback().onWifiEntriesChanged()
1030             testScope.runCurrent()
1031 
1032             assertThat(underTest.isWifiConnectedWithValidSsid()).isFalse()
1033         }
1034 
1035     @Test
1036     fun isWifiConnectedWithValidSsid_activeNetwork_unknownTitle_false() =
1037         testScope.runTest {
1038             collectLastValue(underTest.wifiNetwork)
1039 
1040             val wifiEntry =
1041                 mock<WifiEntry>().apply {
1042                     whenever(this.isPrimaryNetwork).thenReturn(true)
1043                     whenever(this.title).thenReturn(UNKNOWN_SSID)
1044                 }
1045             whenever(wifiPickerTracker.connectedWifiEntry).thenReturn(wifiEntry)
1046             getCallback().onWifiEntriesChanged()
1047             testScope.runCurrent()
1048 
1049             assertThat(underTest.isWifiConnectedWithValidSsid()).isFalse()
1050         }
1051 
1052     @Test
1053     fun isWifiConnectedWithValidSsid_activeNetwork_validTitle_true() =
1054         testScope.runTest {
1055             collectLastValue(underTest.wifiNetwork)
1056 
1057             val wifiEntry =
1058                 mock<WifiEntry>().apply {
1059                     whenever(this.isPrimaryNetwork).thenReturn(true)
1060                     whenever(this.title).thenReturn("fakeSsid")
1061                 }
1062             whenever(wifiPickerTracker.connectedWifiEntry).thenReturn(wifiEntry)
1063             getCallback().onWifiEntriesChanged()
1064             testScope.runCurrent()
1065 
1066             assertThat(underTest.isWifiConnectedWithValidSsid()).isTrue()
1067         }
1068 
1069     @Test
1070     fun isWifiConnectedWithValidSsid_activeToInactive_trueToFalse() =
1071         testScope.runTest {
1072             collectLastValue(underTest.wifiNetwork)
1073 
1074             // Start with active
1075             val wifiEntry =
1076                 mock<WifiEntry>().apply {
1077                     whenever(this.isPrimaryNetwork).thenReturn(true)
1078                     whenever(this.title).thenReturn("fakeSsid")
1079                 }
1080             whenever(wifiPickerTracker.connectedWifiEntry).thenReturn(wifiEntry)
1081             getCallback().onWifiEntriesChanged()
1082             testScope.runCurrent()
1083 
1084             assertThat(underTest.isWifiConnectedWithValidSsid()).isTrue()
1085 
1086             // WHEN the network is lost
1087             whenever(wifiPickerTracker.connectedWifiEntry).thenReturn(null)
1088             getCallback().onWifiEntriesChanged()
1089             testScope.runCurrent()
1090 
1091             // THEN the isWifiConnected updates
1092             assertThat(underTest.isWifiConnectedWithValidSsid()).isFalse()
1093         }
1094 
1095     @Test
1096     fun wifiActivity_callbackGivesNone_activityFlowHasNone() =
1097         testScope.runTest {
1098             val latest by collectLastValue(underTest.wifiActivity)
1099 
1100             getTrafficStateCallback()
1101                 .onStateChanged(WifiManager.TrafficStateCallback.DATA_ACTIVITY_NONE)
1102 
1103             assertThat(latest)
1104                 .isEqualTo(DataActivityModel(hasActivityIn = false, hasActivityOut = false))
1105         }
1106 
1107     @Test
1108     fun wifiActivity_callbackGivesIn_activityFlowHasIn() =
1109         testScope.runTest {
1110             val latest by collectLastValue(underTest.wifiActivity)
1111 
1112             getTrafficStateCallback()
1113                 .onStateChanged(WifiManager.TrafficStateCallback.DATA_ACTIVITY_IN)
1114 
1115             assertThat(latest)
1116                 .isEqualTo(DataActivityModel(hasActivityIn = true, hasActivityOut = false))
1117         }
1118 
1119     @Test
1120     fun wifiActivity_callbackGivesOut_activityFlowHasOut() =
1121         testScope.runTest {
1122             val latest by collectLastValue(underTest.wifiActivity)
1123 
1124             getTrafficStateCallback()
1125                 .onStateChanged(WifiManager.TrafficStateCallback.DATA_ACTIVITY_OUT)
1126 
1127             assertThat(latest)
1128                 .isEqualTo(DataActivityModel(hasActivityIn = false, hasActivityOut = true))
1129         }
1130 
1131     @Test
1132     fun wifiActivity_callbackGivesInout_activityFlowHasInAndOut() =
1133         testScope.runTest {
1134             val latest by collectLastValue(underTest.wifiActivity)
1135 
1136             getTrafficStateCallback()
1137                 .onStateChanged(WifiManager.TrafficStateCallback.DATA_ACTIVITY_INOUT)
1138 
1139             assertThat(latest)
1140                 .isEqualTo(DataActivityModel(hasActivityIn = true, hasActivityOut = true))
1141         }
1142 
1143     @Test
1144     fun wifiScanResults_containsSsidList() =
1145         testScope.runTest {
1146             val latest by collectLastValue(underTest.wifiScanResults)
1147 
1148             val scanResults =
1149                 listOf(
1150                     ScanResult().also { it.SSID = "ssid 1" },
1151                     ScanResult().also { it.SSID = "ssid 2" },
1152                     ScanResult().also { it.SSID = "ssid 3" },
1153                     ScanResult().also { it.SSID = "ssid 4" },
1154                     ScanResult().also { it.SSID = "ssid 5" },
1155                 )
1156             whenever(wifiManager.scanResults).thenReturn(scanResults)
1157             getScanResultsCallback().onScanResultsAvailable()
1158 
1159             val expected =
1160                 listOf(
1161                     WifiScanEntry(ssid = "ssid 1"),
1162                     WifiScanEntry(ssid = "ssid 2"),
1163                     WifiScanEntry(ssid = "ssid 3"),
1164                     WifiScanEntry(ssid = "ssid 4"),
1165                     WifiScanEntry(ssid = "ssid 5"),
1166                 )
1167 
1168             assertThat(latest).isEqualTo(expected)
1169         }
1170 
1171     @Test
1172     fun wifiScanResults_updates() =
1173         testScope.runTest {
1174             val latest by collectLastValue(underTest.wifiScanResults)
1175 
1176             var scanResults =
1177                 listOf(
1178                     ScanResult().also { it.SSID = "ssid 1" },
1179                     ScanResult().also { it.SSID = "ssid 2" },
1180                     ScanResult().also { it.SSID = "ssid 3" },
1181                     ScanResult().also { it.SSID = "ssid 4" },
1182                     ScanResult().also { it.SSID = "ssid 5" },
1183                 )
1184             whenever(wifiManager.scanResults).thenReturn(scanResults)
1185             getScanResultsCallback().onScanResultsAvailable()
1186 
1187             // New scan representing no results
1188             scanResults = listOf()
1189             whenever(wifiManager.scanResults).thenReturn(scanResults)
1190             getScanResultsCallback().onScanResultsAvailable()
1191 
1192             assertThat(latest).isEmpty()
1193         }
1194 
1195     private fun getCallback(): WifiPickerTracker.WifiPickerTrackerCallback {
1196         testScope.runCurrent()
1197         return callbackCaptor.value
1198     }
1199 
1200     private fun getTrafficStateCallback(): WifiManager.TrafficStateCallback {
1201         testScope.runCurrent()
1202         val callbackCaptor = argumentCaptor<WifiManager.TrafficStateCallback>()
1203         verify(wifiManager).registerTrafficStateCallback(any(), callbackCaptor.capture())
1204         return callbackCaptor.value!!
1205     }
1206 
1207     private fun createHotspotWithType(@DeviceType type: Int): HotspotNetworkEntry {
1208         return mock<HotspotNetworkEntry>().apply {
1209             whenever(this.isPrimaryNetwork).thenReturn(true)
1210             whenever(this.deviceType).thenReturn(type)
1211         }
1212     }
1213 
1214     private fun getScanResultsCallback(): WifiManager.ScanResultsCallback {
1215         testScope.runCurrent()
1216         val callbackCaptor = argumentCaptor<WifiManager.ScanResultsCallback>()
1217         verify(wifiManager).registerScanResultsCallback(any(), callbackCaptor.capture())
1218         return callbackCaptor.value!!
1219     }
1220 
1221     private companion object {
1222         const val TITLE = "AB"
1223     }
1224 }
1225