[1/2] Update new status bar data pipeline to support names for multiple sims

Updates the carrier name to use SubscriptionInfo instead of the ACTION_SERVICE_PROVIDERS_UPDATED intent as its source in order to support names for multiple subscriptions. Split from ag/24012407

Bug: 288631206
Test: Added/updated unit tests
Change-Id: Ib40dcf0a14e267c40a69dc4817761dab0e25142c
This commit is contained in:
Shawn Lee
2023-07-10 15:09:23 -07:00
parent 7e01e3c534
commit 1685e6b931
25 changed files with 472 additions and 54 deletions

View File

@@ -60,6 +60,19 @@ sealed interface NetworkNameModel : Diffable<NetworkNameModel> {
}
}
/** This name has been derived from SubscriptionModel. see [SubscriptionModel] */
data class SubscriptionDerived(override val name: String) : NetworkNameModel {
override fun logDiffs(prevVal: NetworkNameModel, row: TableRowLogger) {
if (prevVal !is SubscriptionDerived || prevVal.name != name) {
row.logChange(COL_NETWORK_NAME, "SubscriptionDerived($name)")
}
}
override fun logFull(row: TableRowLogger) {
row.logChange(COL_NETWORK_NAME, "SubscriptionDerived($name)")
}
}
/**
* This name has been derived from the sim via
* [android.telephony.TelephonyManager.getSimOperatorName].

View File

@@ -34,4 +34,7 @@ data class SubscriptionModel(
/** Subscriptions in the same group may be filtered or treated as a single subscription */
val groupUuid: ParcelUuid? = null,
/** Text representing the name for this connection */
val carrierName: String,
)

View File

@@ -115,9 +115,17 @@ interface MobileConnectionRepository {
*/
val cdmaRoaming: StateFlow<Boolean>
/** The service provider name for this network connection, or the default name */
/** The service provider name for this network connection, or the default name. */
val networkName: StateFlow<NetworkNameModel>
/**
* The service provider name for this network connection, or the default name.
*
* TODO(b/296600321): De-duplicate this field with [networkName] after determining the data
* provided is identical
*/
val carrierName: StateFlow<NetworkNameModel>
/**
* True if this type of connection is allowed while airplane mode is on, and false otherwise.
*/

View File

@@ -184,7 +184,10 @@ class DemoMobileConnectionRepository(
override val cdmaRoaming = MutableStateFlow(false)
override val networkName = MutableStateFlow(NetworkNameModel.IntentDerived("demo network"))
override val networkName = MutableStateFlow(NetworkNameModel.IntentDerived(DEMO_CARRIER_NAME))
override val carrierName =
MutableStateFlow(NetworkNameModel.SubscriptionDerived(DEMO_CARRIER_NAME))
override val isAllowedDuringAirplaneMode = MutableStateFlow(false)
@@ -200,6 +203,7 @@ class DemoMobileConnectionRepository(
// This is always true here, because we split out disabled states at the data-source level
dataEnabled.value = true
networkName.value = NetworkNameModel.IntentDerived(event.name)
carrierName.value = NetworkNameModel.SubscriptionDerived("${event.name} ${event.subId}")
_carrierId.value = event.carrierId ?: INVALID_SUBSCRIPTION_ID
@@ -227,6 +231,7 @@ class DemoMobileConnectionRepository(
// This is always true here, because we split out disabled states at the data-source level
dataEnabled.value = true
networkName.value = NetworkNameModel.IntentDerived(CARRIER_MERGED_NAME)
carrierName.value = NetworkNameModel.SubscriptionDerived(CARRIER_MERGED_NAME)
// TODO(b/276943904): is carrierId a thing with carrier merged networks?
_carrierId.value = INVALID_SUBSCRIPTION_ID
numberOfLevels.value = event.numberOfLevels
@@ -248,6 +253,7 @@ class DemoMobileConnectionRepository(
}
companion object {
private const val DEMO_CARRIER_NAME = "Demo Carrier"
private const val CARRIER_MERGED_NAME = "Carrier Merged Network"
}
}

View File

@@ -92,9 +92,12 @@ constructor(
private fun maybeCreateSubscription(subId: Int) {
if (!subscriptionInfoCache.containsKey(subId)) {
SubscriptionModel(subscriptionId = subId, isOpportunistic = false).also {
subscriptionInfoCache[subId] = it
}
SubscriptionModel(
subscriptionId = subId,
isOpportunistic = false,
carrierName = DEFAULT_CARRIER_NAME,
)
.also { subscriptionInfoCache[subId] = it }
_subscriptions.value = subscriptionInfoCache.values.toList()
}
@@ -327,6 +330,7 @@ constructor(
private const val TAG = "DemoMobileConnectionsRepo"
private const val DEFAULT_SUB_ID = 1
private const val DEFAULT_CARRIER_NAME = "demo carrier"
}
}

View File

@@ -108,6 +108,8 @@ class CarrierMergedConnectionRepository(
NetworkNameModel.SimDerived(telephonyManager.simOperatorName),
)
override val carrierName: StateFlow<NetworkNameModel> = networkName
override val numberOfLevels: StateFlow<Int> =
wifiRepository.wifiNetwork
.map {

View File

@@ -22,6 +22,7 @@ import com.android.systemui.log.table.TableLogBuffer
import com.android.systemui.log.table.TableLogBufferFactory
import com.android.systemui.log.table.logDiffsForTable
import com.android.systemui.statusbar.pipeline.mobile.data.model.NetworkNameModel
import com.android.systemui.statusbar.pipeline.mobile.data.model.SubscriptionModel
import com.android.systemui.statusbar.pipeline.mobile.data.repository.MobileConnectionRepository
import javax.inject.Inject
import kotlinx.coroutines.CoroutineScope
@@ -47,6 +48,7 @@ class FullMobileConnectionRepository(
override val subId: Int,
startingIsCarrierMerged: Boolean,
override val tableLogBuffer: TableLogBuffer,
subscriptionModel: StateFlow<SubscriptionModel?>,
private val defaultNetworkName: NetworkNameModel,
private val networkNameSeparator: String,
@Application scope: CoroutineScope,
@@ -80,6 +82,7 @@ class FullMobileConnectionRepository(
mobileRepoFactory.build(
subId,
tableLogBuffer,
subscriptionModel,
defaultNetworkName,
networkNameSeparator,
)
@@ -287,6 +290,16 @@ class FullMobileConnectionRepository(
)
.stateIn(scope, SharingStarted.WhileSubscribed(), activeRepo.value.networkName.value)
override val carrierName =
activeRepo
.flatMapLatest { it.carrierName }
.logDiffsForTable(
tableLogBuffer,
columnPrefix = "",
initialValue = activeRepo.value.carrierName.value,
)
.stateIn(scope, SharingStarted.WhileSubscribed(), activeRepo.value.carrierName.value)
override val isAllowedDuringAirplaneMode =
activeRepo
.flatMapLatest { it.isAllowedDuringAirplaneMode }
@@ -307,6 +320,7 @@ class FullMobileConnectionRepository(
fun build(
subId: Int,
startingIsCarrierMerged: Boolean,
subscriptionModel: StateFlow<SubscriptionModel?>,
defaultNetworkName: NetworkNameModel,
networkNameSeparator: String,
): FullMobileConnectionRepository {
@@ -317,6 +331,7 @@ class FullMobileConnectionRepository(
subId,
startingIsCarrierMerged,
mobileLogger,
subscriptionModel,
defaultNetworkName,
networkNameSeparator,
scope,

View File

@@ -43,6 +43,7 @@ import com.android.systemui.statusbar.pipeline.mobile.data.model.NetworkNameMode
import com.android.systemui.statusbar.pipeline.mobile.data.model.ResolvedNetworkType.DefaultNetworkType
import com.android.systemui.statusbar.pipeline.mobile.data.model.ResolvedNetworkType.OverrideNetworkType
import com.android.systemui.statusbar.pipeline.mobile.data.model.ResolvedNetworkType.UnknownNetworkType
import com.android.systemui.statusbar.pipeline.mobile.data.model.SubscriptionModel
import com.android.systemui.statusbar.pipeline.mobile.data.model.SystemUiCarrierConfig
import com.android.systemui.statusbar.pipeline.mobile.data.model.toDataConnectionType
import com.android.systemui.statusbar.pipeline.mobile.data.model.toNetworkNameModel
@@ -80,6 +81,7 @@ import kotlinx.coroutines.flow.stateIn
@OptIn(ExperimentalCoroutinesApi::class)
class MobileConnectionRepositoryImpl(
override val subId: Int,
subscriptionModel: StateFlow<SubscriptionModel?>,
defaultNetworkName: NetworkNameModel,
networkNameSeparator: String,
private val telephonyManager: TelephonyManager,
@@ -281,6 +283,14 @@ class MobileConnectionRepositoryImpl(
}
.stateIn(scope, SharingStarted.WhileSubscribed(), DEFAULT_NUM_LEVELS)
override val carrierName =
subscriptionModel
.map {
it?.let { model -> NetworkNameModel.SubscriptionDerived(model.carrierName) }
?: defaultNetworkName
}
.stateIn(scope, SharingStarted.WhileSubscribed(), defaultNetworkName)
/**
* There are a few cases where we will need to poll [TelephonyManager] so we can update some
* internal state where callbacks aren't provided. Any of those events should be merged into
@@ -350,11 +360,13 @@ class MobileConnectionRepositoryImpl(
fun build(
subId: Int,
mobileLogger: TableLogBuffer,
subscriptionModel: StateFlow<SubscriptionModel?>,
defaultNetworkName: NetworkNameModel,
networkNameSeparator: String,
): MobileConnectionRepository {
return MobileConnectionRepositoryImpl(
subId,
subscriptionModel,
defaultNetworkName,
networkNameSeparator,
telephonyManager.createForSubscriptionId(subId),

View File

@@ -319,10 +319,17 @@ constructor(
@VisibleForTesting fun getSubIdRepoCache() = subIdRepositoryCache
private fun subscriptionModelForSubId(subId: Int): StateFlow<SubscriptionModel?> {
return subscriptions
.map { list -> list.firstOrNull { model -> model.subscriptionId == subId } }
.stateIn(scope, SharingStarted.WhileSubscribed(), null)
}
private fun createRepositoryForSubId(subId: Int): FullMobileConnectionRepository {
return fullMobileRepoFactory.build(
subId,
isCarrierMerged(subId),
subscriptionModelForSubId(subId),
defaultNetworkName,
networkNameSeparator,
)
@@ -373,6 +380,7 @@ constructor(
subscriptionId = subscriptionId,
isOpportunistic = isOpportunistic,
groupUuid = groupUuid,
carrierName = carrierName.toString(),
)
companion object {

View File

@@ -92,6 +92,22 @@ interface MobileIconInteractor {
*/
val networkName: StateFlow<NetworkNameModel>
/**
* Provider name for this network connection. The name can be one of 3 values:
* 1. The default network name, if one is configured
* 2. A name provided by the [SubscriptionModel] of this network connection
* 3. Or, in the case where the repository sends us the default network name, we check for an
* override in [connectionInfo.operatorAlphaShort], a value that is derived from
* [ServiceState]
*
* TODO(b/296600321): De-duplicate this field with [networkName] after determining the data
* provided is identical
*/
val carrierName: StateFlow<String>
/** True if there is only one active subscription. */
val isSingleCarrier: StateFlow<Boolean>
/** True if this line of service is emergency-only */
val isEmergencyOnly: StateFlow<Boolean>
@@ -126,6 +142,7 @@ class MobileIconInteractorImpl(
defaultSubscriptionHasDataEnabled: StateFlow<Boolean>,
override val alwaysShowDataRatIcon: StateFlow<Boolean>,
override val alwaysUseCdmaLevel: StateFlow<Boolean>,
override val isSingleCarrier: StateFlow<Boolean>,
override val mobileIsDefault: StateFlow<Boolean>,
defaultMobileIconMapping: StateFlow<Map<String, MobileIconGroup>>,
defaultMobileIconGroup: StateFlow<MobileIconGroup>,
@@ -171,6 +188,22 @@ class MobileIconInteractorImpl(
connectionRepository.networkName.value
)
override val carrierName =
combine(connectionRepository.operatorAlphaShort, connectionRepository.carrierName) {
operatorAlphaShort,
networkName ->
if (networkName is NetworkNameModel.Default && operatorAlphaShort != null) {
operatorAlphaShort
} else {
networkName.name
}
}
.stateIn(
scope,
SharingStarted.WhileSubscribed(),
connectionRepository.carrierName.value.name
)
/** What the mobile icon would be before carrierId overrides */
private val defaultNetworkType: StateFlow<MobileIconGroup> =
combine(

View File

@@ -76,6 +76,9 @@ interface MobileIconsInteractor {
/** True if the CDMA level should be preferred over the primary level. */
val alwaysUseCdmaLevel: StateFlow<Boolean>
/** True if there is only one active subscription. */
val isSingleCarrier: StateFlow<Boolean>
/** The icon mapping from network type to [MobileIconGroup] for the default subscription */
val defaultMobileIconMapping: StateFlow<Map<String, MobileIconGroup>>
@@ -252,6 +255,17 @@ constructor(
.mapLatest { it.alwaysShowCdmaRssi }
.stateIn(scope, SharingStarted.WhileSubscribed(), false)
override val isSingleCarrier: StateFlow<Boolean> =
mobileConnectionsRepo.subscriptions
.map { it.size == 1 }
.logDiffsForTable(
tableLogger,
columnPrefix = LOGGING_PREFIX,
columnName = "isSingleCarrier",
initialValue = false,
)
.stateIn(scope, SharingStarted.WhileSubscribed(), false)
/** If there is no mapping in [defaultMobileIconMapping], then use this default icon group */
override val defaultMobileIconGroup: StateFlow<MobileIconGroup> =
mobileConnectionsRepo.defaultMobileIconGroup.stateIn(
@@ -298,6 +312,7 @@ constructor(
activeDataConnectionHasDataEnabled,
alwaysShowDataRatIcon,
alwaysUseCdmaLevel,
isSingleCarrier,
mobileIsDefault,
defaultMobileIconMapping,
defaultMobileIconGroup,

View File

@@ -52,12 +52,19 @@ class FakeMobileConnectionRepository(
override val cdmaRoaming = MutableStateFlow(false)
override val networkName =
MutableStateFlow<NetworkNameModel>(NetworkNameModel.Default("default"))
override val networkName: MutableStateFlow<NetworkNameModel> =
MutableStateFlow(NetworkNameModel.Default(DEFAULT_NETWORK_NAME))
override val carrierName: MutableStateFlow<NetworkNameModel> =
MutableStateFlow(NetworkNameModel.Default(DEFAULT_NETWORK_NAME))
override val isAllowedDuringAirplaneMode = MutableStateFlow(false)
fun setDataEnabled(enabled: Boolean) {
_dataEnabled.value = enabled
}
companion object {
const val DEFAULT_NETWORK_NAME = "default name"
}
}

View File

@@ -75,7 +75,11 @@ class FakeMobileConnectionsRepository(
override fun getRepoForSubId(subId: Int): MobileConnectionRepository {
return subIdRepos[subId]
?: FakeMobileConnectionRepository(subId, tableLogBuffer).also { subIdRepos[subId] = it }
?: FakeMobileConnectionRepository(
subId,
tableLogBuffer,
)
.also { subIdRepos[subId] = it }
}
override val defaultDataSubRatConfig = MutableStateFlow(MobileMappings.Config())

View File

@@ -243,13 +243,29 @@ class MobileRepositorySwitcherTest : SysuiTestCase() {
private val IMMEDIATE = Dispatchers.Main.immediate
private const val SUB_1_ID = 1
private const val SUB_1_NAME = "Carrier $SUB_1_ID"
private val SUB_1 =
mock<SubscriptionInfo>().also { whenever(it.subscriptionId).thenReturn(SUB_1_ID) }
private val MODEL_1 = SubscriptionModel(subscriptionId = SUB_1_ID)
mock<SubscriptionInfo>().also {
whenever(it.subscriptionId).thenReturn(SUB_1_ID)
whenever(it.carrierName).thenReturn(SUB_1_NAME)
}
private val MODEL_1 =
SubscriptionModel(
subscriptionId = SUB_1_ID,
carrierName = SUB_1_NAME,
)
private const val SUB_2_ID = 2
private const val SUB_2_NAME = "Carrier $SUB_2_ID"
private val SUB_2 =
mock<SubscriptionInfo>().also { whenever(it.subscriptionId).thenReturn(SUB_2_ID) }
private val MODEL_2 = SubscriptionModel(subscriptionId = SUB_2_ID)
mock<SubscriptionInfo>().also {
whenever(it.subscriptionId).thenReturn(SUB_2_ID)
whenever(it.carrierName).thenReturn(SUB_2_NAME)
}
private val MODEL_2 =
SubscriptionModel(
subscriptionId = SUB_2_ID,
carrierName = SUB_2_NAME,
)
}
}

View File

@@ -38,7 +38,6 @@ import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.Job
import kotlinx.coroutines.cancel
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.collect
import kotlinx.coroutines.launch
import kotlinx.coroutines.test.TestScope
import kotlinx.coroutines.test.UnconfinedTestDispatcher
@@ -140,6 +139,7 @@ internal class DemoMobileConnectionParameterizedTest(private val testCase: TestC
launch { conn.carrierNetworkChangeActive.collect {} }
launch { conn.isRoaming.collect {} }
launch { conn.networkName.collect {} }
launch { conn.carrierName.collect {} }
launch { conn.isEmergencyOnly.collect {} }
launch { conn.dataConnectionState.collect {} }
}
@@ -163,6 +163,8 @@ internal class DemoMobileConnectionParameterizedTest(private val testCase: TestC
assertThat(conn.isRoaming.value).isEqualTo(model.roaming)
assertThat(conn.networkName.value)
.isEqualTo(NetworkNameModel.IntentDerived(model.name))
assertThat(conn.carrierName.value)
.isEqualTo(NetworkNameModel.SubscriptionDerived("${model.name} ${model.subId}"))
// TODO(b/261029387): check these once we start handling them
assertThat(conn.isEmergencyOnly.value).isFalse()

View File

@@ -546,6 +546,7 @@ class DemoMobileConnectionsRepositoryTest : SysuiTestCase() {
launch { conn.carrierNetworkChangeActive.collect {} }
launch { conn.isRoaming.collect {} }
launch { conn.networkName.collect {} }
launch { conn.carrierName.collect {} }
launch { conn.isEmergencyOnly.collect {} }
launch { conn.dataConnectionState.collect {} }
}
@@ -571,6 +572,8 @@ class DemoMobileConnectionsRepositoryTest : SysuiTestCase() {
assertThat(conn.isRoaming.value).isEqualTo(model.roaming)
assertThat(conn.networkName.value)
.isEqualTo(NetworkNameModel.IntentDerived(model.name))
assertThat(conn.carrierName.value)
.isEqualTo(NetworkNameModel.SubscriptionDerived("${model.name} ${model.subId}"))
// TODO(b/261029387) check these once we start handling them
assertThat(conn.isEmergencyOnly.value).isFalse()

View File

@@ -26,6 +26,7 @@ import com.android.systemui.coroutines.collectLastValue
import com.android.systemui.log.table.TableLogBuffer
import com.android.systemui.log.table.TableLogBufferFactory
import com.android.systemui.statusbar.pipeline.mobile.data.model.NetworkNameModel
import com.android.systemui.statusbar.pipeline.mobile.data.model.SubscriptionModel
import com.android.systemui.statusbar.pipeline.mobile.data.repository.FakeMobileConnectionRepository
import com.android.systemui.statusbar.pipeline.mobile.data.repository.MobileConnectionRepository
import com.android.systemui.statusbar.pipeline.mobile.data.repository.prod.FullMobileConnectionRepository.Companion.COL_EMERGENCY
@@ -43,6 +44,7 @@ import com.google.common.truth.Truth.assertThat
import java.io.PrintWriter
import java.io.StringWriter
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.onEach
import kotlinx.coroutines.test.TestScope
@@ -79,28 +81,51 @@ class FullMobileConnectionRepositoryTest : SysuiTestCase() {
private val mobileFactory = mock<MobileConnectionRepositoryImpl.Factory>()
private val carrierMergedFactory = mock<CarrierMergedConnectionRepository.Factory>()
private val subscriptionModel =
MutableStateFlow(
SubscriptionModel(
subscriptionId = SUB_ID,
carrierName = DEFAULT_NAME,
)
)
private lateinit var mobileRepo: FakeMobileConnectionRepository
private lateinit var carrierMergedRepo: FakeMobileConnectionRepository
@Before
fun setUp() {
mobileRepo = FakeMobileConnectionRepository(SUB_ID, tableLogBuffer)
mobileRepo =
FakeMobileConnectionRepository(
SUB_ID,
tableLogBuffer,
)
carrierMergedRepo =
FakeMobileConnectionRepository(SUB_ID, tableLogBuffer).apply {
// Mimicks the real carrier merged repository
this.isAllowedDuringAirplaneMode.value = true
}
FakeMobileConnectionRepository(
SUB_ID,
tableLogBuffer,
)
.apply {
// Mimicks the real carrier merged repository
this.isAllowedDuringAirplaneMode.value = true
}
whenever(
mobileFactory.build(
eq(SUB_ID),
any(),
eq(DEFAULT_NAME),
any(),
eq(DEFAULT_NAME_MODEL),
eq(SEP),
)
)
.thenReturn(mobileRepo)
whenever(carrierMergedFactory.build(eq(SUB_ID), any())).thenReturn(carrierMergedRepo)
whenever(
carrierMergedFactory.build(
eq(SUB_ID),
any(),
)
)
.thenReturn(carrierMergedRepo)
}
@Test
@@ -120,7 +145,8 @@ class FullMobileConnectionRepositoryTest : SysuiTestCase() {
.build(
SUB_ID,
tableLogBuffer,
DEFAULT_NAME,
subscriptionModel,
DEFAULT_NAME_MODEL,
SEP,
)
}
@@ -138,7 +164,11 @@ class FullMobileConnectionRepositoryTest : SysuiTestCase() {
assertThat(underTest.activeRepo.value).isEqualTo(mobileRepo)
assertThat(underTest.operatorAlphaShort.value).isEqualTo(nonCarrierMergedName)
verify(carrierMergedFactory, never()).build(SUB_ID, tableLogBuffer)
verify(carrierMergedFactory, never())
.build(
SUB_ID,
tableLogBuffer,
)
}
@Test
@@ -348,7 +378,8 @@ class FullMobileConnectionRepositoryTest : SysuiTestCase() {
factory.build(
SUB_ID,
startingIsCarrierMerged = false,
DEFAULT_NAME,
subscriptionModel,
DEFAULT_NAME_MODEL,
SEP,
)
@@ -356,7 +387,8 @@ class FullMobileConnectionRepositoryTest : SysuiTestCase() {
factory.build(
SUB_ID,
startingIsCarrierMerged = false,
DEFAULT_NAME,
subscriptionModel,
DEFAULT_NAME_MODEL,
SEP,
)
@@ -388,7 +420,8 @@ class FullMobileConnectionRepositoryTest : SysuiTestCase() {
factory.build(
SUB_ID,
startingIsCarrierMerged = false,
DEFAULT_NAME,
subscriptionModel,
DEFAULT_NAME_MODEL,
SEP,
)
@@ -397,7 +430,8 @@ class FullMobileConnectionRepositoryTest : SysuiTestCase() {
factory.build(
SUB_ID,
startingIsCarrierMerged = true,
DEFAULT_NAME,
subscriptionModel,
DEFAULT_NAME_MODEL,
SEP,
)
@@ -623,7 +657,8 @@ class FullMobileConnectionRepositoryTest : SysuiTestCase() {
SUB_ID,
startingIsCarrierMerged,
tableLogBuffer,
DEFAULT_NAME,
subscriptionModel,
DEFAULT_NAME_MODEL,
SEP,
testScope.backgroundScope,
mobileFactory,
@@ -639,8 +674,9 @@ class FullMobileConnectionRepositoryTest : SysuiTestCase() {
val realRepo =
MobileConnectionRepositoryImpl(
SUB_ID,
defaultNetworkName = NetworkNameModel.Default("default"),
networkNameSeparator = SEP,
subscriptionModel,
DEFAULT_NAME_MODEL,
SEP,
telephonyManager,
systemUiCarrierConfig = mock(),
fakeBroadcastDispatcher,
@@ -654,7 +690,8 @@ class FullMobileConnectionRepositoryTest : SysuiTestCase() {
mobileFactory.build(
eq(SUB_ID),
any(),
eq(DEFAULT_NAME),
any(),
eq(DEFAULT_NAME_MODEL),
eq(SEP),
)
)
@@ -677,7 +714,13 @@ class FullMobileConnectionRepositoryTest : SysuiTestCase() {
testScope.backgroundScope,
wifiRepository,
)
whenever(carrierMergedFactory.build(eq(SUB_ID), any())).thenReturn(realRepo)
whenever(
carrierMergedFactory.build(
eq(SUB_ID),
any(),
)
)
.thenReturn(realRepo)
return realRepo
}
@@ -690,7 +733,8 @@ class FullMobileConnectionRepositoryTest : SysuiTestCase() {
private companion object {
const val SUB_ID = 42
private val DEFAULT_NAME = NetworkNameModel.Default("default name")
private val DEFAULT_NAME = "default name"
private val DEFAULT_NAME_MODEL = NetworkNameModel.Default(DEFAULT_NAME)
private const val SEP = "-"
private const val BUFFER_SEPARATOR = "|"
}

View File

@@ -62,6 +62,7 @@ import com.android.systemui.statusbar.pipeline.mobile.data.model.ResolvedNetwork
import com.android.systemui.statusbar.pipeline.mobile.data.model.ResolvedNetworkType.DefaultNetworkType
import com.android.systemui.statusbar.pipeline.mobile.data.model.ResolvedNetworkType.OverrideNetworkType
import com.android.systemui.statusbar.pipeline.mobile.data.model.ResolvedNetworkType.UnknownNetworkType
import com.android.systemui.statusbar.pipeline.mobile.data.model.SubscriptionModel
import com.android.systemui.statusbar.pipeline.mobile.data.model.SystemUiCarrierConfig
import com.android.systemui.statusbar.pipeline.mobile.data.model.SystemUiCarrierConfigTest.Companion.configWithOverride
import com.android.systemui.statusbar.pipeline.mobile.data.model.SystemUiCarrierConfigTest.Companion.createTestConfig
@@ -78,6 +79,7 @@ import com.android.systemui.util.mockito.mock
import com.android.systemui.util.mockito.whenever
import com.google.common.truth.Truth.assertThat
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.onEach
import kotlinx.coroutines.test.TestScope
@@ -109,6 +111,14 @@ class MobileConnectionRepositoryTest : SysuiTestCase() {
private val testDispatcher = UnconfinedTestDispatcher()
private val testScope = TestScope(testDispatcher)
private val subscriptionModel: MutableStateFlow<SubscriptionModel?> =
MutableStateFlow(
SubscriptionModel(
subscriptionId = SUB_1_ID,
carrierName = DEFAULT_NAME,
)
)
@Before
fun setUp() {
MockitoAnnotations.initMocks(this)
@@ -119,7 +129,8 @@ class MobileConnectionRepositoryTest : SysuiTestCase() {
underTest =
MobileConnectionRepositoryImpl(
SUB_1_ID,
DEFAULT_NAME,
subscriptionModel,
DEFAULT_NAME_MODEL,
SEP,
telephonyManager,
systemUiCarrierConfig,
@@ -179,6 +190,7 @@ class MobileConnectionRepositoryTest : SysuiTestCase() {
// gsmLevel updates, no change to cdmaLevel
strength = signalStrength(gsmLevel = 3, cdmaLevel = 2, isGsm = true)
callback.onSignalStrengthsChanged(strength)
assertThat(latest).isEqualTo(2)
@@ -637,13 +649,52 @@ class MobileConnectionRepositoryTest : SysuiTestCase() {
job.cancel()
}
@Test
fun networkNameForSubId_updates() =
testScope.runTest {
var latest: NetworkNameModel? = null
val job = underTest.carrierName.onEach { latest = it }.launchIn(this)
subscriptionModel.value =
SubscriptionModel(
subscriptionId = SUB_1_ID,
carrierName = DEFAULT_NAME,
)
assertThat(latest?.name).isEqualTo(DEFAULT_NAME)
val updatedName = "Derived Carrier"
subscriptionModel.value =
SubscriptionModel(
subscriptionId = SUB_1_ID,
carrierName = updatedName,
)
assertThat(latest?.name).isEqualTo(updatedName)
job.cancel()
}
@Test
fun networkNameForSubId_defaultWhenSubscriptionModelNull() =
testScope.runTest {
var latest: NetworkNameModel? = null
val job = underTest.carrierName.onEach { latest = it }.launchIn(this)
subscriptionModel.value = null
assertThat(latest?.name).isEqualTo(DEFAULT_NAME)
job.cancel()
}
@Test
fun networkName_default() =
testScope.runTest {
var latest: NetworkNameModel? = null
val job = underTest.networkName.onEach { latest = it }.launchIn(this)
assertThat(latest).isEqualTo(DEFAULT_NAME)
assertThat(latest).isEqualTo(DEFAULT_NAME_MODEL)
job.cancel()
}
@@ -701,7 +752,7 @@ class MobileConnectionRepositoryTest : SysuiTestCase() {
fakeBroadcastDispatcher.sendIntentToMatchingReceiversOnly(context, intentWithoutInfo)
assertThat(latest).isEqualTo(DEFAULT_NAME)
assertThat(latest).isEqualTo(DEFAULT_NAME_MODEL)
job.cancel()
}
@@ -852,8 +903,9 @@ class MobileConnectionRepositoryTest : SysuiTestCase() {
companion object {
private const val SUB_1_ID = 1
private val DEFAULT_NAME = NetworkNameModel.Default("default name")
private const val SEP = "-"
private val DEFAULT_NAME = "Fake Mobile Network"
private val DEFAULT_NAME_MODEL = NetworkNameModel.Default(DEFAULT_NAME)
private val SEP = "-"
private const val SPN = "testSpn"
private const val PLMN = "testPlmn"

View File

@@ -36,6 +36,7 @@ import com.android.systemui.statusbar.pipeline.mobile.data.MobileInputLogger
import com.android.systemui.statusbar.pipeline.mobile.data.model.DataConnectionState
import com.android.systemui.statusbar.pipeline.mobile.data.model.NetworkNameModel
import com.android.systemui.statusbar.pipeline.mobile.data.model.ResolvedNetworkType
import com.android.systemui.statusbar.pipeline.mobile.data.model.SubscriptionModel
import com.android.systemui.statusbar.pipeline.mobile.data.model.SystemUiCarrierConfig
import com.android.systemui.statusbar.pipeline.mobile.data.model.SystemUiCarrierConfigTest
import com.android.systemui.statusbar.pipeline.mobile.data.repository.FakeMobileConnectionsRepository
@@ -47,6 +48,7 @@ import com.android.systemui.util.mockito.mock
import com.android.systemui.util.mockito.whenever
import com.google.common.truth.Truth.assertThat
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.onEach
import kotlinx.coroutines.test.TestScope
@@ -97,6 +99,7 @@ class MobileConnectionTelephonySmokeTests : SysuiTestCase() {
@Mock private lateinit var telephonyManager: TelephonyManager
@Mock private lateinit var logger: MobileInputLogger
@Mock private lateinit var tableLogger: TableLogBuffer
@Mock private lateinit var subscriptionModel: StateFlow<SubscriptionModel?>
private val mobileMappings = FakeMobileMappingsProxy()
private val systemUiCarrierConfig =
@@ -113,11 +116,16 @@ class MobileConnectionTelephonySmokeTests : SysuiTestCase() {
MockitoAnnotations.initMocks(this)
whenever(telephonyManager.subscriptionId).thenReturn(SUB_1_ID)
connectionsRepo = FakeMobileConnectionsRepository(mobileMappings, tableLogger)
connectionsRepo =
FakeMobileConnectionsRepository(
mobileMappings,
tableLogger,
)
underTest =
MobileConnectionRepositoryImpl(
SUB_1_ID,
subscriptionModel,
DEFAULT_NAME,
SEP,
telephonyManager,

View File

@@ -1190,30 +1190,36 @@ class MobileConnectionsRepositoryTest : SysuiTestCase() {
companion object {
// Subscription 1
private const val SUB_1_ID = 1
private const val SUB_1_NAME = "Carrier $SUB_1_ID"
private val GROUP_1 = ParcelUuid(UUID.randomUUID())
private val SUB_1 =
mock<SubscriptionInfo>().also {
whenever(it.subscriptionId).thenReturn(SUB_1_ID)
whenever(it.groupUuid).thenReturn(GROUP_1)
whenever(it.carrierName).thenReturn(SUB_1_NAME)
}
private val MODEL_1 =
SubscriptionModel(
subscriptionId = SUB_1_ID,
groupUuid = GROUP_1,
carrierName = SUB_1_NAME,
)
// Subscription 2
private const val SUB_2_ID = 2
private const val SUB_2_NAME = "Carrier $SUB_2_ID"
private val GROUP_2 = ParcelUuid(UUID.randomUUID())
private val SUB_2 =
mock<SubscriptionInfo>().also {
whenever(it.subscriptionId).thenReturn(SUB_2_ID)
whenever(it.groupUuid).thenReturn(GROUP_2)
whenever(it.carrierName).thenReturn(SUB_2_NAME)
}
private val MODEL_2 =
SubscriptionModel(
subscriptionId = SUB_2_ID,
groupUuid = GROUP_2,
carrierName = SUB_2_NAME,
)
// Subs 3 and 4 are considered to be in the same group ------------------------------------
@@ -1242,9 +1248,14 @@ class MobileConnectionsRepositoryTest : SysuiTestCase() {
// Carrier merged subscription
private const val SUB_CM_ID = 5
private const val SUB_CM_NAME = "Carrier $SUB_CM_ID"
private val SUB_CM =
mock<SubscriptionInfo>().also { whenever(it.subscriptionId).thenReturn(SUB_CM_ID) }
private val MODEL_CM = SubscriptionModel(subscriptionId = SUB_CM_ID)
mock<SubscriptionInfo>().also {
whenever(it.subscriptionId).thenReturn(SUB_CM_ID)
whenever(it.carrierName).thenReturn(SUB_CM_NAME)
}
private val MODEL_CM =
SubscriptionModel(subscriptionId = SUB_CM_ID, carrierName = SUB_CM_NAME)
private val WIFI_INFO_CM =
mock<WifiInfo>().apply {

View File

@@ -44,6 +44,8 @@ class FakeMobileIconInteractor(
override val mobileIsDefault = MutableStateFlow(true)
override val isSingleCarrier = MutableStateFlow(true)
override val networkTypeIconGroup =
MutableStateFlow<NetworkTypeIconModel>(
NetworkTypeIconModel.DefaultIcon(TelephonyIcons.THREE_G)
@@ -51,6 +53,8 @@ class FakeMobileIconInteractor(
override val networkName = MutableStateFlow(NetworkNameModel.IntentDerived("demo mode"))
override val carrierName = MutableStateFlow("demo mode")
private val _isEmergencyOnly = MutableStateFlow(false)
override val isEmergencyOnly = _isEmergencyOnly

View File

@@ -64,6 +64,8 @@ class FakeMobileIconsInteractor(
override val mobileIsDefault = MutableStateFlow(false)
override val isSingleCarrier = MutableStateFlow(true)
private val _defaultMobileIconMapping = MutableStateFlow(TEST_MAPPING)
override val defaultMobileIconMapping = _defaultMobileIconMapping

View File

@@ -29,6 +29,7 @@ import com.android.systemui.statusbar.pipeline.mobile.data.model.NetworkNameMode
import com.android.systemui.statusbar.pipeline.mobile.data.model.ResolvedNetworkType.CarrierMergedNetworkType
import com.android.systemui.statusbar.pipeline.mobile.data.model.ResolvedNetworkType.DefaultNetworkType
import com.android.systemui.statusbar.pipeline.mobile.data.model.ResolvedNetworkType.OverrideNetworkType
import com.android.systemui.statusbar.pipeline.mobile.data.model.SubscriptionModel
import com.android.systemui.statusbar.pipeline.mobile.data.repository.FakeMobileConnectionRepository
import com.android.systemui.statusbar.pipeline.mobile.domain.interactor.FakeMobileIconsInteractor.Companion.FIVE_G_OVERRIDE
import com.android.systemui.statusbar.pipeline.mobile.domain.interactor.FakeMobileIconsInteractor.Companion.FOUR_G
@@ -40,6 +41,7 @@ import com.android.systemui.util.mockito.mock
import com.android.systemui.util.mockito.whenever
import com.google.common.truth.Truth.assertThat
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.onEach
import kotlinx.coroutines.test.TestScope
@@ -56,6 +58,15 @@ class MobileIconInteractorTest : SysuiTestCase() {
private lateinit var underTest: MobileIconInteractor
private val mobileMappingsProxy = FakeMobileMappingsProxy()
private val mobileIconsInteractor = FakeMobileIconsInteractor(mobileMappingsProxy, mock())
private val subscriptionModel =
MutableStateFlow(
SubscriptionModel(
subscriptionId = SUB_1_ID,
carrierName = DEFAULT_NAME,
)
)
private val connectionRepository = FakeMobileConnectionRepository(SUB_1_ID, mock())
private val testDispatcher = UnconfinedTestDispatcher()
@@ -432,7 +443,7 @@ class MobileIconInteractorTest : SysuiTestCase() {
}
@Test
fun networkName_usesOperatorAlphaShotWhenNonNullAndRepoIsDefault() =
fun networkName_usesOperatorAlphaShortWhenNonNullAndRepoIsDefault() =
testScope.runTest {
var latest: NetworkNameModel? = null
val job = underTest.networkName.onEach { latest = it }.launchIn(this)
@@ -440,7 +451,7 @@ class MobileIconInteractorTest : SysuiTestCase() {
val testOperatorName = "operatorAlphaShort"
// Default network name, operator name is non-null, uses the operator name
connectionRepository.networkName.value = DEFAULT_NAME
connectionRepository.networkName.value = DEFAULT_NAME_MODEL
connectionRepository.operatorAlphaShort.value = testOperatorName
assertThat(latest).isEqualTo(NetworkNameModel.IntentDerived(testOperatorName))
@@ -448,10 +459,39 @@ class MobileIconInteractorTest : SysuiTestCase() {
// Default network name, operator name is null, uses the default
connectionRepository.operatorAlphaShort.value = null
assertThat(latest).isEqualTo(DEFAULT_NAME_MODEL)
// Derived network name, operator name non-null, uses the derived name
connectionRepository.networkName.value = DERIVED_NAME_MODEL
connectionRepository.operatorAlphaShort.value = testOperatorName
assertThat(latest).isEqualTo(DERIVED_NAME_MODEL)
job.cancel()
}
@Test
fun networkNameForSubId_usesOperatorAlphaShortWhenNonNullAndRepoIsDefault() =
testScope.runTest {
var latest: String? = null
val job = underTest.carrierName.onEach { latest = it }.launchIn(this)
val testOperatorName = "operatorAlphaShort"
// Default network name, operator name is non-null, uses the operator name
connectionRepository.carrierName.value = DEFAULT_NAME_MODEL
connectionRepository.operatorAlphaShort.value = testOperatorName
assertThat(latest).isEqualTo(testOperatorName)
// Default network name, operator name is null, uses the default
connectionRepository.operatorAlphaShort.value = null
assertThat(latest).isEqualTo(DEFAULT_NAME)
// Derived network name, operator name non-null, uses the derived name
connectionRepository.networkName.value = DERIVED_NAME
connectionRepository.carrierName.value =
NetworkNameModel.SubscriptionDerived(DERIVED_NAME)
connectionRepository.operatorAlphaShort.value = testOperatorName
assertThat(latest).isEqualTo(DERIVED_NAME)
@@ -459,6 +499,21 @@ class MobileIconInteractorTest : SysuiTestCase() {
job.cancel()
}
@Test
fun isSingleCarrier_matchesParent() =
testScope.runTest {
var latest: Boolean? = null
val job = underTest.isSingleCarrier.onEach { latest = it }.launchIn(this)
mobileIconsInteractor.isSingleCarrier.value = true
assertThat(latest).isTrue()
mobileIconsInteractor.isSingleCarrier.value = false
assertThat(latest).isFalse()
job.cancel()
}
@Test
fun isForceHidden_matchesParent() =
testScope.runTest {
@@ -494,6 +549,7 @@ class MobileIconInteractorTest : SysuiTestCase() {
mobileIconsInteractor.activeDataConnectionHasDataEnabled,
mobileIconsInteractor.alwaysShowDataRatIcon,
mobileIconsInteractor.alwaysUseCdmaLevel,
mobileIconsInteractor.isSingleCarrier,
mobileIconsInteractor.mobileIsDefault,
mobileIconsInteractor.defaultMobileIconMapping,
mobileIconsInteractor.defaultMobileIconGroup,
@@ -510,7 +566,9 @@ class MobileIconInteractorTest : SysuiTestCase() {
private const val SUB_1_ID = 1
private val DEFAULT_NAME = NetworkNameModel.Default("test default name")
private val DERIVED_NAME = NetworkNameModel.IntentDerived("test derived name")
private val DEFAULT_NAME = "test default name"
private val DEFAULT_NAME_MODEL = NetworkNameModel.Default(DEFAULT_NAME)
private val DERIVED_NAME = "test derived name"
private val DERIVED_NAME_MODEL = NetworkNameModel.IntentDerived(DERIVED_NAME)
}
}

View File

@@ -526,6 +526,57 @@ class MobileIconsInteractorTest : SysuiTestCase() {
job.cancel()
}
@Test
fun isSingleCarrier_zeroSubscriptions_false() =
testScope.runTest {
var latest: Boolean? = true
val job = underTest.isSingleCarrier.onEach { latest = it }.launchIn(this)
connectionsRepository.setSubscriptions(emptyList())
assertThat(latest).isFalse()
job.cancel()
}
@Test
fun isSingleCarrier_oneSubscription_true() =
testScope.runTest {
var latest: Boolean? = false
val job = underTest.isSingleCarrier.onEach { latest = it }.launchIn(this)
connectionsRepository.setSubscriptions(listOf(SUB_1))
assertThat(latest).isTrue()
job.cancel()
}
@Test
fun isSingleCarrier_twoSubscriptions_false() =
testScope.runTest {
var latest: Boolean? = true
val job = underTest.isSingleCarrier.onEach { latest = it }.launchIn(this)
connectionsRepository.setSubscriptions(listOf(SUB_1, SUB_2))
assertThat(latest).isFalse()
job.cancel()
}
@Test
fun isSingleCarrier_updates() =
testScope.runTest {
var latest: Boolean? = false
val job = underTest.isSingleCarrier.onEach { latest = it }.launchIn(this)
connectionsRepository.setSubscriptions(listOf(SUB_1))
assertThat(latest).isTrue()
connectionsRepository.setSubscriptions(listOf(SUB_1, SUB_2))
assertThat(latest).isFalse()
job.cancel()
}
@Test
fun mobileIsDefault_mobileFalseAndCarrierMergedFalse_false() =
testScope.runTest {
@@ -745,6 +796,7 @@ class MobileIconsInteractorTest : SysuiTestCase() {
subscriptionId = subscriptionIds.first,
isOpportunistic = opportunistic.first,
groupUuid = groupUuid,
carrierName = "Carrier ${subscriptionIds.first}"
)
val sub2 =
@@ -752,6 +804,7 @@ class MobileIconsInteractorTest : SysuiTestCase() {
subscriptionId = subscriptionIds.second,
isOpportunistic = opportunistic.second,
groupUuid = groupUuid,
carrierName = "Carrier ${opportunistic.second}"
)
return Pair(sub1, sub2)
@@ -760,11 +813,13 @@ class MobileIconsInteractorTest : SysuiTestCase() {
companion object {
private const val SUB_1_ID = 1
private val SUB_1 = SubscriptionModel(subscriptionId = SUB_1_ID)
private val SUB_1 =
SubscriptionModel(subscriptionId = SUB_1_ID, carrierName = "Carrier $SUB_1_ID")
private val CONNECTION_1 = FakeMobileConnectionRepository(SUB_1_ID, mock())
private const val SUB_2_ID = 2
private val SUB_2 = SubscriptionModel(subscriptionId = SUB_2_ID)
private val SUB_2 =
SubscriptionModel(subscriptionId = SUB_2_ID, carrierName = "Carrier $SUB_2_ID")
private val CONNECTION_2 = FakeMobileConnectionRepository(SUB_2_ID, mock())
private const val SUB_3_ID = 3
@@ -773,6 +828,7 @@ class MobileIconsInteractorTest : SysuiTestCase() {
subscriptionId = SUB_3_ID,
isOpportunistic = true,
groupUuid = ParcelUuid(UUID.randomUUID()),
carrierName = "Carrier $SUB_3_ID"
)
private val CONNECTION_3 = FakeMobileConnectionRepository(SUB_3_ID, mock())
@@ -782,6 +838,7 @@ class MobileIconsInteractorTest : SysuiTestCase() {
subscriptionId = SUB_4_ID,
isOpportunistic = true,
groupUuid = ParcelUuid(UUID.randomUUID()),
carrierName = "Carrier $SUB_4_ID"
)
private val CONNECTION_4 = FakeMobileConnectionRepository(SUB_4_ID, mock())
}

View File

@@ -92,15 +92,31 @@ class MobileIconsViewModelTest : SysuiTestCase() {
interactor.filteredSubscriptions.value =
listOf(
SubscriptionModel(subscriptionId = 1, isOpportunistic = false),
SubscriptionModel(
subscriptionId = 1,
isOpportunistic = false,
carrierName = "Carrier 1",
),
)
assertThat(latest).isEqualTo(listOf(1))
interactor.filteredSubscriptions.value =
listOf(
SubscriptionModel(subscriptionId = 2, isOpportunistic = false),
SubscriptionModel(subscriptionId = 5, isOpportunistic = true),
SubscriptionModel(subscriptionId = 7, isOpportunistic = true),
SubscriptionModel(
subscriptionId = 2,
isOpportunistic = false,
carrierName = "Carrier 2",
),
SubscriptionModel(
subscriptionId = 5,
isOpportunistic = true,
carrierName = "Carrier 5",
),
SubscriptionModel(
subscriptionId = 7,
isOpportunistic = true,
carrierName = "Carrier 7",
),
)
assertThat(latest).isEqualTo(listOf(2, 5, 7))
@@ -308,8 +324,23 @@ class MobileIconsViewModelTest : SysuiTestCase() {
}
companion object {
private val SUB_1 = SubscriptionModel(subscriptionId = 1, isOpportunistic = false)
private val SUB_2 = SubscriptionModel(subscriptionId = 2, isOpportunistic = false)
private val SUB_3 = SubscriptionModel(subscriptionId = 3, isOpportunistic = false)
private val SUB_1 =
SubscriptionModel(
subscriptionId = 1,
isOpportunistic = false,
carrierName = "Carrier 1",
)
private val SUB_2 =
SubscriptionModel(
subscriptionId = 2,
isOpportunistic = false,
carrierName = "Carrier 2",
)
private val SUB_3 =
SubscriptionModel(
subscriptionId = 3,
isOpportunistic = false,
carrierName = "Carrier 3",
)
}
}