From 4f454b43c636151b093836c73fac0813bae085ac Mon Sep 17 00:00:00 2001 From: Samuel Huang Date: Fri, 26 Apr 2024 04:08:10 +0000 Subject: [PATCH] Fix the "Use this SIM" switch does not disable during phone calls If the registration failed (e.g., device doesn't support satellite), SatelliteManager will not emit the current state by callback. We send `false` value by ourself to make sure the flow has initial value. Bug: 315928920 Test: atest, manual Change-Id: Ic87f71bc576cfb1f8e4053c5784fca401adaec08 --- .../settings/network/SatelliteRepository.kt | 50 +++++++------------ .../MobileNetworkSwitchController.kt | 2 +- .../network/SatelliteRepositoryTest.kt | 26 +++++++--- 3 files changed, 38 insertions(+), 40 deletions(-) diff --git a/src/com/android/settings/network/SatelliteRepository.kt b/src/com/android/settings/network/SatelliteRepository.kt index f5bac1ee7ab..dffa9d0dd67 100644 --- a/src/com/android/settings/network/SatelliteRepository.kt +++ b/src/com/android/settings/network/SatelliteRepository.kt @@ -33,6 +33,7 @@ import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.callbackFlow import kotlinx.coroutines.flow.flowOf import java.util.concurrent.Executor +import kotlinx.coroutines.flow.flowOn /** * A repository class for interacting with the SatelliteManager API. @@ -112,13 +113,13 @@ class SatelliteRepository( } /** - * Provides a Flow that emits the enabled state of the satellite modem. Updates are triggered + * Provides a Flow that emits the session state of the satellite modem. Updates are triggered * when the modem state changes. * * @param defaultDispatcher The CoroutineDispatcher to use (Defaults to `Dispatchers.Default`). - * @return A Flow emitting `true` when the modem is enabled and `false` otherwise. + * @return A Flow emitting `true` when the session is started and `false` otherwise. */ - fun getIsModemEnabledFlow( + fun getIsSessionStartedFlow( defaultDispatcher: CoroutineDispatcher = Dispatchers.Default, ): Flow { val satelliteManager: SatelliteManager? = @@ -130,42 +131,27 @@ class SatelliteRepository( return callbackFlow { val callback = SatelliteModemStateCallback { state -> - val isEnabled = convertSatelliteModemStateToEnabledState(state) - Log.i(TAG, "Satellite modem state changed: state=$state, isEnabled=$isEnabled") - trySend(isEnabled) + val isSessionStarted = isSatelliteSessionStarted(state) + Log.i(TAG, "Satellite modem state changed: state=$state" + + ", isSessionStarted=$isSessionStarted") + trySend(isSessionStarted) } - val result = satelliteManager.registerForModemStateChanged( + val registerResult = satelliteManager.registerForModemStateChanged( defaultDispatcher.asExecutor(), callback ) - Log.i(TAG, "Call registerForModemStateChanged: result=$result") + + if (registerResult != SatelliteManager.SATELLITE_RESULT_SUCCESS) { + // If the registration failed (e.g., device doesn't support satellite), + // SatelliteManager will not emit the current state by callback. + // We send `false` value by ourself to make sure the flow has initial value. + Log.w(TAG, "Failed to register for satellite modem state change: $registerResult") + trySend(false) + } awaitClose { satelliteManager.unregisterForModemStateChanged(callback) } - } - } - - /** - * Converts a [SatelliteManager.SatelliteModemState] to a boolean representing whether the modem - * is enabled. - * - * @param state The SatelliteModemState provided by the SatelliteManager. - * @return `true` if the modem is enabled, `false` otherwise. - */ - @VisibleForTesting - fun convertSatelliteModemStateToEnabledState( - @SatelliteManager.SatelliteModemState state: Int, - ): Boolean { - // Mapping table based on logic from b/315928920#comment24 - return when (state) { - SatelliteManager.SATELLITE_MODEM_STATE_IDLE, - SatelliteManager.SATELLITE_MODEM_STATE_LISTENING, - SatelliteManager.SATELLITE_MODEM_STATE_DATAGRAM_TRANSFERRING, - SatelliteManager.SATELLITE_MODEM_STATE_DATAGRAM_RETRYING, - SatelliteManager.SATELLITE_MODEM_STATE_NOT_CONNECTED, - SatelliteManager.SATELLITE_MODEM_STATE_CONNECTED -> true - else -> false - } + }.flowOn(Dispatchers.Default) } /** diff --git a/src/com/android/settings/network/telephony/MobileNetworkSwitchController.kt b/src/com/android/settings/network/telephony/MobileNetworkSwitchController.kt index 3e1aab83ff5..00c55eccc3d 100644 --- a/src/com/android/settings/network/telephony/MobileNetworkSwitchController.kt +++ b/src/com/android/settings/network/telephony/MobileNetworkSwitchController.kt @@ -59,7 +59,7 @@ class MobileNetworkSwitchController @JvmOverloads constructor( val changeable by remember { combine( context.callStateFlow(subId).map { it == TelephonyManager.CALL_STATE_IDLE }, - satelliteRepository.getIsModemEnabledFlow() + satelliteRepository.getIsSessionStartedFlow() ) { isCallStateIdle, isSatelliteModemEnabled -> isCallStateIdle && !isSatelliteModemEnabled } diff --git a/tests/robotests/src/com/android/settings/network/SatelliteRepositoryTest.kt b/tests/robotests/src/com/android/settings/network/SatelliteRepositoryTest.kt index 5c6e7eb2941..ef1ca70edbd 100644 --- a/tests/robotests/src/com/android/settings/network/SatelliteRepositoryTest.kt +++ b/tests/robotests/src/com/android/settings/network/SatelliteRepositoryTest.kt @@ -120,7 +120,7 @@ class SatelliteRepositoryTest { @Test fun requestIsSessionStarted_registerFailed() = runBlocking { `when`(mockSatelliteManager.registerForModemStateChanged(any(), any()) - ).thenAnswer { invocation -> + ).thenAnswer { SatelliteManager.SATELLITE_RESULT_ERROR } @@ -187,7 +187,7 @@ class SatelliteRepositoryTest { } @Test - fun getIsModemEnabledFlow_isSatelliteEnabledState() = runBlocking { + fun getIsSessionStartedFlow_isSatelliteEnabledState() = runBlocking { `when`( mockSatelliteManager.registerForModemStateChanged( any(), @@ -199,13 +199,13 @@ class SatelliteRepositoryTest { SatelliteManager.SATELLITE_RESULT_SUCCESS } - val flow = repository.getIsModemEnabledFlow() + val flow = repository.getIsSessionStartedFlow() assertThat(flow.first()).isTrue() } @Test - fun getIsModemEnabledFlow_isSatelliteDisabledState() = runBlocking { + fun getIsSessionStartedFlow_isSatelliteDisabledState() = runBlocking { `when`( mockSatelliteManager.registerForModemStateChanged( any(), @@ -217,16 +217,28 @@ class SatelliteRepositoryTest { SatelliteManager.SATELLITE_RESULT_SUCCESS } - val flow = repository.getIsModemEnabledFlow() + val flow = repository.getIsSessionStartedFlow() assertThat(flow.first()).isFalse() } @Test - fun getIsModemEnabledFlow_nullSatelliteManager() = runBlocking { + fun getIsSessionStartedFlow_nullSatelliteManager() = runBlocking { `when`(spyContext.getSystemService(SatelliteManager::class.java)).thenReturn(null) - val flow = repository.getIsModemEnabledFlow() + val flow = repository.getIsSessionStartedFlow() + assertThat(flow.first()).isFalse() + } + + @Test + fun getIsSessionStartedFlow_registerFailed() = runBlocking { + `when`(mockSatelliteManager.registerForModemStateChanged(any(), any()) + ).thenAnswer { + SatelliteManager.SATELLITE_RESULT_ERROR + } + + val flow = repository.getIsSessionStartedFlow() + assertThat(flow.first()).isFalse() } }