Merge changes If888f060,I6924d3e1,I8290fe89 into main
* changes:
[SB][Wifi] Rename WifiRepositoryViaTrackerLib to WifiRepositoryImpl.
[SB][Wifi] Remove WIFI_TRACKER_LIB_FOR_WIFI_ICON flag and old repo.
[SB][Wifi] Update tests to use new trackerlib repo instead of old repo.
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/FakeWifiRepository.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/FakeWifiRepository.kt
index 106b548..97c8d5f 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/FakeWifiRepository.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/FakeWifiRepository.kt
@@ -17,7 +17,7 @@
package com.android.systemui.statusbar.pipeline.wifi.data.repository
import com.android.systemui.statusbar.pipeline.shared.data.model.DataActivityModel
-import com.android.systemui.statusbar.pipeline.wifi.data.repository.prod.WifiRepositoryHelper.ACTIVITY_DEFAULT
+import com.android.systemui.statusbar.pipeline.wifi.data.repository.prod.WifiRepositoryImpl.Companion.ACTIVITY_DEFAULT
import com.android.systemui.statusbar.pipeline.wifi.shared.model.WifiNetworkModel
import com.android.systemui.statusbar.pipeline.wifi.shared.model.WifiScanEntry
import kotlinx.coroutines.flow.MutableStateFlow
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/WifiRepositorySwitcherTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/WifiRepositorySwitcherTest.kt
index d06a6e2..a6fdd03 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/WifiRepositorySwitcherTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/WifiRepositorySwitcherTest.kt
@@ -16,24 +16,28 @@
package com.android.systemui.statusbar.pipeline.wifi.data.repository
-import android.net.ConnectivityManager
import android.net.wifi.WifiManager
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.demomode.DemoMode
import com.android.systemui.demomode.DemoModeController
+import com.android.systemui.flags.FakeFeatureFlagsClassic
+import com.android.systemui.flags.Flags
+import com.android.systemui.log.LogBuffer
import com.android.systemui.log.table.TableLogBuffer
-import com.android.systemui.statusbar.pipeline.shared.data.repository.FakeConnectivityRepository
+import com.android.systemui.statusbar.connectivity.WifiPickerTrackerFactory
import com.android.systemui.statusbar.pipeline.wifi.data.repository.demo.DemoModeWifiDataSource
import com.android.systemui.statusbar.pipeline.wifi.data.repository.demo.DemoWifiRepository
import com.android.systemui.statusbar.pipeline.wifi.data.repository.demo.model.FakeWifiEventModel
import com.android.systemui.statusbar.pipeline.wifi.data.repository.prod.WifiRepositoryImpl
-import com.android.systemui.statusbar.pipeline.wifi.shared.WifiInputLogger
import com.android.systemui.util.concurrency.FakeExecutor
+import com.android.systemui.util.mockito.any
import com.android.systemui.util.mockito.kotlinArgumentCaptor
+import com.android.systemui.util.mockito.mock
import com.android.systemui.util.mockito.whenever
import com.android.systemui.util.time.FakeSystemClock
+import com.android.wifitrackerlib.WifiPickerTracker
import com.google.common.truth.Truth.assertThat
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.flow.MutableStateFlow
@@ -59,14 +63,21 @@
private lateinit var demoImpl: DemoWifiRepository
@Mock private lateinit var demoModeController: DemoModeController
- @Mock private lateinit var logger: WifiInputLogger
@Mock private lateinit var tableLogger: TableLogBuffer
- @Mock private lateinit var connectivityManager: ConnectivityManager
@Mock private lateinit var wifiManager: WifiManager
@Mock private lateinit var demoModeWifiDataSource: DemoModeWifiDataSource
+ @Mock private lateinit var wifiPickerTrackerFactory: WifiPickerTrackerFactory
+ @Mock private lateinit var wifiPickerTracker: WifiPickerTracker
+
+ private val wifiLogBuffer = LogBuffer("wifi", maxSize = 100, logcatEchoTracker = mock())
private val demoModelFlow = MutableStateFlow<FakeWifiEventModel?>(null)
private val mainExecutor = FakeExecutor(FakeSystemClock())
+ private val featureFlags =
+ FakeFeatureFlagsClassic().also {
+ it.set(Flags.INSTANT_TETHER, true)
+ it.set(Flags.WIFI_SECONDARY_NETWORKS, true)
+ }
private val testDispatcher = UnconfinedTestDispatcher()
private val testScope = TestScope(testDispatcher)
@@ -78,17 +89,18 @@
// Never start in demo mode
whenever(demoModeController.isInDemoMode).thenReturn(false)
+ whenever(wifiPickerTrackerFactory.create(any(), any(), any())).thenReturn(wifiPickerTracker)
+
realImpl =
WifiRepositoryImpl(
- fakeBroadcastDispatcher,
- connectivityManager,
- FakeConnectivityRepository(),
- logger,
- tableLogger,
+ featureFlags,
+ testScope.backgroundScope,
mainExecutor,
testDispatcher,
- testScope.backgroundScope,
+ wifiPickerTrackerFactory,
wifiManager,
+ wifiLogBuffer,
+ tableLogger,
)
whenever(demoModeWifiDataSource.wifiEvents).thenReturn(demoModelFlow)
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/prod/WifiRepositoryImplTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/prod/WifiRepositoryImplTest.kt
deleted file mode 100644
index cf20ba8..0000000
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/prod/WifiRepositoryImplTest.kt
+++ /dev/null
@@ -1,1323 +0,0 @@
-/*
- * Copyright (C) 2022 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.systemui.statusbar.pipeline.wifi.data.repository.prod
-
-import android.content.Intent
-import android.net.ConnectivityManager
-import android.net.Network
-import android.net.NetworkCapabilities
-import android.net.NetworkCapabilities.NET_CAPABILITY_VALIDATED
-import android.net.NetworkCapabilities.TRANSPORT_CELLULAR
-import android.net.NetworkCapabilities.TRANSPORT_VPN
-import android.net.NetworkCapabilities.TRANSPORT_WIFI
-import android.net.TransportInfo
-import android.net.VpnTransportInfo
-import android.net.vcn.VcnTransportInfo
-import android.net.wifi.ScanResult
-import android.net.wifi.WifiInfo
-import android.net.wifi.WifiManager
-import android.net.wifi.WifiManager.TrafficStateCallback
-import android.net.wifi.WifiManager.UNKNOWN_SSID
-import android.telephony.SubscriptionManager.INVALID_SUBSCRIPTION_ID
-import androidx.test.ext.junit.runners.AndroidJUnit4
-import androidx.test.filters.SmallTest
-import com.android.systemui.SysuiTestCase
-import com.android.systemui.coroutines.collectLastValue
-import com.android.systemui.log.table.TableLogBuffer
-import com.android.systemui.statusbar.pipeline.shared.data.model.ConnectivitySlots
-import com.android.systemui.statusbar.pipeline.shared.data.model.DataActivityModel
-import com.android.systemui.statusbar.pipeline.shared.data.repository.ConnectivityRepository
-import com.android.systemui.statusbar.pipeline.shared.data.repository.ConnectivityRepositoryImpl
-import com.android.systemui.statusbar.pipeline.wifi.data.repository.prod.WifiRepositoryImpl.Companion.WIFI_NETWORK_DEFAULT
-import com.android.systemui.statusbar.pipeline.wifi.shared.WifiInputLogger
-import com.android.systemui.statusbar.pipeline.wifi.shared.model.WifiNetworkModel
-import com.android.systemui.statusbar.pipeline.wifi.shared.model.WifiScanEntry
-import com.android.systemui.util.concurrency.FakeExecutor
-import com.android.systemui.util.mockito.any
-import com.android.systemui.util.mockito.argumentCaptor
-import com.android.systemui.util.mockito.mock
-import com.android.systemui.util.mockito.whenever
-import com.android.systemui.util.time.FakeSystemClock
-import com.google.common.truth.Truth.assertThat
-import java.util.concurrent.Executor
-import kotlinx.coroutines.ExperimentalCoroutinesApi
-import kotlinx.coroutines.test.StandardTestDispatcher
-import kotlinx.coroutines.test.TestScope
-import kotlinx.coroutines.test.runCurrent
-import kotlinx.coroutines.test.runTest
-import org.junit.Before
-import org.junit.Test
-import org.junit.runner.RunWith
-import org.mockito.Mock
-import org.mockito.Mockito.verify
-import org.mockito.MockitoAnnotations
-
-/**
- * Note: Any new tests added here may also need to be added to [WifiRepositoryViaTrackerLibTest].
- */
-@Suppress("EXPERIMENTAL_IS_NOT_ENABLED")
-@OptIn(ExperimentalCoroutinesApi::class)
-@SmallTest
-@RunWith(AndroidJUnit4::class)
-class WifiRepositoryImplTest : SysuiTestCase() {
-
- private lateinit var underTest: WifiRepositoryImpl
-
- @Mock private lateinit var logger: WifiInputLogger
- @Mock private lateinit var tableLogger: TableLogBuffer
- @Mock private lateinit var connectivityManager: ConnectivityManager
- @Mock private lateinit var wifiManager: WifiManager
- private lateinit var executor: Executor
- private lateinit var connectivityRepository: ConnectivityRepository
-
- private val dispatcher = StandardTestDispatcher()
- private val testScope = TestScope(dispatcher)
-
- @Before
- fun setUp() {
- MockitoAnnotations.initMocks(this)
- executor = FakeExecutor(FakeSystemClock())
-
- connectivityRepository =
- ConnectivityRepositoryImpl(
- connectivityManager,
- ConnectivitySlots(context),
- context,
- mock(),
- mock(),
- testScope.backgroundScope,
- mock(),
- )
-
- underTest = createRepo()
- }
-
- @Test
- fun isWifiEnabled_initiallyGetsWifiManagerValue() =
- testScope.runTest {
- whenever(wifiManager.isWifiEnabled).thenReturn(true)
-
- underTest = createRepo()
- testScope.runCurrent()
-
- assertThat(underTest.isWifiEnabled.value).isTrue()
- }
-
- @Test
- fun isWifiEnabled_networkCapabilitiesChanged_valueUpdated() =
- testScope.runTest {
- collectLastValue(underTest.wifiNetwork)
- val latest by collectLastValue(underTest.isWifiEnabled)
-
- whenever(wifiManager.isWifiEnabled).thenReturn(true)
- getNetworkCallback()
- .onCapabilitiesChanged(NETWORK, createWifiNetworkCapabilities(PRIMARY_WIFI_INFO))
-
- assertThat(latest).isTrue()
-
- whenever(wifiManager.isWifiEnabled).thenReturn(false)
- getNetworkCallback()
- .onCapabilitiesChanged(NETWORK, createWifiNetworkCapabilities(PRIMARY_WIFI_INFO))
-
- assertThat(latest).isFalse()
- }
-
- @Test
- fun isWifiEnabled_networkLost_valueUpdated() =
- testScope.runTest {
- collectLastValue(underTest.wifiNetwork)
- val latest by collectLastValue(underTest.isWifiEnabled)
-
- whenever(wifiManager.isWifiEnabled).thenReturn(true)
- getNetworkCallback().onLost(NETWORK)
-
- assertThat(latest).isTrue()
-
- whenever(wifiManager.isWifiEnabled).thenReturn(false)
- getNetworkCallback().onLost(NETWORK)
-
- assertThat(latest).isFalse()
- }
-
- @Test
- fun isWifiEnabled_intentsReceived_valueUpdated() =
- testScope.runTest {
- val latest by collectLastValue(underTest.isWifiEnabled)
-
- whenever(wifiManager.isWifiEnabled).thenReturn(true)
- fakeBroadcastDispatcher.sendIntentToMatchingReceiversOnly(
- context,
- Intent(WifiManager.WIFI_STATE_CHANGED_ACTION),
- )
-
- assertThat(latest).isTrue()
-
- whenever(wifiManager.isWifiEnabled).thenReturn(false)
- fakeBroadcastDispatcher.sendIntentToMatchingReceiversOnly(
- context,
- Intent(WifiManager.WIFI_STATE_CHANGED_ACTION),
- )
-
- assertThat(latest).isFalse()
- }
-
- @Test
- fun isWifiEnabled_bothIntentAndNetworkUpdates_valueAlwaysUpdated() =
- testScope.runTest {
- collectLastValue(underTest.wifiNetwork)
- val latest by collectLastValue(underTest.isWifiEnabled)
-
- whenever(wifiManager.isWifiEnabled).thenReturn(false)
- fakeBroadcastDispatcher.sendIntentToMatchingReceiversOnly(
- context,
- Intent(WifiManager.WIFI_STATE_CHANGED_ACTION),
- )
- assertThat(latest).isFalse()
-
- whenever(wifiManager.isWifiEnabled).thenReturn(true)
- getNetworkCallback().onLost(NETWORK)
- assertThat(latest).isTrue()
-
- whenever(wifiManager.isWifiEnabled).thenReturn(false)
- getNetworkCallback()
- .onCapabilitiesChanged(NETWORK, createWifiNetworkCapabilities(PRIMARY_WIFI_INFO))
- assertThat(latest).isFalse()
-
- whenever(wifiManager.isWifiEnabled).thenReturn(true)
- fakeBroadcastDispatcher.sendIntentToMatchingReceiversOnly(
- context,
- Intent(WifiManager.WIFI_STATE_CHANGED_ACTION),
- )
- assertThat(latest).isTrue()
- }
-
- @Test
- fun isWifiDefault_initiallyGetsDefault() =
- testScope.runTest { assertThat(underTest.isWifiDefault.value).isFalse() }
-
- @Test
- fun isWifiDefault_wifiNetwork_isTrue() =
- testScope.runTest {
- val latest by collectLastValue(underTest.isWifiDefault)
-
- val wifiInfo = mock<WifiInfo>().apply { whenever(this.ssid).thenReturn(SSID) }
-
- getDefaultNetworkCallback()
- .onCapabilitiesChanged(NETWORK, createWifiNetworkCapabilities(wifiInfo))
-
- assertThat(latest).isTrue()
- }
-
- /** Regression test for b/266628069. */
- @Test
- fun isWifiDefault_transportInfoIsNotWifi_andNoWifiTransport_false() =
- testScope.runTest {
- val latest by collectLastValue(underTest.isWifiDefault)
-
- val transportInfo =
- VpnTransportInfo(
- /* type= */ 0,
- /* sessionId= */ "sessionId",
- )
- val networkCapabilities =
- mock<NetworkCapabilities>().also {
- whenever(it.hasTransport(TRANSPORT_VPN)).thenReturn(true)
- whenever(it.hasTransport(TRANSPORT_WIFI)).thenReturn(false)
- whenever(it.hasTransport(TRANSPORT_CELLULAR)).thenReturn(false)
- whenever(it.transportInfo).thenReturn(transportInfo)
- }
-
- getDefaultNetworkCallback().onCapabilitiesChanged(NETWORK, networkCapabilities)
-
- assertThat(latest).isFalse()
- }
-
- /** Regression test for b/266628069. */
- @Test
- fun isWifiDefault_transportInfoIsNotWifi_butHasWifiTransport_true() =
- testScope.runTest {
- val latest by collectLastValue(underTest.isWifiDefault)
-
- val transportInfo =
- VpnTransportInfo(
- /* type= */ 0,
- /* sessionId= */ "sessionId",
- )
- val networkCapabilities =
- mock<NetworkCapabilities>().also {
- whenever(it.hasTransport(TRANSPORT_VPN)).thenReturn(true)
- whenever(it.hasTransport(TRANSPORT_WIFI)).thenReturn(true)
- whenever(it.hasTransport(TRANSPORT_CELLULAR)).thenReturn(false)
- whenever(it.transportInfo).thenReturn(transportInfo)
- }
-
- getDefaultNetworkCallback().onCapabilitiesChanged(NETWORK, networkCapabilities)
-
- assertThat(latest).isTrue()
- }
-
- @Test
- fun isWifiDefault_carrierMergedViaCellular_isTrue() =
- testScope.runTest {
- val latest by collectLastValue(underTest.isWifiDefault)
-
- val carrierMergedInfo =
- mock<WifiInfo>().apply { whenever(this.isCarrierMerged).thenReturn(true) }
-
- val capabilities =
- mock<NetworkCapabilities>().apply {
- whenever(this.hasTransport(TRANSPORT_CELLULAR)).thenReturn(true)
- whenever(this.hasTransport(TRANSPORT_WIFI)).thenReturn(false)
- whenever(this.transportInfo).thenReturn(carrierMergedInfo)
- }
-
- getDefaultNetworkCallback().onCapabilitiesChanged(NETWORK, capabilities)
-
- assertThat(latest).isTrue()
- }
-
- @Test
- fun isWifiDefault_carrierMergedViaCellular_withVcnTransport_isTrue() =
- testScope.runTest {
- val latest by collectLastValue(underTest.isWifiDefault)
-
- val capabilities =
- mock<NetworkCapabilities>().apply {
- whenever(this.hasTransport(TRANSPORT_CELLULAR)).thenReturn(true)
- whenever(this.hasTransport(TRANSPORT_WIFI)).thenReturn(false)
- whenever(this.transportInfo).thenReturn(VcnTransportInfo(PRIMARY_WIFI_INFO))
- }
-
- getDefaultNetworkCallback().onCapabilitiesChanged(NETWORK, capabilities)
-
- assertThat(latest).isTrue()
- }
-
- @Test
- fun isWifiDefault_carrierMergedViaWifi_isTrue() =
- testScope.runTest {
- val latest by collectLastValue(underTest.isWifiDefault)
-
- val carrierMergedInfo =
- mock<WifiInfo>().apply { whenever(this.isCarrierMerged).thenReturn(true) }
-
- val capabilities =
- mock<NetworkCapabilities>().apply {
- whenever(this.hasTransport(TRANSPORT_WIFI)).thenReturn(true)
- whenever(this.hasTransport(TRANSPORT_CELLULAR)).thenReturn(false)
- whenever(this.transportInfo).thenReturn(carrierMergedInfo)
- }
-
- getDefaultNetworkCallback().onCapabilitiesChanged(NETWORK, capabilities)
-
- assertThat(latest).isTrue()
- }
-
- @Test
- fun isWifiDefault_carrierMergedViaWifi_withVcnTransport_isTrue() =
- testScope.runTest {
- val latest by collectLastValue(underTest.isWifiDefault)
-
- val capabilities =
- mock<NetworkCapabilities>().apply {
- whenever(this.hasTransport(TRANSPORT_WIFI)).thenReturn(true)
- whenever(this.hasTransport(TRANSPORT_CELLULAR)).thenReturn(false)
- whenever(this.transportInfo).thenReturn(VcnTransportInfo(PRIMARY_WIFI_INFO))
- }
-
- getDefaultNetworkCallback().onCapabilitiesChanged(NETWORK, capabilities)
-
- assertThat(latest).isTrue()
- }
-
- @Test
- fun isWifiDefault_cellularAndWifiTransports_usesCellular_isTrue() =
- testScope.runTest {
- val latest by collectLastValue(underTest.isWifiDefault)
-
- val capabilities =
- mock<NetworkCapabilities>().apply {
- whenever(this.hasTransport(TRANSPORT_CELLULAR)).thenReturn(true)
- whenever(this.hasTransport(TRANSPORT_WIFI)).thenReturn(true)
- whenever(this.transportInfo).thenReturn(VcnTransportInfo(PRIMARY_WIFI_INFO))
- }
-
- getDefaultNetworkCallback().onCapabilitiesChanged(NETWORK, capabilities)
-
- assertThat(latest).isTrue()
- }
-
- @Test
- fun isWifiDefault_cellularNotVcnNetwork_isFalse() =
- testScope.runTest {
- val latest by collectLastValue(underTest.isWifiDefault)
-
- val capabilities =
- mock<NetworkCapabilities>().apply {
- whenever(this.hasTransport(TRANSPORT_CELLULAR)).thenReturn(true)
- whenever(this.transportInfo).thenReturn(mock())
- }
-
- getDefaultNetworkCallback().onCapabilitiesChanged(NETWORK, capabilities)
-
- assertThat(latest).isFalse()
- }
-
- @Test
- fun isWifiDefault_isCarrierMergedViaUnderlyingWifi_isTrue() =
- testScope.runTest {
- val latest by collectLastValue(underTest.isWifiDefault)
-
- val underlyingNetwork = mock<Network>()
- val carrierMergedInfo =
- mock<WifiInfo>().apply {
- mock<WifiInfo>().apply { whenever(this.isCarrierMerged).thenReturn(true) }
- }
- val underlyingWifiCapabilities =
- mock<NetworkCapabilities>().also {
- whenever(it.hasTransport(TRANSPORT_WIFI)).thenReturn(true)
- whenever(it.transportInfo).thenReturn(carrierMergedInfo)
- }
- whenever(connectivityManager.getNetworkCapabilities(underlyingNetwork))
- .thenReturn(underlyingWifiCapabilities)
-
- // WHEN the main capabilities have an underlying carrier merged network via WIFI
- // transport and WifiInfo
- val mainCapabilities =
- mock<NetworkCapabilities>().also {
- whenever(it.hasTransport(TRANSPORT_CELLULAR)).thenReturn(true)
- whenever(it.transportInfo).thenReturn(null)
- whenever(it.underlyingNetworks).thenReturn(listOf(underlyingNetwork))
- }
-
- getDefaultNetworkCallback().onCapabilitiesChanged(NETWORK, mainCapabilities)
-
- // THEN the wifi network is carrier merged, so wifi is default
- assertThat(latest).isTrue()
- }
-
- @Test
- fun isWifiDefault_isCarrierMergedViaUnderlyingCellular_isTrue() =
- testScope.runTest {
- val latest by collectLastValue(underTest.isWifiDefault)
-
- val underlyingCarrierMergedNetwork = mock<Network>()
- val carrierMergedInfo =
- mock<WifiInfo>().apply { whenever(this.isCarrierMerged).thenReturn(true) }
- val underlyingCapabilities =
- mock<NetworkCapabilities>().also {
- whenever(it.hasTransport(TRANSPORT_CELLULAR)).thenReturn(true)
- whenever(it.transportInfo).thenReturn(VcnTransportInfo(carrierMergedInfo))
- }
- whenever(connectivityManager.getNetworkCapabilities(underlyingCarrierMergedNetwork))
- .thenReturn(underlyingCapabilities)
-
- // WHEN the main capabilities have an underlying carrier merged network via CELLULAR
- // transport and VcnTransportInfo
- val mainCapabilities =
- mock<NetworkCapabilities>().also {
- whenever(it.hasTransport(TRANSPORT_CELLULAR)).thenReturn(true)
- whenever(it.transportInfo).thenReturn(null)
- whenever(it.underlyingNetworks)
- .thenReturn(listOf(underlyingCarrierMergedNetwork))
- }
-
- getDefaultNetworkCallback().onCapabilitiesChanged(NETWORK, mainCapabilities)
-
- // THEN the wifi network is carrier merged, so wifi is default
- assertThat(latest).isTrue()
- }
-
- @Test
- fun isWifiDefault_wifiNetworkLost_isFalse() =
- testScope.runTest {
- val latest by collectLastValue(underTest.isWifiDefault)
-
- // First, add a network
- getDefaultNetworkCallback()
- .onCapabilitiesChanged(NETWORK, createWifiNetworkCapabilities(PRIMARY_WIFI_INFO))
- assertThat(latest).isTrue()
-
- // WHEN the network is lost
- getDefaultNetworkCallback().onLost(NETWORK)
-
- // THEN we update to false
- assertThat(latest).isFalse()
- }
-
- @Test
- fun wifiNetwork_initiallyGetsDefault() =
- testScope.runTest {
- val latest by collectLastValue(underTest.wifiNetwork)
-
- assertThat(latest).isEqualTo(WIFI_NETWORK_DEFAULT)
- }
-
- @Test
- fun wifiNetwork_primaryWifiNetworkAdded_flowHasNetwork() =
- testScope.runTest {
- val latest by collectLastValue(underTest.wifiNetwork)
-
- val wifiInfo =
- mock<WifiInfo>().apply {
- whenever(this.ssid).thenReturn(SSID)
- whenever(this.isPrimary).thenReturn(true)
- }
- val network = mock<Network>().apply { whenever(this.getNetId()).thenReturn(NETWORK_ID) }
-
- getNetworkCallback()
- .onCapabilitiesChanged(network, createWifiNetworkCapabilities(wifiInfo))
-
- assertThat(latest is WifiNetworkModel.Active).isTrue()
- val latestActive = latest as WifiNetworkModel.Active
- assertThat(latestActive.networkId).isEqualTo(NETWORK_ID)
- assertThat(latestActive.ssid).isEqualTo(SSID)
- }
-
- @Test
- fun wifiNetwork_neverHasHotspot() =
- testScope.runTest {
- val latest by collectLastValue(underTest.wifiNetwork)
-
- val wifiInfo =
- mock<WifiInfo>().apply {
- whenever(this.ssid).thenReturn(SSID)
- whenever(this.isPrimary).thenReturn(true)
- }
- val network = mock<Network>().apply { whenever(this.getNetId()).thenReturn(NETWORK_ID) }
-
- getNetworkCallback()
- .onCapabilitiesChanged(network, createWifiNetworkCapabilities(wifiInfo))
-
- assertThat(latest is WifiNetworkModel.Active).isTrue()
- assertThat((latest as WifiNetworkModel.Active).hotspotDeviceType)
- .isEqualTo(WifiNetworkModel.HotspotDeviceType.NONE)
- }
-
- @Test
- fun wifiNetwork_isCarrierMerged_flowHasCarrierMerged() =
- testScope.runTest {
- val latest by collectLastValue(underTest.wifiNetwork)
-
- val wifiInfo =
- mock<WifiInfo>().apply {
- whenever(this.isPrimary).thenReturn(true)
- whenever(this.isCarrierMerged).thenReturn(true)
- }
-
- getNetworkCallback()
- .onCapabilitiesChanged(NETWORK, createWifiNetworkCapabilities(wifiInfo))
-
- assertThat(latest is WifiNetworkModel.CarrierMerged).isTrue()
- }
-
- @Test
- fun wifiNetwork_isCarrierMergedViaUnderlyingWifi_flowHasCarrierMerged() =
- testScope.runTest {
- val latest by collectLastValue(underTest.wifiNetwork)
-
- val underlyingNetwork = mock<Network>()
- val carrierMergedInfo =
- mock<WifiInfo>().apply {
- whenever(this.isCarrierMerged).thenReturn(true)
- whenever(this.isPrimary).thenReturn(true)
- }
- val underlyingWifiCapabilities =
- mock<NetworkCapabilities>().also {
- whenever(it.hasTransport(TRANSPORT_WIFI)).thenReturn(true)
- whenever(it.transportInfo).thenReturn(carrierMergedInfo)
- }
- whenever(connectivityManager.getNetworkCapabilities(underlyingNetwork))
- .thenReturn(underlyingWifiCapabilities)
-
- // WHEN the main capabilities have an underlying carrier merged network via WIFI
- // transport and WifiInfo
- val mainCapabilities =
- mock<NetworkCapabilities>().also {
- whenever(it.hasTransport(TRANSPORT_CELLULAR)).thenReturn(true)
- whenever(it.transportInfo).thenReturn(null)
- whenever(it.underlyingNetworks).thenReturn(listOf(underlyingNetwork))
- }
-
- getNetworkCallback().onCapabilitiesChanged(NETWORK, mainCapabilities)
-
- // THEN the wifi network is carrier merged
- assertThat(latest is WifiNetworkModel.CarrierMerged).isTrue()
- }
-
- @Test
- fun wifiNetwork_isCarrierMergedViaUnderlyingCellular_flowHasCarrierMerged() =
- testScope.runTest {
- val latest by collectLastValue(underTest.wifiNetwork)
-
- val underlyingCarrierMergedNetwork = mock<Network>()
- val carrierMergedInfo =
- mock<WifiInfo>().apply {
- whenever(this.isCarrierMerged).thenReturn(true)
- whenever(this.isPrimary).thenReturn(true)
- }
- val underlyingCapabilities =
- mock<NetworkCapabilities>().also {
- whenever(it.hasTransport(TRANSPORT_CELLULAR)).thenReturn(true)
- whenever(it.transportInfo).thenReturn(VcnTransportInfo(carrierMergedInfo))
- }
- whenever(connectivityManager.getNetworkCapabilities(underlyingCarrierMergedNetwork))
- .thenReturn(underlyingCapabilities)
-
- // WHEN the main capabilities have an underlying carrier merged network via CELLULAR
- // transport and VcnTransportInfo
- val mainCapabilities =
- mock<NetworkCapabilities>().also {
- whenever(it.hasTransport(TRANSPORT_CELLULAR)).thenReturn(true)
- whenever(it.transportInfo).thenReturn(null)
- whenever(it.underlyingNetworks)
- .thenReturn(listOf(underlyingCarrierMergedNetwork))
- }
-
- getNetworkCallback().onCapabilitiesChanged(NETWORK, mainCapabilities)
-
- // THEN the wifi network is carrier merged
- assertThat(latest is WifiNetworkModel.CarrierMerged).isTrue()
- }
-
- @Test
- fun wifiNetwork_carrierMergedButInvalidSubId_flowHasInvalid() =
- testScope.runTest {
- val latest by collectLastValue(underTest.wifiNetwork)
-
- val wifiInfo =
- mock<WifiInfo>().apply {
- whenever(this.isPrimary).thenReturn(true)
- whenever(this.isCarrierMerged).thenReturn(true)
- whenever(this.subscriptionId).thenReturn(INVALID_SUBSCRIPTION_ID)
- }
-
- getNetworkCallback()
- .onCapabilitiesChanged(
- NETWORK,
- createWifiNetworkCapabilities(wifiInfo),
- )
-
- assertThat(latest).isInstanceOf(WifiNetworkModel.Invalid::class.java)
- }
-
- @Test
- fun wifiNetwork_isCarrierMerged_getsCorrectValues() =
- testScope.runTest {
- val latest by collectLastValue(underTest.wifiNetwork)
-
- val rssi = -57
- val wifiInfo =
- mock<WifiInfo>().apply {
- whenever(this.isPrimary).thenReturn(true)
- whenever(this.isCarrierMerged).thenReturn(true)
- whenever(this.rssi).thenReturn(rssi)
- whenever(this.subscriptionId).thenReturn(567)
- }
-
- whenever(wifiManager.calculateSignalLevel(rssi)).thenReturn(2)
- whenever(wifiManager.maxSignalLevel).thenReturn(5)
-
- getNetworkCallback()
- .onCapabilitiesChanged(
- NETWORK,
- createWifiNetworkCapabilities(wifiInfo),
- )
-
- assertThat(latest is WifiNetworkModel.CarrierMerged).isTrue()
- val latestCarrierMerged = latest as WifiNetworkModel.CarrierMerged
- assertThat(latestCarrierMerged.networkId).isEqualTo(NETWORK_ID)
- assertThat(latestCarrierMerged.subscriptionId).isEqualTo(567)
- assertThat(latestCarrierMerged.level).isEqualTo(2)
- // numberOfLevels = maxSignalLevel + 1
- assertThat(latestCarrierMerged.numberOfLevels).isEqualTo(6)
- }
-
- @Test
- fun wifiNetwork_notValidated_networkNotValidated() =
- testScope.runTest {
- val latest by collectLastValue(underTest.wifiNetwork)
-
- getNetworkCallback()
- .onCapabilitiesChanged(
- NETWORK,
- createWifiNetworkCapabilities(PRIMARY_WIFI_INFO, isValidated = false)
- )
-
- assertThat((latest as WifiNetworkModel.Active).isValidated).isFalse()
- }
-
- @Test
- fun wifiNetwork_validated_networkValidated() =
- testScope.runTest {
- val latest by collectLastValue(underTest.wifiNetwork)
-
- getNetworkCallback()
- .onCapabilitiesChanged(
- NETWORK,
- createWifiNetworkCapabilities(PRIMARY_WIFI_INFO, isValidated = true)
- )
-
- assertThat((latest as WifiNetworkModel.Active).isValidated).isTrue()
- }
-
- @Test
- fun wifiNetwork_nonPrimaryWifiNetworkAdded_flowHasNoNetwork() =
- testScope.runTest {
- val latest by collectLastValue(underTest.wifiNetwork)
-
- val wifiInfo =
- mock<WifiInfo>().apply {
- whenever(this.ssid).thenReturn(SSID)
- whenever(this.isPrimary).thenReturn(false)
- }
-
- getNetworkCallback()
- .onCapabilitiesChanged(NETWORK, createWifiNetworkCapabilities(wifiInfo))
-
- assertThat(latest is WifiNetworkModel.Inactive).isTrue()
- }
-
- /** Regression test for b/266628069. */
- @Test
- fun wifiNetwork_transportInfoIsNotWifi_flowHasNoNetwork() =
- testScope.runTest {
- val latest by collectLastValue(underTest.wifiNetwork)
-
- val transportInfo =
- VpnTransportInfo(
- /* type= */ 0,
- /* sessionId= */ "sessionId",
- )
- getNetworkCallback()
- .onCapabilitiesChanged(NETWORK, createWifiNetworkCapabilities(transportInfo))
-
- assertThat(latest is WifiNetworkModel.Inactive).isTrue()
- }
-
- @Test
- fun wifiNetwork_cellularVcnNetworkAdded_flowHasNetwork() =
- testScope.runTest {
- val latest by collectLastValue(underTest.wifiNetwork)
-
- val capabilities =
- mock<NetworkCapabilities>().apply {
- whenever(this.hasTransport(TRANSPORT_CELLULAR)).thenReturn(true)
- whenever(this.transportInfo).thenReturn(VcnTransportInfo(PRIMARY_WIFI_INFO))
- }
-
- getNetworkCallback().onCapabilitiesChanged(NETWORK, capabilities)
-
- assertThat(latest is WifiNetworkModel.Active).isTrue()
- val latestActive = latest as WifiNetworkModel.Active
- assertThat(latestActive.networkId).isEqualTo(NETWORK_ID)
- assertThat(latestActive.ssid).isEqualTo(SSID)
- }
-
- @Test
- fun wifiNetwork_nonPrimaryCellularVcnNetworkAdded_flowHasNoNetwork() =
- testScope.runTest {
- val latest by collectLastValue(underTest.wifiNetwork)
-
- val wifiInfo =
- mock<WifiInfo>().apply {
- whenever(this.ssid).thenReturn(SSID)
- whenever(this.isPrimary).thenReturn(false)
- }
- val capabilities =
- mock<NetworkCapabilities>().apply {
- whenever(this.hasTransport(TRANSPORT_CELLULAR)).thenReturn(true)
- whenever(this.transportInfo).thenReturn(VcnTransportInfo(wifiInfo))
- }
-
- getNetworkCallback().onCapabilitiesChanged(NETWORK, capabilities)
-
- assertThat(latest is WifiNetworkModel.Inactive).isTrue()
- }
-
- @Test
- fun wifiNetwork_cellularNotVcnNetworkAdded_flowHasNoNetwork() =
- testScope.runTest {
- val latest by collectLastValue(underTest.wifiNetwork)
-
- val capabilities =
- mock<NetworkCapabilities>().apply {
- whenever(this.hasTransport(TRANSPORT_CELLULAR)).thenReturn(true)
- whenever(this.transportInfo).thenReturn(mock())
- }
-
- getNetworkCallback().onCapabilitiesChanged(NETWORK, capabilities)
-
- assertThat(latest is WifiNetworkModel.Inactive).isTrue()
- }
-
- @Test
- fun wifiNetwork_cellularAndWifiTransports_usesCellular() =
- testScope.runTest {
- val latest by collectLastValue(underTest.wifiNetwork)
-
- val capabilities =
- mock<NetworkCapabilities>().apply {
- whenever(this.hasTransport(TRANSPORT_CELLULAR)).thenReturn(true)
- whenever(this.hasTransport(TRANSPORT_WIFI)).thenReturn(true)
- whenever(this.transportInfo).thenReturn(VcnTransportInfo(PRIMARY_WIFI_INFO))
- }
-
- getNetworkCallback().onCapabilitiesChanged(NETWORK, capabilities)
-
- assertThat(latest is WifiNetworkModel.Active).isTrue()
- val latestActive = latest as WifiNetworkModel.Active
- assertThat(latestActive.networkId).isEqualTo(NETWORK_ID)
- assertThat(latestActive.ssid).isEqualTo(SSID)
- }
-
- @Test
- fun wifiNetwork_newPrimaryWifiNetwork_flowHasNewNetwork() =
- testScope.runTest {
- val latest by collectLastValue(underTest.wifiNetwork)
-
- // Start with the original network
- getNetworkCallback()
- .onCapabilitiesChanged(NETWORK, createWifiNetworkCapabilities(PRIMARY_WIFI_INFO))
-
- // WHEN we update to a new primary network
- val newNetworkId = 456
- val newNetwork =
- mock<Network>().apply { whenever(this.getNetId()).thenReturn(newNetworkId) }
- val newSsid = "CD"
- val newWifiInfo =
- mock<WifiInfo>().apply {
- whenever(this.ssid).thenReturn(newSsid)
- whenever(this.isPrimary).thenReturn(true)
- }
-
- getNetworkCallback()
- .onCapabilitiesChanged(newNetwork, createWifiNetworkCapabilities(newWifiInfo))
-
- // THEN we use the new network
- assertThat(latest is WifiNetworkModel.Active).isTrue()
- val latestActive = latest as WifiNetworkModel.Active
- assertThat(latestActive.networkId).isEqualTo(newNetworkId)
- assertThat(latestActive.ssid).isEqualTo(newSsid)
- }
-
- @Test
- fun wifiNetwork_newNonPrimaryWifiNetwork_flowHasOldNetwork() =
- testScope.runTest {
- val latest by collectLastValue(underTest.wifiNetwork)
-
- // Start with the original network
- getNetworkCallback()
- .onCapabilitiesChanged(NETWORK, createWifiNetworkCapabilities(PRIMARY_WIFI_INFO))
-
- // WHEN we notify of a new but non-primary network
- val newNetworkId = 456
- val newNetwork =
- mock<Network>().apply { whenever(this.getNetId()).thenReturn(newNetworkId) }
- val newSsid = "EF"
- val newWifiInfo =
- mock<WifiInfo>().apply {
- whenever(this.ssid).thenReturn(newSsid)
- whenever(this.isPrimary).thenReturn(false)
- }
-
- getNetworkCallback()
- .onCapabilitiesChanged(newNetwork, createWifiNetworkCapabilities(newWifiInfo))
-
- // THEN we still use the original network
- assertThat(latest is WifiNetworkModel.Active).isTrue()
- val latestActive = latest as WifiNetworkModel.Active
- assertThat(latestActive.networkId).isEqualTo(NETWORK_ID)
- assertThat(latestActive.ssid).isEqualTo(SSID)
- }
-
- @Test
- fun wifiNetwork_newNetworkCapabilities_flowHasNewData() =
- testScope.runTest {
- val latest by collectLastValue(underTest.wifiNetwork)
-
- val wifiInfo =
- mock<WifiInfo>().apply {
- whenever(this.ssid).thenReturn(SSID)
- whenever(this.isPrimary).thenReturn(true)
- }
-
- // Start with the original network
- getNetworkCallback()
- .onCapabilitiesChanged(
- NETWORK,
- createWifiNetworkCapabilities(wifiInfo, isValidated = true)
- )
-
- // WHEN we keep the same network ID but change the SSID
- val newSsid = "CD"
- val newWifiInfo =
- mock<WifiInfo>().apply {
- whenever(this.ssid).thenReturn(newSsid)
- whenever(this.isPrimary).thenReturn(true)
- }
-
- getNetworkCallback()
- .onCapabilitiesChanged(
- NETWORK,
- createWifiNetworkCapabilities(newWifiInfo, isValidated = false)
- )
-
- // THEN we've updated to the new SSID
- assertThat(latest is WifiNetworkModel.Active).isTrue()
- val latestActive = latest as WifiNetworkModel.Active
- assertThat(latestActive.networkId).isEqualTo(NETWORK_ID)
- assertThat(latestActive.ssid).isEqualTo(newSsid)
- assertThat(latestActive.isValidated).isFalse()
- }
-
- @Test
- fun wifiNetwork_noCurrentNetwork_networkLost_flowHasNoNetwork() =
- testScope.runTest {
- val latest by collectLastValue(underTest.wifiNetwork)
-
- // WHEN we receive #onLost without any #onCapabilitiesChanged beforehand
- getNetworkCallback().onLost(NETWORK)
-
- // THEN there's no crash and we still have no network
- assertThat(latest is WifiNetworkModel.Inactive).isTrue()
- }
-
- @Test
- fun wifiNetwork_currentActiveNetworkLost_flowHasNoNetwork() =
- testScope.runTest {
- val latest by collectLastValue(underTest.wifiNetwork)
-
- getNetworkCallback()
- .onCapabilitiesChanged(NETWORK, createWifiNetworkCapabilities(PRIMARY_WIFI_INFO))
- assertThat((latest as WifiNetworkModel.Active).networkId).isEqualTo(NETWORK_ID)
-
- // WHEN we lose our current network
- getNetworkCallback().onLost(NETWORK)
-
- // THEN we update to no network
- assertThat(latest is WifiNetworkModel.Inactive).isTrue()
- }
-
- /** Possible regression test for b/278618530. */
- @Test
- fun wifiNetwork_currentCarrierMergedNetworkLost_flowHasNoNetwork() =
- testScope.runTest {
- val latest by collectLastValue(underTest.wifiNetwork)
-
- val wifiInfo =
- mock<WifiInfo>().apply {
- whenever(this.isPrimary).thenReturn(true)
- whenever(this.isCarrierMerged).thenReturn(true)
- }
-
- getNetworkCallback()
- .onCapabilitiesChanged(NETWORK, createWifiNetworkCapabilities(wifiInfo))
- assertThat(latest is WifiNetworkModel.CarrierMerged).isTrue()
- assertThat((latest as WifiNetworkModel.CarrierMerged).networkId).isEqualTo(NETWORK_ID)
-
- // WHEN we lose our current network
- getNetworkCallback().onLost(NETWORK)
-
- // THEN we update to no network
- assertThat(latest is WifiNetworkModel.Inactive).isTrue()
- }
-
- @Test
- fun wifiNetwork_unknownNetworkLost_flowHasPreviousNetwork() =
- testScope.runTest {
- val latest by collectLastValue(underTest.wifiNetwork)
-
- getNetworkCallback()
- .onCapabilitiesChanged(NETWORK, createWifiNetworkCapabilities(PRIMARY_WIFI_INFO))
- assertThat((latest as WifiNetworkModel.Active).networkId).isEqualTo(NETWORK_ID)
-
- // WHEN we lose an unknown network
- val unknownNetwork = mock<Network>().apply { whenever(this.getNetId()).thenReturn(543) }
- getNetworkCallback().onLost(unknownNetwork)
-
- // THEN we still have our previous network
- assertThat(latest is WifiNetworkModel.Active).isTrue()
- val latestActive = latest as WifiNetworkModel.Active
- assertThat(latestActive.networkId).isEqualTo(NETWORK_ID)
- assertThat(latestActive.ssid).isEqualTo(SSID)
- }
-
- @Test
- fun wifiNetwork_notCurrentNetworkLost_flowHasCurrentNetwork() =
- testScope.runTest {
- val latest by collectLastValue(underTest.wifiNetwork)
-
- getNetworkCallback()
- .onCapabilitiesChanged(NETWORK, createWifiNetworkCapabilities(PRIMARY_WIFI_INFO))
- assertThat((latest as WifiNetworkModel.Active).networkId).isEqualTo(NETWORK_ID)
-
- // WHEN we update to a new network...
- val newNetworkId = 89
- val newNetwork =
- mock<Network>().apply { whenever(this.getNetId()).thenReturn(newNetworkId) }
- getNetworkCallback()
- .onCapabilitiesChanged(newNetwork, createWifiNetworkCapabilities(PRIMARY_WIFI_INFO))
- // ...and lose the old network
- getNetworkCallback().onLost(NETWORK)
-
- // THEN we still have the new network
- assertThat((latest as WifiNetworkModel.Active).networkId).isEqualTo(newNetworkId)
- }
-
- /** Regression test for b/244173280. */
- @Test
- fun wifiNetwork_multipleSubscribers_newSubscribersGetCurrentValue() =
- testScope.runTest {
- val latest1 by collectLastValue(underTest.wifiNetwork)
-
- getNetworkCallback()
- .onCapabilitiesChanged(NETWORK, createWifiNetworkCapabilities(PRIMARY_WIFI_INFO))
-
- assertThat(latest1 is WifiNetworkModel.Active).isTrue()
- val latest1Active = latest1 as WifiNetworkModel.Active
- assertThat(latest1Active.networkId).isEqualTo(NETWORK_ID)
- assertThat(latest1Active.ssid).isEqualTo(SSID)
-
- // WHEN we add a second subscriber after having already emitted a value
- val latest2 by collectLastValue(underTest.wifiNetwork)
-
- // THEN the second subscribe receives the already-emitted value
- assertThat(latest2 is WifiNetworkModel.Active).isTrue()
- val latest2Active = latest2 as WifiNetworkModel.Active
- assertThat(latest2Active.networkId).isEqualTo(NETWORK_ID)
- assertThat(latest2Active.ssid).isEqualTo(SSID)
- }
-
- @Test
- fun secondaryNetworks_alwaysEmpty() =
- testScope.runTest {
- val latest by collectLastValue(underTest.secondaryNetworks)
- collectLastValue(underTest.wifiNetwork)
-
- // Even WHEN we do have non-primary wifi info
- val wifiInfo =
- mock<WifiInfo>().apply {
- whenever(this.ssid).thenReturn(SSID)
- whenever(this.isPrimary).thenReturn(false)
- }
- val network = mock<Network>().apply { whenever(this.getNetId()).thenReturn(NETWORK_ID) }
-
- getNetworkCallback()
- .onCapabilitiesChanged(network, createWifiNetworkCapabilities(wifiInfo))
-
- // THEN the secondary networks list is empty because this repo doesn't support it
- assertThat(latest).isEmpty()
- }
-
- @Test
- fun isWifiConnectedWithValidSsid_inactiveNetwork_false() =
- testScope.runTest {
- collectLastValue(underTest.wifiNetwork)
-
- val wifiInfo =
- mock<WifiInfo>().apply {
- whenever(this.ssid).thenReturn(SSID)
- // A non-primary network is inactive
- whenever(this.isPrimary).thenReturn(false)
- }
-
- getNetworkCallback()
- .onCapabilitiesChanged(NETWORK, createWifiNetworkCapabilities(wifiInfo))
-
- assertThat(underTest.isWifiConnectedWithValidSsid()).isFalse()
- }
-
- @Test
- fun isWifiConnectedWithValidSsid_carrierMergedNetwork_false() =
- testScope.runTest {
- collectLastValue(underTest.wifiNetwork)
-
- val wifiInfo =
- mock<WifiInfo>().apply {
- whenever(this.isPrimary).thenReturn(true)
- whenever(this.isCarrierMerged).thenReturn(true)
- }
-
- getNetworkCallback()
- .onCapabilitiesChanged(NETWORK, createWifiNetworkCapabilities(wifiInfo))
- testScope.runCurrent()
-
- assertThat(underTest.isWifiConnectedWithValidSsid()).isFalse()
- }
-
- @Test
- fun isWifiConnectedWithValidSsid_invalidNetwork_false() =
- testScope.runTest {
- collectLastValue(underTest.wifiNetwork)
-
- val wifiInfo =
- mock<WifiInfo>().apply {
- whenever(this.isPrimary).thenReturn(true)
- whenever(this.isCarrierMerged).thenReturn(true)
- whenever(this.subscriptionId).thenReturn(INVALID_SUBSCRIPTION_ID)
- }
-
- getNetworkCallback()
- .onCapabilitiesChanged(
- NETWORK,
- createWifiNetworkCapabilities(wifiInfo),
- )
- testScope.runCurrent()
-
- assertThat(underTest.isWifiConnectedWithValidSsid()).isFalse()
- }
-
- @Test
- fun isWifiConnectedWithValidSsid_activeNetwork_nullSsid_false() =
- testScope.runTest {
- collectLastValue(underTest.wifiNetwork)
-
- val wifiInfo =
- mock<WifiInfo>().apply {
- whenever(this.isPrimary).thenReturn(true)
- whenever(this.ssid).thenReturn(null)
- }
-
- getNetworkCallback()
- .onCapabilitiesChanged(NETWORK, createWifiNetworkCapabilities(wifiInfo))
- testScope.runCurrent()
-
- assertThat(underTest.isWifiConnectedWithValidSsid()).isFalse()
- }
-
- @Test
- fun isWifiConnectedWithValidSsid_activeNetwork_unknownSsid_false() =
- testScope.runTest {
- collectLastValue(underTest.wifiNetwork)
-
- val wifiInfo =
- mock<WifiInfo>().apply {
- whenever(this.isPrimary).thenReturn(true)
- whenever(this.ssid).thenReturn(UNKNOWN_SSID)
- }
-
- getNetworkCallback()
- .onCapabilitiesChanged(NETWORK, createWifiNetworkCapabilities(wifiInfo))
- testScope.runCurrent()
-
- assertThat(underTest.isWifiConnectedWithValidSsid()).isFalse()
- }
-
- @Test
- fun isWifiConnectedWithValidSsid_activeNetwork_validSsid_true() =
- testScope.runTest {
- collectLastValue(underTest.wifiNetwork)
-
- val wifiInfo =
- mock<WifiInfo>().apply {
- whenever(this.isPrimary).thenReturn(true)
- whenever(this.ssid).thenReturn("FakeSsid")
- }
-
- getNetworkCallback()
- .onCapabilitiesChanged(NETWORK, createWifiNetworkCapabilities(wifiInfo))
- testScope.runCurrent()
-
- assertThat(underTest.isWifiConnectedWithValidSsid()).isTrue()
- }
-
- @Test
- fun isWifiConnectedWithValidSsid_activeToInactive_trueToFalse() =
- testScope.runTest {
- collectLastValue(underTest.wifiNetwork)
-
- // Start with active
- val wifiInfo =
- mock<WifiInfo>().apply {
- whenever(this.isPrimary).thenReturn(true)
- whenever(this.ssid).thenReturn("FakeSsid")
- }
- getNetworkCallback()
- .onCapabilitiesChanged(NETWORK, createWifiNetworkCapabilities(wifiInfo))
- testScope.runCurrent()
-
- assertThat(underTest.isWifiConnectedWithValidSsid()).isTrue()
-
- // WHEN the network is lost
- getNetworkCallback().onLost(NETWORK)
- testScope.runCurrent()
-
- // THEN the isWifiConnected updates
- assertThat(underTest.isWifiConnectedWithValidSsid()).isFalse()
- }
-
- @Test
- fun wifiActivity_callbackGivesNone_activityFlowHasNone() =
- testScope.runTest {
- val latest by collectLastValue(underTest.wifiActivity)
-
- getTrafficStateCallback().onStateChanged(TrafficStateCallback.DATA_ACTIVITY_NONE)
-
- assertThat(latest)
- .isEqualTo(DataActivityModel(hasActivityIn = false, hasActivityOut = false))
- }
-
- @Test
- fun wifiActivity_callbackGivesIn_activityFlowHasIn() =
- testScope.runTest {
- val latest by collectLastValue(underTest.wifiActivity)
-
- getTrafficStateCallback().onStateChanged(TrafficStateCallback.DATA_ACTIVITY_IN)
-
- assertThat(latest)
- .isEqualTo(DataActivityModel(hasActivityIn = true, hasActivityOut = false))
- }
-
- @Test
- fun wifiActivity_callbackGivesOut_activityFlowHasOut() =
- testScope.runTest {
- val latest by collectLastValue(underTest.wifiActivity)
-
- getTrafficStateCallback().onStateChanged(TrafficStateCallback.DATA_ACTIVITY_OUT)
-
- assertThat(latest)
- .isEqualTo(DataActivityModel(hasActivityIn = false, hasActivityOut = true))
- }
-
- @Test
- fun wifiActivity_callbackGivesInout_activityFlowHasInAndOut() =
- testScope.runTest {
- val latest by collectLastValue(underTest.wifiActivity)
-
- getTrafficStateCallback().onStateChanged(TrafficStateCallback.DATA_ACTIVITY_INOUT)
-
- assertThat(latest)
- .isEqualTo(DataActivityModel(hasActivityIn = true, hasActivityOut = true))
- }
-
- @Test
- fun wifiScanResults_containsSsidList() =
- testScope.runTest {
- val latest by collectLastValue(underTest.wifiScanResults)
-
- val scanResults =
- listOf(
- ScanResult().also { it.SSID = "ssid 1" },
- ScanResult().also { it.SSID = "ssid 2" },
- ScanResult().also { it.SSID = "ssid 3" },
- ScanResult().also { it.SSID = "ssid 4" },
- ScanResult().also { it.SSID = "ssid 5" },
- )
- whenever(wifiManager.scanResults).thenReturn(scanResults)
- getScanResultsCallback().onScanResultsAvailable()
-
- val expected =
- listOf(
- WifiScanEntry(ssid = "ssid 1"),
- WifiScanEntry(ssid = "ssid 2"),
- WifiScanEntry(ssid = "ssid 3"),
- WifiScanEntry(ssid = "ssid 4"),
- WifiScanEntry(ssid = "ssid 5"),
- )
-
- assertThat(latest).isEqualTo(expected)
- }
-
- @Test
- fun wifiScanResults_updates() =
- testScope.runTest {
- val latest by collectLastValue(underTest.wifiScanResults)
-
- var scanResults =
- listOf(
- ScanResult().also { it.SSID = "ssid 1" },
- ScanResult().also { it.SSID = "ssid 2" },
- ScanResult().also { it.SSID = "ssid 3" },
- ScanResult().also { it.SSID = "ssid 4" },
- ScanResult().also { it.SSID = "ssid 5" },
- )
- whenever(wifiManager.scanResults).thenReturn(scanResults)
- getScanResultsCallback().onScanResultsAvailable()
-
- // New scan representing no results
- scanResults = emptyList()
- whenever(wifiManager.scanResults).thenReturn(scanResults)
- getScanResultsCallback().onScanResultsAvailable()
-
- assertThat(latest).isEmpty()
- }
-
- private fun createRepo(): WifiRepositoryImpl {
- return WifiRepositoryImpl(
- fakeBroadcastDispatcher,
- connectivityManager,
- connectivityRepository,
- logger,
- tableLogger,
- executor,
- dispatcher,
- testScope.backgroundScope,
- wifiManager,
- )
- }
-
- private fun getTrafficStateCallback(): TrafficStateCallback {
- testScope.runCurrent()
- val callbackCaptor = argumentCaptor<TrafficStateCallback>()
- verify(wifiManager).registerTrafficStateCallback(any(), callbackCaptor.capture())
- return callbackCaptor.value!!
- }
-
- private fun getNetworkCallback(): ConnectivityManager.NetworkCallback {
- testScope.runCurrent()
- val callbackCaptor = argumentCaptor<ConnectivityManager.NetworkCallback>()
- verify(connectivityManager).registerNetworkCallback(any(), callbackCaptor.capture())
- return callbackCaptor.value!!
- }
-
- private fun getDefaultNetworkCallback(): ConnectivityManager.NetworkCallback {
- testScope.runCurrent()
- val callbackCaptor = argumentCaptor<ConnectivityManager.NetworkCallback>()
- verify(connectivityManager).registerDefaultNetworkCallback(callbackCaptor.capture())
- return callbackCaptor.value!!
- }
-
- private fun getScanResultsCallback(): WifiManager.ScanResultsCallback {
- testScope.runCurrent()
- val callbackCaptor = argumentCaptor<WifiManager.ScanResultsCallback>()
- verify(wifiManager).registerScanResultsCallback(any(), callbackCaptor.capture())
- return callbackCaptor.value!!
- }
-
- private fun createWifiNetworkCapabilities(
- transportInfo: TransportInfo,
- isValidated: Boolean = true,
- ): NetworkCapabilities {
- return mock<NetworkCapabilities>().also {
- whenever(it.hasTransport(TRANSPORT_WIFI)).thenReturn(true)
- whenever(it.transportInfo).thenReturn(transportInfo)
- whenever(it.hasCapability(NET_CAPABILITY_VALIDATED)).thenReturn(isValidated)
- }
- }
-
- private companion object {
- const val NETWORK_ID = 45
- val NETWORK = mock<Network>().apply { whenever(this.getNetId()).thenReturn(NETWORK_ID) }
- const val SSID = "AB"
- val PRIMARY_WIFI_INFO: WifiInfo =
- mock<WifiInfo>().apply {
- whenever(this.ssid).thenReturn(SSID)
- whenever(this.isPrimary).thenReturn(true)
- }
- }
-}
diff --git a/packages/SystemUI/src/com/android/systemui/flags/Flags.kt b/packages/SystemUI/src/com/android/systemui/flags/Flags.kt
index 9ada1ef..aac93b5 100644
--- a/packages/SystemUI/src/com/android/systemui/flags/Flags.kt
+++ b/packages/SystemUI/src/com/android/systemui/flags/Flags.kt
@@ -255,9 +255,6 @@
val FILTER_PROVISIONING_NETWORK_SUBSCRIPTIONS =
releasedFlag("filter_provisioning_network_subscriptions")
- // TODO(b/292533677): Tracking Bug
- val WIFI_TRACKER_LIB_FOR_WIFI_ICON = releasedFlag("wifi_tracker_lib_for_wifi_icon")
-
// TODO(b/293863612): Tracking Bug
@JvmField val INCOMPATIBLE_CHARGING_BATTERY_ICON =
releasedFlag("incompatible_charging_battery_icon")
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/dagger/StatusBarPipelineModule.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/dagger/StatusBarPipelineModule.kt
index 2b90e64..6e24412 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/dagger/StatusBarPipelineModule.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/dagger/StatusBarPipelineModule.kt
@@ -19,8 +19,6 @@
import android.net.wifi.WifiManager
import com.android.systemui.CoreStartable
import com.android.systemui.dagger.SysUISingleton
-import com.android.systemui.flags.FeatureFlags
-import com.android.systemui.flags.Flags
import com.android.systemui.log.LogBuffer
import com.android.systemui.log.LogBufferFactory
import com.android.systemui.log.table.TableLogBuffer
@@ -52,12 +50,9 @@
import com.android.systemui.statusbar.pipeline.shared.ui.viewmodel.CollapsedStatusBarViewModelImpl
import com.android.systemui.statusbar.pipeline.wifi.data.repository.RealWifiRepository
import com.android.systemui.statusbar.pipeline.wifi.data.repository.WifiRepository
-import com.android.systemui.statusbar.pipeline.wifi.data.repository.WifiRepositoryDagger
import com.android.systemui.statusbar.pipeline.wifi.data.repository.WifiRepositorySwitcher
-import com.android.systemui.statusbar.pipeline.wifi.data.repository.WifiRepositoryViaTrackerLibDagger
import com.android.systemui.statusbar.pipeline.wifi.data.repository.prod.DisabledWifiRepository
import com.android.systemui.statusbar.pipeline.wifi.data.repository.prod.WifiRepositoryImpl
-import com.android.systemui.statusbar.pipeline.wifi.data.repository.prod.WifiRepositoryViaTrackerLib
import com.android.systemui.statusbar.pipeline.wifi.domain.interactor.WifiInteractor
import com.android.systemui.statusbar.pipeline.wifi.domain.interactor.WifiInteractorImpl
import com.android.systemui.statusbar.policy.data.repository.UserSetupRepository
@@ -131,19 +126,15 @@
impl: CollapsedStatusBarViewBinderImpl
): CollapsedStatusBarViewBinder
- @Binds
- @IntoMap
- @ClassKey(WifiRepositoryDagger::class)
- abstract fun bindWifiRepositoryDagger(impl: WifiRepositoryDagger): CoreStartable
-
companion object {
+
@Provides
@SysUISingleton
- fun provideWifiRepositoryDagger(
+ fun provideRealWifiRepository(
wifiManager: WifiManager?,
disabledWifiRepository: DisabledWifiRepository,
wifiRepositoryImplFactory: WifiRepositoryImpl.Factory,
- ): WifiRepositoryDagger {
+ ): RealWifiRepository {
// If we have a null [WifiManager], then the wifi repository should be permanently
// disabled.
return if (wifiManager == null) {
@@ -155,36 +146,6 @@
@Provides
@SysUISingleton
- fun provideWifiRepositoryViaTrackerLibDagger(
- wifiManager: WifiManager?,
- disabledWifiRepository: DisabledWifiRepository,
- wifiRepositoryFromTrackerLibFactory: WifiRepositoryViaTrackerLib.Factory,
- ): WifiRepositoryViaTrackerLibDagger {
- // If we have a null [WifiManager], then the wifi repository should be permanently
- // disabled.
- return if (wifiManager == null) {
- disabledWifiRepository
- } else {
- wifiRepositoryFromTrackerLibFactory.create(wifiManager)
- }
- }
-
- @Provides
- @SysUISingleton
- fun provideRealWifiRepository(
- wifiRepository: WifiRepositoryDagger,
- wifiRepositoryFromTrackerLib: WifiRepositoryViaTrackerLibDagger,
- flags: FeatureFlags,
- ): RealWifiRepository {
- return if (flags.isEnabled(Flags.WIFI_TRACKER_LIB_FOR_WIFI_ICON)) {
- wifiRepositoryFromTrackerLib
- } else {
- wifiRepository
- }
- }
-
- @Provides
- @SysUISingleton
@Named(FIRST_MOBILE_SUB_SHOWING_NETWORK_TYPE_ICON)
fun provideFirstMobileSubShowingNetworkTypeIconProvider(
mobileIconsViewModel: MobileIconsViewModel,
@@ -197,16 +158,8 @@
@Provides
@SysUISingleton
@WifiInputLog
- fun provideWifiInputLogBuffer(factory: LogBufferFactory): LogBuffer {
- return factory.create("WifiInputLog", 50)
- }
-
- @Provides
- @SysUISingleton
- @WifiTrackerLibInputLog
- fun provideWifiTrackerLibInputLogBuffer(factory: LogBufferFactory): LogBuffer {
- // WifiTrackerLib is pretty noisy, so give it more room than WifiInputLog.
- return factory.create("WifiTrackerLibInputLog", 200)
+ fun provideWifiLogBuffer(factory: LogBufferFactory): LogBuffer {
+ return factory.create("WifiInputLog", 200)
}
@Provides
@@ -218,13 +171,6 @@
@Provides
@SysUISingleton
- @WifiTrackerLibTableLog
- fun provideWifiTrackerLibTableLogBuffer(factory: TableLogBufferFactory): TableLogBuffer {
- return factory.create("WifiTrackerLibTableLog", 100)
- }
-
- @Provides
- @SysUISingleton
@AirplaneTableLog
fun provideAirplaneTableLogBuffer(factory: TableLogBufferFactory): TableLogBuffer {
return factory.create("AirplaneTableLog", 30)
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/dagger/WifiInputLog.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/dagger/WifiInputLog.kt
index 6db6944..9ba802c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/dagger/WifiInputLog.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/dagger/WifiInputLog.kt
@@ -18,8 +18,8 @@
import javax.inject.Qualifier
-/** Wifi logs for inputs into the wifi pipeline. */
-@Qualifier
-@MustBeDocumented
-@kotlin.annotation.Retention(AnnotationRetention.RUNTIME)
-annotation class WifiInputLog
+/**
+ * Wifi logs for inputs into
+ * [com.android.systemui.statusbar.pipeline.wifi.data.repository.prod.WifiRepositoryImpl].
+ */
+@Qualifier @MustBeDocumented @Retention(AnnotationRetention.RUNTIME) annotation class WifiInputLog
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/dagger/WifiTrackerLibInputLog.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/dagger/WifiTrackerLibInputLog.kt
deleted file mode 100644
index b84b01e..0000000
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/dagger/WifiTrackerLibInputLog.kt
+++ /dev/null
@@ -1,25 +0,0 @@
-/*
- * Copyright (C) 2023 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.systemui.statusbar.pipeline.dagger
-
-import javax.inject.Qualifier
-
-/** Wifi logs for inputs into [WifiRepositoryViaTrackerLib]. */
-@Qualifier
-@MustBeDocumented
-@kotlin.annotation.Retention(AnnotationRetention.RUNTIME)
-annotation class WifiTrackerLibInputLog
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/dagger/WifiTrackerLibTableLog.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/dagger/WifiTrackerLibTableLog.kt
deleted file mode 100644
index 7ca7030..0000000
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/dagger/WifiTrackerLibTableLog.kt
+++ /dev/null
@@ -1,25 +0,0 @@
-/*
- * Copyright (C) 2023 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.systemui.statusbar.pipeline.dagger
-
-import javax.inject.Qualifier
-
-/** Wifi logs from [WifiRepositoryViaTrackerLib] in table format. */
-@Qualifier
-@MustBeDocumented
-@Retention(AnnotationRetention.RUNTIME)
-annotation class WifiTrackerLibTableLog
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/WifiRepository.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/WifiRepository.kt
index b22e09e..fc7a672 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/WifiRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/WifiRepository.kt
@@ -16,7 +16,6 @@
package com.android.systemui.statusbar.pipeline.wifi.data.repository
-import com.android.systemui.CoreStartable
import com.android.systemui.statusbar.pipeline.shared.data.model.DataActivityModel
import com.android.systemui.statusbar.pipeline.wifi.shared.model.WifiNetworkModel
import com.android.systemui.statusbar.pipeline.wifi.shared.model.WifiScanEntry
@@ -80,8 +79,3 @@
* repository.
*/
interface RealWifiRepository : WifiRepository
-
-/** Used only by Dagger to bind [WifiRepositoryImpl]. */
-interface WifiRepositoryDagger : RealWifiRepository, CoreStartable
-/** Used only by Dagger to bind [WifiRepositoryViaTrackerLib]. */
-interface WifiRepositoryViaTrackerLibDagger : RealWifiRepository
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/WifiRepositorySwitcher.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/WifiRepositorySwitcher.kt
index ca042e2..af6e8a0 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/WifiRepositorySwitcher.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/WifiRepositorySwitcher.kt
@@ -25,7 +25,6 @@
import com.android.systemui.demomode.DemoModeController
import com.android.systemui.statusbar.pipeline.shared.data.model.DataActivityModel
import com.android.systemui.statusbar.pipeline.wifi.data.repository.demo.DemoWifiRepository
-import com.android.systemui.statusbar.pipeline.wifi.data.repository.prod.WifiRepositoryImpl
import com.android.systemui.statusbar.pipeline.wifi.shared.model.WifiNetworkModel
import com.android.systemui.statusbar.pipeline.wifi.shared.model.WifiScanEntry
import javax.inject.Inject
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/prod/DisabledWifiRepository.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/prod/DisabledWifiRepository.kt
index cfdbe4a..b79fb9b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/prod/DisabledWifiRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/prod/DisabledWifiRepository.kt
@@ -18,8 +18,7 @@
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.statusbar.pipeline.shared.data.model.DataActivityModel
-import com.android.systemui.statusbar.pipeline.wifi.data.repository.WifiRepositoryDagger
-import com.android.systemui.statusbar.pipeline.wifi.data.repository.WifiRepositoryViaTrackerLibDagger
+import com.android.systemui.statusbar.pipeline.wifi.data.repository.RealWifiRepository
import com.android.systemui.statusbar.pipeline.wifi.shared.model.WifiNetworkModel
import com.android.systemui.statusbar.pipeline.wifi.shared.model.WifiScanEntry
import javax.inject.Inject
@@ -34,10 +33,7 @@
* wifi information.
*/
@SysUISingleton
-class DisabledWifiRepository @Inject constructor() :
- WifiRepositoryDagger, WifiRepositoryViaTrackerLibDagger {
- override fun start() {}
-
+class DisabledWifiRepository @Inject constructor() : RealWifiRepository {
override val isWifiEnabled: StateFlow<Boolean> = MutableStateFlow(false).asStateFlow()
override val isWifiDefault: StateFlow<Boolean> = MutableStateFlow(false).asStateFlow()
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/prod/WifiRepositoryHelper.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/prod/WifiRepositoryHelper.kt
deleted file mode 100644
index 67dd32f..0000000
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/prod/WifiRepositoryHelper.kt
+++ /dev/null
@@ -1,114 +0,0 @@
-/*
- * Copyright (C) 2023 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.systemui.statusbar.pipeline.wifi.data.repository.prod
-
-import android.annotation.SuppressLint
-import android.net.wifi.ScanResult
-import android.net.wifi.WifiManager
-import com.android.systemui.common.coroutine.ConflatedCallbackFlow.conflatedCallbackFlow
-import com.android.systemui.dagger.qualifiers.Background
-import com.android.systemui.dagger.qualifiers.Main
-import com.android.systemui.log.table.TableLogBuffer
-import com.android.systemui.log.table.logDiffsForTable
-import com.android.systemui.statusbar.pipeline.shared.data.model.DataActivityModel
-import com.android.systemui.statusbar.pipeline.shared.data.model.toWifiDataActivityModel
-import com.android.systemui.statusbar.pipeline.wifi.shared.model.WifiScanEntry
-import java.util.concurrent.Executor
-import kotlinx.coroutines.CoroutineDispatcher
-import kotlinx.coroutines.CoroutineScope
-import kotlinx.coroutines.asExecutor
-import kotlinx.coroutines.channels.awaitClose
-import kotlinx.coroutines.flow.SharingStarted
-import kotlinx.coroutines.flow.StateFlow
-import kotlinx.coroutines.flow.stateIn
-
-/**
- * Object to provide shared helper functions between [WifiRepositoryImpl] and
- * [WifiRepositoryViaTrackerLib].
- */
-object WifiRepositoryHelper {
- /** Creates a flow that fetches the [DataActivityModel] from [WifiManager]. */
- fun createActivityFlow(
- wifiManager: WifiManager,
- @Main mainExecutor: Executor,
- scope: CoroutineScope,
- tableLogBuffer: TableLogBuffer,
- inputLogger: (String) -> Unit,
- ): StateFlow<DataActivityModel> {
- return conflatedCallbackFlow {
- val callback =
- WifiManager.TrafficStateCallback { state ->
- inputLogger.invoke(prettyPrintActivity(state))
- trySend(state.toWifiDataActivityModel())
- }
- wifiManager.registerTrafficStateCallback(mainExecutor, callback)
- awaitClose { wifiManager.unregisterTrafficStateCallback(callback) }
- }
- .logDiffsForTable(
- tableLogBuffer,
- columnPrefix = ACTIVITY_PREFIX,
- initialValue = ACTIVITY_DEFAULT,
- )
- .stateIn(
- scope,
- started = SharingStarted.WhileSubscribed(),
- initialValue = ACTIVITY_DEFAULT,
- )
- }
-
- /**
- * Creates a flow that listens for new [ScanResult]s from [WifiManager]. Does not request a scan
- */
- fun createNetworkScanFlow(
- wifiManager: WifiManager,
- scope: CoroutineScope,
- @Background dispatcher: CoroutineDispatcher,
- inputLogger: () -> Unit,
- ): StateFlow<List<WifiScanEntry>> {
- return conflatedCallbackFlow {
- val callback =
- object : WifiManager.ScanResultsCallback() {
- @SuppressLint("MissingPermission")
- override fun onScanResultsAvailable() {
- inputLogger.invoke()
- trySend(wifiManager.scanResults.toModel())
- }
- }
-
- wifiManager.registerScanResultsCallback(dispatcher.asExecutor(), callback)
-
- awaitClose { wifiManager.unregisterScanResultsCallback(callback) }
- }
- .stateIn(scope, SharingStarted.Eagerly, emptyList())
- }
-
- private fun List<ScanResult>.toModel(): List<WifiScanEntry> = map { WifiScanEntry(it.SSID) }
-
- // TODO(b/292534484): This print should only be done in [MessagePrinter] part of the log buffer.
- private fun prettyPrintActivity(activity: Int): String {
- return when (activity) {
- WifiManager.TrafficStateCallback.DATA_ACTIVITY_NONE -> "NONE"
- WifiManager.TrafficStateCallback.DATA_ACTIVITY_IN -> "IN"
- WifiManager.TrafficStateCallback.DATA_ACTIVITY_OUT -> "OUT"
- WifiManager.TrafficStateCallback.DATA_ACTIVITY_INOUT -> "INOUT"
- else -> "INVALID"
- }
- }
-
- private const val ACTIVITY_PREFIX = "wifiActivity"
- val ACTIVITY_DEFAULT = DataActivityModel(hasActivityIn = false, hasActivityOut = false)
-}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/prod/WifiRepositoryImpl.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/prod/WifiRepositoryImpl.kt
index 59ef884..20e44e7 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/prod/WifiRepositoryImpl.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/prod/WifiRepositoryImpl.kt
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2022 The Android Open Source Project
+ * Copyright (C) 2023 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -17,309 +17,447 @@
package com.android.systemui.statusbar.pipeline.wifi.data.repository.prod
import android.annotation.SuppressLint
-import android.content.IntentFilter
-import android.net.ConnectivityManager
-import android.net.Network
-import android.net.NetworkCapabilities
-import android.net.NetworkCapabilities.NET_CAPABILITY_NOT_VPN
-import android.net.NetworkCapabilities.NET_CAPABILITY_VALIDATED
-import android.net.NetworkCapabilities.TRANSPORT_CELLULAR
-import android.net.NetworkCapabilities.TRANSPORT_WIFI
-import android.net.NetworkRequest
-import android.net.wifi.WifiInfo
+import android.net.wifi.ScanResult
import android.net.wifi.WifiManager
import android.telephony.SubscriptionManager.INVALID_SUBSCRIPTION_ID
-import com.android.systemui.broadcast.BroadcastDispatcher
+import androidx.lifecycle.Lifecycle
+import androidx.lifecycle.LifecycleOwner
+import androidx.lifecycle.LifecycleRegistry
+import com.android.internal.annotations.VisibleForTesting
import com.android.systemui.common.coroutine.ConflatedCallbackFlow.conflatedCallbackFlow
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Application
import com.android.systemui.dagger.qualifiers.Background
import com.android.systemui.dagger.qualifiers.Main
+import com.android.systemui.flags.FeatureFlags
+import com.android.systemui.flags.Flags
+import com.android.systemui.log.LogBuffer
+import com.android.systemui.log.core.LogLevel
import com.android.systemui.log.table.TableLogBuffer
import com.android.systemui.log.table.logDiffsForTable
+import com.android.systemui.statusbar.connectivity.WifiPickerTrackerFactory
+import com.android.systemui.statusbar.pipeline.dagger.WifiInputLog
import com.android.systemui.statusbar.pipeline.dagger.WifiTableLog
import com.android.systemui.statusbar.pipeline.shared.data.model.DataActivityModel
-import com.android.systemui.statusbar.pipeline.shared.data.repository.ConnectivityRepository
-import com.android.systemui.statusbar.pipeline.shared.data.repository.ConnectivityRepositoryImpl.Companion.getMainOrUnderlyingWifiInfo
-import com.android.systemui.statusbar.pipeline.wifi.data.repository.WifiRepository
+import com.android.systemui.statusbar.pipeline.shared.data.model.toWifiDataActivityModel
+import com.android.systemui.statusbar.pipeline.wifi.data.repository.RealWifiRepository
import com.android.systemui.statusbar.pipeline.wifi.data.repository.WifiRepository.Companion.CARRIER_MERGED_INVALID_SUB_ID_REASON
import com.android.systemui.statusbar.pipeline.wifi.data.repository.WifiRepository.Companion.COL_NAME_IS_DEFAULT
import com.android.systemui.statusbar.pipeline.wifi.data.repository.WifiRepository.Companion.COL_NAME_IS_ENABLED
-import com.android.systemui.statusbar.pipeline.wifi.data.repository.WifiRepositoryDagger
-import com.android.systemui.statusbar.pipeline.wifi.shared.WifiInputLogger
import com.android.systemui.statusbar.pipeline.wifi.shared.model.WifiNetworkModel
+import com.android.systemui.statusbar.pipeline.wifi.shared.model.WifiNetworkModel.Inactive.toHotspotDeviceType
import com.android.systemui.statusbar.pipeline.wifi.shared.model.WifiScanEntry
+import com.android.wifitrackerlib.HotspotNetworkEntry
+import com.android.wifitrackerlib.MergedCarrierEntry
+import com.android.wifitrackerlib.WifiEntry
+import com.android.wifitrackerlib.WifiEntry.WIFI_LEVEL_MAX
+import com.android.wifitrackerlib.WifiEntry.WIFI_LEVEL_MIN
+import com.android.wifitrackerlib.WifiEntry.WIFI_LEVEL_UNREACHABLE
+import com.android.wifitrackerlib.WifiPickerTracker
import java.util.concurrent.Executor
import javax.inject.Inject
import kotlinx.coroutines.CoroutineDispatcher
import kotlinx.coroutines.CoroutineScope
-import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.asExecutor
import kotlinx.coroutines.channels.awaitClose
-import kotlinx.coroutines.flow.Flow
-import kotlinx.coroutines.flow.MutableSharedFlow
-import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.SharingStarted
import kotlinx.coroutines.flow.StateFlow
-import kotlinx.coroutines.flow.asStateFlow
+import kotlinx.coroutines.flow.callbackFlow
import kotlinx.coroutines.flow.distinctUntilChanged
import kotlinx.coroutines.flow.map
-import kotlinx.coroutines.flow.mapLatest
-import kotlinx.coroutines.flow.merge
-import kotlinx.coroutines.flow.onEach
-import kotlinx.coroutines.flow.onStart
import kotlinx.coroutines.flow.stateIn
-import kotlinx.coroutines.launch
-import kotlinx.coroutines.withContext
-/** Real implementation of [WifiRepository]. */
-@Suppress("EXPERIMENTAL_IS_NOT_ENABLED")
-@OptIn(ExperimentalCoroutinesApi::class)
+/**
+ * A real implementation of [WifiRepository] that uses [com.android.wifitrackerlib] as the source of
+ * truth for wifi information.
+ */
@SysUISingleton
-@SuppressLint("MissingPermission")
class WifiRepositoryImpl
@Inject
constructor(
- broadcastDispatcher: BroadcastDispatcher,
- connectivityManager: ConnectivityManager,
- connectivityRepository: ConnectivityRepository,
- logger: WifiInputLogger,
- @WifiTableLog wifiTableLogBuffer: TableLogBuffer,
- @Main mainExecutor: Executor,
- @Background private val bgDispatcher: CoroutineDispatcher,
+ featureFlags: FeatureFlags,
@Application private val scope: CoroutineScope,
+ @Main private val mainExecutor: Executor,
+ @Background private val bgDispatcher: CoroutineDispatcher,
+ private val wifiPickerTrackerFactory: WifiPickerTrackerFactory,
private val wifiManager: WifiManager,
-) : WifiRepositoryDagger {
+ @WifiInputLog private val inputLogger: LogBuffer,
+ @WifiTableLog private val tableLogger: TableLogBuffer,
+) : RealWifiRepository, LifecycleOwner {
- override fun start() {
- // There are two possible [WifiRepository] implementations: This class (old) and
- // [WifiRepositoryFromTrackerLib] (new). While we migrate to the new class, we want this old
- // class to still be running in the background so that we can collect logs and compare
- // discrepancies. This #start method collects on the flows to ensure that the logs are
- // collected.
- scope.launch { isWifiEnabled.collect {} }
- scope.launch { isWifiDefault.collect {} }
- scope.launch { wifiNetwork.collect {} }
- scope.launch { wifiActivity.collect {} }
+ override val lifecycle =
+ LifecycleRegistry(this).also {
+ mainExecutor.execute { it.currentState = Lifecycle.State.CREATED }
+ }
+
+ private val isInstantTetherEnabled = featureFlags.isEnabled(Flags.INSTANT_TETHER)
+
+ private var wifiPickerTracker: WifiPickerTracker? = null
+
+ private val wifiPickerTrackerInfo: StateFlow<WifiPickerTrackerInfo> = run {
+ var current =
+ WifiPickerTrackerInfo(
+ state = WIFI_STATE_DEFAULT,
+ isDefault = false,
+ primaryNetwork = WIFI_NETWORK_DEFAULT,
+ secondaryNetworks = emptyList(),
+ )
+ callbackFlow {
+ val callback =
+ object : WifiPickerTracker.WifiPickerTrackerCallback {
+ override fun onWifiEntriesChanged() {
+ val connectedEntry = wifiPickerTracker.mergedOrPrimaryConnection
+ logOnWifiEntriesChanged(connectedEntry)
+
+ val secondaryNetworks =
+ if (featureFlags.isEnabled(Flags.WIFI_SECONDARY_NETWORKS)) {
+ val activeNetworks =
+ wifiPickerTracker?.activeWifiEntries ?: emptyList()
+ activeNetworks
+ .filter { it != connectedEntry && !it.isPrimaryNetwork }
+ .map { it.toWifiNetworkModel() }
+ } else {
+ emptyList()
+ }
+
+ // [WifiPickerTracker.connectedWifiEntry] will return the same instance
+ // but with updated internals. For example, when its validation status
+ // changes from false to true, the same instance is re-used but with the
+ // validated field updated.
+ //
+ // Because it's the same instance, the flow won't re-emit the value
+ // (even though the internals have changed). So, we need to transform it
+ // into our internal model immediately. [toWifiNetworkModel] always
+ // returns a new instance, so the flow is guaranteed to emit.
+ send(
+ newPrimaryNetwork = connectedEntry?.toPrimaryWifiNetworkModel()
+ ?: WIFI_NETWORK_DEFAULT,
+ newSecondaryNetworks = secondaryNetworks,
+ newIsDefault = connectedEntry?.isDefaultNetwork ?: false,
+ )
+ }
+
+ override fun onWifiStateChanged() {
+ val state = wifiPickerTracker?.wifiState
+ logOnWifiStateChanged(state)
+ send(newState = state ?: WIFI_STATE_DEFAULT)
+ }
+
+ override fun onNumSavedNetworksChanged() {}
+
+ override fun onNumSavedSubscriptionsChanged() {}
+
+ private fun send(
+ newState: Int = current.state,
+ newIsDefault: Boolean = current.isDefault,
+ newPrimaryNetwork: WifiNetworkModel = current.primaryNetwork,
+ newSecondaryNetworks: List<WifiNetworkModel> =
+ current.secondaryNetworks,
+ ) {
+ val new =
+ WifiPickerTrackerInfo(
+ newState,
+ newIsDefault,
+ newPrimaryNetwork,
+ newSecondaryNetworks,
+ )
+ current = new
+ trySend(new)
+ }
+ }
+
+ wifiPickerTracker =
+ wifiPickerTrackerFactory.create(lifecycle, callback, "WifiRepository").apply {
+ // By default, [WifiPickerTracker] will scan to see all available wifi
+ // networks in the area. Because SysUI only needs to display the
+ // **connected** network, we don't need scans to be running (and in fact,
+ // running scans is costly and should be avoided whenever possible).
+ this?.disableScanning()
+ }
+ // The lifecycle must be STARTED in order for the callback to receive events.
+ mainExecutor.execute { lifecycle.currentState = Lifecycle.State.STARTED }
+ awaitClose {
+ mainExecutor.execute { lifecycle.currentState = Lifecycle.State.CREATED }
+ }
+ }
+ .stateIn(scope, SharingStarted.Eagerly, current)
}
- private val wifiStateChangeEvents: Flow<Unit> =
- broadcastDispatcher
- .broadcastFlow(IntentFilter(WifiManager.WIFI_STATE_CHANGED_ACTION))
- .onEach { logger.logIntent("WIFI_STATE_CHANGED_ACTION") }
-
- private val wifiNetworkChangeEvents: MutableSharedFlow<Unit> =
- MutableSharedFlow(extraBufferCapacity = 1)
-
- // Because [WifiManager] doesn't expose a wifi enabled change listener, we do it
- // internally by fetching [WifiManager.isWifiEnabled] whenever we think the state may
- // have changed.
override val isWifiEnabled: StateFlow<Boolean> =
- merge(wifiNetworkChangeEvents, wifiStateChangeEvents)
- .onStart { emit(Unit) }
- .mapLatest { isWifiEnabled() }
+ wifiPickerTrackerInfo
+ .map { it.state == WifiManager.WIFI_STATE_ENABLED }
.distinctUntilChanged()
.logDiffsForTable(
- wifiTableLogBuffer,
+ tableLogger,
columnPrefix = "",
columnName = COL_NAME_IS_ENABLED,
initialValue = false,
)
- .stateIn(
- scope = scope,
- started = SharingStarted.Eagerly,
- initialValue = false,
- )
+ .stateIn(scope, SharingStarted.Eagerly, false)
- // [WifiManager.isWifiEnabled] is a blocking IPC call, so fetch it in the background.
- private suspend fun isWifiEnabled(): Boolean =
- withContext(bgDispatcher) { wifiManager.isWifiEnabled }
-
- override val isWifiDefault: StateFlow<Boolean> =
- connectivityRepository.defaultConnections
- // TODO(b/274493701): Should wifi be considered default if it's carrier merged?
- .map { it.wifi.isDefault || it.carrierMerged.isDefault }
+ override val wifiNetwork: StateFlow<WifiNetworkModel> =
+ wifiPickerTrackerInfo
+ .map { it.primaryNetwork }
.distinctUntilChanged()
.logDiffsForTable(
- wifiTableLogBuffer,
+ tableLogger,
+ columnPrefix = "",
+ initialValue = WIFI_NETWORK_DEFAULT,
+ )
+ .stateIn(scope, SharingStarted.Eagerly, WIFI_NETWORK_DEFAULT)
+
+ override val secondaryNetworks: StateFlow<List<WifiNetworkModel>> =
+ wifiPickerTrackerInfo
+ .map { it.secondaryNetworks }
+ .distinctUntilChanged()
+ .logDiffsForTable(
+ tableLogger,
+ columnPrefix = "",
+ columnName = "secondaryNetworks",
+ initialValue = emptyList(),
+ )
+ .stateIn(scope, SharingStarted.Eagerly, emptyList())
+
+ /**
+ * [WifiPickerTracker.getConnectedWifiEntry] stores a [MergedCarrierEntry] separately from the
+ * [WifiEntry] for the primary connection. Therefore, we have to prefer the carrier-merged entry
+ * if it exists, falling back on the connected entry if null
+ */
+ private val WifiPickerTracker?.mergedOrPrimaryConnection: WifiEntry?
+ get() {
+ val mergedEntry: MergedCarrierEntry? = this?.mergedCarrierEntry
+ return if (mergedEntry != null && mergedEntry.isDefaultNetwork) {
+ mergedEntry
+ } else {
+ this?.connectedWifiEntry
+ }
+ }
+
+ /**
+ * Converts WifiTrackerLib's [WifiEntry] into our internal model only if the entry is the
+ * primary network. Returns an inactive network if it's not primary.
+ */
+ private fun WifiEntry.toPrimaryWifiNetworkModel(): WifiNetworkModel {
+ return if (!this.isPrimaryNetwork) {
+ WIFI_NETWORK_DEFAULT
+ } else {
+ this.toWifiNetworkModel()
+ }
+ }
+
+ /** Converts WifiTrackerLib's [WifiEntry] into our internal model. */
+ private fun WifiEntry.toWifiNetworkModel(): WifiNetworkModel {
+ return if (this is MergedCarrierEntry) {
+ this.convertCarrierMergedToModel()
+ } else {
+ this.convertNormalToModel()
+ }
+ }
+
+ private fun MergedCarrierEntry.convertCarrierMergedToModel(): WifiNetworkModel {
+ return if (this.subscriptionId == INVALID_SUBSCRIPTION_ID) {
+ WifiNetworkModel.Invalid(CARRIER_MERGED_INVALID_SUB_ID_REASON)
+ } else {
+ WifiNetworkModel.CarrierMerged(
+ networkId = NETWORK_ID,
+ subscriptionId = this.subscriptionId,
+ level = this.level,
+ // WifiManager APIs to calculate the signal level start from 0, so
+ // maxSignalLevel + 1 represents the total level buckets count.
+ numberOfLevels = wifiManager.maxSignalLevel + 1,
+ )
+ }
+ }
+
+ private fun WifiEntry.convertNormalToModel(): WifiNetworkModel {
+ if (this.level == WIFI_LEVEL_UNREACHABLE || this.level !in WIFI_LEVEL_MIN..WIFI_LEVEL_MAX) {
+ // If our level means the network is unreachable or the level is otherwise invalid, we
+ // don't have an active network.
+ return WifiNetworkModel.Inactive
+ }
+
+ val hotspotDeviceType =
+ if (isInstantTetherEnabled && this is HotspotNetworkEntry) {
+ this.deviceType.toHotspotDeviceType()
+ } else {
+ WifiNetworkModel.HotspotDeviceType.NONE
+ }
+
+ return WifiNetworkModel.Active(
+ networkId = NETWORK_ID,
+ isValidated = this.hasInternetAccess(),
+ level = this.level,
+ ssid = this.title,
+ hotspotDeviceType = hotspotDeviceType,
+ // With WifiTrackerLib, [WifiEntry.title] will appropriately fetch the SSID for
+ // typical wifi networks *and* passpoint/OSU APs. So, the AP-specific values can
+ // always be false/null in this repository.
+ // TODO(b/292534484): Remove these fields from the wifi network model once this
+ // repository is fully enabled.
+ isPasspointAccessPoint = false,
+ isOnlineSignUpForPasspointAccessPoint = false,
+ passpointProviderFriendlyName = null,
+ )
+ }
+
+ override val isWifiDefault: StateFlow<Boolean> =
+ wifiPickerTrackerInfo
+ .map { it.isDefault }
+ .distinctUntilChanged()
+ .logDiffsForTable(
+ tableLogger,
columnPrefix = "",
columnName = COL_NAME_IS_DEFAULT,
initialValue = false,
)
- .stateIn(scope, started = SharingStarted.WhileSubscribed(), initialValue = false)
+ .stateIn(scope, SharingStarted.Eagerly, false)
- override val wifiNetwork: StateFlow<WifiNetworkModel> =
+ override val wifiActivity: StateFlow<DataActivityModel> =
conflatedCallbackFlow {
- var currentWifi: WifiNetworkModel = WIFI_NETWORK_DEFAULT
-
val callback =
- object : ConnectivityManager.NetworkCallback(FLAG_INCLUDE_LOCATION_INFO) {
- override fun onCapabilitiesChanged(
- network: Network,
- networkCapabilities: NetworkCapabilities
- ) {
- logger.logOnCapabilitiesChanged(
- network,
- networkCapabilities,
- isDefaultNetworkCallback = false,
- )
-
- wifiNetworkChangeEvents.tryEmit(Unit)
-
- val wifiInfo =
- networkCapabilities.getMainOrUnderlyingWifiInfo(connectivityManager)
- if (wifiInfo?.isPrimary == true) {
- val wifiNetworkModel =
- createWifiNetworkModel(
- wifiInfo,
- network,
- networkCapabilities,
- wifiManager,
- )
- currentWifi = wifiNetworkModel
- trySend(wifiNetworkModel)
- }
- }
-
- override fun onLost(network: Network) {
- logger.logOnLost(network, isDefaultNetworkCallback = false)
-
- wifiNetworkChangeEvents.tryEmit(Unit)
-
- val wifi = currentWifi
- if (
- (wifi is WifiNetworkModel.Active &&
- wifi.networkId == network.getNetId()) ||
- (wifi is WifiNetworkModel.CarrierMerged &&
- wifi.networkId == network.getNetId())
- ) {
- val newNetworkModel = WifiNetworkModel.Inactive
- currentWifi = newNetworkModel
- trySend(newNetworkModel)
- }
- }
+ WifiManager.TrafficStateCallback { state ->
+ logActivity(state)
+ trySend(state.toWifiDataActivityModel())
}
-
- connectivityManager.registerNetworkCallback(WIFI_NETWORK_CALLBACK_REQUEST, callback)
-
- awaitClose { connectivityManager.unregisterNetworkCallback(callback) }
+ wifiManager.registerTrafficStateCallback(mainExecutor, callback)
+ awaitClose { wifiManager.unregisterTrafficStateCallback(callback) }
}
- .distinctUntilChanged()
.logDiffsForTable(
- wifiTableLogBuffer,
- columnPrefix = "",
- initialValue = WIFI_NETWORK_DEFAULT,
+ tableLogger,
+ columnPrefix = ACTIVITY_PREFIX,
+ initialValue = ACTIVITY_DEFAULT,
)
- // There will be multiple wifi icons in different places that will frequently
- // subscribe/unsubscribe to flows as the views attach/detach. Using [stateIn] ensures
- // that new subscribes will get the latest value immediately upon subscription.
- // Otherwise, the views could show stale data. See b/244173280.
.stateIn(
scope,
started = SharingStarted.WhileSubscribed(),
- initialValue = WIFI_NETWORK_DEFAULT,
+ initialValue = ACTIVITY_DEFAULT,
)
- // Secondary networks can only be supported by [WifiRepositoryViaTrackerLib].
- override val secondaryNetworks: StateFlow<List<WifiNetworkModel>> =
- MutableStateFlow(emptyList<WifiNetworkModel>()).asStateFlow()
-
- override val wifiActivity: StateFlow<DataActivityModel> =
- WifiRepositoryHelper.createActivityFlow(
- wifiManager,
- mainExecutor,
- scope,
- wifiTableLogBuffer,
- logger::logActivity,
- )
-
override val wifiScanResults: StateFlow<List<WifiScanEntry>> =
- WifiRepositoryHelper.createNetworkScanFlow(
- wifiManager,
- scope,
- bgDispatcher,
- logger::logScanResults
- )
+ conflatedCallbackFlow {
+ val callback =
+ object : WifiManager.ScanResultsCallback() {
+ @SuppressLint("MissingPermission")
+ override fun onScanResultsAvailable() {
+ logScanResults()
+ trySend(wifiManager.scanResults.toModel())
+ }
+ }
- companion object {
- // Start out with no known wifi network.
- // Note: [WifiStatusTracker] (the old implementation of connectivity logic) does do an
- // initial fetch to get a starting wifi network. But, it uses a deprecated API
- // [WifiManager.getConnectionInfo()], and the deprecation doc indicates to just use
- // [ConnectivityManager.NetworkCallback] results instead. So, for now we'll just rely on the
- // NetworkCallback inside [wifiNetwork] for our wifi network information.
- val WIFI_NETWORK_DEFAULT = WifiNetworkModel.Inactive
+ wifiManager.registerScanResultsCallback(bgDispatcher.asExecutor(), callback)
- const val WIFI_STATE_DEFAULT = WifiManager.WIFI_STATE_DISABLED
-
- private fun createWifiNetworkModel(
- wifiInfo: WifiInfo,
- network: Network,
- networkCapabilities: NetworkCapabilities,
- wifiManager: WifiManager,
- ): WifiNetworkModel {
- return if (wifiInfo.isCarrierMerged) {
- if (wifiInfo.subscriptionId == INVALID_SUBSCRIPTION_ID) {
- WifiNetworkModel.Invalid(CARRIER_MERGED_INVALID_SUB_ID_REASON)
- } else {
- WifiNetworkModel.CarrierMerged(
- networkId = network.getNetId(),
- subscriptionId = wifiInfo.subscriptionId,
- level = wifiManager.calculateSignalLevel(wifiInfo.rssi),
- // The WiFi signal level returned by WifiManager#calculateSignalLevel start
- // from 0, so WifiManager#getMaxSignalLevel + 1 represents the total level
- // buckets count.
- numberOfLevels = wifiManager.maxSignalLevel + 1,
- )
- }
- } else {
- WifiNetworkModel.Active(
- network.getNetId(),
- isValidated = networkCapabilities.hasCapability(NET_CAPABILITY_VALIDATED),
- level = wifiManager.calculateSignalLevel(wifiInfo.rssi),
- wifiInfo.ssid,
- // This repository doesn't support any hotspot information.
- WifiNetworkModel.HotspotDeviceType.NONE,
- wifiInfo.isPasspointAp,
- wifiInfo.isOsuAp,
- wifiInfo.passpointProviderFriendlyName
- )
+ awaitClose { wifiManager.unregisterScanResultsCallback(callback) }
}
- }
+ .stateIn(scope, SharingStarted.Eagerly, emptyList())
- private val WIFI_NETWORK_CALLBACK_REQUEST: NetworkRequest =
- NetworkRequest.Builder()
- .clearCapabilities()
- .addCapability(NET_CAPABILITY_NOT_VPN)
- .addTransportType(TRANSPORT_WIFI)
- .addTransportType(TRANSPORT_CELLULAR)
- .build()
+ private fun List<ScanResult>.toModel(): List<WifiScanEntry> = map { WifiScanEntry(it.SSID) }
+
+ private fun logOnWifiEntriesChanged(connectedEntry: WifiEntry?) {
+ inputLogger.log(
+ TAG,
+ LogLevel.DEBUG,
+ { str1 = connectedEntry.toString() },
+ { "onWifiEntriesChanged. ConnectedEntry=$str1" },
+ )
}
+ private fun logOnWifiStateChanged(state: Int?) {
+ inputLogger.log(
+ TAG,
+ LogLevel.DEBUG,
+ { int1 = state ?: -1 },
+ { "onWifiStateChanged. State=${if (int1 == -1) null else int1}" },
+ )
+ }
+
+ private fun logActivity(activity: Int) {
+ inputLogger.log(
+ TAG,
+ LogLevel.DEBUG,
+ { str1 = prettyPrintActivity(activity) },
+ { "onActivityChanged: $str1" }
+ )
+ }
+
+ // TODO(b/292534484): This print should only be done in [MessagePrinter] part of the log buffer.
+ private fun prettyPrintActivity(activity: Int): String {
+ return when (activity) {
+ WifiManager.TrafficStateCallback.DATA_ACTIVITY_NONE -> "NONE"
+ WifiManager.TrafficStateCallback.DATA_ACTIVITY_IN -> "IN"
+ WifiManager.TrafficStateCallback.DATA_ACTIVITY_OUT -> "OUT"
+ WifiManager.TrafficStateCallback.DATA_ACTIVITY_INOUT -> "INOUT"
+ else -> "INVALID"
+ }
+ }
+
+ private fun logScanResults() =
+ inputLogger.log(TAG, LogLevel.DEBUG, {}, { "onScanResultsAvailable" })
+
+ /**
+ * Data class storing all the information fetched from [WifiPickerTracker].
+ *
+ * Used so that we only register a single callback on [WifiPickerTracker].
+ */
+ data class WifiPickerTrackerInfo(
+ /** The current wifi state. See [WifiManager.getWifiState]. */
+ val state: Int,
+ /** True if wifi is currently the default connection and false otherwise. */
+ val isDefault: Boolean,
+ /** The currently primary wifi network. */
+ val primaryNetwork: WifiNetworkModel,
+ /** The current secondary network(s), if any. Specifically excludes the primary network. */
+ val secondaryNetworks: List<WifiNetworkModel>
+ )
+
@SysUISingleton
class Factory
@Inject
constructor(
- private val broadcastDispatcher: BroadcastDispatcher,
- private val connectivityManager: ConnectivityManager,
- private val connectivityRepository: ConnectivityRepository,
- private val logger: WifiInputLogger,
- @WifiTableLog private val wifiTableLogBuffer: TableLogBuffer,
+ private val featureFlags: FeatureFlags,
+ @Application private val scope: CoroutineScope,
@Main private val mainExecutor: Executor,
@Background private val bgDispatcher: CoroutineDispatcher,
- @Application private val scope: CoroutineScope,
+ private val wifiPickerTrackerFactory: WifiPickerTrackerFactory,
+ @WifiInputLog private val inputLogger: LogBuffer,
+ @WifiTableLog private val tableLogger: TableLogBuffer,
) {
fun create(wifiManager: WifiManager): WifiRepositoryImpl {
return WifiRepositoryImpl(
- broadcastDispatcher,
- connectivityManager,
- connectivityRepository,
- logger,
- wifiTableLogBuffer,
+ featureFlags,
+ scope,
mainExecutor,
bgDispatcher,
- scope,
+ wifiPickerTrackerFactory,
wifiManager,
+ inputLogger,
+ tableLogger,
)
}
}
+
+ companion object {
+ // Start out with no known wifi network.
+ @VisibleForTesting val WIFI_NETWORK_DEFAULT = WifiNetworkModel.Inactive
+
+ private const val WIFI_STATE_DEFAULT = WifiManager.WIFI_STATE_DISABLED
+
+ private const val ACTIVITY_PREFIX = "wifiActivity"
+ val ACTIVITY_DEFAULT = DataActivityModel(hasActivityIn = false, hasActivityOut = false)
+
+ private const val TAG = "WifiTrackerLibInputLog"
+
+ /**
+ * [WifiNetworkModel.Active.networkId] is only used at the repository layer. It's used by
+ * [WifiRepositoryImpl], which tracks the ID in order to correctly apply the framework
+ * callbacks within the repository.
+ *
+ * Since this class does not need to manually apply framework callbacks and since the
+ * network ID is not used beyond the repository, it's safe to use an invalid ID in this
+ * repository.
+ *
+ * The [WifiNetworkModel.Active.networkId] field should be deleted once we've fully migrated
+ * to [WifiRepositoryImpl].
+ */
+ private const val NETWORK_ID = -1
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/prod/WifiRepositoryViaTrackerLib.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/prod/WifiRepositoryViaTrackerLib.kt
deleted file mode 100644
index 1670dd3..0000000
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/prod/WifiRepositoryViaTrackerLib.kt
+++ /dev/null
@@ -1,414 +0,0 @@
-/*
- * Copyright (C) 2023 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.systemui.statusbar.pipeline.wifi.data.repository.prod
-
-import android.net.wifi.WifiManager
-import android.telephony.SubscriptionManager.INVALID_SUBSCRIPTION_ID
-import androidx.lifecycle.Lifecycle
-import androidx.lifecycle.LifecycleOwner
-import androidx.lifecycle.LifecycleRegistry
-import com.android.systemui.dagger.SysUISingleton
-import com.android.systemui.dagger.qualifiers.Application
-import com.android.systemui.dagger.qualifiers.Background
-import com.android.systemui.dagger.qualifiers.Main
-import com.android.systemui.flags.FeatureFlags
-import com.android.systemui.flags.Flags
-import com.android.systemui.log.LogBuffer
-import com.android.systemui.log.core.LogLevel
-import com.android.systemui.log.table.TableLogBuffer
-import com.android.systemui.log.table.logDiffsForTable
-import com.android.systemui.statusbar.connectivity.WifiPickerTrackerFactory
-import com.android.systemui.statusbar.pipeline.dagger.WifiTrackerLibInputLog
-import com.android.systemui.statusbar.pipeline.dagger.WifiTrackerLibTableLog
-import com.android.systemui.statusbar.pipeline.shared.data.model.DataActivityModel
-import com.android.systemui.statusbar.pipeline.wifi.data.repository.WifiRepository.Companion.CARRIER_MERGED_INVALID_SUB_ID_REASON
-import com.android.systemui.statusbar.pipeline.wifi.data.repository.WifiRepository.Companion.COL_NAME_IS_DEFAULT
-import com.android.systemui.statusbar.pipeline.wifi.data.repository.WifiRepository.Companion.COL_NAME_IS_ENABLED
-import com.android.systemui.statusbar.pipeline.wifi.data.repository.WifiRepositoryViaTrackerLibDagger
-import com.android.systemui.statusbar.pipeline.wifi.data.repository.prod.WifiRepositoryImpl.Companion.WIFI_NETWORK_DEFAULT
-import com.android.systemui.statusbar.pipeline.wifi.data.repository.prod.WifiRepositoryImpl.Companion.WIFI_STATE_DEFAULT
-import com.android.systemui.statusbar.pipeline.wifi.shared.model.WifiNetworkModel
-import com.android.systemui.statusbar.pipeline.wifi.shared.model.WifiNetworkModel.Inactive.toHotspotDeviceType
-import com.android.systemui.statusbar.pipeline.wifi.shared.model.WifiScanEntry
-import com.android.wifitrackerlib.HotspotNetworkEntry
-import com.android.wifitrackerlib.MergedCarrierEntry
-import com.android.wifitrackerlib.WifiEntry
-import com.android.wifitrackerlib.WifiEntry.WIFI_LEVEL_MAX
-import com.android.wifitrackerlib.WifiEntry.WIFI_LEVEL_MIN
-import com.android.wifitrackerlib.WifiEntry.WIFI_LEVEL_UNREACHABLE
-import com.android.wifitrackerlib.WifiPickerTracker
-import java.util.concurrent.Executor
-import javax.inject.Inject
-import kotlinx.coroutines.CoroutineDispatcher
-import kotlinx.coroutines.CoroutineScope
-import kotlinx.coroutines.channels.awaitClose
-import kotlinx.coroutines.flow.SharingStarted
-import kotlinx.coroutines.flow.StateFlow
-import kotlinx.coroutines.flow.callbackFlow
-import kotlinx.coroutines.flow.distinctUntilChanged
-import kotlinx.coroutines.flow.map
-import kotlinx.coroutines.flow.stateIn
-
-/**
- * An implementation of [WifiRepository] that uses [com.android.wifitrackerlib] as the source of
- * truth for wifi information.
- *
- * Serves as a possible replacement for [WifiRepositoryImpl]. See b/292534484.
- */
-@SysUISingleton
-class WifiRepositoryViaTrackerLib
-@Inject
-constructor(
- featureFlags: FeatureFlags,
- @Application private val scope: CoroutineScope,
- @Main private val mainExecutor: Executor,
- @Background private val bgDispatcher: CoroutineDispatcher,
- private val wifiPickerTrackerFactory: WifiPickerTrackerFactory,
- private val wifiManager: WifiManager,
- @WifiTrackerLibInputLog private val inputLogger: LogBuffer,
- @WifiTrackerLibTableLog private val wifiTrackerLibTableLogBuffer: TableLogBuffer,
-) : WifiRepositoryViaTrackerLibDagger, LifecycleOwner {
-
- override val lifecycle =
- LifecycleRegistry(this).also {
- mainExecutor.execute { it.currentState = Lifecycle.State.CREATED }
- }
-
- private val isInstantTetherEnabled = featureFlags.isEnabled(Flags.INSTANT_TETHER)
-
- private var wifiPickerTracker: WifiPickerTracker? = null
-
- private val wifiPickerTrackerInfo: StateFlow<WifiPickerTrackerInfo> = run {
- var current =
- WifiPickerTrackerInfo(
- state = WIFI_STATE_DEFAULT,
- isDefault = false,
- primaryNetwork = WIFI_NETWORK_DEFAULT,
- secondaryNetworks = emptyList(),
- )
- callbackFlow {
- val callback =
- object : WifiPickerTracker.WifiPickerTrackerCallback {
- override fun onWifiEntriesChanged() {
- val connectedEntry = wifiPickerTracker.mergedOrPrimaryConnection
- logOnWifiEntriesChanged(connectedEntry)
-
- val secondaryNetworks =
- if (featureFlags.isEnabled(Flags.WIFI_SECONDARY_NETWORKS)) {
- val activeNetworks =
- wifiPickerTracker?.activeWifiEntries ?: emptyList()
- activeNetworks
- .filter { it != connectedEntry && !it.isPrimaryNetwork }
- .map { it.toWifiNetworkModel() }
- } else {
- emptyList()
- }
-
- // [WifiPickerTracker.connectedWifiEntry] will return the same instance
- // but with updated internals. For example, when its validation status
- // changes from false to true, the same instance is re-used but with the
- // validated field updated.
- //
- // Because it's the same instance, the flow won't re-emit the value
- // (even though the internals have changed). So, we need to transform it
- // into our internal model immediately. [toWifiNetworkModel] always
- // returns a new instance, so the flow is guaranteed to emit.
- send(
- newPrimaryNetwork = connectedEntry?.toPrimaryWifiNetworkModel()
- ?: WIFI_NETWORK_DEFAULT,
- newSecondaryNetworks = secondaryNetworks,
- newIsDefault = connectedEntry?.isDefaultNetwork ?: false,
- )
- }
-
- override fun onWifiStateChanged() {
- val state = wifiPickerTracker?.wifiState
- logOnWifiStateChanged(state)
- send(newState = state ?: WIFI_STATE_DEFAULT)
- }
-
- override fun onNumSavedNetworksChanged() {}
-
- override fun onNumSavedSubscriptionsChanged() {}
-
- private fun send(
- newState: Int = current.state,
- newIsDefault: Boolean = current.isDefault,
- newPrimaryNetwork: WifiNetworkModel = current.primaryNetwork,
- newSecondaryNetworks: List<WifiNetworkModel> =
- current.secondaryNetworks,
- ) {
- val new =
- WifiPickerTrackerInfo(
- newState,
- newIsDefault,
- newPrimaryNetwork,
- newSecondaryNetworks,
- )
- current = new
- trySend(new)
- }
- }
-
- wifiPickerTracker =
- wifiPickerTrackerFactory.create(lifecycle, callback, "WifiRepository").apply {
- // By default, [WifiPickerTracker] will scan to see all available wifi
- // networks in the area. Because SysUI only needs to display the
- // **connected** network, we don't need scans to be running (and in fact,
- // running scans is costly and should be avoided whenever possible).
- this?.disableScanning()
- }
- // The lifecycle must be STARTED in order for the callback to receive events.
- mainExecutor.execute { lifecycle.currentState = Lifecycle.State.STARTED }
- awaitClose {
- mainExecutor.execute { lifecycle.currentState = Lifecycle.State.CREATED }
- }
- }
- .stateIn(scope, SharingStarted.Eagerly, current)
- }
-
- override val isWifiEnabled: StateFlow<Boolean> =
- wifiPickerTrackerInfo
- .map { it.state == WifiManager.WIFI_STATE_ENABLED }
- .distinctUntilChanged()
- .logDiffsForTable(
- wifiTrackerLibTableLogBuffer,
- columnPrefix = "",
- columnName = COL_NAME_IS_ENABLED,
- initialValue = false,
- )
- .stateIn(scope, SharingStarted.Eagerly, false)
-
- override val wifiNetwork: StateFlow<WifiNetworkModel> =
- wifiPickerTrackerInfo
- .map { it.primaryNetwork }
- .distinctUntilChanged()
- .logDiffsForTable(
- wifiTrackerLibTableLogBuffer,
- columnPrefix = "",
- initialValue = WIFI_NETWORK_DEFAULT,
- )
- .stateIn(scope, SharingStarted.Eagerly, WIFI_NETWORK_DEFAULT)
-
- override val secondaryNetworks: StateFlow<List<WifiNetworkModel>> =
- wifiPickerTrackerInfo
- .map { it.secondaryNetworks }
- .distinctUntilChanged()
- .logDiffsForTable(
- wifiTrackerLibTableLogBuffer,
- columnPrefix = "",
- columnName = "secondaryNetworks",
- initialValue = emptyList(),
- )
- .stateIn(scope, SharingStarted.Eagerly, emptyList())
-
- /**
- * [WifiPickerTracker.getConnectedWifiEntry] stores a [MergedCarrierEntry] separately from the
- * [WifiEntry] for the primary connection. Therefore, we have to prefer the carrier-merged entry
- * if it exists, falling back on the connected entry if null
- */
- private val WifiPickerTracker?.mergedOrPrimaryConnection: WifiEntry?
- get() {
- val mergedEntry: MergedCarrierEntry? = this?.mergedCarrierEntry
- return if (mergedEntry != null && mergedEntry.isDefaultNetwork) {
- mergedEntry
- } else {
- this?.connectedWifiEntry
- }
- }
-
- /**
- * Converts WifiTrackerLib's [WifiEntry] into our internal model only if the entry is the
- * primary network. Returns an inactive network if it's not primary.
- */
- private fun WifiEntry.toPrimaryWifiNetworkModel(): WifiNetworkModel {
- return if (!this.isPrimaryNetwork) {
- WIFI_NETWORK_DEFAULT
- } else {
- this.toWifiNetworkModel()
- }
- }
-
- /** Converts WifiTrackerLib's [WifiEntry] into our internal model. */
- private fun WifiEntry.toWifiNetworkModel(): WifiNetworkModel {
- return if (this is MergedCarrierEntry) {
- this.convertCarrierMergedToModel()
- } else {
- this.convertNormalToModel()
- }
- }
-
- private fun MergedCarrierEntry.convertCarrierMergedToModel(): WifiNetworkModel {
- return if (this.subscriptionId == INVALID_SUBSCRIPTION_ID) {
- WifiNetworkModel.Invalid(CARRIER_MERGED_INVALID_SUB_ID_REASON)
- } else {
- WifiNetworkModel.CarrierMerged(
- networkId = NETWORK_ID,
- subscriptionId = this.subscriptionId,
- level = this.level,
- // WifiManager APIs to calculate the signal level start from 0, so
- // maxSignalLevel + 1 represents the total level buckets count.
- numberOfLevels = wifiManager.maxSignalLevel + 1,
- )
- }
- }
-
- private fun WifiEntry.convertNormalToModel(): WifiNetworkModel {
- if (this.level == WIFI_LEVEL_UNREACHABLE || this.level !in WIFI_LEVEL_MIN..WIFI_LEVEL_MAX) {
- // If our level means the network is unreachable or the level is otherwise invalid, we
- // don't have an active network.
- return WifiNetworkModel.Inactive
- }
-
- val hotspotDeviceType =
- if (isInstantTetherEnabled && this is HotspotNetworkEntry) {
- this.deviceType.toHotspotDeviceType()
- } else {
- WifiNetworkModel.HotspotDeviceType.NONE
- }
-
- return WifiNetworkModel.Active(
- networkId = NETWORK_ID,
- isValidated = this.hasInternetAccess(),
- level = this.level,
- ssid = this.title,
- hotspotDeviceType = hotspotDeviceType,
- // With WifiTrackerLib, [WifiEntry.title] will appropriately fetch the SSID for
- // typical wifi networks *and* passpoint/OSU APs. So, the AP-specific values can
- // always be false/null in this repository.
- // TODO(b/292534484): Remove these fields from the wifi network model once this
- // repository is fully enabled.
- isPasspointAccessPoint = false,
- isOnlineSignUpForPasspointAccessPoint = false,
- passpointProviderFriendlyName = null,
- )
- }
-
- override val isWifiDefault: StateFlow<Boolean> =
- wifiPickerTrackerInfo
- .map { it.isDefault }
- .distinctUntilChanged()
- .logDiffsForTable(
- wifiTrackerLibTableLogBuffer,
- columnPrefix = "",
- columnName = COL_NAME_IS_DEFAULT,
- initialValue = false,
- )
- .stateIn(scope, SharingStarted.Eagerly, false)
-
- override val wifiActivity: StateFlow<DataActivityModel> =
- WifiRepositoryHelper.createActivityFlow(
- wifiManager,
- mainExecutor,
- scope,
- wifiTrackerLibTableLogBuffer,
- this::logActivity,
- )
-
- override val wifiScanResults: StateFlow<List<WifiScanEntry>> =
- WifiRepositoryHelper.createNetworkScanFlow(
- wifiManager,
- scope,
- bgDispatcher,
- this::logScanResults,
- )
-
- private fun logOnWifiEntriesChanged(connectedEntry: WifiEntry?) {
- inputLogger.log(
- TAG,
- LogLevel.DEBUG,
- { str1 = connectedEntry.toString() },
- { "onWifiEntriesChanged. ConnectedEntry=$str1" },
- )
- }
-
- private fun logOnWifiStateChanged(state: Int?) {
- inputLogger.log(
- TAG,
- LogLevel.DEBUG,
- { int1 = state ?: -1 },
- { "onWifiStateChanged. State=${if (int1 == -1) null else int1}" },
- )
- }
-
- private fun logActivity(activity: String) {
- inputLogger.log(TAG, LogLevel.DEBUG, { str1 = activity }, { "onActivityChanged: $str1" })
- }
-
- private fun logScanResults() =
- inputLogger.log(TAG, LogLevel.DEBUG, {}, { "onScanResultsAvailable" })
-
- /**
- * Data class storing all the information fetched from [WifiPickerTracker].
- *
- * Used so that we only register a single callback on [WifiPickerTracker].
- */
- data class WifiPickerTrackerInfo(
- /** The current wifi state. See [WifiManager.getWifiState]. */
- val state: Int,
- /** True if wifi is currently the default connection and false otherwise. */
- val isDefault: Boolean,
- /** The currently primary wifi network. */
- val primaryNetwork: WifiNetworkModel,
- /** The current secondary network(s), if any. Specifically excludes the primary network. */
- val secondaryNetworks: List<WifiNetworkModel>
- )
-
- @SysUISingleton
- class Factory
- @Inject
- constructor(
- private val featureFlags: FeatureFlags,
- @Application private val scope: CoroutineScope,
- @Main private val mainExecutor: Executor,
- @Background private val bgDispatcher: CoroutineDispatcher,
- private val wifiPickerTrackerFactory: WifiPickerTrackerFactory,
- @WifiTrackerLibInputLog private val inputLogger: LogBuffer,
- @WifiTrackerLibTableLog private val wifiTrackerLibTableLogBuffer: TableLogBuffer,
- ) {
- fun create(wifiManager: WifiManager): WifiRepositoryViaTrackerLib {
- return WifiRepositoryViaTrackerLib(
- featureFlags,
- scope,
- mainExecutor,
- bgDispatcher,
- wifiPickerTrackerFactory,
- wifiManager,
- inputLogger,
- wifiTrackerLibTableLogBuffer,
- )
- }
- }
-
- companion object {
- private const val TAG = "WifiTrackerLibInputLog"
-
- /**
- * [WifiNetworkModel.Active.networkId] is only used at the repository layer. It's used by
- * [WifiRepositoryImpl], which tracks the ID in order to correctly apply the framework
- * callbacks within the repository.
- *
- * Since this class does not need to manually apply framework callbacks and since the
- * network ID is not used beyond the repository, it's safe to use an invalid ID in this
- * repository.
- *
- * The [WifiNetworkModel.Active.networkId] field should be deleted once we've fully migrated
- * to [WifiRepositoryViaTrackerLib].
- */
- private const val NETWORK_ID = -1
- }
-}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/shared/WifiInputLogger.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/shared/WifiInputLogger.kt
deleted file mode 100644
index b76bb51..0000000
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/shared/WifiInputLogger.kt
+++ /dev/null
@@ -1,66 +0,0 @@
-/*
- * Copyright (C) 2023 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.systemui.statusbar.pipeline.wifi.shared
-
-import android.net.Network
-import android.net.NetworkCapabilities
-import com.android.systemui.dagger.SysUISingleton
-import com.android.systemui.log.LogBuffer
-import com.android.systemui.log.core.LogLevel
-import com.android.systemui.statusbar.pipeline.dagger.WifiInputLog
-import com.android.systemui.statusbar.pipeline.shared.LoggerHelper
-import javax.inject.Inject
-
-/**
- * Logger for all the wifi-related inputs (intents, callbacks, etc.) that the wifi repo receives.
- */
-@SysUISingleton
-class WifiInputLogger
-@Inject
-constructor(
- @WifiInputLog val buffer: LogBuffer,
-) {
- fun logOnCapabilitiesChanged(
- network: Network,
- networkCapabilities: NetworkCapabilities,
- isDefaultNetworkCallback: Boolean,
- ) {
- LoggerHelper.logOnCapabilitiesChanged(
- buffer,
- TAG,
- network,
- networkCapabilities,
- isDefaultNetworkCallback,
- )
- }
-
- fun logOnLost(network: Network, isDefaultNetworkCallback: Boolean) {
- LoggerHelper.logOnLost(buffer, TAG, network, isDefaultNetworkCallback)
- }
-
- fun logIntent(intentName: String) {
- buffer.log(TAG, LogLevel.DEBUG, { str1 = intentName }, { "Intent received: $str1" })
- }
-
- fun logActivity(activity: String) {
- buffer.log(TAG, LogLevel.DEBUG, { str1 = activity }, { "Activity: $str1" })
- }
-
- fun logScanResults() = buffer.log(TAG, LogLevel.DEBUG, {}, { "onScanResultsAvailable" })
-}
-
-private const val TAG = "WifiInputLog"
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionsRepositoryTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionsRepositoryTest.kt
index b7a3b30..b5525b1 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionsRepositoryTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionsRepositoryTest.kt
@@ -26,6 +26,7 @@
import android.net.NetworkCapabilities.TRANSPORT_WIFI
import android.net.vcn.VcnTransportInfo
import android.net.wifi.WifiInfo
+import android.net.wifi.WifiManager
import android.os.ParcelUuid
import android.telephony.CarrierConfigManager
import android.telephony.SubscriptionInfo
@@ -46,8 +47,10 @@
import com.android.systemui.coroutines.collectLastValue
import com.android.systemui.flags.FakeFeatureFlagsClassic
import com.android.systemui.flags.Flags
+import com.android.systemui.log.LogBuffer
import com.android.systemui.log.table.TableLogBuffer
import com.android.systemui.log.table.TableLogBufferFactory
+import com.android.systemui.statusbar.connectivity.WifiPickerTrackerFactory
import com.android.systemui.statusbar.pipeline.airplane.data.repository.FakeAirplaneModeRepository
import com.android.systemui.statusbar.pipeline.mobile.data.MobileInputLogger
import com.android.systemui.statusbar.pipeline.mobile.data.model.SubscriptionModel
@@ -64,10 +67,14 @@
import com.android.systemui.util.concurrency.FakeExecutor
import com.android.systemui.util.mockito.any
import com.android.systemui.util.mockito.argumentCaptor
+import com.android.systemui.util.mockito.capture
import com.android.systemui.util.mockito.eq
import com.android.systemui.util.mockito.mock
import com.android.systemui.util.mockito.whenever
import com.android.systemui.util.time.FakeSystemClock
+import com.android.wifitrackerlib.MergedCarrierEntry
+import com.android.wifitrackerlib.WifiEntry
+import com.android.wifitrackerlib.WifiPickerTracker
import com.google.common.truth.Truth.assertThat
import java.util.UUID
import kotlinx.coroutines.ExperimentalCoroutinesApi
@@ -97,7 +104,11 @@
class MobileConnectionsRepositoryTest : SysuiTestCase() {
private val flags =
- FakeFeatureFlagsClassic().also { it.set(Flags.ROAMING_INDICATOR_VIA_DISPLAY_INFO, true) }
+ FakeFeatureFlagsClassic().also {
+ it.set(Flags.ROAMING_INDICATOR_VIA_DISPLAY_INFO, true)
+ it.set(Flags.INSTANT_TETHER, true)
+ it.set(Flags.WIFI_SECONDARY_NETWORKS, true)
+ }
private lateinit var connectionFactory: MobileConnectionRepositoryImpl.Factory
private lateinit var carrierMergedFactory: CarrierMergedConnectionRepository.Factory
@@ -114,9 +125,17 @@
@Mock private lateinit var summaryLogger: TableLogBuffer
@Mock private lateinit var logBufferFactory: TableLogBufferFactory
@Mock private lateinit var updateMonitor: KeyguardUpdateMonitor
+ @Mock private lateinit var wifiManager: WifiManager
+ @Mock private lateinit var wifiPickerTrackerFactory: WifiPickerTrackerFactory
+ @Mock private lateinit var wifiPickerTracker: WifiPickerTracker
+ @Mock private lateinit var wifiTableLogBuffer: TableLogBuffer
private val mobileMappings = FakeMobileMappingsProxy()
private val subscriptionManagerProxy = FakeSubscriptionManagerProxy()
+ private val mainExecutor = FakeExecutor(FakeSystemClock())
+ private val wifiLogBuffer = LogBuffer("wifi", maxSize = 100, logcatEchoTracker = mock())
+ private val wifiPickerTrackerCallback =
+ argumentCaptor<WifiPickerTracker.WifiPickerTrackerCallback>()
private val dispatcher = StandardTestDispatcher()
private val testScope = TestScope(dispatcher)
@@ -139,6 +158,9 @@
mock<TableLogBuffer>()
}
+ whenever(wifiPickerTrackerFactory.create(any(), capture(wifiPickerTrackerCallback), any()))
+ .thenReturn(wifiPickerTracker)
+
// For convenience, set up the subscription info callbacks
whenever(subscriptionManager.getActiveSubscriptionInfo(anyInt())).thenAnswer { invocation ->
when (invocation.getArgument(0) as Int) {
@@ -165,15 +187,14 @@
wifiRepository =
WifiRepositoryImpl(
- fakeBroadcastDispatcher,
- connectivityManager,
- connectivityRepository,
- mock(),
- mock(),
- FakeExecutor(FakeSystemClock()),
- dispatcher,
+ flags,
testScope.backgroundScope,
- mock(),
+ mainExecutor,
+ dispatcher,
+ wifiPickerTrackerFactory,
+ wifiManager,
+ wifiLogBuffer,
+ wifiTableLogBuffer,
)
carrierConfigRepository =
@@ -278,7 +299,7 @@
testScope.runTest {
val latest by collectLastValue(underTest.subscriptions)
- getNormalNetworkCallback().onCapabilitiesChanged(NETWORK, WIFI_NETWORK_CAPS_CM)
+ setWifiState(isCarrierMerged = true)
whenever(subscriptionManager.completeActiveSubscriptionInfoList)
.thenReturn(listOf(SUB_CM))
getSubscriptionCallback().onSubscriptionsChanged()
@@ -291,7 +312,7 @@
testScope.runTest {
val latest by collectLastValue(underTest.subscriptions)
- getNormalNetworkCallback().onCapabilitiesChanged(NETWORK, WIFI_NETWORK_CAPS_CM)
+ setWifiState(isCarrierMerged = true)
whenever(subscriptionManager.completeActiveSubscriptionInfoList)
.thenReturn(listOf(SUB_1, SUB_2, SUB_CM))
getSubscriptionCallback().onSubscriptionsChanged()
@@ -445,7 +466,7 @@
collectLastValue(underTest.subscriptions)
getDefaultNetworkCallback().onCapabilitiesChanged(NETWORK, WIFI_NETWORK_CAPS_CM)
- getNormalNetworkCallback().onCapabilitiesChanged(NETWORK, WIFI_NETWORK_CAPS_CM)
+ setWifiState(isCarrierMerged = true)
whenever(subscriptionManager.completeActiveSubscriptionInfoList)
.thenReturn(listOf(SUB_CM))
getSubscriptionCallback().onSubscriptionsChanged()
@@ -462,7 +483,7 @@
collectLastValue(underTest.subscriptions)
getDefaultNetworkCallback().onCapabilitiesChanged(NETWORK, WIFI_NETWORK_CAPS_CM)
- getNormalNetworkCallback().onCapabilitiesChanged(NETWORK, WIFI_NETWORK_CAPS_CM)
+ setWifiState(isCarrierMerged = true)
whenever(subscriptionManager.completeActiveSubscriptionInfoList)
.thenReturn(listOf(SUB_1, SUB_CM))
getSubscriptionCallback().onSubscriptionsChanged()
@@ -479,7 +500,7 @@
collectLastValue(underTest.subscriptions)
getDefaultNetworkCallback().onCapabilitiesChanged(NETWORK, WIFI_NETWORK_CAPS_CM)
- getNormalNetworkCallback().onCapabilitiesChanged(NETWORK, WIFI_NETWORK_CAPS_CM)
+ setWifiState(isCarrierMerged = true)
whenever(subscriptionManager.completeActiveSubscriptionInfoList)
.thenReturn(listOf(SUB_1, SUB_CM))
getSubscriptionCallback().onSubscriptionsChanged()
@@ -491,7 +512,7 @@
// WHEN the wifi network updates to be not carrier merged
getDefaultNetworkCallback().onCapabilitiesChanged(NETWORK, WIFI_NETWORK_CAPS_ACTIVE)
- getNormalNetworkCallback().onCapabilitiesChanged(NETWORK, WIFI_NETWORK_CAPS_ACTIVE)
+ setWifiState(isCarrierMerged = false)
runCurrent()
// THEN the repos update
@@ -507,7 +528,7 @@
collectLastValue(underTest.subscriptions)
getDefaultNetworkCallback().onCapabilitiesChanged(NETWORK, WIFI_NETWORK_CAPS_ACTIVE)
- getNormalNetworkCallback().onCapabilitiesChanged(NETWORK, WIFI_NETWORK_CAPS_ACTIVE)
+ setWifiState(isCarrierMerged = false)
whenever(subscriptionManager.completeActiveSubscriptionInfoList)
.thenReturn(listOf(SUB_1, SUB_CM))
getSubscriptionCallback().onSubscriptionsChanged()
@@ -520,7 +541,7 @@
// WHEN the wifi network updates to be carrier merged
getDefaultNetworkCallback().onCapabilitiesChanged(NETWORK, WIFI_NETWORK_CAPS_CM)
- getNormalNetworkCallback().onCapabilitiesChanged(NETWORK, WIFI_NETWORK_CAPS_CM)
+ setWifiState(isCarrierMerged = true)
runCurrent()
// THEN the repos update
@@ -562,7 +583,7 @@
collectLastValue(underTest.subscriptions)
getDefaultNetworkCallback().onCapabilitiesChanged(NETWORK, WIFI_NETWORK_CAPS_CM)
- getNormalNetworkCallback().onCapabilitiesChanged(NETWORK, WIFI_NETWORK_CAPS_CM)
+ setWifiState(isCarrierMerged = true)
whenever(subscriptionManager.completeActiveSubscriptionInfoList)
.thenReturn(listOf(SUB_1, SUB_2, SUB_CM))
getSubscriptionCallback().onSubscriptionsChanged()
@@ -845,7 +866,7 @@
val latest by collectLastValue(underTest.hasCarrierMergedConnection)
getDefaultNetworkCallback().onCapabilitiesChanged(NETWORK, caps)
- getNormalNetworkCallback().onCapabilitiesChanged(NETWORK, caps)
+ setWifiState(isCarrierMerged = true)
assertThat(latest).isTrue()
}
@@ -867,7 +888,7 @@
val latest by collectLastValue(underTest.hasCarrierMergedConnection)
getDefaultNetworkCallback().onCapabilitiesChanged(NETWORK, caps)
- getNormalNetworkCallback().onCapabilitiesChanged(NETWORK, caps)
+ setWifiState(isCarrierMerged = true)
assertThat(latest).isTrue()
}
@@ -890,7 +911,7 @@
val latest by collectLastValue(underTest.hasCarrierMergedConnection)
getDefaultNetworkCallback().onCapabilitiesChanged(NETWORK, caps)
- getNormalNetworkCallback().onCapabilitiesChanged(NETWORK, caps)
+ setWifiState(isCarrierMerged = true)
assertThat(latest).isTrue()
}
@@ -912,7 +933,7 @@
val latest by collectLastValue(underTest.hasCarrierMergedConnection)
getDefaultNetworkCallback().onCapabilitiesChanged(NETWORK, caps)
- getNormalNetworkCallback().onCapabilitiesChanged(NETWORK, caps)
+ setWifiState(isCarrierMerged = true)
assertThat(latest).isTrue()
}
@@ -946,7 +967,7 @@
}
getDefaultNetworkCallback().onCapabilitiesChanged(NETWORK, mainCapabilities)
- getNormalNetworkCallback().onCapabilitiesChanged(NETWORK, mainCapabilities)
+ setWifiState(isCarrierMerged = true)
// THEN there's a carrier merged connection
assertThat(latest).isTrue()
@@ -982,7 +1003,7 @@
}
getDefaultNetworkCallback().onCapabilitiesChanged(NETWORK, mainCapabilities)
- getNormalNetworkCallback().onCapabilitiesChanged(NETWORK, mainCapabilities)
+ setWifiState(isCarrierMerged = true)
// THEN there's a carrier merged connection
assertThat(latest).isTrue()
@@ -1005,7 +1026,7 @@
getDefaultNetworkCallback().onCapabilitiesChanged(NETWORK, caps)
// BUT the wifi repo has gotten updates that it *is* carrier merged
- getNormalNetworkCallback().onCapabilitiesChanged(NETWORK, WIFI_NETWORK_CAPS_CM)
+ setWifiState(isCarrierMerged = true)
// THEN hasCarrierMergedConnection is true
assertThat(latest).isTrue()
@@ -1026,7 +1047,7 @@
getDefaultNetworkCallback().onCapabilitiesChanged(NETWORK, caps)
// BUT the wifi repo has gotten updates that it *is* carrier merged
- getNormalNetworkCallback().onCapabilitiesChanged(NETWORK, WIFI_NETWORK_CAPS_CM)
+ setWifiState(isCarrierMerged = true)
// THEN hasCarrierMergedConnection is **false** (The default network being CELLULAR
// takes precedence over the wifi network being carrier merged.)
@@ -1048,7 +1069,7 @@
getDefaultNetworkCallback().onCapabilitiesChanged(NETWORK, caps)
// BUT the wifi repo has gotten updates that it *is* carrier merged
- getNormalNetworkCallback().onCapabilitiesChanged(NETWORK, WIFI_NETWORK_CAPS_CM)
+ setWifiState(isCarrierMerged = true)
// AND we're in airplane mode
airplaneModeRepository.setIsAirplaneMode(true)
@@ -1277,12 +1298,26 @@
return callbackCaptor.value!!
}
- // Note: This is used to update the [WifiRepository].
- private fun TestScope.getNormalNetworkCallback(): ConnectivityManager.NetworkCallback {
- runCurrent()
- val callbackCaptor = argumentCaptor<ConnectivityManager.NetworkCallback>()
- verify(connectivityManager).registerNetworkCallback(any(), callbackCaptor.capture())
- return callbackCaptor.value!!
+ private fun setWifiState(isCarrierMerged: Boolean) {
+ if (isCarrierMerged) {
+ val mergedEntry =
+ mock<MergedCarrierEntry>().apply {
+ whenever(this.isPrimaryNetwork).thenReturn(true)
+ whenever(this.isDefaultNetwork).thenReturn(true)
+ whenever(this.subscriptionId).thenReturn(SUB_CM_ID)
+ }
+ whenever(wifiPickerTracker.mergedCarrierEntry).thenReturn(mergedEntry)
+ whenever(wifiPickerTracker.connectedWifiEntry).thenReturn(null)
+ } else {
+ val wifiEntry =
+ mock<WifiEntry>().apply {
+ whenever(this.isPrimaryNetwork).thenReturn(true)
+ whenever(this.isDefaultNetwork).thenReturn(true)
+ }
+ whenever(wifiPickerTracker.connectedWifiEntry).thenReturn(wifiEntry)
+ whenever(wifiPickerTracker.mergedCarrierEntry).thenReturn(null)
+ }
+ wifiPickerTrackerCallback.value.onWifiEntriesChanged()
}
private fun TestScope.getSubscriptionCallback():
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/prod/WifiRepositoryViaTrackerLibTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/prod/WifiRepositoryImplTest.kt
similarity index 99%
rename from packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/prod/WifiRepositoryViaTrackerLibTest.kt
rename to packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/prod/WifiRepositoryImplTest.kt
index 3126362..f8d50f5 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/prod/WifiRepositoryViaTrackerLibTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/prod/WifiRepositoryImplTest.kt
@@ -68,14 +68,14 @@
@OptIn(ExperimentalCoroutinesApi::class)
@SmallTest
@TestableLooper.RunWithLooper(setAsMainLooper = true)
-class WifiRepositoryViaTrackerLibTest : SysuiTestCase() {
+class WifiRepositoryImplTest : SysuiTestCase() {
// Using lazy means that the class will only be constructed once it's fetched. Because the
// repository internally sets some values on construction, we need to set up some test
// parameters (like feature flags) *before* construction. Using lazy allows us to do that setup
// inside each test case without needing to manually recreate the repository.
- private val underTest: WifiRepositoryViaTrackerLib by lazy {
- WifiRepositoryViaTrackerLib(
+ private val underTest: WifiRepositoryImpl by lazy {
+ WifiRepositoryImpl(
featureFlags,
testScope.backgroundScope,
executor,