Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit ca5ed2ce authored by Caitlin Shkuratov's avatar Caitlin Shkuratov
Browse files

[Status bar] Take underlying networks into account for wifi.

Bug: 225902574
Test: atest ConnectivityRepositoryImplTest WifiRepositoryImplTest
MobileConnectionsRepositoryTest

Change-Id: Ie576d9ce4f6babf62ff231a4f7d769663348e977
parent 0abe80aa
Loading
Loading
Loading
Loading
+34 −10
Original line number Diff line number Diff line
@@ -44,11 +44,11 @@ import com.android.systemui.statusbar.pipeline.shared.data.model.DefaultConnecti
import com.android.systemui.statusbar.pipeline.shared.data.model.DefaultConnectionModel.Ethernet
import com.android.systemui.statusbar.pipeline.shared.data.model.DefaultConnectionModel.Mobile
import com.android.systemui.statusbar.pipeline.shared.data.model.DefaultConnectionModel.Wifi
import com.android.systemui.statusbar.pipeline.shared.data.repository.ConnectivityRepositoryImpl.Companion.getMainOrUnderlyingWifiInfo
import com.android.systemui.tuner.TunerService
import java.io.PrintWriter
import javax.inject.Inject
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.channels.awaitClose
import kotlinx.coroutines.flow.SharingStarted
import kotlinx.coroutines.flow.StateFlow
@@ -68,12 +68,12 @@ interface ConnectivityRepository {
    val defaultConnections: StateFlow<DefaultConnectionModel>
}

@OptIn(ExperimentalCoroutinesApi::class)
@SuppressLint("MissingPermission")
@SysUISingleton
class ConnectivityRepositoryImpl
@Inject
constructor(
    connectivityManager: ConnectivityManager,
    private val connectivityManager: ConnectivityManager,
    private val connectivitySlots: ConnectivitySlots,
    context: Context,
    dumpManager: DumpManager,
@@ -144,15 +144,14 @@ constructor(
                        ) {
                            logger.logOnDefaultCapabilitiesChanged(network, networkCapabilities)

                            val wifiInfo =
                                networkCapabilities.getMainOrUnderlyingWifiInfo(connectivityManager)

                            val isWifiDefault =
                                networkCapabilities.hasTransport(TRANSPORT_WIFI) ||
                                    networkCapabilities.getMainOrUnderlyingWifiInfo() != null
                                networkCapabilities.hasTransport(TRANSPORT_WIFI) || wifiInfo != null
                            val isMobileDefault =
                                networkCapabilities.hasTransport(TRANSPORT_CELLULAR)
                            val isCarrierMergedDefault =
                                networkCapabilities
                                    .getMainOrUnderlyingWifiInfo()
                                    ?.isCarrierMerged == true
                            val isCarrierMergedDefault = wifiInfo?.isCarrierMerged == true
                            val isEthernetDefault =
                                networkCapabilities.hasTransport(TRANSPORT_ETHERNET)

@@ -209,7 +208,32 @@ constructor(
         * always use [WifiInfo] if it's available, so we need to check the underlying transport
         * info.
         */
        fun NetworkCapabilities.getMainOrUnderlyingWifiInfo(): WifiInfo? {
        fun NetworkCapabilities.getMainOrUnderlyingWifiInfo(
            connectivityManager: ConnectivityManager,
        ): WifiInfo? {
            val mainWifiInfo = this.getMainWifiInfo()
            if (mainWifiInfo != null) {
                return mainWifiInfo
            }
            // Only CELLULAR networks may have underlying wifi information that's relevant to SysUI,
            // so skip the underlying network check if it's not CELLULAR.
            if (!this.hasTransport(TRANSPORT_CELLULAR)) {
                return mainWifiInfo
            }

            // Some connections, like VPN connections, may have underlying networks that are
            // eventually traced to a wifi or carrier merged connection. So, check those underlying
            // networks for possible wifi information as well. See b/225902574.
            return this.underlyingNetworks?.firstNotNullOfOrNull { underlyingNetwork ->
                connectivityManager.getNetworkCapabilities(underlyingNetwork)?.getMainWifiInfo()
            }
        }

        /**
         * Checks the network capabilities for wifi info, but does *not* check the underlying
         * networks. See [getMainOrUnderlyingWifiInfo].
         */
        private fun NetworkCapabilities.getMainWifiInfo(): WifiInfo? {
            // Wifi info can either come from a WIFI Transport, or from a CELLULAR transport for
            // virtual networks like VCN.
            val canHaveWifiInfo =
+2 −1
Original line number Diff line number Diff line
@@ -138,7 +138,8 @@ constructor(

                            wifiNetworkChangeEvents.tryEmit(Unit)

                            val wifiInfo = networkCapabilities.getMainOrUnderlyingWifiInfo()
                            val wifiInfo =
                                networkCapabilities.getMainOrUnderlyingWifiInfo(connectivityManager)
                            if (wifiInfo?.isPrimary == true) {
                                val wifiNetworkModel =
                                    createWifiNetworkModel(
+74 −0
Original line number Diff line number Diff line
@@ -75,6 +75,7 @@ import org.junit.Test
import org.mockito.ArgumentMatchers.anyInt
import org.mockito.ArgumentMatchers.anyString
import org.mockito.Mock
import org.mockito.Mockito
import org.mockito.Mockito.verify
import org.mockito.MockitoAnnotations

@@ -812,6 +813,79 @@ class MobileConnectionsRepositoryTest : SysuiTestCase() {
            job.cancel()
        }

    @Test
    fun mobileIsDefault_isCarrierMergedViaUnderlyingWifi_isDefault() =
        runBlocking(IMMEDIATE) {
            var latest: Boolean? = null
            val job = underTest.mobileIsDefault.onEach { latest = it }.launchIn(this)

            val underlyingNetwork = mock<Network>()
            val carrierMergedInfo =
                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 carrier merged is default, so mobile is default
            assertThat(latest).isTrue()

            job.cancel()
        }

    @Test
    fun mobileIsDefault_isCarrierMergedViaUnderlyingCellular_isDefault() =
        runBlocking(IMMEDIATE) {
            var latest: Boolean? = null
            val job = underTest.mobileIsDefault.onEach { latest = it }.launchIn(this)

            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 carrier merged is default, so mobile is default
            assertThat(latest).isTrue()

            job.cancel()
        }

    @Test
    fun mobileIsDefault_wifiDefault_mobileNotDefault() =
        runBlocking(IMMEDIATE) {
+379 −0

File changed.

Preview size limit exceeded, changes collapsed.

+145 −1
Original line number Diff line number Diff line
@@ -400,7 +400,7 @@ class WifiRepositoryImplTest : SysuiTestCase() {
        }

    @Test
    fun wifiNetwork_cellularAndWifiTransports_usesCellular_isTrue() =
    fun isWifiDefault_cellularAndWifiTransports_usesCellular_isTrue() =
        runBlocking(IMMEDIATE) {
            val job = underTest.isWifiDefault.launchIn(this)

@@ -436,6 +436,75 @@ class WifiRepositoryImplTest : SysuiTestCase() {
            job.cancel()
        }

    @Test
    fun isWifiDefault_isCarrierMergedViaUnderlyingWifi_isTrue() =
        runBlocking(IMMEDIATE) {
            val job = underTest.isWifiDefault.launchIn(this)

            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(underTest.isWifiDefault.value).isTrue()

            job.cancel()
        }

    @Test
    fun isWifiDefault_isCarrierMergedViaUnderlyingCellular_isTrue() =
        runBlocking(IMMEDIATE) {
            val job = underTest.isWifiDefault.launchIn(this)

            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(underTest.isWifiDefault.value).isTrue()

            job.cancel()
        }

    @Test
    fun isWifiDefault_wifiNetworkLost_isFalse() =
        runBlocking(IMMEDIATE) {
@@ -510,6 +579,81 @@ class WifiRepositoryImplTest : SysuiTestCase() {
            job.cancel()
        }

    @Test
    fun wifiNetwork_isCarrierMergedViaUnderlyingWifi_flowHasCarrierMerged() =
        runBlocking(IMMEDIATE) {
            var latest: WifiNetworkModel? = null
            val job = underTest.wifiNetwork.onEach { latest = it }.launchIn(this)

            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()

            job.cancel()
        }

    @Test
    fun wifiNetwork_isCarrierMergedViaUnderlyingCellular_flowHasCarrierMerged() =
        runBlocking(IMMEDIATE) {
            var latest: WifiNetworkModel? = null
            val job = underTest.wifiNetwork.onEach { latest = it }.launchIn(this)

            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()

            job.cancel()
        }

    @Test
    fun wifiNetwork_carrierMergedButInvalidSubId_flowHasInvalid() =
        runBlocking(IMMEDIATE) {