Merge "Filter out the satellite PLMNs from the current connected network" into main
diff --git a/src/com/android/settings/network/telephony/NetworkSelectRepository.kt b/src/com/android/settings/network/telephony/NetworkSelectRepository.kt
index 1f5fbc2..d95c90e 100644
--- a/src/com/android/settings/network/telephony/NetworkSelectRepository.kt
+++ b/src/com/android/settings/network/telephony/NetworkSelectRepository.kt
@@ -18,8 +18,10 @@
 
 import android.content.Context
 import android.telephony.AccessNetworkConstants
+import android.telephony.CarrierConfigManager
 import android.telephony.NetworkRegistrationInfo
 import android.telephony.TelephonyManager
+import android.telephony.satellite.SatelliteManager
 import androidx.lifecycle.Lifecycle
 import androidx.lifecycle.LifecycleOwner
 import androidx.lifecycle.lifecycleScope
@@ -28,9 +30,11 @@
 import kotlinx.coroutines.launch
 import kotlinx.coroutines.withContext
 
-class NetworkSelectRepository(context: Context, subId: Int) {
+class NetworkSelectRepository(context: Context, private val subId: Int) {
     private val telephonyManager =
         context.getSystemService(TelephonyManager::class.java)!!.createForSubscriptionId(subId)
+    private val satelliteManager = context.getSystemService(SatelliteManager::class.java)
+    private val carrierConfigManager = context.getSystemService(CarrierConfigManager::class.java)
 
     data class NetworkRegistrationAndForbiddenInfo(
         val networkList: List<NetworkRegistrationInfo>,
@@ -55,10 +59,21 @@
         if (telephonyManager.dataState != TelephonyManager.DATA_CONNECTED) return null
         // Try to get the network registration states
         val serviceState = telephonyManager.serviceState ?: return null
-        val networkList = serviceState.getNetworkRegistrationInfoListForTransportType(
+        var networkList = serviceState.getNetworkRegistrationInfoListForTransportType(
             AccessNetworkConstants.TRANSPORT_TYPE_WWAN
         )
         if (networkList.isEmpty()) return null
+
+        val satellitePlmn = getSatellitePlmns()
+        // If connected network is Satellite, filter out
+        if (satellitePlmn.isNotEmpty()) {
+            val filteredNetworkList = networkList.filter {
+                val cellIdentity = it.cellIdentity
+                val plmn = cellIdentity?.plmn
+                plmn != null && !satellitePlmn.contains(plmn)
+            }
+            networkList = filteredNetworkList
+        }
         // Due to the aggregation of cell between carriers, it's possible to get CellIdentity
         // containing forbidden PLMN.
         // Getting current network from ServiceState is no longer a good idea.
@@ -72,4 +87,24 @@
     private fun getForbiddenPlmns(): List<String> {
         return telephonyManager.forbiddenPlmns?.toList() ?: emptyList()
     }
+
+    /**
+     * Update satellite PLMNs from the satellite framework.
+     */
+    private fun getSatellitePlmns(): List<String> {
+        val config = carrierConfigManager.getConfigForSubId(
+            subId,
+            CarrierConfigManager.KEY_REMOVE_SATELLITE_PLMN_IN_MANUAL_NETWORK_SCAN_BOOL
+        )
+
+        val shouldFilter = config.getBoolean(
+            CarrierConfigManager.KEY_REMOVE_SATELLITE_PLMN_IN_MANUAL_NETWORK_SCAN_BOOL,
+            true)
+
+        return if (shouldFilter) {
+            satelliteManager.getSatellitePlmnsForCarrier(subId)
+        } else {
+            emptyList();
+        }
+    }
 }
diff --git a/tests/spa_unit/src/com/android/settings/network/telephony/NetworkSelectRepositoryTest.kt b/tests/spa_unit/src/com/android/settings/network/telephony/NetworkSelectRepositoryTest.kt
index 4137de4..0cbfe02 100644
--- a/tests/spa_unit/src/com/android/settings/network/telephony/NetworkSelectRepositoryTest.kt
+++ b/tests/spa_unit/src/com/android/settings/network/telephony/NetworkSelectRepositoryTest.kt
@@ -17,20 +17,21 @@
 package com.android.settings.network.telephony
 
 import android.content.Context
-import android.telephony.AccessNetworkConstants
-import android.telephony.NetworkRegistrationInfo
-import android.telephony.ServiceState
-import android.telephony.TelephonyManager
+import android.os.PersistableBundle
+import android.telephony.*
+import android.telephony.satellite.SatelliteManager
 import androidx.test.core.app.ApplicationProvider
 import androidx.test.ext.junit.runners.AndroidJUnit4
 import com.android.settings.network.telephony.scan.NetworkScanRepositoryTest
 import com.google.common.truth.Truth.assertThat
 import org.junit.Test
 import org.junit.runner.RunWith
+import org.mockito.ArgumentMatchers.anyInt
 import org.mockito.kotlin.doReturn
 import org.mockito.kotlin.mock
 import org.mockito.kotlin.spy
 import org.mockito.kotlin.stub
+import org.mockito.kotlin.whenever
 
 @RunWith(AndroidJUnit4::class)
 class NetworkSelectRepositoryTest {
@@ -49,8 +50,16 @@
         on { serviceState } doReturn mockServiceState
     }
 
+    private val mockSatelliteManager = mock<SatelliteManager> {
+        on { getSatellitePlmnsForCarrier(anyInt()) } doReturn SatellitePlmns
+    }
+
+    private var mockCarrierConfigManager = mock<CarrierConfigManager>()
+
     private val context: Context = spy(ApplicationProvider.getApplicationContext()) {
         on { getSystemService(TelephonyManager::class.java) } doReturn mockTelephonyManager
+        on { getSystemService(SatelliteManager::class.java) } doReturn mockSatelliteManager
+        on { getSystemService(CarrierConfigManager::class.java) } doReturn mockCarrierConfigManager
     }
 
     private val repository = NetworkSelectRepository(context, SUB_ID)
@@ -105,6 +114,14 @@
             on { forbiddenPlmns } doReturn arrayOf(FORBIDDEN_PLMN)
         }
 
+        val config = PersistableBundle()
+        config.putBoolean(
+            CarrierConfigManager.KEY_REMOVE_SATELLITE_PLMN_IN_MANUAL_NETWORK_SCAN_BOOL,
+            false)
+        whenever(mockCarrierConfigManager.getConfigForSubId(
+            SUB_ID, CarrierConfigManager.KEY_REMOVE_SATELLITE_PLMN_IN_MANUAL_NETWORK_SCAN_BOOL))
+            .thenReturn(config)
+
         val info = repository.getNetworkRegistrationInfo()
 
         assertThat(info).isEqualTo(
@@ -115,9 +132,76 @@
         )
     }
 
+    @Test
+    fun getNetworkRegistrationInfo_filterSatellitePlmn() {
+
+        val info1 = createTestNetworkRegistrationInfo("310", "260")
+        val info2 = createTestNetworkRegistrationInfo("310", "261")
+        val satelliteInfo = createTestNetworkRegistrationInfo(satelliteMcc, satelliteMnc)
+        val registrationInfos = listOf(info1, info2, satelliteInfo)
+        val filteredRegistrationInfos = listOf(info1, info2)
+
+        mockServiceState.stub {
+            on {
+                getNetworkRegistrationInfoListForTransportType(
+                    AccessNetworkConstants.TRANSPORT_TYPE_WWAN
+                )
+            } doReturn registrationInfos
+        }
+        mockTelephonyManager.stub {
+            on { forbiddenPlmns } doReturn arrayOf(FORBIDDEN_PLMN)
+        }
+
+        // disable satellite plmn filter
+        var config = PersistableBundle()
+        config.putBoolean(
+            CarrierConfigManager.KEY_REMOVE_SATELLITE_PLMN_IN_MANUAL_NETWORK_SCAN_BOOL,
+            false)
+        whenever(mockCarrierConfigManager.getConfigForSubId(
+            SUB_ID, CarrierConfigManager.KEY_REMOVE_SATELLITE_PLMN_IN_MANUAL_NETWORK_SCAN_BOOL))
+            .thenReturn(config)
+
+        var infoList = repository.getNetworkRegistrationInfo()
+
+        assertThat(infoList).isEqualTo(
+            NetworkSelectRepository.NetworkRegistrationAndForbiddenInfo(
+                networkList = registrationInfos,
+                forbiddenPlmns = listOf(FORBIDDEN_PLMN),
+            )
+        )
+
+        // enable satellite plmn filter
+        config = PersistableBundle()
+        config.putBoolean(
+            CarrierConfigManager.KEY_REMOVE_SATELLITE_PLMN_IN_MANUAL_NETWORK_SCAN_BOOL,
+            true)
+        whenever(mockCarrierConfigManager.getConfigForSubId(
+            SUB_ID, CarrierConfigManager.KEY_REMOVE_SATELLITE_PLMN_IN_MANUAL_NETWORK_SCAN_BOOL))
+            .thenReturn(config)
+
+        infoList = repository.getNetworkRegistrationInfo()
+
+        assertThat(infoList).isEqualTo(
+            NetworkSelectRepository.NetworkRegistrationAndForbiddenInfo(
+                networkList = filteredRegistrationInfos,
+                forbiddenPlmns = listOf(FORBIDDEN_PLMN),
+            )
+        )
+    }
+
     private companion object {
         const val SUB_ID = 1
         val NetworkRegistrationInfos = listOf(NetworkRegistrationInfo.Builder().build())
         const val FORBIDDEN_PLMN = "Forbidden PLMN"
+        const val satelliteMcc = "310"
+        const val satelliteMnc = "810"
+        val SatellitePlmns = listOf(satelliteMcc + satelliteMnc)
+
+        fun createTestNetworkRegistrationInfo(mcc: String, mnc: String): NetworkRegistrationInfo {
+            val cellInfo = CellIdentityLte(0, 0, 0, 0, IntArray(2) { 0 },
+                0, mcc, mnc, "", "", emptyList(), null)
+
+            return NetworkRegistrationInfo.Builder().setCellIdentity(cellInfo).build()
+        }
     }
 }