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.mobile.data.repository.prod 18 19 import android.content.BroadcastReceiver 20 import android.content.Context 21 import android.content.Intent 22 import android.net.ConnectivityManager 23 import android.net.ConnectivityManager.NetworkCallback 24 import android.platform.test.annotations.EnableFlags 25 import android.telephony.AccessNetworkConstants.TRANSPORT_TYPE_WLAN 26 import android.telephony.AccessNetworkConstants.TRANSPORT_TYPE_WWAN 27 import android.telephony.CarrierConfigManager.KEY_INFLATE_SIGNAL_STRENGTH_BOOL 28 import android.telephony.CarrierConfigManager.KEY_SHOW_5G_SLICE_ICON_BOOL 29 import android.telephony.NetworkRegistrationInfo 30 import android.telephony.NetworkRegistrationInfo.DOMAIN_PS 31 import android.telephony.NetworkRegistrationInfo.REGISTRATION_STATE_DENIED 32 import android.telephony.NetworkRegistrationInfo.REGISTRATION_STATE_HOME 33 import android.telephony.ServiceState 34 import android.telephony.ServiceState.STATE_IN_SERVICE 35 import android.telephony.ServiceState.STATE_OUT_OF_SERVICE 36 import android.telephony.SubscriptionManager.EXTRA_SUBSCRIPTION_INDEX 37 import android.telephony.SubscriptionManager.PROFILE_CLASS_UNSET 38 import android.telephony.TelephonyCallback 39 import android.telephony.TelephonyCallback.CarrierRoamingNtnModeListener 40 import android.telephony.TelephonyCallback.DataActivityListener 41 import android.telephony.TelephonyCallback.DisplayInfoListener 42 import android.telephony.TelephonyCallback.ServiceStateListener 43 import android.telephony.TelephonyDisplayInfo 44 import android.telephony.TelephonyDisplayInfo.OVERRIDE_NETWORK_TYPE_LTE_CA 45 import android.telephony.TelephonyDisplayInfo.OVERRIDE_NETWORK_TYPE_NONE 46 import android.telephony.TelephonyManager 47 import android.telephony.TelephonyManager.DATA_ACTIVITY_DORMANT 48 import android.telephony.TelephonyManager.DATA_ACTIVITY_IN 49 import android.telephony.TelephonyManager.DATA_ACTIVITY_INOUT 50 import android.telephony.TelephonyManager.DATA_ACTIVITY_NONE 51 import android.telephony.TelephonyManager.DATA_ACTIVITY_OUT 52 import android.telephony.TelephonyManager.DATA_CONNECTED 53 import android.telephony.TelephonyManager.DATA_CONNECTING 54 import android.telephony.TelephonyManager.DATA_DISCONNECTED 55 import android.telephony.TelephonyManager.DATA_DISCONNECTING 56 import android.telephony.TelephonyManager.DATA_HANDOVER_IN_PROGRESS 57 import android.telephony.TelephonyManager.DATA_SUSPENDED 58 import android.telephony.TelephonyManager.DATA_UNKNOWN 59 import android.telephony.TelephonyManager.ERI_OFF 60 import android.telephony.TelephonyManager.ERI_ON 61 import android.telephony.TelephonyManager.EXTRA_CARRIER_ID 62 import android.telephony.TelephonyManager.EXTRA_PLMN 63 import android.telephony.TelephonyManager.EXTRA_SHOW_PLMN 64 import android.telephony.TelephonyManager.EXTRA_SHOW_SPN 65 import android.telephony.TelephonyManager.EXTRA_SPN 66 import android.telephony.TelephonyManager.EXTRA_SUBSCRIPTION_ID 67 import android.telephony.TelephonyManager.NETWORK_TYPE_LTE 68 import android.telephony.TelephonyManager.NETWORK_TYPE_UNKNOWN 69 import androidx.test.filters.SmallTest 70 import com.android.settingslib.mobile.MobileMappings 71 import com.android.systemui.SysuiTestCase 72 import com.android.systemui.coroutines.collectLastValue 73 import com.android.systemui.flags.FakeFeatureFlagsClassic 74 import com.android.systemui.flags.Flags.ROAMING_INDICATOR_VIA_DISPLAY_INFO 75 import com.android.systemui.log.table.TableLogBuffer 76 import com.android.systemui.statusbar.pipeline.mobile.data.MobileInputLogger 77 import com.android.systemui.statusbar.pipeline.mobile.data.model.DataConnectionState 78 import com.android.systemui.statusbar.pipeline.mobile.data.model.NetworkNameModel 79 import com.android.systemui.statusbar.pipeline.mobile.data.model.ResolvedNetworkType 80 import com.android.systemui.statusbar.pipeline.mobile.data.model.ResolvedNetworkType.DefaultNetworkType 81 import com.android.systemui.statusbar.pipeline.mobile.data.model.ResolvedNetworkType.OverrideNetworkType 82 import com.android.systemui.statusbar.pipeline.mobile.data.model.ResolvedNetworkType.UnknownNetworkType 83 import com.android.systemui.statusbar.pipeline.mobile.data.model.SubscriptionModel 84 import com.android.systemui.statusbar.pipeline.mobile.data.model.SystemUiCarrierConfig 85 import com.android.systemui.statusbar.pipeline.mobile.data.model.SystemUiCarrierConfigTest.Companion.configWithOverride 86 import com.android.systemui.statusbar.pipeline.mobile.data.model.SystemUiCarrierConfigTest.Companion.createTestConfig 87 import com.android.systemui.statusbar.pipeline.mobile.data.model.toNetworkNameModel 88 import com.android.systemui.statusbar.pipeline.mobile.data.repository.FakeMobileConnectionsRepository 89 import com.android.systemui.statusbar.pipeline.mobile.data.repository.MobileConnectionRepository.Companion.DEFAULT_NUM_LEVELS 90 import com.android.systemui.statusbar.pipeline.mobile.data.repository.prod.MobileTelephonyHelpers.signalStrength 91 import com.android.systemui.statusbar.pipeline.mobile.data.repository.prod.MobileTelephonyHelpers.telephonyDisplayInfo 92 import com.android.systemui.statusbar.pipeline.mobile.util.FakeMobileMappingsProxy 93 import com.android.systemui.statusbar.pipeline.shared.data.model.DataActivityModel 94 import com.android.systemui.statusbar.pipeline.shared.data.model.toMobileDataActivityModel 95 import com.android.systemui.util.mockito.any 96 import com.android.systemui.util.mockito.argumentCaptor 97 import com.android.systemui.util.mockito.mock 98 import com.android.systemui.util.mockito.whenever 99 import com.android.systemui.util.mockito.withArgCaptor 100 import com.google.common.truth.Truth.assertThat 101 import kotlinx.coroutines.ExperimentalCoroutinesApi 102 import kotlinx.coroutines.flow.MutableStateFlow 103 import kotlinx.coroutines.flow.launchIn 104 import kotlinx.coroutines.flow.onEach 105 import kotlinx.coroutines.test.TestScope 106 import kotlinx.coroutines.test.UnconfinedTestDispatcher 107 import kotlinx.coroutines.test.runTest 108 import org.junit.Before 109 import org.junit.Test 110 import org.mockito.Mock 111 import org.mockito.Mockito.verify 112 import org.mockito.MockitoAnnotations 113 114 @Suppress("EXPERIMENTAL_IS_NOT_ENABLED") 115 @OptIn(ExperimentalCoroutinesApi::class) 116 @SmallTest 117 class MobileConnectionRepositoryTest : SysuiTestCase() { 118 private lateinit var underTest: MobileConnectionRepositoryImpl 119 private lateinit var connectionsRepo: FakeMobileConnectionsRepository 120 121 private val flags = <lambda>null122 FakeFeatureFlagsClassic().also { it.set(ROAMING_INDICATOR_VIA_DISPLAY_INFO, true) } 123 124 @Mock private lateinit var connectivityManager: ConnectivityManager 125 @Mock private lateinit var telephonyManager: TelephonyManager 126 @Mock private lateinit var logger: MobileInputLogger 127 @Mock private lateinit var tableLogger: TableLogBuffer 128 @Mock private lateinit var context: Context 129 130 private val mobileMappings = FakeMobileMappingsProxy() 131 private val systemUiCarrierConfig = 132 SystemUiCarrierConfig( 133 SUB_1_ID, 134 createTestConfig(), 135 ) 136 137 private val testDispatcher = UnconfinedTestDispatcher() 138 private val testScope = TestScope(testDispatcher) 139 140 private val subscriptionModel: MutableStateFlow<SubscriptionModel?> = 141 MutableStateFlow( 142 SubscriptionModel( 143 subscriptionId = SUB_1_ID, 144 carrierName = DEFAULT_NAME, 145 profileClass = PROFILE_CLASS_UNSET, 146 ) 147 ) 148 149 @Before setUpnull150 fun setUp() { 151 MockitoAnnotations.initMocks(this) 152 whenever(telephonyManager.subscriptionId).thenReturn(SUB_1_ID) 153 154 connectionsRepo = FakeMobileConnectionsRepository(mobileMappings, tableLogger) 155 156 underTest = 157 MobileConnectionRepositoryImpl( 158 SUB_1_ID, 159 context, 160 subscriptionModel, 161 DEFAULT_NAME_MODEL, 162 SEP, 163 connectivityManager, 164 telephonyManager, 165 systemUiCarrierConfig, 166 fakeBroadcastDispatcher, 167 mobileMappings, 168 testDispatcher, 169 logger, 170 tableLogger, 171 flags, 172 testScope.backgroundScope, 173 ) 174 } 175 176 @Test emergencyOnlynull177 fun emergencyOnly() = 178 testScope.runTest { 179 var latest: Boolean? = null 180 val job = underTest.isEmergencyOnly.onEach { latest = it }.launchIn(this) 181 182 val serviceState = ServiceState() 183 serviceState.isEmergencyOnly = true 184 185 getTelephonyCallbackForType<ServiceStateListener>().onServiceStateChanged(serviceState) 186 187 assertThat(latest).isEqualTo(true) 188 189 job.cancel() 190 } 191 192 @Test emergencyOnly_togglesnull193 fun emergencyOnly_toggles() = 194 testScope.runTest { 195 var latest: Boolean? = null 196 val job = underTest.isEmergencyOnly.onEach { latest = it }.launchIn(this) 197 198 val callback = getTelephonyCallbackForType<ServiceStateListener>() 199 callback.onServiceStateChanged(ServiceState().also { it.isEmergencyOnly = true }) 200 assertThat(latest).isTrue() 201 202 callback.onServiceStateChanged(ServiceState().also { it.isEmergencyOnly = false }) 203 204 assertThat(latest).isFalse() 205 206 job.cancel() 207 } 208 209 @Test cdmaLevelUpdatesnull210 fun cdmaLevelUpdates() = 211 testScope.runTest { 212 var latest: Int? = null 213 val job = underTest.cdmaLevel.onEach { latest = it }.launchIn(this) 214 215 val callback = getTelephonyCallbackForType<TelephonyCallback.SignalStrengthsListener>() 216 var strength = signalStrength(gsmLevel = 1, cdmaLevel = 2, isGsm = true) 217 callback.onSignalStrengthsChanged(strength) 218 219 assertThat(latest).isEqualTo(2) 220 221 // gsmLevel updates, no change to cdmaLevel 222 strength = signalStrength(gsmLevel = 3, cdmaLevel = 2, isGsm = true) 223 callback.onSignalStrengthsChanged(strength) 224 225 assertThat(latest).isEqualTo(2) 226 227 job.cancel() 228 } 229 230 @Test gsmLevelUpdatesnull231 fun gsmLevelUpdates() = 232 testScope.runTest { 233 var latest: Int? = null 234 val job = underTest.primaryLevel.onEach { latest = it }.launchIn(this) 235 236 val callback = getTelephonyCallbackForType<TelephonyCallback.SignalStrengthsListener>() 237 var strength = signalStrength(gsmLevel = 1, cdmaLevel = 2, isGsm = true) 238 callback.onSignalStrengthsChanged(strength) 239 240 assertThat(latest).isEqualTo(1) 241 242 strength = signalStrength(gsmLevel = 3, cdmaLevel = 2, isGsm = true) 243 callback.onSignalStrengthsChanged(strength) 244 245 assertThat(latest).isEqualTo(3) 246 247 job.cancel() 248 } 249 250 @Test isGsmnull251 fun isGsm() = 252 testScope.runTest { 253 var latest: Boolean? = null 254 val job = underTest.isGsm.onEach { latest = it }.launchIn(this) 255 256 val callback = getTelephonyCallbackForType<TelephonyCallback.SignalStrengthsListener>() 257 var strength = signalStrength(gsmLevel = 1, cdmaLevel = 2, isGsm = true) 258 callback.onSignalStrengthsChanged(strength) 259 260 assertThat(latest).isTrue() 261 262 strength = signalStrength(gsmLevel = 1, cdmaLevel = 2, isGsm = false) 263 callback.onSignalStrengthsChanged(strength) 264 265 assertThat(latest).isFalse() 266 267 job.cancel() 268 } 269 270 @Test dataConnectionState_connectednull271 fun dataConnectionState_connected() = 272 testScope.runTest { 273 var latest: DataConnectionState? = null 274 val job = underTest.dataConnectionState.onEach { latest = it }.launchIn(this) 275 276 val callback = 277 getTelephonyCallbackForType<TelephonyCallback.DataConnectionStateListener>() 278 callback.onDataConnectionStateChanged(DATA_CONNECTED, 200 /* unused */) 279 280 assertThat(latest).isEqualTo(DataConnectionState.Connected) 281 282 job.cancel() 283 } 284 285 @Test dataConnectionState_connectingnull286 fun dataConnectionState_connecting() = 287 testScope.runTest { 288 var latest: DataConnectionState? = null 289 val job = underTest.dataConnectionState.onEach { latest = it }.launchIn(this) 290 291 val callback = 292 getTelephonyCallbackForType<TelephonyCallback.DataConnectionStateListener>() 293 callback.onDataConnectionStateChanged(DATA_CONNECTING, 200 /* unused */) 294 295 assertThat(latest).isEqualTo(DataConnectionState.Connecting) 296 297 job.cancel() 298 } 299 300 @Test dataConnectionState_disconnectednull301 fun dataConnectionState_disconnected() = 302 testScope.runTest { 303 var latest: DataConnectionState? = null 304 val job = underTest.dataConnectionState.onEach { latest = it }.launchIn(this) 305 306 val callback = 307 getTelephonyCallbackForType<TelephonyCallback.DataConnectionStateListener>() 308 callback.onDataConnectionStateChanged(DATA_DISCONNECTED, 200 /* unused */) 309 310 assertThat(latest).isEqualTo(DataConnectionState.Disconnected) 311 312 job.cancel() 313 } 314 315 @Test dataConnectionState_disconnectingnull316 fun dataConnectionState_disconnecting() = 317 testScope.runTest { 318 var latest: DataConnectionState? = null 319 val job = underTest.dataConnectionState.onEach { latest = it }.launchIn(this) 320 321 val callback = 322 getTelephonyCallbackForType<TelephonyCallback.DataConnectionStateListener>() 323 callback.onDataConnectionStateChanged(DATA_DISCONNECTING, 200 /* unused */) 324 325 assertThat(latest).isEqualTo(DataConnectionState.Disconnecting) 326 327 job.cancel() 328 } 329 330 @Test dataConnectionState_suspendednull331 fun dataConnectionState_suspended() = 332 testScope.runTest { 333 var latest: DataConnectionState? = null 334 val job = underTest.dataConnectionState.onEach { latest = it }.launchIn(this) 335 336 val callback = 337 getTelephonyCallbackForType<TelephonyCallback.DataConnectionStateListener>() 338 callback.onDataConnectionStateChanged(DATA_SUSPENDED, 200 /* unused */) 339 340 assertThat(latest).isEqualTo(DataConnectionState.Suspended) 341 342 job.cancel() 343 } 344 345 @Test dataConnectionState_handoverInProgressnull346 fun dataConnectionState_handoverInProgress() = 347 testScope.runTest { 348 var latest: DataConnectionState? = null 349 val job = underTest.dataConnectionState.onEach { latest = it }.launchIn(this) 350 351 val callback = 352 getTelephonyCallbackForType<TelephonyCallback.DataConnectionStateListener>() 353 callback.onDataConnectionStateChanged(DATA_HANDOVER_IN_PROGRESS, 200 /* unused */) 354 355 assertThat(latest).isEqualTo(DataConnectionState.HandoverInProgress) 356 357 job.cancel() 358 } 359 360 @Test dataConnectionState_unknownnull361 fun dataConnectionState_unknown() = 362 testScope.runTest { 363 var latest: DataConnectionState? = null 364 val job = underTest.dataConnectionState.onEach { latest = it }.launchIn(this) 365 366 val callback = 367 getTelephonyCallbackForType<TelephonyCallback.DataConnectionStateListener>() 368 callback.onDataConnectionStateChanged(DATA_UNKNOWN, 200 /* unused */) 369 370 assertThat(latest).isEqualTo(DataConnectionState.Unknown) 371 372 job.cancel() 373 } 374 375 @Test dataConnectionState_invalidnull376 fun dataConnectionState_invalid() = 377 testScope.runTest { 378 var latest: DataConnectionState? = null 379 val job = underTest.dataConnectionState.onEach { latest = it }.launchIn(this) 380 381 val callback = 382 getTelephonyCallbackForType<TelephonyCallback.DataConnectionStateListener>() 383 callback.onDataConnectionStateChanged(45, 200 /* unused */) 384 385 assertThat(latest).isEqualTo(DataConnectionState.Invalid) 386 387 job.cancel() 388 } 389 390 @Test dataActivitynull391 fun dataActivity() = 392 testScope.runTest { 393 var latest: DataActivityModel? = null 394 val job = underTest.dataActivityDirection.onEach { latest = it }.launchIn(this) 395 396 val callback = getTelephonyCallbackForType<DataActivityListener>() 397 callback.onDataActivity(DATA_ACTIVITY_INOUT) 398 399 assertThat(latest).isEqualTo(DATA_ACTIVITY_INOUT.toMobileDataActivityModel()) 400 401 job.cancel() 402 } 403 404 @Test carrierId_initialValueCapturednull405 fun carrierId_initialValueCaptured() = 406 testScope.runTest { 407 whenever(telephonyManager.simCarrierId).thenReturn(1234) 408 409 var latest: Int? = null 410 val job = underTest.carrierId.onEach { latest = it }.launchIn(this) 411 412 assertThat(latest).isEqualTo(1234) 413 414 job.cancel() 415 } 416 417 @Test carrierId_updatesOnBroadcastnull418 fun carrierId_updatesOnBroadcast() = 419 testScope.runTest { 420 whenever(telephonyManager.simCarrierId).thenReturn(1234) 421 422 var latest: Int? = null 423 val job = underTest.carrierId.onEach { latest = it }.launchIn(this) 424 425 fakeBroadcastDispatcher.sendIntentToMatchingReceiversOnly( 426 context, 427 carrierIdIntent(carrierId = 4321), 428 ) 429 430 assertThat(latest).isEqualTo(4321) 431 432 job.cancel() 433 } 434 435 @Test carrierNetworkChangenull436 fun carrierNetworkChange() = 437 testScope.runTest { 438 var latest: Boolean? = null 439 val job = underTest.carrierNetworkChangeActive.onEach { latest = it }.launchIn(this) 440 441 val callback = getTelephonyCallbackForType<TelephonyCallback.CarrierNetworkListener>() 442 callback.onCarrierNetworkChange(true) 443 444 assertThat(latest).isEqualTo(true) 445 446 job.cancel() 447 } 448 449 @Test networkType_defaultnull450 fun networkType_default() = 451 testScope.runTest { 452 var latest: ResolvedNetworkType? = null 453 val job = underTest.resolvedNetworkType.onEach { latest = it }.launchIn(this) 454 455 val expected = UnknownNetworkType 456 457 assertThat(latest).isEqualTo(expected) 458 459 job.cancel() 460 } 461 462 @Test networkType_unknown_hasCorrectKeynull463 fun networkType_unknown_hasCorrectKey() = 464 testScope.runTest { 465 var latest: ResolvedNetworkType? = null 466 val job = underTest.resolvedNetworkType.onEach { latest = it }.launchIn(this) 467 468 val callback = getTelephonyCallbackForType<TelephonyCallback.DisplayInfoListener>() 469 val ti = 470 telephonyDisplayInfo( 471 networkType = NETWORK_TYPE_UNKNOWN, 472 overrideNetworkType = NETWORK_TYPE_UNKNOWN, 473 ) 474 475 callback.onDisplayInfoChanged(ti) 476 477 val expected = UnknownNetworkType 478 assertThat(latest).isEqualTo(expected) 479 assertThat(latest!!.lookupKey).isEqualTo(MobileMappings.toIconKey(NETWORK_TYPE_UNKNOWN)) 480 481 job.cancel() 482 } 483 484 @Test networkType_updatesUsingDefaultnull485 fun networkType_updatesUsingDefault() = 486 testScope.runTest { 487 var latest: ResolvedNetworkType? = null 488 val job = underTest.resolvedNetworkType.onEach { latest = it }.launchIn(this) 489 490 val callback = getTelephonyCallbackForType<TelephonyCallback.DisplayInfoListener>() 491 val overrideType = OVERRIDE_NETWORK_TYPE_NONE 492 val type = NETWORK_TYPE_LTE 493 val ti = telephonyDisplayInfo(networkType = type, overrideNetworkType = overrideType) 494 callback.onDisplayInfoChanged(ti) 495 496 val expected = DefaultNetworkType(mobileMappings.toIconKey(type)) 497 assertThat(latest).isEqualTo(expected) 498 499 job.cancel() 500 } 501 502 @Test networkType_updatesUsingOverridenull503 fun networkType_updatesUsingOverride() = 504 testScope.runTest { 505 var latest: ResolvedNetworkType? = null 506 val job = underTest.resolvedNetworkType.onEach { latest = it }.launchIn(this) 507 508 val callback = getTelephonyCallbackForType<TelephonyCallback.DisplayInfoListener>() 509 val type = OVERRIDE_NETWORK_TYPE_LTE_CA 510 val ti = telephonyDisplayInfo(networkType = type, overrideNetworkType = type) 511 callback.onDisplayInfoChanged(ti) 512 513 val expected = OverrideNetworkType(mobileMappings.toIconKeyOverride(type)) 514 assertThat(latest).isEqualTo(expected) 515 516 job.cancel() 517 } 518 519 @Test networkType_unknownNetworkWithOverride_usesOverrideKeynull520 fun networkType_unknownNetworkWithOverride_usesOverrideKey() = 521 testScope.runTest { 522 var latest: ResolvedNetworkType? = null 523 val job = underTest.resolvedNetworkType.onEach { latest = it }.launchIn(this) 524 525 val callback = getTelephonyCallbackForType<TelephonyCallback.DisplayInfoListener>() 526 val unknown = NETWORK_TYPE_UNKNOWN 527 val type = OVERRIDE_NETWORK_TYPE_LTE_CA 528 val ti = telephonyDisplayInfo(unknown, type) 529 callback.onDisplayInfoChanged(ti) 530 531 val expected = OverrideNetworkType(mobileMappings.toIconKeyOverride(type)) 532 assertThat(latest).isEqualTo(expected) 533 534 job.cancel() 535 } 536 537 @Test dataEnabled_initial_falsenull538 fun dataEnabled_initial_false() = 539 testScope.runTest { 540 whenever(telephonyManager.isDataConnectionAllowed).thenReturn(false) 541 542 assertThat(underTest.dataEnabled.value).isFalse() 543 } 544 545 @Test isDataEnabled_tracksTelephonyCallbacknull546 fun isDataEnabled_tracksTelephonyCallback() = 547 testScope.runTest { 548 var latest: Boolean? = null 549 val job = underTest.dataEnabled.onEach { latest = it }.launchIn(this) 550 551 whenever(telephonyManager.isDataConnectionAllowed).thenReturn(false) 552 assertThat(underTest.dataEnabled.value).isFalse() 553 554 val callback = getTelephonyCallbackForType<TelephonyCallback.DataEnabledListener>() 555 556 callback.onDataEnabledChanged(true, 1) 557 assertThat(latest).isTrue() 558 559 callback.onDataEnabledChanged(false, 1) 560 assertThat(latest).isFalse() 561 562 job.cancel() 563 } 564 565 @Test numberOfLevels_isDefaultnull566 fun numberOfLevels_isDefault() = 567 testScope.runTest { 568 var latest: Int? = null 569 val job = underTest.numberOfLevels.onEach { latest = it }.launchIn(this) 570 571 assertThat(latest).isEqualTo(DEFAULT_NUM_LEVELS) 572 573 job.cancel() 574 } 575 576 @Test roaming_cdma_queriesTelephonyManagernull577 fun roaming_cdma_queriesTelephonyManager() = 578 testScope.runTest { 579 var latest: Boolean? = null 580 val job = underTest.cdmaRoaming.onEach { latest = it }.launchIn(this) 581 582 val cb = getTelephonyCallbackForType<ServiceStateListener>() 583 584 // CDMA roaming is off, GSM roaming is on 585 whenever(telephonyManager.cdmaEnhancedRoamingIndicatorDisplayNumber).thenReturn(ERI_OFF) 586 cb.onServiceStateChanged(ServiceState().also { it.roaming = true }) 587 588 assertThat(latest).isFalse() 589 590 // CDMA roaming is on, GSM roaming is off 591 whenever(telephonyManager.cdmaEnhancedRoamingIndicatorDisplayNumber).thenReturn(ERI_ON) 592 cb.onServiceStateChanged(ServiceState().also { it.roaming = false }) 593 594 assertThat(latest).isTrue() 595 596 job.cancel() 597 } 598 599 /** 600 * [TelephonyManager.getCdmaEnhancedRoamingIndicatorDisplayNumber] returns -1 if the service is 601 * not running or if there is an error while retrieving the cdma ERI 602 */ 603 @Test cdmaRoaming_ignoresNegativeOnenull604 fun cdmaRoaming_ignoresNegativeOne() = 605 testScope.runTest { 606 var latest: Boolean? = null 607 val job = underTest.cdmaRoaming.onEach { latest = it }.launchIn(this) 608 609 val serviceState = ServiceState() 610 serviceState.roaming = false 611 612 val cb = getTelephonyCallbackForType<ServiceStateListener>() 613 614 // CDMA roaming is unavailable (-1), GSM roaming is off 615 whenever(telephonyManager.cdmaEnhancedRoamingIndicatorDisplayNumber).thenReturn(-1) 616 cb.onServiceStateChanged(serviceState) 617 618 assertThat(latest).isFalse() 619 620 job.cancel() 621 } 622 623 @Test roaming_gsm_queriesDisplayInfo_viaDisplayInfonull624 fun roaming_gsm_queriesDisplayInfo_viaDisplayInfo() = 625 testScope.runTest { 626 // GIVEN flag is true 627 flags.set(ROAMING_INDICATOR_VIA_DISPLAY_INFO, true) 628 629 // Re-create the repository, because the flag is read at init 630 underTest = 631 MobileConnectionRepositoryImpl( 632 SUB_1_ID, 633 context, 634 subscriptionModel, 635 DEFAULT_NAME_MODEL, 636 SEP, 637 connectivityManager, 638 telephonyManager, 639 systemUiCarrierConfig, 640 fakeBroadcastDispatcher, 641 mobileMappings, 642 testDispatcher, 643 logger, 644 tableLogger, 645 flags, 646 testScope.backgroundScope, 647 ) 648 649 var latest: Boolean? = null 650 val job = underTest.isRoaming.onEach { latest = it }.launchIn(this) 651 652 val cb = getTelephonyCallbackForType<DisplayInfoListener>() 653 654 // CDMA roaming is off, GSM roaming is off 655 whenever(telephonyManager.cdmaEnhancedRoamingIndicatorDisplayNumber).thenReturn(ERI_OFF) 656 cb.onDisplayInfoChanged( 657 TelephonyDisplayInfo(NETWORK_TYPE_LTE, NETWORK_TYPE_UNKNOWN, false) 658 ) 659 660 assertThat(latest).isFalse() 661 662 // CDMA roaming is off, GSM roaming is on 663 cb.onDisplayInfoChanged( 664 TelephonyDisplayInfo(NETWORK_TYPE_LTE, NETWORK_TYPE_UNKNOWN, true) 665 ) 666 667 assertThat(latest).isTrue() 668 669 job.cancel() 670 } 671 672 @Test roaming_gsm_queriesDisplayInfo_viaServiceStatenull673 fun roaming_gsm_queriesDisplayInfo_viaServiceState() = 674 testScope.runTest { 675 // GIVEN flag is false 676 flags.set(ROAMING_INDICATOR_VIA_DISPLAY_INFO, false) 677 678 // Re-create the repository, because the flag is read at init 679 underTest = 680 MobileConnectionRepositoryImpl( 681 SUB_1_ID, 682 context, 683 subscriptionModel, 684 DEFAULT_NAME_MODEL, 685 SEP, 686 connectivityManager, 687 telephonyManager, 688 systemUiCarrierConfig, 689 fakeBroadcastDispatcher, 690 mobileMappings, 691 testDispatcher, 692 logger, 693 tableLogger, 694 flags, 695 testScope.backgroundScope, 696 ) 697 698 var latest: Boolean? = null 699 val job = underTest.isRoaming.onEach { latest = it }.launchIn(this) 700 701 val cb = getTelephonyCallbackForType<ServiceStateListener>() 702 703 // CDMA roaming is off, GSM roaming is off 704 whenever(telephonyManager.cdmaEnhancedRoamingIndicatorDisplayNumber).thenReturn(ERI_OFF) 705 cb.onServiceStateChanged(ServiceState().also { it.roaming = false }) 706 707 assertThat(latest).isFalse() 708 709 // CDMA roaming is off, GSM roaming is on 710 cb.onServiceStateChanged(ServiceState().also { it.roaming = true }) 711 712 assertThat(latest).isTrue() 713 714 job.cancel() 715 } 716 717 @Test activity_updatesFromCallbacknull718 fun activity_updatesFromCallback() = 719 testScope.runTest { 720 var latest: DataActivityModel? = null 721 val job = underTest.dataActivityDirection.onEach { latest = it }.launchIn(this) 722 723 assertThat(latest) 724 .isEqualTo(DataActivityModel(hasActivityIn = false, hasActivityOut = false)) 725 726 val cb = getTelephonyCallbackForType<DataActivityListener>() 727 cb.onDataActivity(DATA_ACTIVITY_IN) 728 assertThat(latest) 729 .isEqualTo(DataActivityModel(hasActivityIn = true, hasActivityOut = false)) 730 731 cb.onDataActivity(DATA_ACTIVITY_OUT) 732 assertThat(latest) 733 .isEqualTo(DataActivityModel(hasActivityIn = false, hasActivityOut = true)) 734 735 cb.onDataActivity(DATA_ACTIVITY_INOUT) 736 assertThat(latest) 737 .isEqualTo(DataActivityModel(hasActivityIn = true, hasActivityOut = true)) 738 739 cb.onDataActivity(DATA_ACTIVITY_NONE) 740 assertThat(latest) 741 .isEqualTo(DataActivityModel(hasActivityIn = false, hasActivityOut = false)) 742 743 cb.onDataActivity(DATA_ACTIVITY_DORMANT) 744 assertThat(latest) 745 .isEqualTo(DataActivityModel(hasActivityIn = false, hasActivityOut = false)) 746 747 cb.onDataActivity(1234) 748 assertThat(latest) 749 .isEqualTo(DataActivityModel(hasActivityIn = false, hasActivityOut = false)) 750 751 job.cancel() 752 } 753 754 @Test networkNameForSubId_updatesnull755 fun networkNameForSubId_updates() = 756 testScope.runTest { 757 var latest: NetworkNameModel? = null 758 val job = underTest.carrierName.onEach { latest = it }.launchIn(this) 759 760 subscriptionModel.value = 761 SubscriptionModel( 762 subscriptionId = SUB_1_ID, 763 carrierName = DEFAULT_NAME, 764 profileClass = PROFILE_CLASS_UNSET, 765 ) 766 767 assertThat(latest?.name).isEqualTo(DEFAULT_NAME) 768 769 val updatedName = "Derived Carrier" 770 subscriptionModel.value = 771 SubscriptionModel( 772 subscriptionId = SUB_1_ID, 773 carrierName = updatedName, 774 profileClass = PROFILE_CLASS_UNSET, 775 ) 776 777 assertThat(latest?.name).isEqualTo(updatedName) 778 779 job.cancel() 780 } 781 782 @Test networkNameForSubId_defaultWhenSubscriptionModelNullnull783 fun networkNameForSubId_defaultWhenSubscriptionModelNull() = 784 testScope.runTest { 785 var latest: NetworkNameModel? = null 786 val job = underTest.carrierName.onEach { latest = it }.launchIn(this) 787 788 subscriptionModel.value = null 789 790 assertThat(latest?.name).isEqualTo(DEFAULT_NAME) 791 792 job.cancel() 793 } 794 795 @Test networkName_defaultnull796 fun networkName_default() = 797 testScope.runTest { 798 var latest: NetworkNameModel? = null 799 val job = underTest.networkName.onEach { latest = it }.launchIn(this) 800 801 assertThat(latest).isEqualTo(DEFAULT_NAME_MODEL) 802 803 job.cancel() 804 } 805 806 @Test networkName_usesBroadcastInfo_returnsDerivednull807 fun networkName_usesBroadcastInfo_returnsDerived() = 808 testScope.runTest { 809 var latest: NetworkNameModel? = null 810 val job = underTest.networkName.onEach { latest = it }.launchIn(this) 811 812 val intent = spnIntent() 813 val captor = argumentCaptor<BroadcastReceiver>() 814 verify(context).registerReceiver(captor.capture(), any()) 815 captor.value!!.onReceive(context, intent) 816 817 assertThat(latest).isEqualTo(intent.toNetworkNameModel(SEP)) 818 819 job.cancel() 820 } 821 822 @Test networkName_broadcastNotForThisSubId_keepsOldValuenull823 fun networkName_broadcastNotForThisSubId_keepsOldValue() = 824 testScope.runTest { 825 var latest: NetworkNameModel? = null 826 val job = underTest.networkName.onEach { latest = it }.launchIn(this) 827 828 val intent = spnIntent() 829 val captor = argumentCaptor<BroadcastReceiver>() 830 verify(context).registerReceiver(captor.capture(), any()) 831 captor.value!!.onReceive(context, intent) 832 833 assertThat(latest).isEqualTo(intent.toNetworkNameModel(SEP)) 834 835 // WHEN an intent with a different subId is sent 836 val wrongSubIntent = spnIntent(subId = 101) 837 838 captor.value!!.onReceive(context, wrongSubIntent) 839 840 // THEN the previous intent's name is still used 841 assertThat(latest).isEqualTo(intent.toNetworkNameModel(SEP)) 842 843 job.cancel() 844 } 845 846 @Test networkName_broadcastHasNoData_updatesToDefaultnull847 fun networkName_broadcastHasNoData_updatesToDefault() = 848 testScope.runTest { 849 var latest: NetworkNameModel? = null 850 val job = underTest.networkName.onEach { latest = it }.launchIn(this) 851 852 val intent = spnIntent() 853 val captor = argumentCaptor<BroadcastReceiver>() 854 verify(context).registerReceiver(captor.capture(), any()) 855 captor.value!!.onReceive(context, intent) 856 857 assertThat(latest).isEqualTo(intent.toNetworkNameModel(SEP)) 858 859 val intentWithoutInfo = 860 spnIntent( 861 showSpn = false, 862 showPlmn = false, 863 ) 864 865 captor.value!!.onReceive(context, intentWithoutInfo) 866 867 assertThat(latest).isEqualTo(DEFAULT_NAME_MODEL) 868 869 job.cancel() 870 } 871 872 @Test networkName_usingEagerStrategy_retainsNameBetweenSubscribersnull873 fun networkName_usingEagerStrategy_retainsNameBetweenSubscribers() = 874 testScope.runTest { 875 // Use the [StateFlow.value] getter so we can prove that the collection happens 876 // even when there is no [Job] 877 878 // Starts out default 879 assertThat(underTest.networkName.value).isEqualTo(DEFAULT_NAME_MODEL) 880 881 val intent = spnIntent() 882 val captor = argumentCaptor<BroadcastReceiver>() 883 verify(context).registerReceiver(captor.capture(), any()) 884 captor.value!!.onReceive(context, intent) 885 886 // The value is still there despite no active subscribers 887 assertThat(underTest.networkName.value).isEqualTo(intent.toNetworkNameModel(SEP)) 888 } 889 890 @Test operatorAlphaShort_trackednull891 fun operatorAlphaShort_tracked() = 892 testScope.runTest { 893 var latest: String? = null 894 895 val job = underTest.operatorAlphaShort.onEach { latest = it }.launchIn(this) 896 897 val shortName = "short name" 898 val serviceState = ServiceState() 899 serviceState.setOperatorName( 900 /* longName */ "long name", 901 /* shortName */ shortName, 902 /* numeric */ "12345", 903 ) 904 905 getTelephonyCallbackForType<ServiceStateListener>().onServiceStateChanged(serviceState) 906 907 assertThat(latest).isEqualTo(shortName) 908 909 job.cancel() 910 } 911 912 @Test isInService_notIwlannull913 fun isInService_notIwlan() = 914 testScope.runTest { 915 var latest: Boolean? = null 916 val job = underTest.isInService.onEach { latest = it }.launchIn(this) 917 918 val nriInService = 919 NetworkRegistrationInfo.Builder() 920 .setDomain(DOMAIN_PS) 921 .setTransportType(TRANSPORT_TYPE_WWAN) 922 .setRegistrationState(REGISTRATION_STATE_HOME) 923 .build() 924 925 getTelephonyCallbackForType<ServiceStateListener>() 926 .onServiceStateChanged( 927 ServiceState().also { 928 it.voiceRegState = STATE_IN_SERVICE 929 it.addNetworkRegistrationInfo(nriInService) 930 } 931 ) 932 933 assertThat(latest).isTrue() 934 935 getTelephonyCallbackForType<ServiceStateListener>() 936 .onServiceStateChanged( 937 ServiceState().also { 938 it.voiceRegState = STATE_OUT_OF_SERVICE 939 it.addNetworkRegistrationInfo(nriInService) 940 } 941 ) 942 assertThat(latest).isTrue() 943 944 val nriNotInService = 945 NetworkRegistrationInfo.Builder() 946 .setDomain(DOMAIN_PS) 947 .setTransportType(TRANSPORT_TYPE_WWAN) 948 .setRegistrationState(REGISTRATION_STATE_DENIED) 949 .build() 950 getTelephonyCallbackForType<ServiceStateListener>() 951 .onServiceStateChanged( 952 ServiceState().also { 953 it.voiceRegState = STATE_OUT_OF_SERVICE 954 it.addNetworkRegistrationInfo(nriNotInService) 955 } 956 ) 957 assertThat(latest).isFalse() 958 959 job.cancel() 960 } 961 962 @Test isInService_isIwlan_voiceOutOfService_dataInServicenull963 fun isInService_isIwlan_voiceOutOfService_dataInService() = 964 testScope.runTest { 965 var latest: Boolean? = null 966 val job = underTest.isInService.onEach { latest = it }.launchIn(this) 967 968 val iwlanData = 969 NetworkRegistrationInfo.Builder() 970 .setDomain(DOMAIN_PS) 971 .setTransportType(TRANSPORT_TYPE_WLAN) 972 .setRegistrationState(REGISTRATION_STATE_HOME) 973 .build() 974 val serviceState = 975 ServiceState().also { 976 it.voiceRegState = STATE_OUT_OF_SERVICE 977 it.addNetworkRegistrationInfo(iwlanData) 978 } 979 980 getTelephonyCallbackForType<ServiceStateListener>().onServiceStateChanged(serviceState) 981 assertThat(latest).isFalse() 982 983 job.cancel() 984 } 985 986 @Test 987 @EnableFlags(com.android.internal.telephony.flags.Flags.FLAG_CARRIER_ENABLED_SATELLITE_FLAG) isNonTerrestrial_updatesFromCallback0null988 fun isNonTerrestrial_updatesFromCallback0() = 989 testScope.runTest { 990 val latest by collectLastValue(underTest.isNonTerrestrial) 991 992 // Starts out false 993 assertThat(latest).isFalse() 994 995 val callback = getTelephonyCallbackForType<CarrierRoamingNtnModeListener>() 996 997 callback.onCarrierRoamingNtnModeChanged(true) 998 assertThat(latest).isTrue() 999 1000 callback.onCarrierRoamingNtnModeChanged(false) 1001 assertThat(latest).isFalse() 1002 } 1003 1004 @Test numberOfLevels_usesCarrierConfignull1005 fun numberOfLevels_usesCarrierConfig() = 1006 testScope.runTest { 1007 var latest: Int? = null 1008 val job = underTest.numberOfLevels.onEach { latest = it }.launchIn(this) 1009 1010 assertThat(latest).isEqualTo(DEFAULT_NUM_LEVELS) 1011 1012 systemUiCarrierConfig.processNewCarrierConfig( 1013 configWithOverride(KEY_INFLATE_SIGNAL_STRENGTH_BOOL, true) 1014 ) 1015 1016 assertThat(latest).isEqualTo(DEFAULT_NUM_LEVELS + 1) 1017 1018 systemUiCarrierConfig.processNewCarrierConfig( 1019 configWithOverride(KEY_INFLATE_SIGNAL_STRENGTH_BOOL, false) 1020 ) 1021 1022 assertThat(latest).isEqualTo(DEFAULT_NUM_LEVELS) 1023 1024 job.cancel() 1025 } 1026 1027 @Test inflateSignalStrength_usesCarrierConfignull1028 fun inflateSignalStrength_usesCarrierConfig() = 1029 testScope.runTest { 1030 val latest by collectLastValue(underTest.inflateSignalStrength) 1031 1032 assertThat(latest).isEqualTo(false) 1033 1034 systemUiCarrierConfig.processNewCarrierConfig( 1035 configWithOverride(KEY_INFLATE_SIGNAL_STRENGTH_BOOL, true) 1036 ) 1037 1038 assertThat(latest).isEqualTo(true) 1039 1040 systemUiCarrierConfig.processNewCarrierConfig( 1041 configWithOverride(KEY_INFLATE_SIGNAL_STRENGTH_BOOL, false) 1042 ) 1043 1044 assertThat(latest).isEqualTo(false) 1045 } 1046 1047 @Test allowNetworkSliceIndicator_exposesCarrierConfigValuenull1048 fun allowNetworkSliceIndicator_exposesCarrierConfigValue() = 1049 testScope.runTest { 1050 val latest by collectLastValue(underTest.allowNetworkSliceIndicator) 1051 1052 systemUiCarrierConfig.processNewCarrierConfig( 1053 configWithOverride(KEY_SHOW_5G_SLICE_ICON_BOOL, true) 1054 ) 1055 1056 assertThat(latest).isTrue() 1057 1058 systemUiCarrierConfig.processNewCarrierConfig( 1059 configWithOverride(KEY_SHOW_5G_SLICE_ICON_BOOL, false) 1060 ) 1061 1062 assertThat(latest).isFalse() 1063 } 1064 1065 @Test isAllowedDuringAirplaneMode_alwaysFalsenull1066 fun isAllowedDuringAirplaneMode_alwaysFalse() = 1067 testScope.runTest { 1068 val latest by collectLastValue(underTest.isAllowedDuringAirplaneMode) 1069 1070 assertThat(latest).isFalse() 1071 } 1072 1073 @Test hasPrioritizedCaps_defaultFalsenull1074 fun hasPrioritizedCaps_defaultFalse() { 1075 assertThat(underTest.hasPrioritizedNetworkCapabilities.value).isFalse() 1076 } 1077 1078 @Test hasPrioritizedCaps_trueWhenAvailablenull1079 fun hasPrioritizedCaps_trueWhenAvailable() = 1080 testScope.runTest { 1081 val latest by collectLastValue(underTest.hasPrioritizedNetworkCapabilities) 1082 1083 val callback: NetworkCallback = 1084 withArgCaptor<NetworkCallback> { 1085 verify(connectivityManager).registerNetworkCallback(any(), capture()) 1086 } 1087 1088 callback.onAvailable(mock()) 1089 1090 assertThat(latest).isTrue() 1091 } 1092 1093 @Test hasPrioritizedCaps_becomesFalseWhenNetworkLostnull1094 fun hasPrioritizedCaps_becomesFalseWhenNetworkLost() = 1095 testScope.runTest { 1096 val latest by collectLastValue(underTest.hasPrioritizedNetworkCapabilities) 1097 1098 val callback: NetworkCallback = 1099 withArgCaptor<NetworkCallback> { 1100 verify(connectivityManager).registerNetworkCallback(any(), capture()) 1101 } 1102 1103 callback.onAvailable(mock()) 1104 1105 assertThat(latest).isTrue() 1106 1107 callback.onLost(mock()) 1108 1109 assertThat(latest).isFalse() 1110 } 1111 getTelephonyCallbackForTypenull1112 private inline fun <reified T> getTelephonyCallbackForType(): T { 1113 return MobileTelephonyHelpers.getTelephonyCallbackForType(telephonyManager) 1114 } 1115 carrierIdIntentnull1116 private fun carrierIdIntent( 1117 subId: Int = SUB_1_ID, 1118 carrierId: Int, 1119 ): Intent = 1120 Intent(TelephonyManager.ACTION_SUBSCRIPTION_CARRIER_IDENTITY_CHANGED).apply { 1121 putExtra(EXTRA_SUBSCRIPTION_ID, subId) 1122 putExtra(EXTRA_CARRIER_ID, carrierId) 1123 } 1124 spnIntentnull1125 private fun spnIntent( 1126 subId: Int = SUB_1_ID, 1127 showSpn: Boolean = true, 1128 spn: String = SPN, 1129 showPlmn: Boolean = true, 1130 plmn: String = PLMN, 1131 ): Intent = 1132 Intent(TelephonyManager.ACTION_SERVICE_PROVIDERS_UPDATED).apply { 1133 putExtra(EXTRA_SUBSCRIPTION_INDEX, subId) 1134 putExtra(EXTRA_SHOW_SPN, showSpn) 1135 putExtra(EXTRA_SPN, spn) 1136 putExtra(EXTRA_SHOW_PLMN, showPlmn) 1137 putExtra(EXTRA_PLMN, plmn) 1138 } 1139 1140 companion object { 1141 private const val SUB_1_ID = 1 1142 1143 private const val DEFAULT_NAME = "Fake Mobile Network" 1144 private val DEFAULT_NAME_MODEL = NetworkNameModel.Default(DEFAULT_NAME) 1145 private const val SEP = "-" 1146 1147 private const val SPN = "testSpn" 1148 private const val PLMN = "testPlmn" 1149 } 1150 } 1151