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
This commit is contained in:
Samuel Huang
2024-04-26 04:08:10 +00:00
parent fea80bf236
commit 4f454b43c6
3 changed files with 38 additions and 40 deletions

View File

@@ -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<Boolean> {
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)
}
/**

View File

@@ -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
}

View File

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