[Sb refactor] Support NetworkName in new mobile pipeline

The network name can come from one of 3 places:
1. TelephonyManager.ACTION_SERVICE_PROVIDERS_UPDATED, which passes an
   intent containing a network name which we can derive
2. ServiceState.getOperatorAlphaShort(), from the service state changed
   telephony callback
3. A default value, set in the framework config
   `lockscreen_carrier_default`

Based on the implementation that currently lives in
`MobileSignalController`, we were only using `NetworkName` a.k.a.
`EXTRA_SPN`, and not `NetworkNameData` a.k.a. `EXTRA_DATA_SPN`.
Therefore this CL only adds support for the former.

The front end does not consume this piece of data yet, since it is only
needed for QuickSettings. Future CLs will add support for a
LocationBasedMobileViewModel (similar to Wi-Fi), which can then start
consuming the values.

Test: MobileConnectionRepositoryTest
Test: DemoMobileConnectionsRepositoryTest
Test: MobileIconInteractorTest
Bug: 238425913
Change-Id: I04fa90bf7b52aa992f9721c7301f541f6085cf68
This commit is contained in:
Evan Laird
2022-12-08 15:58:31 -05:00
parent 0fb69e956b
commit 6acee7b1ee
16 changed files with 318 additions and 9 deletions

View File

@@ -39,33 +39,42 @@ import com.android.systemui.statusbar.pipeline.shared.data.model.DataActivityMod
* threading complex system objects through the pipeline.
*/
data class MobileConnectionModel(
/** From [ServiceStateListener.onServiceStateChanged] */
/** Fields below are from [ServiceStateListener.onServiceStateChanged] */
val isEmergencyOnly: Boolean = false,
val isRoaming: Boolean = false,
/**
* See [android.telephony.ServiceState.getOperatorAlphaShort], this value is defined as the
* current registered operator name in short alphanumeric format. In some cases this name might
* be preferred over other methods of calculating the network name
*/
val operatorAlphaShort: String? = null,
/** From [SignalStrengthsListener.onSignalStrengthsChanged] */
/** Fields below from [SignalStrengthsListener.onSignalStrengthsChanged] */
val isGsm: Boolean = false,
@IntRange(from = 0, to = 4)
val cdmaLevel: Int = CellSignalStrength.SIGNAL_STRENGTH_NONE_OR_UNKNOWN,
@IntRange(from = 0, to = 4)
val primaryLevel: Int = CellSignalStrength.SIGNAL_STRENGTH_NONE_OR_UNKNOWN,
/** Mapped from [DataConnectionStateListener.onDataConnectionStateChanged] */
/** Fields below from [DataConnectionStateListener.onDataConnectionStateChanged] */
val dataConnectionState: DataConnectionState = Disconnected,
/** From [DataActivityListener.onDataActivity]. See [TelephonyManager] for the values */
/**
* Fields below from [DataActivityListener.onDataActivity]. See [TelephonyManager] for the
* values
*/
val dataActivityDirection: DataActivityModel =
DataActivityModel(
hasActivityIn = false,
hasActivityOut = false,
),
/** From [CarrierNetworkListener.onCarrierNetworkChange] */
/** Fields below from [CarrierNetworkListener.onCarrierNetworkChange] */
val carrierNetworkChangeActive: Boolean = false,
/** Fields below from [DisplayInfoListener.onDisplayInfoChanged]. */
/**
* From [DisplayInfoListener.onDisplayInfoChanged].
*
* [resolvedNetworkType] is the [TelephonyDisplayInfo.getOverrideNetworkType] if it exists or
* [TelephonyDisplayInfo.getNetworkType]. This is used to look up the proper network type icon
*/

View File

@@ -0,0 +1,62 @@
/*
* Copyright (C) 2022 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.systemui.statusbar.pipeline.mobile.data.model
import android.content.Intent
import android.telephony.TelephonyManager.EXTRA_DATA_SPN
import android.telephony.TelephonyManager.EXTRA_PLMN
import android.telephony.TelephonyManager.EXTRA_SHOW_PLMN
import android.telephony.TelephonyManager.EXTRA_SHOW_SPN
/**
* Encapsulates the data needed to show a network name for a mobile network. The data is parsed from
* the intent sent by [android.telephony.TelephonyManager.ACTION_SERVICE_PROVIDERS_UPDATED].
*/
sealed interface NetworkNameModel {
val name: String
/** The default name is read from [com.android.internal.R.string.lockscreen_carrier_default] */
data class Default(override val name: String) : NetworkNameModel
/**
* This name has been derived from telephony intents. see
* [android.telephony.TelephonyManager.ACTION_SERVICE_PROVIDERS_UPDATED]
*/
data class Derived(override val name: String) : NetworkNameModel
}
fun Intent.toNetworkNameModel(separator: String): NetworkNameModel? {
val showSpn = getBooleanExtra(EXTRA_SHOW_SPN, false)
val spn = getStringExtra(EXTRA_DATA_SPN)
val showPlmn = getBooleanExtra(EXTRA_SHOW_PLMN, false)
val plmn = getStringExtra(EXTRA_PLMN)
val str = StringBuilder()
val strData = StringBuilder()
if (showPlmn && plmn != null) {
str.append(plmn)
strData.append(plmn)
}
if (showSpn && spn != null) {
if (str.isNotEmpty()) {
str.append(separator)
}
str.append(spn)
}
return if (str.isNotEmpty()) NetworkNameModel.Derived(str.toString()) else null
}

View File

@@ -21,6 +21,7 @@ import android.telephony.SubscriptionManager
import android.telephony.TelephonyCallback
import android.telephony.TelephonyManager
import com.android.systemui.statusbar.pipeline.mobile.data.model.MobileConnectionModel
import com.android.systemui.statusbar.pipeline.mobile.data.model.NetworkNameModel
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.StateFlow
@@ -58,4 +59,7 @@ interface MobileConnectionRepository {
* True if the Enhanced Roaming Indicator (ERI) display number is not [TelephonyManager.ERI_OFF]
*/
val cdmaRoaming: StateFlow<Boolean>
/** The service provider name for this network connection, or the default name */
val networkName: StateFlow<NetworkNameModel>
}

View File

@@ -27,6 +27,7 @@ import com.android.systemui.dagger.qualifiers.Application
import com.android.systemui.statusbar.pipeline.mobile.data.model.DataConnectionState
import com.android.systemui.statusbar.pipeline.mobile.data.model.MobileConnectionModel
import com.android.systemui.statusbar.pipeline.mobile.data.model.MobileConnectivityModel
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.ResolvedNetworkType.DefaultNetworkType
import com.android.systemui.statusbar.pipeline.mobile.data.model.SubscriptionModel
@@ -187,6 +188,7 @@ constructor(
// This is always true here, because we split out disabled states at the data-source level
connection.dataEnabled.value = true
connection.isDefaultDataSubscription.value = state.dataType != null
connection.networkName.value = NetworkNameModel.Derived(state.name)
connection.cdmaRoaming.value = state.roaming
connection.connectionInfo.value = state.toMobileConnectionModel()
@@ -266,4 +268,6 @@ class DemoMobileConnectionRepository(override val subId: Int) : MobileConnection
override val isDefaultDataSubscription = MutableStateFlow(true)
override val cdmaRoaming = MutableStateFlow(false)
override val networkName = MutableStateFlow(NetworkNameModel.Derived("demo network"))
}

View File

@@ -99,6 +99,7 @@ constructor(
val activity = getString("activity")?.toActivity()
val carrierNetworkChange = getString("carriernetworkchange") == "show"
val roaming = getString("roam") == "show"
val name = getString("networkname") ?: "demo mode"
return Mobile(
level = level,
@@ -109,6 +110,7 @@ constructor(
activity = activity,
carrierNetworkChange = carrierNetworkChange,
roaming = roaming,
name = name,
)
}
}

View File

@@ -35,6 +35,7 @@ sealed interface FakeNetworkEventModel {
@DataActivityType val activity: Int?,
val carrierNetworkChange: Boolean,
val roaming: Boolean,
val name: String,
) : FakeNetworkEventModel
data class MobileDisabled(

View File

@@ -17,26 +17,32 @@
package com.android.systemui.statusbar.pipeline.mobile.data.repository.prod
import android.content.Context
import android.content.IntentFilter
import android.database.ContentObserver
import android.provider.Settings.Global
import android.telephony.CellSignalStrength
import android.telephony.CellSignalStrengthCdma
import android.telephony.ServiceState
import android.telephony.SignalStrength
import android.telephony.SubscriptionManager.INVALID_SUBSCRIPTION_ID
import android.telephony.TelephonyCallback
import android.telephony.TelephonyDisplayInfo
import android.telephony.TelephonyDisplayInfo.OVERRIDE_NETWORK_TYPE_NONE
import android.telephony.TelephonyManager
import android.telephony.TelephonyManager.ERI_OFF
import android.telephony.TelephonyManager.EXTRA_SUBSCRIPTION_ID
import android.telephony.TelephonyManager.NETWORK_TYPE_UNKNOWN
import com.android.systemui.broadcast.BroadcastDispatcher
import com.android.systemui.common.coroutine.ConflatedCallbackFlow.conflatedCallbackFlow
import com.android.systemui.dagger.qualifiers.Application
import com.android.systemui.dagger.qualifiers.Background
import com.android.systemui.statusbar.pipeline.mobile.data.model.MobileConnectionModel
import com.android.systemui.statusbar.pipeline.mobile.data.model.NetworkNameModel
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.toDataConnectionType
import com.android.systemui.statusbar.pipeline.mobile.data.model.toNetworkNameModel
import com.android.systemui.statusbar.pipeline.mobile.data.repository.MobileConnectionRepository
import com.android.systemui.statusbar.pipeline.mobile.util.MobileMappingsProxy
import com.android.systemui.statusbar.pipeline.shared.ConnectivityPipelineLogger
@@ -63,8 +69,11 @@ import kotlinx.coroutines.flow.stateIn
class MobileConnectionRepositoryImpl(
private val context: Context,
override val subId: Int,
defaultNetworkName: NetworkNameModel,
networkNameSeparator: String,
private val telephonyManager: TelephonyManager,
private val globalSettings: GlobalSettings,
broadcastDispatcher: BroadcastDispatcher,
defaultDataSubId: StateFlow<Int>,
globalMobileDataSettingChangedEvent: Flow<Unit>,
mobileMappingsProxy: MobileMappingsProxy,
@@ -101,6 +110,7 @@ class MobileConnectionRepositoryImpl(
state.copy(
isEmergencyOnly = serviceState.isEmergencyOnly,
isRoaming = serviceState.roaming,
operatorAlphaShort = serviceState.operatorAlphaShort,
)
trySend(state)
}
@@ -222,6 +232,19 @@ class MobileConnectionRepositoryImpl(
.mapLatest { telephonyManager.cdmaEnhancedRoamingIndicatorDisplayNumber != ERI_OFF }
.stateIn(scope, SharingStarted.WhileSubscribed(), false)
override val networkName: StateFlow<NetworkNameModel> =
broadcastDispatcher
.broadcastFlow(IntentFilter(TelephonyManager.ACTION_SERVICE_PROVIDERS_UPDATED)) {
intent,
_ ->
if (intent.getIntExtra(EXTRA_SUBSCRIPTION_ID, INVALID_SUBSCRIPTION_ID) != subId) {
defaultNetworkName
} else {
intent.toNetworkNameModel(networkNameSeparator) ?: defaultNetworkName
}
}
.stateIn(scope, SharingStarted.WhileSubscribed(), defaultNetworkName)
override val dataEnabled: StateFlow<Boolean> =
telephonyPollingEvent
.mapLatest { dataConnectionAllowed() }
@@ -237,6 +260,7 @@ class MobileConnectionRepositoryImpl(
class Factory
@Inject
constructor(
private val broadcastDispatcher: BroadcastDispatcher,
private val context: Context,
private val telephonyManager: TelephonyManager,
private val logger: ConnectivityPipelineLogger,
@@ -247,14 +271,19 @@ class MobileConnectionRepositoryImpl(
) {
fun build(
subId: Int,
defaultNetworkName: NetworkNameModel,
networkNameSeparator: String,
defaultDataSubId: StateFlow<Int>,
globalMobileDataSettingChangedEvent: Flow<Unit>,
): MobileConnectionRepository {
return MobileConnectionRepositoryImpl(
context,
subId,
defaultNetworkName,
networkNameSeparator,
telephonyManager.createForSubscriptionId(subId),
globalSettings,
broadcastDispatcher,
defaultDataSubId,
globalMobileDataSettingChangedEvent,
mobileMappingsProxy,

View File

@@ -38,12 +38,14 @@ import androidx.annotation.VisibleForTesting
import com.android.internal.telephony.PhoneConstants
import com.android.settingslib.SignalIcon.MobileIconGroup
import com.android.settingslib.mobile.MobileMappings.Config
import com.android.systemui.R
import com.android.systemui.broadcast.BroadcastDispatcher
import com.android.systemui.common.coroutine.ConflatedCallbackFlow.conflatedCallbackFlow
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Application
import com.android.systemui.dagger.qualifiers.Background
import com.android.systemui.statusbar.pipeline.mobile.data.model.MobileConnectivityModel
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 com.android.systemui.statusbar.pipeline.mobile.data.repository.MobileConnectionsRepository
@@ -88,6 +90,14 @@ constructor(
) : MobileConnectionsRepository {
private var subIdRepositoryCache: MutableMap<Int, MobileConnectionRepository> = mutableMapOf()
private val defaultNetworkName =
NetworkNameModel.Default(
context.getString(com.android.internal.R.string.lockscreen_carrier_default)
)
private val networkNameSeparator: String =
context.getString(R.string.status_bar_network_name_separator)
/**
* State flow that emits the set of mobile data subscriptions, each represented by its own
* [SubscriptionInfo]. We probably only need the [SubscriptionInfo.getSubscriptionId] of each
@@ -243,6 +253,8 @@ constructor(
private fun createRepositoryForSubId(subId: Int): MobileConnectionRepository {
return mobileConnectionRepositoryFactory.build(
subId,
defaultNetworkName,
networkNameSeparator,
defaultDataSubId,
globalMobileDataSettingChangedEvent,
)

View File

@@ -20,6 +20,7 @@ import android.telephony.CarrierConfigManager
import com.android.settingslib.SignalIcon.MobileIconGroup
import com.android.systemui.dagger.qualifiers.Application
import com.android.systemui.statusbar.pipeline.mobile.data.model.DataConnectionState.Connected
import com.android.systemui.statusbar.pipeline.mobile.data.model.NetworkNameModel
import com.android.systemui.statusbar.pipeline.mobile.data.repository.MobileConnectionRepository
import com.android.systemui.statusbar.pipeline.shared.data.model.DataActivityModel
import com.android.systemui.util.CarrierConfigTracker
@@ -56,6 +57,15 @@ interface MobileIconInteractor {
/** Observable for RAT type (network type) indicator */
val networkTypeIconGroup: StateFlow<MobileIconGroup>
/**
* 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 derived name based off of the intent [ACTION_SERVICE_PROVIDERS_UPDATED]
* 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]
*/
val networkName: StateFlow<NetworkNameModel>
/** True if this line of service is emergency-only */
val isEmergencyOnly: StateFlow<Boolean>
@@ -93,6 +103,22 @@ class MobileIconInteractorImpl(
override val isDefaultDataEnabled = defaultSubscriptionHasDataEnabled
override val networkName =
combine(connectionInfo, connectionRepository.networkName) { connection, networkName ->
if (
networkName is NetworkNameModel.Default && connection.operatorAlphaShort != null
) {
NetworkNameModel.Derived(connection.operatorAlphaShort)
} else {
networkName
}
}
.stateIn(
scope,
SharingStarted.WhileSubscribed(),
connectionRepository.networkName.value
)
/** Observable for the current RAT indicator icon ([MobileIconGroup]) */
override val networkTypeIconGroup: StateFlow<MobileIconGroup> =
combine(

View File

@@ -17,6 +17,7 @@
package com.android.systemui.statusbar.pipeline.mobile.data.repository
import com.android.systemui.statusbar.pipeline.mobile.data.model.MobileConnectionModel
import com.android.systemui.statusbar.pipeline.mobile.data.model.NetworkNameModel
import kotlinx.coroutines.flow.MutableStateFlow
// TODO(b/261632894): remove this in favor of the real impl or DemoMobileConnectionRepository
@@ -32,6 +33,9 @@ class FakeMobileConnectionRepository(override val subId: Int) : MobileConnection
override val cdmaRoaming = MutableStateFlow(false)
override val networkName =
MutableStateFlow<NetworkNameModel>(NetworkNameModel.Default("default"))
fun setConnectionInfo(model: MobileConnectionModel) {
_connectionInfo.value = model
}

View File

@@ -25,6 +25,7 @@ import com.android.settingslib.mobile.TelephonyIcons
import com.android.systemui.SysuiTestCase
import com.android.systemui.statusbar.pipeline.mobile.data.model.DataConnectionState
import com.android.systemui.statusbar.pipeline.mobile.data.model.MobileConnectionModel
import com.android.systemui.statusbar.pipeline.mobile.data.model.NetworkNameModel
import com.android.systemui.statusbar.pipeline.mobile.data.repository.demo.model.FakeNetworkEventModel
import com.android.systemui.statusbar.pipeline.shared.data.model.toMobileDataActivityModel
import com.android.systemui.util.mockito.mock
@@ -98,6 +99,7 @@ internal class DemoMobileConnectionParameterizedTest(private val testCase: TestC
activity = testCase.activity,
carrierNetworkChange = testCase.carrierNetworkChange,
roaming = testCase.roaming,
name = "demo name",
)
fakeNetworkEventFlow.value = networkModel
@@ -121,6 +123,7 @@ internal class DemoMobileConnectionParameterizedTest(private val testCase: TestC
assertThat(connectionInfo.carrierNetworkChangeActive)
.isEqualTo(model.carrierNetworkChange)
assertThat(connectionInfo.isRoaming).isEqualTo(model.roaming)
assertThat(conn.networkName.value).isEqualTo(NetworkNameModel.Derived(model.name))
// TODO(b/261029387): check these once we start handling them
assertThat(connectionInfo.isEmergencyOnly).isFalse()
@@ -144,6 +147,7 @@ internal class DemoMobileConnectionParameterizedTest(private val testCase: TestC
@Annotation.DataActivityType val activity: Int,
val carrierNetworkChange: Boolean,
val roaming: Boolean,
val name: String,
) {
override fun toString(): String {
return "INPUT(level=$level, " +
@@ -153,7 +157,8 @@ internal class DemoMobileConnectionParameterizedTest(private val testCase: TestC
"inflateStrength=$inflateStrength, " +
"activity=$activity, " +
"carrierNetworkChange=$carrierNetworkChange, " +
"roaming=$roaming)"
"roaming=$roaming, " +
"name=$name)"
}
// Convenience for iterating test data and creating new cases
@@ -166,6 +171,7 @@ internal class DemoMobileConnectionParameterizedTest(private val testCase: TestC
@Annotation.DataActivityType activity: Int? = null,
carrierNetworkChange: Boolean? = null,
roaming: Boolean? = null,
name: String? = null,
): TestCase =
TestCase(
level = level ?: this.level,
@@ -176,6 +182,7 @@ internal class DemoMobileConnectionParameterizedTest(private val testCase: TestC
activity = activity ?: this.activity,
carrierNetworkChange = carrierNetworkChange ?: this.carrierNetworkChange,
roaming = roaming ?: this.roaming,
name = name ?: this.name,
)
}
@@ -204,6 +211,7 @@ internal class DemoMobileConnectionParameterizedTest(private val testCase: TestC
private val carrierNetworkChange = booleanList
// false first so the base case doesn't have roaming set (more common)
private val roaming = listOf(false, true)
private val names = listOf("name 1", "name 2")
@Parameters(name = "{0}") @JvmStatic fun data() = testData()
@@ -239,6 +247,7 @@ internal class DemoMobileConnectionParameterizedTest(private val testCase: TestC
activity.first(),
carrierNetworkChange.first(),
roaming.first(),
names.first(),
)
val tail =
@@ -249,7 +258,8 @@ internal class DemoMobileConnectionParameterizedTest(private val testCase: TestC
inflateStrength.map { baseCase.modifiedBy(inflateStrength = it) },
activity.map { baseCase.modifiedBy(activity = it) },
carrierNetworkChange.map { baseCase.modifiedBy(carrierNetworkChange = it) },
roaming.map { baseCase.modifiedBy(roaming = it) }
roaming.map { baseCase.modifiedBy(roaming = it) },
names.map { baseCase.modifiedBy(name = it) },
)
.flatten()

View File

@@ -25,6 +25,7 @@ import com.android.settingslib.mobile.TelephonyIcons.THREE_G
import com.android.systemui.SysuiTestCase
import com.android.systemui.statusbar.pipeline.mobile.data.model.DataConnectionState
import com.android.systemui.statusbar.pipeline.mobile.data.model.MobileConnectionModel
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.demo.model.FakeNetworkEventModel
import com.android.systemui.statusbar.pipeline.mobile.data.repository.demo.model.FakeNetworkEventModel.MobileDisabled
@@ -296,6 +297,7 @@ class DemoMobileConnectionsRepositoryTest : SysuiTestCase() {
assertThat(connectionInfo.carrierNetworkChangeActive)
.isEqualTo(model.carrierNetworkChange)
assertThat(connectionInfo.isRoaming).isEqualTo(model.roaming)
assertThat(conn.networkName.value).isEqualTo(NetworkNameModel.Derived(model.name))
// TODO(b/261029387) check these once we start handling them
assertThat(connectionInfo.isEmergencyOnly).isFalse()
@@ -328,4 +330,5 @@ fun validMobileEvent(
activity = activity,
carrierNetworkChange = carrierNetworkChange,
roaming = roaming,
name = "demo name",
)

View File

@@ -16,6 +16,7 @@
package com.android.systemui.statusbar.pipeline.mobile.data.repository.prod
import android.content.Intent
import android.os.UserHandle
import android.provider.Settings
import android.telephony.CellSignalStrengthCdma
@@ -40,15 +41,22 @@ import android.telephony.TelephonyManager.DATA_DISCONNECTING
import android.telephony.TelephonyManager.DATA_UNKNOWN
import android.telephony.TelephonyManager.ERI_OFF
import android.telephony.TelephonyManager.ERI_ON
import android.telephony.TelephonyManager.EXTRA_PLMN
import android.telephony.TelephonyManager.EXTRA_SHOW_PLMN
import android.telephony.TelephonyManager.EXTRA_SHOW_SPN
import android.telephony.TelephonyManager.EXTRA_SPN
import android.telephony.TelephonyManager.EXTRA_SUBSCRIPTION_ID
import android.telephony.TelephonyManager.NETWORK_TYPE_LTE
import android.telephony.TelephonyManager.NETWORK_TYPE_UNKNOWN
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.statusbar.pipeline.mobile.data.model.DataConnectionState
import com.android.systemui.statusbar.pipeline.mobile.data.model.MobileConnectionModel
import com.android.systemui.statusbar.pipeline.mobile.data.model.NetworkNameModel
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.toNetworkNameModel
import com.android.systemui.statusbar.pipeline.mobile.data.repository.FakeMobileConnectionsRepository
import com.android.systemui.statusbar.pipeline.mobile.util.FakeMobileMappingsProxy
import com.android.systemui.statusbar.pipeline.shared.ConnectivityPipelineLogger
@@ -98,8 +106,11 @@ class MobileConnectionRepositoryTest : SysuiTestCase() {
MobileConnectionRepositoryImpl(
context,
SUB_1_ID,
DEFAULT_NAME,
SEP,
telephonyManager,
globalSettings,
fakeBroadcastDispatcher,
connectionsRepo.defaultDataSubId,
connectionsRepo.globalMobileDataSettingChangedEvent,
mobileMappings,
@@ -506,6 +517,74 @@ class MobileConnectionRepositoryTest : SysuiTestCase() {
job.cancel()
}
@Test
fun `network name - default`() =
runBlocking(IMMEDIATE) {
var latest: NetworkNameModel? = null
val job = underTest.networkName.onEach { latest = it }.launchIn(this)
assertThat(latest).isEqualTo(DEFAULT_NAME)
job.cancel()
}
@Test
fun `network name - uses broadcast info - returns derived`() =
runBlocking(IMMEDIATE) {
var latest: NetworkNameModel? = null
val job = underTest.networkName.onEach { latest = it }.launchIn(this)
val intent = spnIntent()
fakeBroadcastDispatcher.registeredReceivers.forEach { receiver ->
receiver.onReceive(context, intent)
}
assertThat(latest).isEqualTo(intent.toNetworkNameModel(SEP))
job.cancel()
}
@Test
fun `network name - broadcast not for this sub id - returns default`() =
runBlocking(IMMEDIATE) {
var latest: NetworkNameModel? = null
val job = underTest.networkName.onEach { latest = it }.launchIn(this)
val intent = spnIntent(subId = 101)
fakeBroadcastDispatcher.registeredReceivers.forEach { receiver ->
receiver.onReceive(context, intent)
}
assertThat(latest).isEqualTo(DEFAULT_NAME)
job.cancel()
}
@Test
fun `network name - operatorAlphaShort - tracked`() =
runBlocking(IMMEDIATE) {
var latest: String? = null
val job =
underTest.connectionInfo.onEach { latest = it.operatorAlphaShort }.launchIn(this)
val shortName = "short name"
val serviceState = ServiceState()
serviceState.setOperatorName(
/* longName */ "long name",
/* shortName */ shortName,
/* numeric */ "12345",
)
getTelephonyCallbackForType<ServiceStateListener>().onServiceStateChanged(serviceState)
assertThat(latest).isEqualTo(shortName)
job.cancel()
}
private fun getTelephonyCallbacks(): List<TelephonyCallback> {
val callbackCaptor = argumentCaptor<TelephonyCallback>()
Mockito.verify(telephonyManager).registerTelephonyCallback(any(), callbackCaptor.capture())
@@ -531,10 +610,31 @@ class MobileConnectionRepositoryTest : SysuiTestCase() {
return signalStrength
}
private fun spnIntent(
subId: Int = SUB_1_ID,
showSpn: Boolean = true,
spn: String = SPN,
showPlmn: Boolean = true,
plmn: String = PLMN,
): Intent =
Intent(TelephonyManager.ACTION_SERVICE_PROVIDERS_UPDATED).apply {
putExtra(EXTRA_SUBSCRIPTION_ID, subId)
putExtra(EXTRA_SHOW_SPN, showSpn)
putExtra(EXTRA_SPN, spn)
putExtra(EXTRA_SHOW_PLMN, showPlmn)
putExtra(EXTRA_PLMN, plmn)
}
companion object {
private val IMMEDIATE = Dispatchers.Main.immediate
private const val SUB_1_ID = 1
private val SUB_1 =
mock<SubscriptionInfo>().also { whenever(it.subscriptionId).thenReturn(SUB_1_ID) }
private val DEFAULT_NAME = NetworkNameModel.Default("default name")
private const val SEP = "-"
private const val SPN = "testSpn"
private const val PLMN = "testPlmn"
}
}

View File

@@ -91,6 +91,7 @@ class MobileConnectionsRepositoryTest : SysuiTestCase() {
connectionFactory =
MobileConnectionRepositoryImpl.Factory(
fakeBroadcastDispatcher,
context = context,
telephonyManager = telephonyManager,
bgDispatcher = IMMEDIATE,

View File

@@ -19,6 +19,7 @@ package com.android.systemui.statusbar.pipeline.mobile.domain.interactor
import android.telephony.CellSignalStrength
import com.android.settingslib.SignalIcon
import com.android.settingslib.mobile.TelephonyIcons
import com.android.systemui.statusbar.pipeline.mobile.data.model.NetworkNameModel
import com.android.systemui.statusbar.pipeline.shared.data.model.DataActivityModel
import kotlinx.coroutines.flow.MutableStateFlow
@@ -36,6 +37,8 @@ class FakeMobileIconInteractor : MobileIconInteractor {
private val _iconGroup = MutableStateFlow<SignalIcon.MobileIconGroup>(TelephonyIcons.THREE_G)
override val networkTypeIconGroup = _iconGroup
override val networkName = MutableStateFlow(NetworkNameModel.Derived("demo mode"))
private val _isEmergencyOnly = MutableStateFlow(false)
override val isEmergencyOnly = _isEmergencyOnly

View File

@@ -25,6 +25,7 @@ import com.android.settingslib.mobile.TelephonyIcons
import com.android.systemui.SysuiTestCase
import com.android.systemui.statusbar.pipeline.mobile.data.model.DataConnectionState
import com.android.systemui.statusbar.pipeline.mobile.data.model.MobileConnectionModel
import com.android.systemui.statusbar.pipeline.mobile.data.model.NetworkNameModel
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.repository.FakeMobileConnectionRepository
@@ -392,6 +393,41 @@ class MobileIconInteractorTest : SysuiTestCase() {
job.cancel()
}
@Test
fun `network name - uses operatorAlphaShot when non null and repo is default`() =
runBlocking(IMMEDIATE) {
var latest: NetworkNameModel? = null
val job = underTest.networkName.onEach { latest = it }.launchIn(this)
val testOperatorName = "operatorAlphaShort"
// Default network name, operator name is non-null, uses the operator name
connectionRepository.networkName.value = DEFAULT_NAME
connectionRepository.setConnectionInfo(
MobileConnectionModel(operatorAlphaShort = testOperatorName)
)
yield()
assertThat(latest).isEqualTo(NetworkNameModel.Derived(testOperatorName))
// Default network name, operator name is null, uses the default
connectionRepository.setConnectionInfo(MobileConnectionModel(operatorAlphaShort = null))
yield()
assertThat(latest).isEqualTo(DEFAULT_NAME)
// Derived network name, operator name non-null, uses the derived name
connectionRepository.networkName.value = DERIVED_NAME
connectionRepository.setConnectionInfo(
MobileConnectionModel(operatorAlphaShort = testOperatorName)
)
yield()
assertThat(latest).isEqualTo(DERIVED_NAME)
job.cancel()
}
companion object {
private val IMMEDIATE = Dispatchers.Main.immediate
@@ -401,5 +437,8 @@ class MobileIconInteractorTest : SysuiTestCase() {
private const val SUB_1_ID = 1
private val SUB_1 =
mock<SubscriptionInfo>().also { whenever(it.subscriptionId).thenReturn(SUB_1_ID) }
private val DEFAULT_NAME = NetworkNameModel.Default("test default name")
private val DERIVED_NAME = NetworkNameModel.Derived("test derived name")
}
}