1 /* 2 * Copyright (C) 2023 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.systemui.statusbar.pipeline.satellite.data.prod 18 19 import android.os.OutcomeReceiver 20 import android.os.Process 21 import android.telephony.TelephonyCallback 22 import android.telephony.TelephonyManager 23 import android.telephony.satellite.NtnSignalStrength 24 import android.telephony.satellite.NtnSignalStrengthCallback 25 import android.telephony.satellite.SatelliteCommunicationAllowedStateCallback 26 import android.telephony.satellite.SatelliteManager 27 import android.telephony.satellite.SatelliteManager.SATELLITE_MODEM_STATE_CONNECTED 28 import android.telephony.satellite.SatelliteManager.SATELLITE_MODEM_STATE_DATAGRAM_RETRYING 29 import android.telephony.satellite.SatelliteManager.SATELLITE_MODEM_STATE_DATAGRAM_TRANSFERRING 30 import android.telephony.satellite.SatelliteManager.SATELLITE_MODEM_STATE_IDLE 31 import android.telephony.satellite.SatelliteManager.SATELLITE_MODEM_STATE_LISTENING 32 import android.telephony.satellite.SatelliteManager.SATELLITE_MODEM_STATE_NOT_CONNECTED 33 import android.telephony.satellite.SatelliteManager.SATELLITE_MODEM_STATE_OFF 34 import android.telephony.satellite.SatelliteManager.SATELLITE_MODEM_STATE_UNAVAILABLE 35 import android.telephony.satellite.SatelliteManager.SATELLITE_MODEM_STATE_UNKNOWN 36 import android.telephony.satellite.SatelliteManager.SATELLITE_RESULT_ERROR 37 import android.telephony.satellite.SatelliteManager.SatelliteException 38 import android.telephony.satellite.SatelliteModemStateCallback 39 import android.telephony.satellite.SatelliteProvisionStateCallback 40 import android.telephony.satellite.SatelliteSupportedStateCallback 41 import androidx.test.ext.junit.runners.AndroidJUnit4 42 import androidx.test.filters.SmallTest 43 import com.android.systemui.SysuiTestCase 44 import com.android.systemui.coroutines.collectLastValue 45 import com.android.systemui.log.core.FakeLogBuffer 46 import com.android.systemui.statusbar.pipeline.mobile.data.repository.prod.MobileTelephonyHelpers 47 import com.android.systemui.statusbar.pipeline.satellite.data.prod.DeviceBasedSatelliteRepositoryImpl.Companion.MIN_UPTIME 48 import com.android.systemui.statusbar.pipeline.satellite.shared.model.SatelliteConnectionState 49 import com.android.systemui.util.mockito.any 50 import com.android.systemui.util.mockito.whenever 51 import com.android.systemui.util.mockito.withArgCaptor 52 import com.android.systemui.util.time.FakeSystemClock 53 import com.google.common.truth.Truth.assertThat 54 import java.util.Optional 55 import kotlin.test.Test 56 import kotlinx.coroutines.ExperimentalCoroutinesApi 57 import kotlinx.coroutines.test.StandardTestDispatcher 58 import kotlinx.coroutines.test.TestScope 59 import kotlinx.coroutines.test.runCurrent 60 import kotlinx.coroutines.test.runTest 61 import org.junit.Before 62 import org.junit.runner.RunWith 63 import org.mockito.Mock 64 import org.mockito.Mockito 65 import org.mockito.Mockito.atLeastOnce 66 import org.mockito.Mockito.doAnswer 67 import org.mockito.Mockito.never 68 import org.mockito.Mockito.times 69 import org.mockito.Mockito.verify 70 import org.mockito.MockitoAnnotations 71 import org.mockito.kotlin.doThrow 72 73 @Suppress("EXPERIMENTAL_IS_NOT_ENABLED") 74 @OptIn(ExperimentalCoroutinesApi::class) 75 @SmallTest 76 @RunWith(AndroidJUnit4::class) 77 class DeviceBasedSatelliteRepositoryImplTest : SysuiTestCase() { 78 private lateinit var underTest: DeviceBasedSatelliteRepositoryImpl 79 80 @Mock private lateinit var satelliteManager: SatelliteManager 81 @Mock private lateinit var telephonyManager: TelephonyManager 82 83 private val systemClock = FakeSystemClock() 84 private val dispatcher = StandardTestDispatcher() 85 private val testScope = TestScope(dispatcher) 86 87 @Before setUpnull88 fun setUp() { 89 MockitoAnnotations.initMocks(this) 90 } 91 92 @Test nullSatelliteManager_usesDefaultValuesnull93 fun nullSatelliteManager_usesDefaultValues() = 94 testScope.runTest { 95 setupDefaultRepo() 96 underTest = 97 DeviceBasedSatelliteRepositoryImpl( 98 Optional.empty(), 99 telephonyManager, 100 dispatcher, 101 testScope.backgroundScope, 102 logBuffer = FakeLogBuffer.Factory.create(), 103 verboseLogBuffer = FakeLogBuffer.Factory.create(), 104 systemClock, 105 context.resources, 106 ) 107 108 val connectionState by collectLastValue(underTest.connectionState) 109 val strength by collectLastValue(underTest.signalStrength) 110 val allowed by collectLastValue(underTest.isSatelliteAllowedForCurrentLocation) 111 112 assertThat(connectionState).isEqualTo(SatelliteConnectionState.Off) 113 assertThat(strength).isEqualTo(0) 114 assertThat(allowed).isFalse() 115 } 116 117 @Test connectionState_mapsFromSatelliteModemStatenull118 fun connectionState_mapsFromSatelliteModemState() = 119 testScope.runTest { 120 setupDefaultRepo() 121 val latest by collectLastValue(underTest.connectionState) 122 runCurrent() 123 val callback = 124 withArgCaptor<SatelliteModemStateCallback> { 125 verify(satelliteManager).registerForModemStateChanged(any(), capture()) 126 } 127 128 // Mapping from modem state to SatelliteConnectionState is rote, just run all of the 129 // possibilities here 130 131 // Off states 132 callback.onSatelliteModemStateChanged(SATELLITE_MODEM_STATE_OFF) 133 assertThat(latest).isEqualTo(SatelliteConnectionState.Off) 134 callback.onSatelliteModemStateChanged(SATELLITE_MODEM_STATE_UNAVAILABLE) 135 assertThat(latest).isEqualTo(SatelliteConnectionState.Off) 136 137 // On states 138 callback.onSatelliteModemStateChanged(SATELLITE_MODEM_STATE_IDLE) 139 assertThat(latest).isEqualTo(SatelliteConnectionState.On) 140 callback.onSatelliteModemStateChanged(SATELLITE_MODEM_STATE_LISTENING) 141 assertThat(latest).isEqualTo(SatelliteConnectionState.On) 142 callback.onSatelliteModemStateChanged(SATELLITE_MODEM_STATE_NOT_CONNECTED) 143 assertThat(latest).isEqualTo(SatelliteConnectionState.On) 144 145 // Connected states 146 callback.onSatelliteModemStateChanged(SATELLITE_MODEM_STATE_CONNECTED) 147 assertThat(latest).isEqualTo(SatelliteConnectionState.Connected) 148 callback.onSatelliteModemStateChanged(SATELLITE_MODEM_STATE_DATAGRAM_TRANSFERRING) 149 assertThat(latest).isEqualTo(SatelliteConnectionState.Connected) 150 callback.onSatelliteModemStateChanged(SATELLITE_MODEM_STATE_DATAGRAM_RETRYING) 151 assertThat(latest).isEqualTo(SatelliteConnectionState.Connected) 152 153 // Unknown states 154 callback.onSatelliteModemStateChanged(SATELLITE_MODEM_STATE_UNKNOWN) 155 assertThat(latest).isEqualTo(SatelliteConnectionState.Unknown) 156 // Garbage value (for completeness' sake) 157 callback.onSatelliteModemStateChanged(123456) 158 assertThat(latest).isEqualTo(SatelliteConnectionState.Unknown) 159 } 160 161 @Test signalStrength_readsSatelliteManagerStatenull162 fun signalStrength_readsSatelliteManagerState() = 163 testScope.runTest { 164 setupDefaultRepo() 165 val latest by collectLastValue(underTest.signalStrength) 166 runCurrent() 167 val callback = 168 withArgCaptor<NtnSignalStrengthCallback> { 169 verify(satelliteManager).registerForNtnSignalStrengthChanged(any(), capture()) 170 } 171 172 assertThat(latest).isEqualTo(0) 173 174 callback.onNtnSignalStrengthChanged(NtnSignalStrength(1)) 175 assertThat(latest).isEqualTo(1) 176 177 callback.onNtnSignalStrengthChanged(NtnSignalStrength(2)) 178 assertThat(latest).isEqualTo(2) 179 180 callback.onNtnSignalStrengthChanged(NtnSignalStrength(3)) 181 assertThat(latest).isEqualTo(3) 182 183 callback.onNtnSignalStrengthChanged(NtnSignalStrength(4)) 184 assertThat(latest).isEqualTo(4) 185 } 186 187 @Test isSatelliteAllowed_listensToSatelliteManagerCallbacknull188 fun isSatelliteAllowed_listensToSatelliteManagerCallback() = 189 testScope.runTest { 190 setupDefaultRepo() 191 192 val latest by collectLastValue(underTest.isSatelliteAllowedForCurrentLocation) 193 runCurrent() 194 195 val callback = 196 withArgCaptor<SatelliteCommunicationAllowedStateCallback> { 197 verify(satelliteManager) 198 .registerForCommunicationAllowedStateChanged(any(), capture()) 199 } 200 201 // WHEN satellite manager says it's not available 202 callback.onSatelliteCommunicationAllowedStateChanged(false) 203 204 // THEN it's not! 205 assertThat(latest).isFalse() 206 207 // WHEN satellite manager says it's changed to available 208 callback.onSatelliteCommunicationAllowedStateChanged(true) 209 210 // THEN it is! 211 assertThat(latest).isTrue() 212 } 213 214 @Test isSatelliteAllowed_falseWhenErrorOccursnull215 fun isSatelliteAllowed_falseWhenErrorOccurs() = 216 testScope.runTest { 217 setupDefaultRepo() 218 219 // GIVEN SatelliteManager gon' throw exceptions when we ask to register the callback 220 doThrow(RuntimeException("Test exception")) 221 .`when`(satelliteManager) 222 .registerForCommunicationAllowedStateChanged(any(), any()) 223 224 // WHEN the latest value is requested (and thus causes an exception to be thrown) 225 val latest by collectLastValue(underTest.isSatelliteAllowedForCurrentLocation) 226 227 // THEN the value is just false, and we didn't crash! 228 assertThat(latest).isFalse() 229 } 230 231 @Test isSatelliteAllowed_reRegistersOnTelephonyProcessCrashnull232 fun isSatelliteAllowed_reRegistersOnTelephonyProcessCrash() = 233 testScope.runTest { 234 setupDefaultRepo() 235 val latest by collectLastValue(underTest.isSatelliteAllowedForCurrentLocation) 236 runCurrent() 237 238 val callback = 239 withArgCaptor<SatelliteCommunicationAllowedStateCallback> { 240 verify(satelliteManager) 241 .registerForCommunicationAllowedStateChanged(any(), capture()) 242 } 243 244 val telephonyCallback = 245 MobileTelephonyHelpers.getTelephonyCallbackForType< 246 TelephonyCallback.RadioPowerStateListener 247 >( 248 telephonyManager 249 ) 250 251 // GIVEN satellite is currently provisioned 252 callback.onSatelliteCommunicationAllowedStateChanged(true) 253 254 assertThat(latest).isTrue() 255 256 // WHEN a crash event happens (detected by radio state change) 257 telephonyCallback.onRadioPowerStateChanged(TelephonyManager.RADIO_POWER_ON) 258 runCurrent() 259 telephonyCallback.onRadioPowerStateChanged(TelephonyManager.RADIO_POWER_OFF) 260 runCurrent() 261 262 // THEN listener is re-registered 263 verify(satelliteManager, times(2)) 264 .registerForCommunicationAllowedStateChanged(any(), any()) 265 } 266 267 @Test satelliteProvisioned_notSupported_defaultFalsenull268 fun satelliteProvisioned_notSupported_defaultFalse() = 269 testScope.runTest { 270 // GIVEN satellite is not supported 271 setUpRepo(uptime = MIN_UPTIME, satMan = satelliteManager, satelliteSupported = false) 272 273 assertThat(underTest.isSatelliteProvisioned.value).isFalse() 274 } 275 276 @Test satelliteProvisioned_supported_defaultFalsenull277 fun satelliteProvisioned_supported_defaultFalse() = 278 testScope.runTest { 279 // GIVEN satellite is supported 280 setUpRepo(uptime = MIN_UPTIME, satMan = satelliteManager, satelliteSupported = true) 281 282 // THEN default provisioned state is false 283 assertThat(underTest.isSatelliteProvisioned.value).isFalse() 284 } 285 286 @Test satelliteProvisioned_returnsException_defaultsToFalsenull287 fun satelliteProvisioned_returnsException_defaultsToFalse() = 288 testScope.runTest { 289 // GIVEN satellite is supported on device 290 doAnswer { 291 val callback: OutcomeReceiver<Boolean, SatelliteException> = 292 it.getArgument(1) as OutcomeReceiver<Boolean, SatelliteException> 293 callback.onResult(true) 294 } 295 .whenever(satelliteManager) 296 .requestIsSupported(any(), any()) 297 298 // GIVEN satellite returns an error when asked if provisioned 299 doAnswer { 300 val receiver = it.arguments[1] as OutcomeReceiver<Boolean, SatelliteException> 301 receiver.onError(SatelliteException(SATELLITE_RESULT_ERROR)) 302 null 303 } 304 .whenever(satelliteManager) 305 .requestIsProvisioned(any(), any<OutcomeReceiver<Boolean, SatelliteException>>()) 306 307 // GIVEN we've been up long enough to start querying 308 systemClock.setUptimeMillis(Process.getStartUptimeMillis() + MIN_UPTIME) 309 310 underTest = 311 DeviceBasedSatelliteRepositoryImpl( 312 Optional.of(satelliteManager), 313 telephonyManager, 314 dispatcher, 315 testScope.backgroundScope, 316 logBuffer = FakeLogBuffer.Factory.create(), 317 verboseLogBuffer = FakeLogBuffer.Factory.create(), 318 systemClock, 319 context.resources, 320 ) 321 322 // WHEN we try to check for provisioned status 323 val provisioned by collectLastValue(underTest.isSatelliteProvisioned) 324 325 // THEN well, first we don't throw... 326 // AND THEN we assume that it's not provisioned 327 assertThat(provisioned).isFalse() 328 } 329 330 @Test satelliteProvisioned_throwsWhenQuerying_defaultsToFalsenull331 fun satelliteProvisioned_throwsWhenQuerying_defaultsToFalse() = 332 testScope.runTest { 333 // GIVEN satellite is supported on device 334 doAnswer { 335 val callback: OutcomeReceiver<Boolean, SatelliteException> = 336 it.getArgument(1) as OutcomeReceiver<Boolean, SatelliteException> 337 callback.onResult(true) 338 } 339 .whenever(satelliteManager) 340 .requestIsSupported(any(), any()) 341 342 // GIVEN satellite throws when asked if provisioned 343 whenever(satelliteManager.requestIsProvisioned(any(), any())) 344 .thenThrow(SecurityException()) 345 346 // GIVEN we've been up long enough to start querying 347 systemClock.setUptimeMillis(Process.getStartUptimeMillis() + MIN_UPTIME) 348 349 underTest = 350 DeviceBasedSatelliteRepositoryImpl( 351 Optional.of(satelliteManager), 352 telephonyManager, 353 dispatcher, 354 testScope.backgroundScope, 355 logBuffer = FakeLogBuffer.Factory.create(), 356 verboseLogBuffer = FakeLogBuffer.Factory.create(), 357 systemClock, 358 context.resources, 359 ) 360 361 // WHEN we try to check for provisioned status 362 val provisioned by collectLastValue(underTest.isSatelliteProvisioned) 363 364 // THEN well, first we don't throw... 365 // AND THEN we assume that it's not provisioned 366 assertThat(provisioned).isFalse() 367 } 368 369 @Test satelliteProvisioned_supported_provisioned_queriesInitialStateBeforeCallbacksnull370 fun satelliteProvisioned_supported_provisioned_queriesInitialStateBeforeCallbacks() = 371 testScope.runTest { 372 // GIVEN satellite is supported, and provisioned 373 setUpRepo( 374 uptime = MIN_UPTIME, 375 satMan = satelliteManager, 376 satelliteSupported = true, 377 initialSatelliteIsProvisioned = true, 378 ) 379 380 val provisioned by collectLastValue(underTest.isSatelliteProvisioned) 381 382 runCurrent() 383 384 // THEN the current state is requested 385 verify(satelliteManager, atLeastOnce()).requestIsProvisioned(any(), any()) 386 387 // AND the state is correct 388 assertThat(provisioned).isTrue() 389 } 390 391 @Test satelliteProvisioned_supported_notProvisioned_queriesInitialStateBeforeCallbacksnull392 fun satelliteProvisioned_supported_notProvisioned_queriesInitialStateBeforeCallbacks() = 393 testScope.runTest { 394 // GIVEN satellite is supported, and provisioned 395 setUpRepo( 396 uptime = MIN_UPTIME, 397 satMan = satelliteManager, 398 satelliteSupported = true, 399 initialSatelliteIsProvisioned = false, 400 ) 401 402 val provisioned by collectLastValue(underTest.isSatelliteProvisioned) 403 404 runCurrent() 405 406 // THEN the current state is requested 407 verify(satelliteManager, atLeastOnce()).requestIsProvisioned(any(), any()) 408 409 // AND the state is correct 410 assertThat(provisioned).isFalse() 411 } 412 413 @Test satelliteProvisioned_supported_notInitiallyProvisioned_tracksCallbacknull414 fun satelliteProvisioned_supported_notInitiallyProvisioned_tracksCallback() = 415 testScope.runTest { 416 // GIVEN satellite is not supported 417 setUpRepo( 418 uptime = MIN_UPTIME, 419 satMan = satelliteManager, 420 satelliteSupported = true, 421 initialSatelliteIsProvisioned = false, 422 ) 423 424 val provisioned by collectLastValue(underTest.isSatelliteProvisioned) 425 runCurrent() 426 427 val callback = 428 withArgCaptor<SatelliteProvisionStateCallback> { 429 verify(satelliteManager).registerForProvisionStateChanged(any(), capture()) 430 } 431 432 // WHEN provisioning state changes 433 callback.onSatelliteProvisionStateChanged(true) 434 435 // THEN the value is reflected in the repo 436 assertThat(provisioned).isTrue() 437 } 438 439 @Test satelliteProvisioned_supported_tracksCallback_reRegistersOnCrashnull440 fun satelliteProvisioned_supported_tracksCallback_reRegistersOnCrash() = 441 testScope.runTest { 442 // GIVEN satellite is supported 443 setUpRepo(uptime = MIN_UPTIME, satMan = satelliteManager, satelliteSupported = true) 444 445 val provisioned by collectLastValue(underTest.isSatelliteProvisioned) 446 447 runCurrent() 448 449 val callback = 450 withArgCaptor<SatelliteProvisionStateCallback> { 451 verify(satelliteManager).registerForProvisionStateChanged(any(), capture()) 452 } 453 val telephonyCallback = 454 MobileTelephonyHelpers.getTelephonyCallbackForType< 455 TelephonyCallback.RadioPowerStateListener 456 >( 457 telephonyManager 458 ) 459 460 // GIVEN satellite is currently provisioned 461 callback.onSatelliteProvisionStateChanged(true) 462 463 assertThat(provisioned).isTrue() 464 465 // WHEN a crash event happens (detected by radio state change) 466 telephonyCallback.onRadioPowerStateChanged(TelephonyManager.RADIO_POWER_ON) 467 runCurrent() 468 telephonyCallback.onRadioPowerStateChanged(TelephonyManager.RADIO_POWER_OFF) 469 runCurrent() 470 471 // THEN listeners are re-registered 472 verify(satelliteManager, times(2)).registerForProvisionStateChanged(any(), any()) 473 // AND the state is queried again 474 verify(satelliteManager, times(2)).requestIsProvisioned(any(), any()) 475 } 476 477 @Test satelliteNotSupported_listenersAreNotRegisterednull478 fun satelliteNotSupported_listenersAreNotRegistered() = 479 testScope.runTest { 480 // GIVEN satellite is not supported 481 setUpRepo(uptime = MIN_UPTIME, satMan = satelliteManager, satelliteSupported = false) 482 483 // WHEN data is requested from the repo 484 val connectionState by collectLastValue(underTest.connectionState) 485 val signalStrength by collectLastValue(underTest.signalStrength) 486 487 // THEN the manager is not asked for the information, and default values are returned 488 verify(satelliteManager, never()).registerForModemStateChanged(any(), any()) 489 verify(satelliteManager, never()).registerForNtnSignalStrengthChanged(any(), any()) 490 } 491 492 @Test satelliteSupported_registersCallbackForStateChangesnull493 fun satelliteSupported_registersCallbackForStateChanges() = 494 testScope.runTest { 495 // GIVEN a supported satellite manager. 496 setupDefaultRepo() 497 runCurrent() 498 499 // THEN the repo registers for state changes of satellite support 500 verify(satelliteManager, times(1)).registerForSupportedStateChanged(any(), any()) 501 } 502 503 @Test satelliteNotSupported_registersCallbackForStateChangesnull504 fun satelliteNotSupported_registersCallbackForStateChanges() = 505 testScope.runTest { 506 // GIVEN satellite is not supported 507 setUpRepo(uptime = MIN_UPTIME, satMan = satelliteManager, satelliteSupported = false) 508 509 runCurrent() 510 // THEN the repo registers for state changes of satellite support 511 verify(satelliteManager, times(1)).registerForSupportedStateChanged(any(), any()) 512 } 513 514 @Test satelliteSupportedStateChangedCallbackThrows_doesNotCrashnull515 fun satelliteSupportedStateChangedCallbackThrows_doesNotCrash() = 516 testScope.runTest { 517 // GIVEN, satellite manager throws when registering for supported state changes 518 whenever(satelliteManager.registerForSupportedStateChanged(any(), any())) 519 .thenThrow(IllegalStateException()) 520 521 // GIVEN a supported satellite manager. 522 setupDefaultRepo() 523 runCurrent() 524 525 // THEN a listener for satellite supported changed can attempt to register, 526 // with no crash 527 verify(satelliteManager).registerForSupportedStateChanged(any(), any()) 528 } 529 530 @Test satelliteSupported_supportIsLost_unregistersListenersnull531 fun satelliteSupported_supportIsLost_unregistersListeners() = 532 testScope.runTest { 533 // GIVEN a supported satellite manager. 534 setupDefaultRepo() 535 runCurrent() 536 537 val callback = 538 withArgCaptor<SatelliteSupportedStateCallback> { 539 verify(satelliteManager).registerForSupportedStateChanged(any(), capture()) 540 } 541 542 // WHEN data is requested from the repo 543 val connectionState by collectLastValue(underTest.connectionState) 544 val signalStrength by collectLastValue(underTest.signalStrength) 545 546 // THEN the listeners are registered 547 verify(satelliteManager, times(1)).registerForModemStateChanged(any(), any()) 548 verify(satelliteManager, times(1)).registerForNtnSignalStrengthChanged(any(), any()) 549 550 // WHEN satellite support turns off 551 callback.onSatelliteSupportedStateChanged(false) 552 runCurrent() 553 554 // THEN listeners are unregistered 555 verify(satelliteManager, times(1)).unregisterForModemStateChanged(any()) 556 verify(satelliteManager, times(1)).unregisterForNtnSignalStrengthChanged(any()) 557 } 558 559 @Test satelliteNotSupported_supportShowsUp_registersListenersnull560 fun satelliteNotSupported_supportShowsUp_registersListeners() = 561 testScope.runTest { 562 // GIVEN satellite is not supported 563 setUpRepo(uptime = MIN_UPTIME, satMan = satelliteManager, satelliteSupported = false) 564 runCurrent() 565 566 val callback = 567 withArgCaptor<SatelliteSupportedStateCallback> { 568 verify(satelliteManager).registerForSupportedStateChanged(any(), capture()) 569 } 570 571 // WHEN data is requested from the repo 572 val connectionState by collectLastValue(underTest.connectionState) 573 val signalStrength by collectLastValue(underTest.signalStrength) 574 575 // THEN the listeners are not yet registered 576 verify(satelliteManager, times(0)).registerForModemStateChanged(any(), any()) 577 verify(satelliteManager, times(0)).registerForNtnSignalStrengthChanged(any(), any()) 578 579 // WHEN satellite support turns on 580 callback.onSatelliteSupportedStateChanged(true) 581 runCurrent() 582 583 // THEN listeners are registered 584 verify(satelliteManager, times(1)).registerForModemStateChanged(any(), any()) 585 verify(satelliteManager, times(1)).registerForNtnSignalStrengthChanged(any(), any()) 586 } 587 588 @Test repoDoesNotCheckForSupportUntilMinUptimenull589 fun repoDoesNotCheckForSupportUntilMinUptime() = 590 testScope.runTest { 591 // GIVEN we init 100ms after sysui starts up 592 setUpRepo(uptime = 100, satMan = satelliteManager, satelliteSupported = true) 593 594 // WHEN data is requested 595 val connectionState by collectLastValue(underTest.connectionState) 596 val signalStrength by collectLastValue(underTest.signalStrength) 597 598 // THEN we have not yet talked to satellite manager, since we are well before MIN_UPTIME 599 Mockito.verifyNoMoreInteractions(satelliteManager) 600 601 // WHEN enough time has passed 602 systemClock.advanceTime(MIN_UPTIME) 603 runCurrent() 604 605 // THEN we finally register with the satellite manager 606 verify(satelliteManager).registerForModemStateChanged(any(), any()) 607 } 608 609 @Test telephonyCrash_repoReregistersConnectionStateListenernull610 fun telephonyCrash_repoReregistersConnectionStateListener() = 611 testScope.runTest { 612 setupDefaultRepo() 613 614 // GIVEN connection state is requested 615 val connectionState by collectLastValue(underTest.connectionState) 616 617 runCurrent() 618 619 val telephonyCallback = 620 MobileTelephonyHelpers.getTelephonyCallbackForType< 621 TelephonyCallback.RadioPowerStateListener 622 >( 623 telephonyManager 624 ) 625 626 // THEN listener is registered once 627 verify(satelliteManager, times(1)).registerForModemStateChanged(any(), any()) 628 629 // WHEN a crash event happens (detected by radio state change) 630 telephonyCallback.onRadioPowerStateChanged(TelephonyManager.RADIO_POWER_ON) 631 runCurrent() 632 telephonyCallback.onRadioPowerStateChanged(TelephonyManager.RADIO_POWER_OFF) 633 runCurrent() 634 635 // THEN listeners are unregistered and re-registered 636 verify(satelliteManager, times(1)).unregisterForModemStateChanged(any()) 637 verify(satelliteManager, times(2)).registerForModemStateChanged(any(), any()) 638 } 639 640 @Test telephonyCrash_repoReregistersSignalStrengthListenernull641 fun telephonyCrash_repoReregistersSignalStrengthListener() = 642 testScope.runTest { 643 setupDefaultRepo() 644 645 // GIVEN signal strength is requested 646 val signalStrength by collectLastValue(underTest.signalStrength) 647 648 runCurrent() 649 650 val telephonyCallback = 651 MobileTelephonyHelpers.getTelephonyCallbackForType< 652 TelephonyCallback.RadioPowerStateListener 653 >( 654 telephonyManager 655 ) 656 657 // THEN listeners are registered the first time 658 verify(satelliteManager, times(1)).registerForNtnSignalStrengthChanged(any(), any()) 659 660 // WHEN a crash event happens (detected by radio state change) 661 telephonyCallback.onRadioPowerStateChanged(TelephonyManager.RADIO_POWER_ON) 662 runCurrent() 663 telephonyCallback.onRadioPowerStateChanged(TelephonyManager.RADIO_POWER_OFF) 664 runCurrent() 665 666 // THEN listeners are unregistered and re-registered 667 verify(satelliteManager, times(1)).unregisterForNtnSignalStrengthChanged(any()) 668 verify(satelliteManager, times(2)).registerForNtnSignalStrengthChanged(any(), any()) 669 } 670 setUpReponull671 private fun setUpRepo( 672 uptime: Long = MIN_UPTIME, 673 satMan: SatelliteManager? = satelliteManager, 674 satelliteSupported: Boolean = true, 675 initialSatelliteIsProvisioned: Boolean = true, 676 ) { 677 doAnswer { 678 val callback: OutcomeReceiver<Boolean, SatelliteException> = 679 it.getArgument(1) as OutcomeReceiver<Boolean, SatelliteException> 680 callback.onResult(satelliteSupported) 681 } 682 .whenever(satelliteManager) 683 .requestIsSupported(any(), any()) 684 685 doAnswer { 686 val callback: OutcomeReceiver<Boolean, SatelliteException> = 687 it.getArgument(1) as OutcomeReceiver<Boolean, SatelliteException> 688 callback.onResult(initialSatelliteIsProvisioned) 689 } 690 .whenever(satelliteManager) 691 .requestIsProvisioned(any(), any()) 692 693 systemClock.setUptimeMillis(Process.getStartUptimeMillis() + uptime) 694 695 underTest = 696 DeviceBasedSatelliteRepositoryImpl( 697 if (satMan != null) Optional.of(satMan) else Optional.empty(), 698 telephonyManager, 699 dispatcher, 700 testScope.backgroundScope, 701 logBuffer = FakeLogBuffer.Factory.create(), 702 verboseLogBuffer = FakeLogBuffer.Factory.create(), 703 systemClock, 704 context.resources, 705 ) 706 } 707 708 // Set system time to MIN_UPTIME and create a repo with satellite supported setupDefaultReponull709 private fun setupDefaultRepo() { 710 setUpRepo(uptime = MIN_UPTIME, satMan = satelliteManager, satelliteSupported = true) 711 } 712 } 713