Disable SIM On/Off operation when device is in a Satellite session
Bug: 330585109 Test: SatelliteManagerTestOnMockService SatelliteSessionControllerTest SatelliteControllerTest Manual test with demo and real mode Change-Id: Iade6426981f76a0b9b71828e0c86d3088c3e974e
This commit is contained in:
@@ -25,7 +25,6 @@ import androidx.annotation.VisibleForTesting
|
|||||||
import androidx.concurrent.futures.CallbackToFutureAdapter
|
import androidx.concurrent.futures.CallbackToFutureAdapter
|
||||||
import com.google.common.util.concurrent.Futures.immediateFuture
|
import com.google.common.util.concurrent.Futures.immediateFuture
|
||||||
import com.google.common.util.concurrent.ListenableFuture
|
import com.google.common.util.concurrent.ListenableFuture
|
||||||
import java.util.concurrent.Executor
|
|
||||||
import kotlinx.coroutines.CoroutineDispatcher
|
import kotlinx.coroutines.CoroutineDispatcher
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
import kotlinx.coroutines.asExecutor
|
import kotlinx.coroutines.asExecutor
|
||||||
@@ -33,6 +32,7 @@ import kotlinx.coroutines.channels.awaitClose
|
|||||||
import kotlinx.coroutines.flow.Flow
|
import kotlinx.coroutines.flow.Flow
|
||||||
import kotlinx.coroutines.flow.callbackFlow
|
import kotlinx.coroutines.flow.callbackFlow
|
||||||
import kotlinx.coroutines.flow.flowOf
|
import kotlinx.coroutines.flow.flowOf
|
||||||
|
import java.util.concurrent.Executor
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A repository class for interacting with the SatelliteManager API.
|
* A repository class for interacting with the SatelliteManager API.
|
||||||
@@ -74,6 +74,41 @@ class SatelliteRepository(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks if a satellite session has started.
|
||||||
|
*
|
||||||
|
* @param executor The executor to run the asynchronous operation on
|
||||||
|
* @return A ListenableFuture that will resolve to `true` if a satellite session has started,
|
||||||
|
* `false` otherwise.
|
||||||
|
*/
|
||||||
|
fun requestIsSessionStarted(executor: Executor): ListenableFuture<Boolean> {
|
||||||
|
val satelliteManager: SatelliteManager? =
|
||||||
|
context.getSystemService(SatelliteManager::class.java)
|
||||||
|
if (satelliteManager == null) {
|
||||||
|
Log.w(TAG, "SatelliteManager is null")
|
||||||
|
return immediateFuture(false)
|
||||||
|
}
|
||||||
|
|
||||||
|
return CallbackToFutureAdapter.getFuture { completer ->
|
||||||
|
val callback = object : SatelliteModemStateCallback {
|
||||||
|
override fun onSatelliteModemStateChanged(state: Int) {
|
||||||
|
val isSessionStarted = isSatelliteSessionStarted(state)
|
||||||
|
Log.i(TAG, "Satellite modem state changed: state=$state"
|
||||||
|
+ ", isSessionStarted=$isSessionStarted")
|
||||||
|
completer.set(isSessionStarted)
|
||||||
|
satelliteManager.unregisterForModemStateChanged(this)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
val registerResult = satelliteManager.registerForModemStateChanged(executor, callback)
|
||||||
|
if (registerResult != SatelliteManager.SATELLITE_RESULT_SUCCESS) {
|
||||||
|
Log.w(TAG, "Failed to register for satellite modem state change: $registerResult")
|
||||||
|
completer.set(false)
|
||||||
|
}
|
||||||
|
"requestIsSessionStarted"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Provides a Flow that emits the enabled state of the satellite modem. Updates are triggered
|
* Provides a Flow that emits the enabled state of the satellite modem. Updates are triggered
|
||||||
* when the modem state changes.
|
* when the modem state changes.
|
||||||
@@ -134,5 +169,20 @@ class SatelliteRepository(
|
|||||||
companion object {
|
companion object {
|
||||||
private const val TAG: String = "SatelliteRepository"
|
private const val TAG: String = "SatelliteRepository"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if the modem is in a satellite session.
|
||||||
|
*
|
||||||
|
* @param state The SatelliteModemState provided by the SatelliteManager.
|
||||||
|
* @return `true` if the modem is in a satellite session, `false` otherwise.
|
||||||
|
*/
|
||||||
|
fun isSatelliteSessionStarted(@SatelliteManager.SatelliteModemState state: Int): Boolean {
|
||||||
|
return when (state) {
|
||||||
|
SatelliteManager.SATELLITE_MODEM_STATE_OFF,
|
||||||
|
SatelliteManager.SATELLITE_MODEM_STATE_UNAVAILABLE,
|
||||||
|
SatelliteManager.SATELLITE_MODEM_STATE_UNKNOWN -> false
|
||||||
|
else -> true
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -56,22 +56,23 @@ public class SimSlotChangeReceiver extends BroadcastReceiver {
|
|||||||
|
|
||||||
public static void runOnBackgroundThread(Context context) {
|
public static void runOnBackgroundThread(Context context) {
|
||||||
if (shouldHandleSlotChange(context)) {
|
if (shouldHandleSlotChange(context)) {
|
||||||
Log.d(TAG, "Checking satellite enabled status");
|
Log.d(TAG, "Checking satellite session status");
|
||||||
Executor executor = Executors.newSingleThreadExecutor();
|
Executor executor = Executors.newSingleThreadExecutor();
|
||||||
ListenableFuture<Boolean> satelliteEnabledFuture = new SatelliteRepository(context)
|
ListenableFuture<Boolean> isSatelliteSessionStartedFuture =
|
||||||
.requestIsEnabled(executor);
|
new SatelliteRepository(context).requestIsSessionStarted(executor);
|
||||||
satelliteEnabledFuture.addListener(() -> {
|
isSatelliteSessionStartedFuture.addListener(() -> {
|
||||||
boolean isSatelliteEnabled = false;
|
boolean isSatelliteSessionStarted = false;
|
||||||
try {
|
try {
|
||||||
isSatelliteEnabled = satelliteEnabledFuture.get();
|
isSatelliteSessionStarted = isSatelliteSessionStartedFuture.get();
|
||||||
} catch (ExecutionException | InterruptedException e) {
|
} catch (ExecutionException | InterruptedException e) {
|
||||||
Log.w(TAG, "Can't get satellite enabled status", e);
|
Log.w(TAG, "Can't get satellite session status", e);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isSatelliteEnabled) {
|
if (isSatelliteSessionStarted) {
|
||||||
Log.i(TAG, "Satellite is enabled. Unable to handle SIM slot changes");
|
Log.i(TAG, "Device is in a satellite session. Unable to handle SIM slot"
|
||||||
|
+ " changes");
|
||||||
} else {
|
} else {
|
||||||
Log.i(TAG, "Satellite is disabled. Handle slot changes");
|
Log.i(TAG, "Not in a satellite session. Handle slot changes");
|
||||||
SimSlotChangeHandler.get().onSlotsStatusChange(context.getApplicationContext());
|
SimSlotChangeHandler.get().onSlotsStatusChange(context.getApplicationContext());
|
||||||
}
|
}
|
||||||
}, executor);
|
}, executor);
|
||||||
|
@@ -24,7 +24,6 @@ import android.telephony.satellite.SatelliteModemStateCallback
|
|||||||
import androidx.test.core.app.ApplicationProvider
|
import androidx.test.core.app.ApplicationProvider
|
||||||
import com.google.common.truth.Truth.assertThat
|
import com.google.common.truth.Truth.assertThat
|
||||||
import com.google.common.util.concurrent.ListenableFuture
|
import com.google.common.util.concurrent.ListenableFuture
|
||||||
import java.util.concurrent.Executor
|
|
||||||
import kotlinx.coroutines.flow.first
|
import kotlinx.coroutines.flow.first
|
||||||
import kotlinx.coroutines.runBlocking
|
import kotlinx.coroutines.runBlocking
|
||||||
import org.junit.Assert.assertFalse
|
import org.junit.Assert.assertFalse
|
||||||
@@ -35,12 +34,12 @@ import org.junit.Test
|
|||||||
import org.junit.runner.RunWith
|
import org.junit.runner.RunWith
|
||||||
import org.mockito.ArgumentMatchers.eq
|
import org.mockito.ArgumentMatchers.eq
|
||||||
import org.mockito.Mock
|
import org.mockito.Mock
|
||||||
import org.mockito.Mockito.any
|
import org.mockito.Mockito.*
|
||||||
import org.mockito.Mockito.`when`
|
|
||||||
import org.mockito.Spy
|
import org.mockito.Spy
|
||||||
import org.mockito.junit.MockitoJUnit
|
import org.mockito.junit.MockitoJUnit
|
||||||
import org.mockito.junit.MockitoRule
|
import org.mockito.junit.MockitoRule
|
||||||
import org.robolectric.RobolectricTestRunner
|
import org.robolectric.RobolectricTestRunner
|
||||||
|
import java.util.concurrent.Executor
|
||||||
|
|
||||||
|
|
||||||
@RunWith(RobolectricTestRunner::class)
|
@RunWith(RobolectricTestRunner::class)
|
||||||
@@ -90,6 +89,55 @@ class SatelliteRepositoryTest {
|
|||||||
assertTrue(result.get())
|
assertTrue(result.get())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun requestIsSessionStarted_resultIsTrue() = runBlocking {
|
||||||
|
`when`(mockSatelliteManager.registerForModemStateChanged(any(), any())
|
||||||
|
).thenAnswer { invocation ->
|
||||||
|
val callback = invocation.getArgument<SatelliteModemStateCallback>(1)
|
||||||
|
callback.onSatelliteModemStateChanged(SatelliteManager.SATELLITE_MODEM_STATE_CONNECTED)
|
||||||
|
SatelliteManager.SATELLITE_RESULT_SUCCESS
|
||||||
|
}
|
||||||
|
|
||||||
|
val result: ListenableFuture<Boolean> = repository.requestIsSessionStarted(mockExecutor)
|
||||||
|
assertTrue(result.get())
|
||||||
|
verify(mockSatelliteManager).unregisterForModemStateChanged(any())
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun requestIsSessionStarted_resultIsFalse() = runBlocking {
|
||||||
|
`when`(mockSatelliteManager.registerForModemStateChanged(any(), any())
|
||||||
|
).thenAnswer { invocation ->
|
||||||
|
val callback = invocation.getArgument<SatelliteModemStateCallback>(1)
|
||||||
|
callback.onSatelliteModemStateChanged(SatelliteManager.SATELLITE_MODEM_STATE_OFF)
|
||||||
|
SatelliteManager.SATELLITE_RESULT_SUCCESS
|
||||||
|
}
|
||||||
|
|
||||||
|
val result: ListenableFuture<Boolean> = repository.requestIsSessionStarted(mockExecutor)
|
||||||
|
assertFalse(result.get())
|
||||||
|
verify(mockSatelliteManager).unregisterForModemStateChanged(any())
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun requestIsSessionStarted_registerFailed() = runBlocking {
|
||||||
|
`when`(mockSatelliteManager.registerForModemStateChanged(any(), any())
|
||||||
|
).thenAnswer { invocation ->
|
||||||
|
SatelliteManager.SATELLITE_RESULT_ERROR
|
||||||
|
}
|
||||||
|
|
||||||
|
val result: ListenableFuture<Boolean> = repository.requestIsSessionStarted(mockExecutor)
|
||||||
|
assertFalse(result.get())
|
||||||
|
verify(mockSatelliteManager, never()).unregisterForModemStateChanged(any())
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun requestIsSessionStarted_nullSatelliteManager() = runBlocking {
|
||||||
|
`when`(spyContext.getSystemService(SatelliteManager::class.java)).thenReturn(null)
|
||||||
|
|
||||||
|
val result: ListenableFuture<Boolean> = repository.requestIsSessionStarted(mockExecutor)
|
||||||
|
assertFalse(result.get())
|
||||||
|
verifyNoInteractions(mockSatelliteManager)
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun requestIsEnabled_resultIsFalse() = runBlocking {
|
fun requestIsEnabled_resultIsFalse() = runBlocking {
|
||||||
`when`(
|
`when`(
|
||||||
|
Reference in New Issue
Block a user