1 /* 2 * Copyright (C) 2022 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.systemui.statusbar.pipeline.shared.data.repository 18 19 import android.net.ConnectivityManager 20 import android.net.Network 21 import android.net.NetworkCapabilities 22 import android.net.NetworkCapabilities.TRANSPORT_CELLULAR 23 import android.net.NetworkCapabilities.TRANSPORT_ETHERNET 24 import android.net.NetworkCapabilities.TRANSPORT_VPN 25 import android.net.NetworkCapabilities.TRANSPORT_WIFI 26 import android.net.TelephonyNetworkSpecifier 27 import android.net.VpnTransportInfo 28 import android.net.vcn.VcnTransportInfo 29 import android.net.wifi.WifiInfo 30 import android.platform.test.annotations.DisableFlags 31 import android.platform.test.annotations.EnableFlags 32 import android.telephony.SubscriptionManager.INVALID_SUBSCRIPTION_ID 33 import androidx.test.ext.junit.runners.AndroidJUnit4 34 import androidx.test.filters.SmallTest 35 import com.android.systemui.Flags.FLAG_STATUS_BAR_ALWAYS_CHECK_UNDERLYING_NETWORKS 36 import com.android.systemui.SysuiTestCase 37 import com.android.systemui.coroutines.collectLastValue 38 import com.android.systemui.dump.dumpManager 39 import com.android.systemui.kosmos.testScope 40 import com.android.systemui.log.core.FakeLogBuffer 41 import com.android.systemui.statusbar.pipeline.shared.ConnectivityInputLogger 42 import com.android.systemui.statusbar.pipeline.shared.data.model.ConnectivitySlot 43 import com.android.systemui.statusbar.pipeline.shared.data.model.ConnectivitySlots 44 import com.android.systemui.statusbar.pipeline.shared.data.repository.ConnectivityRepositoryImpl.Companion.DEFAULT_HIDDEN_ICONS_RESOURCE 45 import com.android.systemui.statusbar.pipeline.shared.data.repository.ConnectivityRepositoryImpl.Companion.HIDDEN_ICONS_TUNABLE_KEY 46 import com.android.systemui.statusbar.pipeline.shared.data.repository.ConnectivityRepositoryImpl.Companion.getMainOrUnderlyingWifiInfo 47 import com.android.systemui.testKosmos 48 import com.android.systemui.tuner.TunerService 49 import com.google.common.truth.Truth.assertThat 50 import kotlinx.coroutines.ExperimentalCoroutinesApi 51 import kotlinx.coroutines.test.runCurrent 52 import kotlinx.coroutines.test.runTest 53 import org.junit.Before 54 import org.junit.Test 55 import org.junit.runner.RunWith 56 import org.mockito.kotlin.any 57 import org.mockito.kotlin.argumentCaptor 58 import org.mockito.kotlin.eq 59 import org.mockito.kotlin.mock 60 import org.mockito.kotlin.verify 61 import org.mockito.kotlin.whenever 62 63 @OptIn(ExperimentalCoroutinesApi::class) 64 @SmallTest 65 @RunWith(AndroidJUnit4::class) 66 class ConnectivityRepositoryImplTest : SysuiTestCase() { 67 private val kosmos = testKosmos() 68 69 private lateinit var underTest: ConnectivityRepositoryImpl 70 71 private val connectivityManager = mock<ConnectivityManager>() 72 private val connectivitySlots = mock<ConnectivitySlots>() 73 private val dumpManager = kosmos.dumpManager 74 private val logger = ConnectivityInputLogger(FakeLogBuffer.Factory.create()) 75 private val testScope = kosmos.testScope 76 private val tunerService = mock<TunerService>() 77 78 private val vcnTransportInfo = VcnTransportInfo.Builder().build() 79 80 @Before setUpnull81 fun setUp() { 82 createAndSetRepo() 83 } 84 85 @Test forceHiddenSlots_initiallyGetsDefaultnull86 fun forceHiddenSlots_initiallyGetsDefault() = 87 testScope.runTest { 88 setUpEthernetWifiMobileSlotNames() 89 context 90 .getOrCreateTestableResources() 91 .addOverride(DEFAULT_HIDDEN_ICONS_RESOURCE, arrayOf(SLOT_WIFI, SLOT_ETHERNET)) 92 // Re-create our [ConnectivityRepositoryImpl], since it fetches 93 // config_statusBarIconsToExclude when it's first constructed 94 createAndSetRepo() 95 96 val latest by collectLastValue(underTest.forceHiddenSlots) 97 runCurrent() 98 99 assertThat(latest).containsExactly(ConnectivitySlot.ETHERNET, ConnectivitySlot.WIFI) 100 } 101 102 @Test forceHiddenSlots_slotNamesAdded_flowHasSlotsnull103 fun forceHiddenSlots_slotNamesAdded_flowHasSlots() = 104 testScope.runTest { 105 setUpEthernetWifiMobileSlotNames() 106 107 val latest by collectLastValue(underTest.forceHiddenSlots) 108 runCurrent() 109 110 getTunable().onTuningChanged(HIDDEN_ICONS_TUNABLE_KEY, SLOT_MOBILE) 111 112 assertThat(latest).containsExactly(ConnectivitySlot.MOBILE) 113 } 114 115 @Test forceHiddenSlots_wrongKey_doesNotUpdatenull116 fun forceHiddenSlots_wrongKey_doesNotUpdate() = 117 testScope.runTest { 118 setUpEthernetWifiMobileSlotNames() 119 120 val latest by collectLastValue(underTest.forceHiddenSlots) 121 runCurrent() 122 123 getTunable().onTuningChanged(HIDDEN_ICONS_TUNABLE_KEY, SLOT_MOBILE) 124 125 // WHEN onTuningChanged with the wrong key 126 getTunable().onTuningChanged("wrongKey", SLOT_WIFI) 127 128 // THEN we didn't update our value and still have the old one 129 assertThat(latest).containsExactly(ConnectivitySlot.MOBILE) 130 } 131 132 @Test forceHiddenSlots_slotNamesAddedThenNull_flowHasDefaultnull133 fun forceHiddenSlots_slotNamesAddedThenNull_flowHasDefault() = 134 testScope.runTest { 135 setUpEthernetWifiMobileSlotNames() 136 context 137 .getOrCreateTestableResources() 138 .addOverride(DEFAULT_HIDDEN_ICONS_RESOURCE, arrayOf(SLOT_WIFI, SLOT_ETHERNET)) 139 // Re-create our [ConnectivityRepositoryImpl], since it fetches 140 // config_statusBarIconsToExclude when it's first constructed 141 createAndSetRepo() 142 143 val latest by collectLastValue(underTest.forceHiddenSlots) 144 runCurrent() 145 146 // First, update the slots 147 getTunable().onTuningChanged(HIDDEN_ICONS_TUNABLE_KEY, SLOT_MOBILE) 148 assertThat(latest).containsExactly(ConnectivitySlot.MOBILE) 149 150 // WHEN we update to a null value 151 getTunable().onTuningChanged(HIDDEN_ICONS_TUNABLE_KEY, null) 152 153 // THEN we go back to our default value 154 assertThat(latest).containsExactly(ConnectivitySlot.ETHERNET, ConnectivitySlot.WIFI) 155 } 156 157 @Test forceHiddenSlots_someInvalidSlotNames_flowHasValidSlotsOnlynull158 fun forceHiddenSlots_someInvalidSlotNames_flowHasValidSlotsOnly() = 159 testScope.runTest { 160 val latest by collectLastValue(underTest.forceHiddenSlots) 161 runCurrent() 162 163 whenever(connectivitySlots.getSlotFromName(SLOT_WIFI)).thenReturn(ConnectivitySlot.WIFI) 164 whenever(connectivitySlots.getSlotFromName(SLOT_MOBILE)).thenReturn(null) 165 166 getTunable().onTuningChanged(HIDDEN_ICONS_TUNABLE_KEY, "$SLOT_WIFI,$SLOT_MOBILE") 167 168 assertThat(latest).containsExactly(ConnectivitySlot.WIFI) 169 } 170 171 @Test forceHiddenSlots_someEmptySlotNames_flowHasValidSlotsOnlynull172 fun forceHiddenSlots_someEmptySlotNames_flowHasValidSlotsOnly() = 173 testScope.runTest { 174 setUpEthernetWifiMobileSlotNames() 175 176 val latest by collectLastValue(underTest.forceHiddenSlots) 177 runCurrent() 178 179 // WHEN there's empty and blank slot names 180 getTunable().onTuningChanged(HIDDEN_ICONS_TUNABLE_KEY, "$SLOT_MOBILE, ,,$SLOT_WIFI") 181 182 // THEN we skip that slot but still process the other ones 183 assertThat(latest).containsExactly(ConnectivitySlot.WIFI, ConnectivitySlot.MOBILE) 184 } 185 186 @Test forceHiddenSlots_allInvalidOrEmptySlotNames_flowHasEmptynull187 fun forceHiddenSlots_allInvalidOrEmptySlotNames_flowHasEmpty() = 188 testScope.runTest { 189 val latest by collectLastValue(underTest.forceHiddenSlots) 190 runCurrent() 191 192 whenever(connectivitySlots.getSlotFromName(SLOT_WIFI)).thenReturn(null) 193 whenever(connectivitySlots.getSlotFromName(SLOT_ETHERNET)).thenReturn(null) 194 whenever(connectivitySlots.getSlotFromName(SLOT_MOBILE)).thenReturn(null) 195 196 getTunable() 197 .onTuningChanged( 198 HIDDEN_ICONS_TUNABLE_KEY, 199 "$SLOT_MOBILE,,$SLOT_WIFI,$SLOT_ETHERNET,,," 200 ) 201 202 assertThat(latest).isEmpty() 203 } 204 205 @Test forceHiddenSlots_newSubscriberGetsCurrentValuenull206 fun forceHiddenSlots_newSubscriberGetsCurrentValue() = 207 testScope.runTest { 208 setUpEthernetWifiMobileSlotNames() 209 210 val latest1 by collectLastValue(underTest.forceHiddenSlots) 211 runCurrent() 212 213 getTunable().onTuningChanged(HIDDEN_ICONS_TUNABLE_KEY, "$SLOT_WIFI,$SLOT_ETHERNET") 214 215 assertThat(latest1).containsExactly(ConnectivitySlot.WIFI, ConnectivitySlot.ETHERNET) 216 217 // WHEN we add a second subscriber after having already emitted a value 218 val latest2 by collectLastValue(underTest.forceHiddenSlots) 219 runCurrent() 220 221 // THEN the second subscribe receives the already-emitted value 222 assertThat(latest2).containsExactly(ConnectivitySlot.WIFI, ConnectivitySlot.ETHERNET) 223 } 224 225 @Test defaultConnections_noTransports_nothingIsDefaultnull226 fun defaultConnections_noTransports_nothingIsDefault() = 227 testScope.runTest { 228 val latest by collectLastValue(underTest.defaultConnections) 229 230 val capabilities = 231 mock<NetworkCapabilities>().also { 232 whenever(it.hasTransport(TRANSPORT_CELLULAR)).thenReturn(false) 233 whenever(it.hasTransport(TRANSPORT_ETHERNET)).thenReturn(false) 234 whenever(it.hasTransport(TRANSPORT_WIFI)).thenReturn(false) 235 } 236 237 getDefaultNetworkCallback().onCapabilitiesChanged(NETWORK, capabilities) 238 239 assertThat(latest!!.mobile.isDefault).isFalse() 240 assertThat(latest!!.wifi.isDefault).isFalse() 241 assertThat(latest!!.ethernet.isDefault).isFalse() 242 assertThat(latest!!.carrierMerged.isDefault).isFalse() 243 } 244 245 @Test defaultConnections_cellularTransport_mobileIsDefaultnull246 fun defaultConnections_cellularTransport_mobileIsDefault() = 247 testScope.runTest { 248 val latest by collectLastValue(underTest.defaultConnections) 249 250 val capabilities = 251 mock<NetworkCapabilities>().also { 252 whenever(it.hasTransport(TRANSPORT_CELLULAR)).thenReturn(true) 253 whenever(it.hasTransport(TRANSPORT_ETHERNET)).thenReturn(false) 254 whenever(it.hasTransport(TRANSPORT_WIFI)).thenReturn(false) 255 } 256 257 getDefaultNetworkCallback().onCapabilitiesChanged(NETWORK, capabilities) 258 259 assertThat(latest!!.mobile.isDefault).isTrue() 260 assertThat(latest!!.wifi.isDefault).isFalse() 261 assertThat(latest!!.ethernet.isDefault).isFalse() 262 assertThat(latest!!.carrierMerged.isDefault).isFalse() 263 } 264 265 @Test defaultConnections_wifiTransport_wifiIsDefaultnull266 fun defaultConnections_wifiTransport_wifiIsDefault() = 267 testScope.runTest { 268 val latest by collectLastValue(underTest.defaultConnections) 269 270 val capabilities = 271 mock<NetworkCapabilities>().also { 272 whenever(it.hasTransport(TRANSPORT_CELLULAR)).thenReturn(false) 273 whenever(it.hasTransport(TRANSPORT_ETHERNET)).thenReturn(false) 274 whenever(it.hasTransport(TRANSPORT_WIFI)).thenReturn(true) 275 } 276 277 getDefaultNetworkCallback().onCapabilitiesChanged(NETWORK, capabilities) 278 279 assertThat(latest!!.wifi.isDefault).isTrue() 280 assertThat(latest!!.ethernet.isDefault).isFalse() 281 assertThat(latest!!.carrierMerged.isDefault).isFalse() 282 assertThat(latest!!.mobile.isDefault).isFalse() 283 } 284 285 @Test defaultConnections_ethernetTransport_ethernetIsDefaultnull286 fun defaultConnections_ethernetTransport_ethernetIsDefault() = 287 testScope.runTest { 288 val latest by collectLastValue(underTest.defaultConnections) 289 290 val capabilities = 291 mock<NetworkCapabilities>().also { 292 whenever(it.hasTransport(TRANSPORT_CELLULAR)).thenReturn(false) 293 whenever(it.hasTransport(TRANSPORT_ETHERNET)).thenReturn(true) 294 whenever(it.hasTransport(TRANSPORT_WIFI)).thenReturn(false) 295 } 296 297 getDefaultNetworkCallback().onCapabilitiesChanged(NETWORK, capabilities) 298 299 assertThat(latest!!.ethernet.isDefault).isTrue() 300 assertThat(latest!!.wifi.isDefault).isFalse() 301 assertThat(latest!!.carrierMerged.isDefault).isFalse() 302 assertThat(latest!!.mobile.isDefault).isFalse() 303 } 304 305 @Test defaultConnections_carrierMergedViaWifi_wifiAndCarrierMergedDefaultnull306 fun defaultConnections_carrierMergedViaWifi_wifiAndCarrierMergedDefault() = 307 testScope.runTest { 308 val latest by collectLastValue(underTest.defaultConnections) 309 310 val carrierMergedInfo = 311 mock<WifiInfo>().apply { whenever(this.isCarrierMerged).thenReturn(true) } 312 val capabilities = 313 mock<NetworkCapabilities>().also { 314 whenever(it.hasTransport(TRANSPORT_WIFI)).thenReturn(true) 315 whenever(it.transportInfo).thenReturn(carrierMergedInfo) 316 whenever(it.hasTransport(TRANSPORT_CELLULAR)).thenReturn(false) 317 whenever(it.hasTransport(TRANSPORT_ETHERNET)).thenReturn(false) 318 } 319 320 getDefaultNetworkCallback().onCapabilitiesChanged(NETWORK, capabilities) 321 322 assertThat(latest!!.wifi.isDefault).isTrue() 323 assertThat(latest!!.carrierMerged.isDefault).isTrue() 324 assertThat(latest!!.mobile.isDefault).isFalse() 325 } 326 327 @Test defaultConnections_carrierMergedViaMobile_mobileCarrierMergedWifiDefaultnull328 fun defaultConnections_carrierMergedViaMobile_mobileCarrierMergedWifiDefault() = 329 testScope.runTest { 330 val latest by collectLastValue(underTest.defaultConnections) 331 332 val carrierMergedInfo = 333 mock<WifiInfo>().apply { whenever(this.isCarrierMerged).thenReturn(true) } 334 val capabilities = 335 mock<NetworkCapabilities>().also { 336 whenever(it.hasTransport(TRANSPORT_CELLULAR)).thenReturn(true) 337 whenever(it.transportInfo).thenReturn(carrierMergedInfo) 338 whenever(it.hasTransport(TRANSPORT_ETHERNET)).thenReturn(false) 339 whenever(it.hasTransport(TRANSPORT_WIFI)).thenReturn(false) 340 } 341 342 getDefaultNetworkCallback().onCapabilitiesChanged(NETWORK, capabilities) 343 344 assertThat(latest!!.mobile.isDefault).isTrue() 345 assertThat(latest!!.carrierMerged.isDefault).isTrue() 346 assertThat(latest!!.wifi.isDefault).isTrue() 347 } 348 newWifiNetworknull349 private fun newWifiNetwork(wifiInfo: WifiInfo): Network { 350 val network = mock<Network>() 351 val capabilities = 352 mock<NetworkCapabilities>().also { 353 whenever(it.hasTransport(TRANSPORT_WIFI)).thenReturn(true) 354 whenever(it.transportInfo).thenReturn(wifiInfo) 355 } 356 whenever(connectivityManager.getNetworkCapabilities(network)).thenReturn(capabilities) 357 358 return network 359 } 360 newCellNetworknull361 private fun newCellNetwork(subId: Int): Network { 362 val network = mock<Network>() 363 val capabilities = 364 mock<NetworkCapabilities>().also { 365 whenever(it.hasTransport(TRANSPORT_CELLULAR)).thenReturn(true) 366 whenever(it.networkSpecifier).thenReturn(TelephonyNetworkSpecifier(subId)) 367 } 368 whenever(connectivityManager.getNetworkCapabilities(network)).thenReturn(capabilities) 369 370 return network 371 } 372 373 @Test defaultConnections_carrierMergedViaWifiWithVcnTransport_wifiAndCarrierMergedDefaultnull374 fun defaultConnections_carrierMergedViaWifiWithVcnTransport_wifiAndCarrierMergedDefault() = 375 testScope.runTest { 376 val latest by collectLastValue(underTest.defaultConnections) 377 378 val carrierMergedInfo = 379 mock<WifiInfo>().apply { whenever(this.isCarrierMerged).thenReturn(true) } 380 val underlyingWifi = newWifiNetwork(carrierMergedInfo) 381 val capabilities = 382 mock<NetworkCapabilities>().also { 383 whenever(it.hasTransport(TRANSPORT_WIFI)).thenReturn(true) 384 whenever(it.transportInfo).thenReturn(vcnTransportInfo) 385 whenever(it.underlyingNetworks).thenReturn(listOf(underlyingWifi)) 386 whenever(it.hasTransport(TRANSPORT_CELLULAR)).thenReturn(false) 387 whenever(it.hasTransport(TRANSPORT_ETHERNET)).thenReturn(false) 388 } 389 390 getDefaultNetworkCallback().onCapabilitiesChanged(NETWORK, capabilities) 391 392 assertThat(latest!!.wifi.isDefault).isTrue() 393 assertThat(latest!!.carrierMerged.isDefault).isTrue() 394 assertThat(latest!!.mobile.isDefault).isFalse() 395 } 396 397 /** VCN over W+ (aka VCN over carrier merged). See b/352162710#comment27 scenario #1. */ 398 @Test defaultConnections_carrierMergedViaMobileWithVcnTransport_mobileCarrierMergedWifiDefaultnull399 fun defaultConnections_carrierMergedViaMobileWithVcnTransport_mobileCarrierMergedWifiDefault() = 400 testScope.runTest { 401 val latest by collectLastValue(underTest.defaultConnections) 402 403 val carrierMergedInfo = 404 mock<WifiInfo>().apply { whenever(this.isCarrierMerged).thenReturn(true) } 405 val underlyingWifi = newWifiNetwork(carrierMergedInfo) 406 val capabilities = 407 mock<NetworkCapabilities>().also { 408 whenever(it.hasTransport(TRANSPORT_CELLULAR)).thenReturn(true) 409 whenever(it.transportInfo).thenReturn(vcnTransportInfo) 410 whenever(it.underlyingNetworks).thenReturn(listOf(underlyingWifi)) 411 whenever(it.hasTransport(TRANSPORT_ETHERNET)).thenReturn(false) 412 whenever(it.hasTransport(TRANSPORT_WIFI)).thenReturn(false) 413 } 414 415 getDefaultNetworkCallback().onCapabilitiesChanged(NETWORK, capabilities) 416 417 assertThat(latest!!.mobile.isDefault).isTrue() 418 assertThat(latest!!.carrierMerged.isDefault).isTrue() 419 assertThat(latest!!.wifi.isDefault).isTrue() 420 } 421 422 /** VPN over W+ (aka VPN over carrier merged). See b/352162710#comment27 scenario #2. */ 423 @Test 424 @EnableFlags(FLAG_STATUS_BAR_ALWAYS_CHECK_UNDERLYING_NETWORKS) defaultConnections_vpnOverCarrierMerged_carrierMergedDefaultnull425 fun defaultConnections_vpnOverCarrierMerged_carrierMergedDefault() = 426 testScope.runTest { 427 val latest by collectLastValue(underTest.defaultConnections) 428 429 // Underlying carrier merged network 430 val underlyingCarrierMergedNetwork = mock<Network>() 431 val carrierMergedInfo = 432 mock<WifiInfo>().apply { whenever(this.isCarrierMerged).thenReturn(true) } 433 val underlyingCapabilities = 434 mock<NetworkCapabilities>().also { 435 whenever(it.hasTransport(TRANSPORT_WIFI)).thenReturn(true) 436 whenever(it.transportInfo).thenReturn(carrierMergedInfo) 437 } 438 whenever(connectivityManager.getNetworkCapabilities(underlyingCarrierMergedNetwork)) 439 .thenReturn(underlyingCapabilities) 440 441 val mainCapabilities = 442 mock<NetworkCapabilities>().also { 443 whenever(it.hasTransport(TRANSPORT_ETHERNET)).thenReturn(false) 444 // Transports are WIFI|VPN, *not* CELLULAR. 445 whenever(it.hasTransport(TRANSPORT_CELLULAR)).thenReturn(false) 446 whenever(it.hasTransport(TRANSPORT_WIFI)).thenReturn(true) 447 whenever(it.hasTransport(TRANSPORT_VPN)).thenReturn(true) 448 whenever(it.transportInfo).thenReturn(VpnTransportInfo(0, null, false, false)) 449 whenever(it.underlyingNetworks) 450 .thenReturn(listOf(underlyingCarrierMergedNetwork)) 451 } 452 453 getDefaultNetworkCallback().onCapabilitiesChanged(NETWORK, mainCapabilities) 454 455 assertThat(latest!!.carrierMerged.isDefault).isTrue() 456 } 457 458 @Test defaultConnections_notCarrierMergedViaWifi_carrierMergedNotDefaultnull459 fun defaultConnections_notCarrierMergedViaWifi_carrierMergedNotDefault() = 460 testScope.runTest { 461 val latest by collectLastValue(underTest.defaultConnections) 462 463 val carrierMergedInfo = 464 mock<WifiInfo>().apply { whenever(this.isCarrierMerged).thenReturn(false) } 465 val capabilities = 466 mock<NetworkCapabilities>().also { 467 whenever(it.hasTransport(TRANSPORT_WIFI)).thenReturn(true) 468 whenever(it.transportInfo).thenReturn(carrierMergedInfo) 469 whenever(it.hasTransport(TRANSPORT_CELLULAR)).thenReturn(false) 470 whenever(it.hasTransport(TRANSPORT_ETHERNET)).thenReturn(false) 471 } 472 473 getDefaultNetworkCallback().onCapabilitiesChanged(NETWORK, capabilities) 474 475 assertThat(latest!!.carrierMerged.isDefault).isFalse() 476 } 477 478 @Test defaultConnections_notCarrierMergedViaMobile_carrierMergedNotDefaultnull479 fun defaultConnections_notCarrierMergedViaMobile_carrierMergedNotDefault() = 480 testScope.runTest { 481 val latest by collectLastValue(underTest.defaultConnections) 482 483 val carrierMergedInfo = 484 mock<WifiInfo>().apply { whenever(this.isCarrierMerged).thenReturn(false) } 485 val capabilities = 486 mock<NetworkCapabilities>().also { 487 whenever(it.hasTransport(TRANSPORT_CELLULAR)).thenReturn(true) 488 whenever(it.transportInfo).thenReturn(carrierMergedInfo) 489 whenever(it.hasTransport(TRANSPORT_ETHERNET)).thenReturn(false) 490 whenever(it.hasTransport(TRANSPORT_WIFI)).thenReturn(false) 491 } 492 493 getDefaultNetworkCallback().onCapabilitiesChanged(NETWORK, capabilities) 494 495 assertThat(latest!!.carrierMerged.isDefault).isFalse() 496 } 497 498 @Test defaultConnections_transportInfoNotWifi_wifiNotDefaultnull499 fun defaultConnections_transportInfoNotWifi_wifiNotDefault() = 500 testScope.runTest { 501 val latest by collectLastValue(underTest.defaultConnections) 502 503 val capabilities = 504 mock<NetworkCapabilities>().also { 505 whenever(it.transportInfo).thenReturn(mock()) 506 whenever(it.hasTransport(TRANSPORT_CELLULAR)).thenReturn(true) 507 whenever(it.hasTransport(TRANSPORT_ETHERNET)).thenReturn(false) 508 whenever(it.hasTransport(TRANSPORT_WIFI)).thenReturn(false) 509 } 510 511 getDefaultNetworkCallback().onCapabilitiesChanged(NETWORK, capabilities) 512 513 assertThat(latest!!.wifi.isDefault).isFalse() 514 } 515 516 @Test defaultConnections_nullUnderlyingInfo_noErrornull517 fun defaultConnections_nullUnderlyingInfo_noError() { 518 val mainCapabilities = 519 mock<NetworkCapabilities>().also { 520 whenever(it.hasTransport(TRANSPORT_CELLULAR)).thenReturn(true) 521 whenever(it.transportInfo).thenReturn(null) 522 whenever(it.underlyingNetworks).thenReturn(null) 523 } 524 525 getDefaultNetworkCallback().onCapabilitiesChanged(NETWORK, mainCapabilities) 526 // No assert, just verify no error 527 } 528 529 @Test defaultConnections_underlyingInfoHasNullCapabilities_noErrornull530 fun defaultConnections_underlyingInfoHasNullCapabilities_noError() { 531 val underlyingNetworkWithNull = mock<Network>() 532 whenever(connectivityManager.getNetworkCapabilities(underlyingNetworkWithNull)) 533 .thenReturn(null) 534 535 val mainCapabilities = 536 mock<NetworkCapabilities>().also { 537 whenever(it.hasTransport(TRANSPORT_CELLULAR)).thenReturn(true) 538 whenever(it.transportInfo).thenReturn(null) 539 whenever(it.underlyingNetworks).thenReturn(listOf(underlyingNetworkWithNull)) 540 } 541 542 getDefaultNetworkCallback().onCapabilitiesChanged(NETWORK, mainCapabilities) 543 // No assert, just verify no error 544 } 545 546 // This test verifies our internal API for completeness, but we don't expect this case to ever 547 // happen in practice. 548 @Test defaultConnections_cellular_underlyingCarrierMergedViaWifi_allDefaultnull549 fun defaultConnections_cellular_underlyingCarrierMergedViaWifi_allDefault() = 550 testScope.runTest { 551 val latest by collectLastValue(underTest.defaultConnections) 552 553 // Underlying carrier merged network 554 val underlyingCarrierMergedNetwork = mock<Network>() 555 val carrierMergedInfo = 556 mock<WifiInfo>().apply { whenever(this.isCarrierMerged).thenReturn(true) } 557 val underlyingCapabilities = 558 mock<NetworkCapabilities>().also { 559 whenever(it.hasTransport(TRANSPORT_WIFI)).thenReturn(true) 560 whenever(it.transportInfo).thenReturn(carrierMergedInfo) 561 } 562 whenever(connectivityManager.getNetworkCapabilities(underlyingCarrierMergedNetwork)) 563 .thenReturn(underlyingCapabilities) 564 565 // Main network with underlying network 566 val mainCapabilities = 567 mock<NetworkCapabilities>().also { 568 whenever(it.hasTransport(TRANSPORT_CELLULAR)).thenReturn(true) 569 whenever(it.transportInfo).thenReturn(null) 570 whenever(it.underlyingNetworks) 571 .thenReturn(listOf(underlyingCarrierMergedNetwork)) 572 } 573 574 getDefaultNetworkCallback().onCapabilitiesChanged(NETWORK, mainCapabilities) 575 576 assertThat(latest!!.mobile.isDefault).isTrue() 577 assertThat(latest!!.carrierMerged.isDefault).isTrue() 578 assertThat(latest!!.wifi.isDefault).isTrue() 579 } 580 581 /** 582 * Test for b/225902574: VPN over VCN over W+ (aka VPN over VCN over carrier merged). 583 * 584 * Also see b/352162710#comment27 scenario #3 and b/352162710#comment30. 585 */ 586 @Test defaultConnections_cellular_underlyingCarrierMergedViaMobileWithVcnTransport_allDefaultnull587 fun defaultConnections_cellular_underlyingCarrierMergedViaMobileWithVcnTransport_allDefault() = 588 testScope.runTest { 589 val latest by collectLastValue(underTest.defaultConnections) 590 591 // Underlying carrier merged network 592 val underlyingCarrierMergedNetwork = mock<Network>() 593 val carrierMergedInfo = 594 mock<WifiInfo>().apply { whenever(this.isCarrierMerged).thenReturn(true) } 595 val underlyingWifi = newWifiNetwork(carrierMergedInfo) 596 val underlyingCapabilities = 597 mock<NetworkCapabilities>().also { 598 whenever(it.hasTransport(TRANSPORT_CELLULAR)).thenReturn(true) 599 whenever(it.transportInfo).thenReturn(vcnTransportInfo) 600 whenever(it.underlyingNetworks).thenReturn(listOf(underlyingWifi)) 601 } 602 whenever(connectivityManager.getNetworkCapabilities(underlyingCarrierMergedNetwork)) 603 .thenReturn(underlyingCapabilities) 604 605 // Main network with underlying network 606 val mainCapabilities = 607 mock<NetworkCapabilities>().also { 608 whenever(it.hasTransport(TRANSPORT_CELLULAR)).thenReturn(true) 609 whenever(it.hasTransport(TRANSPORT_VPN)).thenReturn(true) 610 whenever(it.transportInfo).thenReturn(null) 611 whenever(it.underlyingNetworks) 612 .thenReturn(listOf(underlyingCarrierMergedNetwork)) 613 } 614 615 getDefaultNetworkCallback().onCapabilitiesChanged(NETWORK, mainCapabilities) 616 617 assertThat(latest!!.mobile.isDefault).isTrue() 618 assertThat(latest!!.carrierMerged.isDefault).isTrue() 619 assertThat(latest!!.wifi.isDefault).isTrue() 620 } 621 622 @Test defaultConnections_multipleTransports_multipleDefaultnull623 fun defaultConnections_multipleTransports_multipleDefault() = 624 testScope.runTest { 625 val latest by collectLastValue(underTest.defaultConnections) 626 627 val capabilities = 628 mock<NetworkCapabilities>().also { 629 whenever(it.hasTransport(TRANSPORT_CELLULAR)).thenReturn(true) 630 whenever(it.hasTransport(TRANSPORT_ETHERNET)).thenReturn(true) 631 whenever(it.hasTransport(TRANSPORT_WIFI)).thenReturn(true) 632 } 633 634 getDefaultNetworkCallback().onCapabilitiesChanged(NETWORK, capabilities) 635 636 assertThat(latest!!.mobile.isDefault).isTrue() 637 assertThat(latest!!.ethernet.isDefault).isTrue() 638 assertThat(latest!!.wifi.isDefault).isTrue() 639 } 640 641 @Test defaultConnections_hasValidated_isValidatedTruenull642 fun defaultConnections_hasValidated_isValidatedTrue() = 643 testScope.runTest { 644 val latest by collectLastValue(underTest.defaultConnections) 645 646 val capabilities = 647 mock<NetworkCapabilities>().also { 648 whenever(it.hasCapability(NetworkCapabilities.NET_CAPABILITY_VALIDATED)) 649 .thenReturn(true) 650 } 651 652 getDefaultNetworkCallback().onCapabilitiesChanged(NETWORK, capabilities) 653 654 assertThat(latest!!.isValidated).isTrue() 655 } 656 657 @Test defaultConnections_noValidated_isValidatedFalsenull658 fun defaultConnections_noValidated_isValidatedFalse() = 659 testScope.runTest { 660 val latest by collectLastValue(underTest.defaultConnections) 661 662 val capabilities = 663 mock<NetworkCapabilities>().also { 664 whenever(it.hasCapability(NetworkCapabilities.NET_CAPABILITY_VALIDATED)) 665 .thenReturn(false) 666 } 667 668 getDefaultNetworkCallback().onCapabilitiesChanged(NETWORK, capabilities) 669 670 assertThat(latest!!.isValidated).isFalse() 671 } 672 673 @Test vcnSubId_initiallyNullnull674 fun vcnSubId_initiallyNull() { 675 assertThat(underTest.vcnSubId.value).isNull() 676 } 677 678 @Test vcnSubId_tracksVcnTransportInfonull679 fun vcnSubId_tracksVcnTransportInfo() = 680 testScope.runTest { 681 val underlyingCell = newCellNetwork(SUB_1_ID) 682 683 val latest by collectLastValue(underTest.vcnSubId) 684 685 val capabilities = 686 mock<NetworkCapabilities>().also { 687 whenever(it.hasTransport(TRANSPORT_CELLULAR)).thenReturn(true) 688 whenever(it.transportInfo).thenReturn(vcnTransportInfo) 689 whenever(it.underlyingNetworks).thenReturn(listOf(underlyingCell)) 690 } 691 692 getDefaultNetworkCallback().onCapabilitiesChanged(NETWORK, capabilities) 693 694 assertThat(latest).isEqualTo(SUB_1_ID) 695 } 696 697 @Test vcnSubId_filersOutInvalidnull698 fun vcnSubId_filersOutInvalid() = 699 testScope.runTest { 700 val underlyingCell = newCellNetwork(INVALID_SUBSCRIPTION_ID) 701 702 val latest by collectLastValue(underTest.vcnSubId) 703 704 val capabilities = 705 mock<NetworkCapabilities>().also { 706 whenever(it.hasTransport(TRANSPORT_CELLULAR)).thenReturn(true) 707 whenever(it.transportInfo).thenReturn(vcnTransportInfo) 708 whenever(it.underlyingNetworks).thenReturn(listOf(underlyingCell)) 709 } 710 711 getDefaultNetworkCallback().onCapabilitiesChanged(NETWORK, capabilities) 712 713 assertThat(latest).isNull() 714 } 715 716 @Test vcnSubId_nullIfNoTransportInfonull717 fun vcnSubId_nullIfNoTransportInfo() = 718 testScope.runTest { 719 val latest by collectLastValue(underTest.vcnSubId) 720 721 val capabilities = 722 mock<NetworkCapabilities>().also { 723 whenever(it.hasTransport(TRANSPORT_CELLULAR)).thenReturn(true) 724 whenever(it.transportInfo).thenReturn(null) 725 } 726 727 getDefaultNetworkCallback().onCapabilitiesChanged(NETWORK, capabilities) 728 729 assertThat(latest).isNull() 730 } 731 732 @Test vcnSubId_nullIfVcnInfoIsNotCellularnull733 fun vcnSubId_nullIfVcnInfoIsNotCellular() = 734 testScope.runTest { 735 // If the underlying network of the VCN is a WiFi network, then there is no subId that 736 // could disagree with telephony's active data subscription id. 737 738 val latest by collectLastValue(underTest.vcnSubId) 739 740 val wifiInfo = mock<WifiInfo>() 741 val underlyingWifi = newWifiNetwork(wifiInfo) 742 val capabilities = 743 mock<NetworkCapabilities>().also { 744 whenever(it.hasTransport(TRANSPORT_CELLULAR)).thenReturn(true) 745 whenever(it.transportInfo).thenReturn(vcnTransportInfo) 746 whenever(it.underlyingNetworks).thenReturn(listOf(underlyingWifi)) 747 } 748 749 getDefaultNetworkCallback().onCapabilitiesChanged(NETWORK, capabilities) 750 751 assertThat(latest).isNull() 752 } 753 754 @Test vcnSubId_changingVcnInfoIsTrackednull755 fun vcnSubId_changingVcnInfoIsTracked() = 756 testScope.runTest { 757 val latest by collectLastValue(underTest.vcnSubId) 758 759 val wifiInfo = mock<WifiInfo>() 760 val underlyingWifi = newWifiNetwork(wifiInfo) 761 val underlyingCell1 = newCellNetwork(SUB_1_ID) 762 val underlyingCell2 = newCellNetwork(SUB_2_ID) 763 764 val capabilities = 765 mock<NetworkCapabilities>().also { 766 whenever(it.hasTransport(TRANSPORT_WIFI)).thenReturn(true) 767 whenever(it.transportInfo).thenReturn(vcnTransportInfo) 768 whenever(it.underlyingNetworks).thenReturn(listOf(underlyingWifi)) 769 } 770 771 // WIFI VCN info 772 getDefaultNetworkCallback().onCapabilitiesChanged(NETWORK, capabilities) 773 774 assertThat(latest).isNull() 775 776 // Cellular VCN info with subId 1 777 whenever(capabilities.hasTransport(eq(TRANSPORT_CELLULAR))).thenReturn(true) 778 whenever(capabilities.transportInfo).thenReturn(vcnTransportInfo) 779 whenever(capabilities.underlyingNetworks).thenReturn(listOf(underlyingCell1)) 780 781 getDefaultNetworkCallback().onCapabilitiesChanged(NETWORK, capabilities) 782 783 assertThat(latest).isEqualTo(SUB_1_ID) 784 785 // Cellular VCN info with subId 2 786 whenever(capabilities.transportInfo).thenReturn(vcnTransportInfo) 787 whenever(capabilities.underlyingNetworks).thenReturn(listOf(underlyingCell2)) 788 789 getDefaultNetworkCallback().onCapabilitiesChanged(NETWORK, capabilities) 790 791 assertThat(latest).isEqualTo(SUB_2_ID) 792 793 // No VCN anymore 794 whenever(capabilities.transportInfo).thenReturn(null) 795 796 getDefaultNetworkCallback().onCapabilitiesChanged(NETWORK, capabilities) 797 798 assertThat(latest).isNull() 799 } 800 801 @Test getMainOrUnderlyingWifiInfo_wifi_hasInfonull802 fun getMainOrUnderlyingWifiInfo_wifi_hasInfo() { 803 val wifiInfo = mock<WifiInfo>() 804 val capabilities = 805 mock<NetworkCapabilities>().also { 806 whenever(it.hasTransport(TRANSPORT_WIFI)).thenReturn(true) 807 whenever(it.transportInfo).thenReturn(wifiInfo) 808 } 809 810 val result = capabilities.getMainOrUnderlyingWifiInfo(connectivityManager) 811 812 assertThat(result).isEqualTo(wifiInfo) 813 } 814 815 @Test getMainOrUnderlyingWifiInfo_vcnWithWifi_hasInfonull816 fun getMainOrUnderlyingWifiInfo_vcnWithWifi_hasInfo() { 817 val wifiInfo = mock<WifiInfo>() 818 val underlyingWifi = newWifiNetwork(wifiInfo) 819 val capabilities = 820 mock<NetworkCapabilities>().also { 821 whenever(it.hasTransport(TRANSPORT_WIFI)).thenReturn(true) 822 whenever(it.transportInfo).thenReturn(vcnTransportInfo) 823 whenever(it.underlyingNetworks).thenReturn(listOf(underlyingWifi)) 824 } 825 826 val result = capabilities.getMainOrUnderlyingWifiInfo(connectivityManager) 827 828 assertThat(result).isEqualTo(wifiInfo) 829 } 830 831 @Test getMainOrUnderlyingWifiInfo_notCellularOrWifiTransport_noInfonull832 fun getMainOrUnderlyingWifiInfo_notCellularOrWifiTransport_noInfo() { 833 val capabilities = 834 mock<NetworkCapabilities>().also { 835 whenever(it.hasTransport(TRANSPORT_WIFI)).thenReturn(false) 836 whenever(it.hasTransport(TRANSPORT_CELLULAR)).thenReturn(false) 837 whenever(it.transportInfo).thenReturn(mock<WifiInfo>()) 838 } 839 840 val result = capabilities.getMainOrUnderlyingWifiInfo(connectivityManager) 841 842 assertThat(result).isNull() 843 } 844 845 @Test getMainOrUnderlyingWifiInfo_cellular_underlyingWifi_hasInfonull846 fun getMainOrUnderlyingWifiInfo_cellular_underlyingWifi_hasInfo() { 847 val underlyingNetwork = mock<Network>() 848 val underlyingWifiInfo = mock<WifiInfo>() 849 val underlyingWifiCapabilities = 850 mock<NetworkCapabilities>().also { 851 whenever(it.hasTransport(TRANSPORT_WIFI)).thenReturn(true) 852 whenever(it.transportInfo).thenReturn(underlyingWifiInfo) 853 } 854 whenever(connectivityManager.getNetworkCapabilities(underlyingNetwork)) 855 .thenReturn(underlyingWifiCapabilities) 856 857 // WHEN the main capabilities have an underlying wifi network 858 val mainCapabilities = 859 mock<NetworkCapabilities>().also { 860 whenever(it.hasTransport(TRANSPORT_CELLULAR)).thenReturn(true) 861 whenever(it.transportInfo).thenReturn(null) 862 whenever(it.underlyingNetworks).thenReturn(listOf(underlyingNetwork)) 863 } 864 865 val result = mainCapabilities.getMainOrUnderlyingWifiInfo(connectivityManager) 866 867 // THEN we fetch the underlying wifi info 868 assertThat(result).isEqualTo(underlyingWifiInfo) 869 } 870 871 @Test 872 @DisableFlags(FLAG_STATUS_BAR_ALWAYS_CHECK_UNDERLYING_NETWORKS) getMainOrUnderlyingWifiInfo_notCellular_underlyingWifi_noInfonull873 fun getMainOrUnderlyingWifiInfo_notCellular_underlyingWifi_noInfo() { 874 val underlyingNetwork = mock<Network>() 875 val underlyingWifiInfo = mock<WifiInfo>() 876 val underlyingWifiCapabilities = 877 mock<NetworkCapabilities>().also { 878 whenever(it.hasTransport(TRANSPORT_WIFI)).thenReturn(true) 879 whenever(it.transportInfo).thenReturn(underlyingWifiInfo) 880 } 881 whenever(connectivityManager.getNetworkCapabilities(underlyingNetwork)) 882 .thenReturn(underlyingWifiCapabilities) 883 884 // WHEN the main capabilities have an underlying wifi network but is *not* CELLULAR 885 val mainCapabilities = 886 mock<NetworkCapabilities>().also { 887 whenever(it.hasTransport(TRANSPORT_ETHERNET)).thenReturn(true) 888 whenever(it.hasTransport(TRANSPORT_CELLULAR)).thenReturn(false) 889 whenever(it.transportInfo).thenReturn(null) 890 whenever(it.underlyingNetworks).thenReturn(listOf(underlyingNetwork)) 891 } 892 893 val result = mainCapabilities.getMainOrUnderlyingWifiInfo(connectivityManager) 894 895 // THEN we DON'T fetch the underlying wifi info 896 assertThat(result).isNull() 897 } 898 899 @Test getMainOrUnderlyingWifiInfo_cellular_underlyingVcnWithWifi_hasInfonull900 fun getMainOrUnderlyingWifiInfo_cellular_underlyingVcnWithWifi_hasInfo() { 901 val wifiInfo = mock<WifiInfo>() 902 val underlyingNetwork = mock<Network>() 903 904 // The Wifi network that is under the VCN network 905 val physicalWifiNetwork = newWifiNetwork(wifiInfo) 906 907 val underlyingWifiCapabilities = 908 mock<NetworkCapabilities>().also { 909 whenever(it.hasTransport(TRANSPORT_WIFI)).thenReturn(true) 910 whenever(it.transportInfo).thenReturn(vcnTransportInfo) 911 whenever(it.underlyingNetworks).thenReturn(listOf(physicalWifiNetwork)) 912 } 913 whenever(connectivityManager.getNetworkCapabilities(underlyingNetwork)) 914 .thenReturn(underlyingWifiCapabilities) 915 916 // WHEN the main capabilities have an underlying VCN network with wifi 917 val mainCapabilities = 918 mock<NetworkCapabilities>().also { 919 whenever(it.hasTransport(TRANSPORT_CELLULAR)).thenReturn(true) 920 whenever(it.transportInfo).thenReturn(null) 921 whenever(it.underlyingNetworks).thenReturn(listOf(underlyingNetwork)) 922 } 923 924 val result = mainCapabilities.getMainOrUnderlyingWifiInfo(connectivityManager) 925 926 // THEN we fetch the wifi info 927 assertThat(result).isEqualTo(wifiInfo) 928 } 929 930 @Test 931 @DisableFlags(FLAG_STATUS_BAR_ALWAYS_CHECK_UNDERLYING_NETWORKS) getMainOrUnderlyingWifiInfo_notCellular_underlyingVcnWithWifi_noInfonull932 fun getMainOrUnderlyingWifiInfo_notCellular_underlyingVcnWithWifi_noInfo() { 933 val underlyingNetwork = mock<Network>() 934 935 // The Wifi network that is under the VCN network 936 val physicalWifiNetwork = newWifiNetwork(mock<WifiInfo>()) 937 938 val underlyingWifiCapabilities = 939 mock<NetworkCapabilities>().also { 940 whenever(it.hasTransport(TRANSPORT_WIFI)).thenReturn(true) 941 whenever(it.transportInfo).thenReturn(vcnTransportInfo) 942 whenever(it.underlyingNetworks).thenReturn(listOf(physicalWifiNetwork)) 943 } 944 whenever(connectivityManager.getNetworkCapabilities(underlyingNetwork)) 945 .thenReturn(underlyingWifiCapabilities) 946 947 // WHEN the main capabilities have an underlying wifi network but it is *not* CELLULAR 948 val mainCapabilities = 949 mock<NetworkCapabilities>().also { 950 whenever(it.hasTransport(TRANSPORT_ETHERNET)).thenReturn(true) 951 whenever(it.hasTransport(TRANSPORT_CELLULAR)).thenReturn(false) 952 whenever(it.transportInfo).thenReturn(null) 953 whenever(it.underlyingNetworks).thenReturn(listOf(underlyingNetwork)) 954 } 955 956 val result = mainCapabilities.getMainOrUnderlyingWifiInfo(connectivityManager) 957 958 // THEN we DON'T fetch the underlying wifi info 959 assertThat(result).isNull() 960 } 961 962 @Test getMainOrUnderlyingWifiInfo_cellular_underlyingCellularWithCarrierMerged_hasInfonull963 fun getMainOrUnderlyingWifiInfo_cellular_underlyingCellularWithCarrierMerged_hasInfo() { 964 // Underlying carrier merged network 965 val underlyingCarrierMergedNetwork = mock<Network>() 966 val carrierMergedInfo = 967 mock<WifiInfo>().apply { whenever(this.isCarrierMerged).thenReturn(true) } 968 969 // The Wifi network that is under the VCN network 970 val physicalWifiNetwork = newWifiNetwork(carrierMergedInfo) 971 972 val underlyingCapabilities = 973 mock<NetworkCapabilities>().also { 974 whenever(it.hasTransport(TRANSPORT_CELLULAR)).thenReturn(true) 975 whenever(it.transportInfo).thenReturn(vcnTransportInfo) 976 whenever(it.underlyingNetworks).thenReturn(listOf(physicalWifiNetwork)) 977 } 978 whenever(connectivityManager.getNetworkCapabilities(underlyingCarrierMergedNetwork)) 979 .thenReturn(underlyingCapabilities) 980 981 // Main network with underlying network 982 val mainCapabilities = 983 mock<NetworkCapabilities>().also { 984 whenever(it.hasTransport(TRANSPORT_CELLULAR)).thenReturn(true) 985 whenever(it.transportInfo).thenReturn(null) 986 whenever(it.underlyingNetworks).thenReturn(listOf(underlyingCarrierMergedNetwork)) 987 } 988 989 val result = mainCapabilities.getMainOrUnderlyingWifiInfo(connectivityManager) 990 991 assertThat(result).isEqualTo(carrierMergedInfo) 992 assertThat(result!!.isCarrierMerged).isTrue() 993 } 994 995 @Test getMainOrUnderlyingWifiInfo_multipleUnderlying_usesFirstNonNullnull996 fun getMainOrUnderlyingWifiInfo_multipleUnderlying_usesFirstNonNull() { 997 // First underlying: Not wifi 998 val underlyingNotWifiNetwork = mock<Network>() 999 val underlyingNotWifiCapabilities = 1000 mock<NetworkCapabilities>().also { 1001 whenever(it.hasTransport(TRANSPORT_WIFI)).thenReturn(false) 1002 whenever(it.transportInfo).thenReturn(null) 1003 } 1004 whenever(connectivityManager.getNetworkCapabilities(underlyingNotWifiNetwork)) 1005 .thenReturn(underlyingNotWifiCapabilities) 1006 1007 // Second underlying: wifi 1008 val underlyingWifiNetwork1 = mock<Network>() 1009 val underlyingWifiInfo1 = mock<WifiInfo>() 1010 val underlyingWifiCapabilities1 = 1011 mock<NetworkCapabilities>().also { 1012 whenever(it.hasTransport(TRANSPORT_WIFI)).thenReturn(true) 1013 whenever(it.transportInfo).thenReturn(underlyingWifiInfo1) 1014 } 1015 whenever(connectivityManager.getNetworkCapabilities(underlyingWifiNetwork1)) 1016 .thenReturn(underlyingWifiCapabilities1) 1017 1018 // Third underlying: also wifi 1019 val underlyingWifiNetwork2 = mock<Network>() 1020 val underlyingWifiInfo2 = mock<WifiInfo>() 1021 val underlyingWifiCapabilities2 = 1022 mock<NetworkCapabilities>().also { 1023 whenever(it.hasTransport(TRANSPORT_WIFI)).thenReturn(true) 1024 whenever(it.transportInfo).thenReturn(underlyingWifiInfo2) 1025 } 1026 whenever(connectivityManager.getNetworkCapabilities(underlyingWifiNetwork2)) 1027 .thenReturn(underlyingWifiCapabilities2) 1028 1029 // WHEN the main capabilities has multiple underlying networks 1030 val mainCapabilities = 1031 mock<NetworkCapabilities>().also { 1032 whenever(it.hasTransport(TRANSPORT_CELLULAR)).thenReturn(true) 1033 whenever(it.transportInfo).thenReturn(null) 1034 whenever(it.underlyingNetworks) 1035 .thenReturn( 1036 listOf( 1037 underlyingNotWifiNetwork, 1038 underlyingWifiNetwork1, 1039 underlyingWifiNetwork2, 1040 ) 1041 ) 1042 } 1043 1044 val result = mainCapabilities.getMainOrUnderlyingWifiInfo(connectivityManager) 1045 1046 // THEN the first wifi one is used 1047 assertThat(result).isEqualTo(underlyingWifiInfo1) 1048 } 1049 1050 @Test getMainOrUnderlyingWifiInfo_nestedUnderlying_doesNotLookAtNestednull1051 fun getMainOrUnderlyingWifiInfo_nestedUnderlying_doesNotLookAtNested() { 1052 // WHEN there are two layers of underlying networks... 1053 1054 // Nested network 1055 val nestedUnderlyingNetwork = mock<Network>() 1056 val nestedWifiInfo = mock<WifiInfo>() 1057 val nestedCapabilities = 1058 mock<NetworkCapabilities>().also { 1059 whenever(it.hasTransport(TRANSPORT_WIFI)).thenReturn(true) 1060 whenever(it.transportInfo).thenReturn(nestedWifiInfo) 1061 } 1062 whenever(connectivityManager.getNetworkCapabilities(nestedUnderlyingNetwork)) 1063 .thenReturn(nestedCapabilities) 1064 1065 // Underlying network containing the nested network 1066 val underlyingNetwork = mock<Network>() 1067 val underlyingCapabilities = 1068 mock<NetworkCapabilities>().also { 1069 whenever(it.hasTransport(TRANSPORT_CELLULAR)).thenReturn(true) 1070 whenever(it.transportInfo).thenReturn(null) 1071 whenever(it.underlyingNetworks).thenReturn(listOf(nestedUnderlyingNetwork)) 1072 } 1073 whenever(connectivityManager.getNetworkCapabilities(underlyingNetwork)) 1074 .thenReturn(underlyingCapabilities) 1075 1076 // Main network containing the underlying network, which contains the nested network 1077 val mainCapabilities = 1078 mock<NetworkCapabilities>().also { 1079 whenever(it.hasTransport(TRANSPORT_CELLULAR)).thenReturn(true) 1080 whenever(it.transportInfo).thenReturn(null) 1081 whenever(it.underlyingNetworks).thenReturn(listOf(underlyingNetwork)) 1082 } 1083 1084 val result = mainCapabilities.getMainOrUnderlyingWifiInfo(connectivityManager) 1085 1086 // THEN only the first layer is checked, and the first layer has no wifi info 1087 assertThat(result).isNull() 1088 } 1089 createAndSetReponull1090 private fun createAndSetRepo() { 1091 underTest = 1092 ConnectivityRepositoryImpl( 1093 connectivityManager, 1094 connectivitySlots, 1095 context, 1096 dumpManager, 1097 logger, 1098 testScope.backgroundScope, 1099 tunerService, 1100 ) 1101 testScope.runCurrent() 1102 } 1103 getTunablenull1104 private fun getTunable(): TunerService.Tunable { 1105 val callbackCaptor = argumentCaptor<TunerService.Tunable>() 1106 verify(tunerService).addTunable(callbackCaptor.capture(), any()) 1107 return callbackCaptor.firstValue 1108 } 1109 setUpEthernetWifiMobileSlotNamesnull1110 private fun setUpEthernetWifiMobileSlotNames() { 1111 whenever(connectivitySlots.getSlotFromName(SLOT_ETHERNET)) 1112 .thenReturn(ConnectivitySlot.ETHERNET) 1113 whenever(connectivitySlots.getSlotFromName(SLOT_WIFI)).thenReturn(ConnectivitySlot.WIFI) 1114 whenever(connectivitySlots.getSlotFromName(SLOT_MOBILE)).thenReturn(ConnectivitySlot.MOBILE) 1115 } 1116 getDefaultNetworkCallbacknull1117 private fun getDefaultNetworkCallback(): ConnectivityManager.NetworkCallback { 1118 val callbackCaptor = argumentCaptor<ConnectivityManager.NetworkCallback>() 1119 verify(connectivityManager).registerDefaultNetworkCallback(callbackCaptor.capture()) 1120 return callbackCaptor.firstValue 1121 } 1122 1123 private companion object { 1124 private const val SLOT_ETHERNET = "ethernet" 1125 private const val SLOT_WIFI = "wifi" 1126 private const val SLOT_MOBILE = "mobile" 1127 1128 private const val SUB_1_ID = 1 1129 private const val SUB_2_ID = 2 1130 1131 const val NETWORK_ID = 45 <lambda>null1132 val NETWORK = mock<Network>().apply { whenever(this.getNetId()).thenReturn(NETWORK_ID) } 1133 } 1134 } 1135