Better mapping lookup for demo mode

Move the entire lookup into `MobileMappings` to the
repository layer. So when network types come down, they are immediately
transformed into `ResolvedNetworkType` objects and given a key at that
moment, using the default mobile mapping config

This allows us to A) better insulate us from external depenencies and B)
implement a very trivial mapping for Demo mode. TBD on whether or not we
should allow switching to use the real mobile mappings implementation

Test: tests in tests/src/com/andrdoid/systemui/statusbar/pipeline/mobile/*
Bug: 261185097
Change-Id: I727ad3ca823f3eb225a56f371aa3cef46c340f57
This commit is contained in:
Evan Laird
2022-12-02 12:33:12 -05:00
parent cc43d6a878
commit f58969d7c1
16 changed files with 215 additions and 115 deletions

View File

@@ -27,7 +27,6 @@ import android.telephony.TelephonyCallback.ServiceStateListener
import android.telephony.TelephonyCallback.SignalStrengthsListener
import android.telephony.TelephonyDisplayInfo
import android.telephony.TelephonyManager
import android.telephony.TelephonyManager.NETWORK_TYPE_UNKNOWN
import com.android.systemui.statusbar.pipeline.mobile.data.model.DataConnectionState.Disconnected
/**
@@ -65,5 +64,5 @@ data class MobileSubscriptionModel(
* [resolvedNetworkType] is the [TelephonyDisplayInfo.getOverrideNetworkType] if it exists or
* [TelephonyDisplayInfo.getNetworkType]. This is used to look up the proper network type icon
*/
val resolvedNetworkType: ResolvedNetworkType = DefaultNetworkType(NETWORK_TYPE_UNKNOWN),
val resolvedNetworkType: ResolvedNetworkType = ResolvedNetworkType.UnknownNetworkType,
)

View File

@@ -17,6 +17,7 @@
package com.android.systemui.statusbar.pipeline.mobile.data.model
import android.telephony.Annotation.NetworkType
import android.telephony.TelephonyManager.NETWORK_TYPE_UNKNOWN
import com.android.systemui.statusbar.pipeline.mobile.util.MobileMappingsProxy
/**
@@ -26,8 +27,20 @@ import com.android.systemui.statusbar.pipeline.mobile.util.MobileMappingsProxy
*/
sealed interface ResolvedNetworkType {
@NetworkType val type: Int
val lookupKey: String
object UnknownNetworkType : ResolvedNetworkType {
override val type: Int = NETWORK_TYPE_UNKNOWN
override val lookupKey: String = "unknown"
}
data class DefaultNetworkType(
@NetworkType override val type: Int,
override val lookupKey: String,
) : ResolvedNetworkType
data class OverrideNetworkType(
@NetworkType override val type: Int,
override val lookupKey: String,
) : ResolvedNetworkType
}
data class DefaultNetworkType(@NetworkType override val type: Int) : ResolvedNetworkType
data class OverrideNetworkType(@NetworkType override val type: Int) : ResolvedNetworkType

View File

@@ -19,8 +19,7 @@ package com.android.systemui.statusbar.pipeline.mobile.data.repository
import android.provider.Settings
import android.telephony.SubscriptionInfo
import android.telephony.SubscriptionManager
import com.android.settingslib.mobile.MobileMappings
import com.android.settingslib.mobile.MobileMappings.Config
import com.android.settingslib.SignalIcon.MobileIconGroup
import com.android.systemui.statusbar.pipeline.mobile.data.model.MobileConnectivityModel
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.StateFlow
@@ -36,9 +35,6 @@ interface MobileConnectionsRepository {
/** Observable for the subscriptionId of the current mobile data connection */
val activeMobileDataSubscriptionId: StateFlow<Int>
/** Observable for [MobileMappings.Config] tracking the defaults */
val defaultDataSubRatConfig: StateFlow<Config>
/** Tracks [SubscriptionManager.getDefaultDataSubscriptionId] */
val defaultDataSubId: StateFlow<Int>
@@ -50,4 +46,10 @@ interface MobileConnectionsRepository {
/** Observe changes to the [Settings.Global.MOBILE_DATA] setting */
val globalMobileDataSettingChangedEvent: Flow<Unit>
/** The icon mapping from network type to [MobileIconGroup] for the default subscription */
val defaultMobileIconMapping: Flow<Map<String, MobileIconGroup>>
/** Fallback [MobileIconGroup] in the case where there is no icon in the mapping */
val defaultMobileIconGroup: Flow<MobileIconGroup>
}

View File

@@ -19,7 +19,7 @@ package com.android.systemui.statusbar.pipeline.mobile.data.repository
import android.os.Bundle
import android.telephony.SubscriptionInfo
import androidx.annotation.VisibleForTesting
import com.android.settingslib.mobile.MobileMappings
import com.android.settingslib.SignalIcon
import com.android.systemui.common.coroutine.ConflatedCallbackFlow.conflatedCallbackFlow
import com.android.systemui.dagger.qualifiers.Application
import com.android.systemui.demomode.DemoMode
@@ -127,14 +127,11 @@ constructor(
realRepository.activeMobileDataSubscriptionId.value
)
override val defaultDataSubRatConfig: StateFlow<MobileMappings.Config> =
activeRepo
.flatMapLatest { it.defaultDataSubRatConfig }
.stateIn(
scope,
SharingStarted.WhileSubscribed(),
realRepository.defaultDataSubRatConfig.value
)
override val defaultMobileIconMapping: Flow<Map<String, SignalIcon.MobileIconGroup>> =
activeRepo.flatMapLatest { it.defaultMobileIconMapping }
override val defaultMobileIconGroup: Flow<SignalIcon.MobileIconGroup> =
activeRepo.flatMapLatest { it.defaultMobileIconGroup }
override val defaultDataSubId: StateFlow<Int> =
activeRepo

View File

@@ -17,26 +17,18 @@
package com.android.systemui.statusbar.pipeline.mobile.data.repository.demo
import android.content.Context
import android.telephony.Annotation
import android.telephony.SubscriptionInfo
import android.telephony.SubscriptionManager.INVALID_SUBSCRIPTION_ID
import android.telephony.TelephonyDisplayInfo.OVERRIDE_NETWORK_TYPE_NR_ADVANCED
import android.telephony.TelephonyManager.NETWORK_TYPE_GSM
import android.telephony.TelephonyManager.NETWORK_TYPE_LTE
import android.telephony.TelephonyManager.NETWORK_TYPE_NR
import android.telephony.TelephonyManager.NETWORK_TYPE_UMTS
import android.telephony.TelephonyManager.NETWORK_TYPE_UNKNOWN
import android.util.Log
import com.android.settingslib.SignalIcon
import com.android.settingslib.mobile.MobileMappings
import com.android.settingslib.mobile.TelephonyIcons
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.DefaultNetworkType
import com.android.systemui.statusbar.pipeline.mobile.data.model.MobileConnectivityModel
import com.android.systemui.statusbar.pipeline.mobile.data.model.MobileSubscriptionModel
import com.android.systemui.statusbar.pipeline.mobile.data.model.OverrideNetworkType
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.repository.MobileConnectionRepository
import com.android.systemui.statusbar.pipeline.mobile.data.repository.MobileConnectionsRepository
import com.android.systemui.statusbar.pipeline.mobile.data.repository.demo.model.FakeNetworkEventModel
@@ -49,7 +41,9 @@ import kotlinx.coroutines.Job
import kotlinx.coroutines.flow.MutableSharedFlow
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.SharingStarted
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.filterNotNull
import kotlinx.coroutines.flow.flowOf
import kotlinx.coroutines.flow.mapLatest
import kotlinx.coroutines.flow.onEach
import kotlinx.coroutines.flow.stateIn
@@ -133,8 +127,31 @@ constructor(
)
/** Demo mode doesn't currently support modifications to the mobile mappings */
override val defaultDataSubRatConfig =
MutableStateFlow(MobileMappings.Config.readConfig(context))
val defaultDataSubRatConfig = MutableStateFlow(MobileMappings.Config.readConfig(context))
override val defaultMobileIconGroup = flowOf(TelephonyIcons.THREE_G)
override val defaultMobileIconMapping = MutableStateFlow(TelephonyIcons.ICON_NAME_TO_ICON)
/**
* In order to maintain compatibility with the old demo mode shell command API, reverse the
* [MobileMappings] lookup from (NetworkType: String -> Icon: MobileIconGroup), so that we can
* parse the string from the command line into a preferred icon group, and send _a_ valid
* network type for that icon through the pipeline.
*
* Note: collisions don't matter here, because the data source (the command line) only cares
* about the resulting icon, not the underlying network type.
*/
private val mobileMappingsReverseLookup: StateFlow<Map<SignalIcon.MobileIconGroup, String>> =
defaultMobileIconMapping
.mapLatest { networkToIconMap -> networkToIconMap.reverse() }
.stateIn(
scope,
SharingStarted.WhileSubscribed(),
defaultMobileIconMapping.value.reverse()
)
private fun <K, V> Map<K, V>.reverse() = entries.associateBy({ it.value }) { it.key }
// TODO(b/261029387): add a command for this value
override val defaultDataSubId =
@@ -229,45 +246,34 @@ constructor(
private fun subIdsString(): String =
_subscriptions.value.joinToString(",") { it.subscriptionId.toString() }
private fun Mobile.toMobileSubscriptionModel(): MobileSubscriptionModel {
return MobileSubscriptionModel(
isEmergencyOnly = false, // TODO(b/261029387): not yet supported
isGsm = false, // TODO(b/261029387): not yet supported
cdmaLevel = level ?: 0,
primaryLevel = level ?: 0,
dataConnectionState =
DataConnectionState.Connected, // TODO(b/261029387): not yet supported
dataActivityDirection = activity,
carrierNetworkChangeActive = carrierNetworkChange,
resolvedNetworkType = dataType.toResolvedNetworkType()
)
}
private fun SignalIcon.MobileIconGroup?.toResolvedNetworkType(): ResolvedNetworkType {
val key = mobileMappingsReverseLookup.value[this] ?: "dis"
return DefaultNetworkType(DEMO_NET_TYPE, key)
}
companion object {
private const val TAG = "DemoMobileConnectionsRepo"
private const val DEFAULT_SUB_ID = 1
private const val DEMO_NET_TYPE = 1234
}
}
private fun Mobile.toMobileSubscriptionModel(): MobileSubscriptionModel {
return MobileSubscriptionModel(
isEmergencyOnly = false, // TODO(b/261029387): not yet supported
isGsm = false, // TODO(b/261029387): not yet supported
cdmaLevel = level ?: 0,
primaryLevel = level ?: 0,
dataConnectionState = DataConnectionState.Connected, // TODO(b/261029387): not yet supported
dataActivityDirection = activity,
carrierNetworkChangeActive = carrierNetworkChange,
// TODO(b/261185097): once mobile mappings can be mocked at this layer, we can build our
// own demo map
resolvedNetworkType = dataType.toResolvedNetworkType()
)
}
@Annotation.NetworkType
private fun SignalIcon.MobileIconGroup?.toNetworkType(): Int =
when (this) {
TelephonyIcons.THREE_G -> NETWORK_TYPE_GSM
TelephonyIcons.LTE -> NETWORK_TYPE_LTE
TelephonyIcons.FOUR_G -> NETWORK_TYPE_UMTS
TelephonyIcons.NR_5G -> NETWORK_TYPE_NR
TelephonyIcons.NR_5G_PLUS -> OVERRIDE_NETWORK_TYPE_NR_ADVANCED
else -> NETWORK_TYPE_UNKNOWN
}
private fun SignalIcon.MobileIconGroup?.toResolvedNetworkType(): ResolvedNetworkType =
when (this) {
TelephonyIcons.NR_5G_PLUS -> OverrideNetworkType(toNetworkType())
else -> DefaultNetworkType(toNetworkType())
}
class DemoMobileConnectionRepository(override val subId: Int) : MobileConnectionRepository {
override val subscriptionModelFlow = MutableStateFlow(MobileSubscriptionModel())

View File

@@ -27,18 +27,20 @@ import android.telephony.TelephonyCallback
import android.telephony.TelephonyDisplayInfo
import android.telephony.TelephonyDisplayInfo.OVERRIDE_NETWORK_TYPE_NONE
import android.telephony.TelephonyManager
import android.telephony.TelephonyManager.NETWORK_TYPE_UNKNOWN
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.DefaultNetworkType
import com.android.systemui.statusbar.pipeline.mobile.data.model.MobileSubscriptionModel
import com.android.systemui.statusbar.pipeline.mobile.data.model.OverrideNetworkType
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.repository.MobileConnectionRepository
import com.android.systemui.statusbar.pipeline.mobile.util.MobileMappingsProxy
import com.android.systemui.statusbar.pipeline.shared.ConnectivityPipelineLogger
import com.android.systemui.statusbar.pipeline.shared.ConnectivityPipelineLogger.Companion.logOutputChange
import com.android.systemui.util.settings.GlobalSettings
import java.lang.IllegalStateException
import javax.inject.Inject
import kotlinx.coroutines.CoroutineDispatcher
import kotlinx.coroutines.CoroutineScope
@@ -63,6 +65,7 @@ class MobileConnectionRepositoryImpl(
private val globalSettings: GlobalSettings,
defaultDataSubId: StateFlow<Int>,
globalMobileDataSettingChangedEvent: Flow<Unit>,
mobileMappingsProxy: MobileMappingsProxy,
bgDispatcher: CoroutineDispatcher,
logger: ConnectivityPipelineLogger,
scope: CoroutineScope,
@@ -141,14 +144,27 @@ class MobileConnectionRepositoryImpl(
override fun onDisplayInfoChanged(
telephonyDisplayInfo: TelephonyDisplayInfo
) {
val networkType =
if (
if (telephonyDisplayInfo.networkType == NETWORK_TYPE_UNKNOWN) {
UnknownNetworkType
} else if (
telephonyDisplayInfo.overrideNetworkType ==
OVERRIDE_NETWORK_TYPE_NONE
) {
DefaultNetworkType(telephonyDisplayInfo.networkType)
DefaultNetworkType(
telephonyDisplayInfo.networkType,
mobileMappingsProxy.toIconKey(
telephonyDisplayInfo.networkType
)
)
} else {
OverrideNetworkType(telephonyDisplayInfo.overrideNetworkType)
OverrideNetworkType(
telephonyDisplayInfo.overrideNetworkType,
mobileMappingsProxy.toIconKeyOverride(
telephonyDisplayInfo.overrideNetworkType
)
)
}
state = state.copy(resolvedNetworkType = networkType)
trySend(state)
@@ -211,6 +227,7 @@ class MobileConnectionRepositoryImpl(
private val telephonyManager: TelephonyManager,
private val logger: ConnectivityPipelineLogger,
private val globalSettings: GlobalSettings,
private val mobileMappingsProxy: MobileMappingsProxy,
@Background private val bgDispatcher: CoroutineDispatcher,
@Application private val scope: CoroutineScope,
) {
@@ -226,6 +243,7 @@ class MobileConnectionRepositoryImpl(
globalSettings,
defaultDataSubId,
globalMobileDataSettingChangedEvent,
mobileMappingsProxy,
bgDispatcher,
logger,
scope,

View File

@@ -36,6 +36,7 @@ import android.telephony.TelephonyCallback.ActiveDataSubscriptionIdListener
import android.telephony.TelephonyManager
import androidx.annotation.VisibleForTesting
import com.android.internal.telephony.PhoneConstants
import com.android.settingslib.SignalIcon.MobileIconGroup
import com.android.settingslib.mobile.MobileMappings
import com.android.settingslib.mobile.MobileMappings.Config
import com.android.systemui.broadcast.BroadcastDispatcher
@@ -46,6 +47,7 @@ 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.repository.MobileConnectionRepository
import com.android.systemui.statusbar.pipeline.mobile.data.repository.MobileConnectionsRepository
import com.android.systemui.statusbar.pipeline.mobile.util.MobileMappingsProxy
import com.android.systemui.statusbar.pipeline.shared.ConnectivityPipelineLogger
import com.android.systemui.util.settings.GlobalSettings
import javax.inject.Inject
@@ -59,6 +61,7 @@ import kotlinx.coroutines.flow.MutableSharedFlow
import kotlinx.coroutines.flow.SharingStarted
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.distinctUntilChanged
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.mapLatest
import kotlinx.coroutines.flow.merge
import kotlinx.coroutines.flow.onEach
@@ -75,6 +78,7 @@ constructor(
private val subscriptionManager: SubscriptionManager,
private val telephonyManager: TelephonyManager,
private val logger: ConnectivityPipelineLogger,
mobileMappingsProxy: MobileMappingsProxy,
broadcastDispatcher: BroadcastDispatcher,
private val globalSettings: GlobalSettings,
private val context: Context,
@@ -157,7 +161,7 @@ constructor(
*
* This flow will produce whenever the default data subscription or the carrier config changes.
*/
override val defaultDataSubRatConfig: StateFlow<Config> =
private val defaultDataSubRatConfig: StateFlow<Config> =
merge(defaultDataSubIdChangeEvent, carrierConfigChangedEvent)
.mapLatest { Config.readConfig(context) }
.stateIn(
@@ -166,6 +170,12 @@ constructor(
initialValue = Config.readConfig(context)
)
override val defaultMobileIconMapping: Flow<Map<String, MobileIconGroup>> =
defaultDataSubRatConfig.map { mobileMappingsProxy.mapIconSets(it) }
override val defaultMobileIconGroup: Flow<MobileIconGroup> =
defaultDataSubRatConfig.map { mobileMappingsProxy.getDefaultIcons(it) }
override fun getRepoForSubId(subId: Int): MobileConnectionRepository {
if (!isValidSubId(subId)) {
throw IllegalArgumentException(

View File

@@ -20,10 +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.DefaultNetworkType
import com.android.systemui.statusbar.pipeline.mobile.data.model.OverrideNetworkType
import com.android.systemui.statusbar.pipeline.mobile.data.repository.MobileConnectionRepository
import com.android.systemui.statusbar.pipeline.mobile.util.MobileMappingsProxy
import com.android.systemui.util.CarrierConfigTracker
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.ExperimentalCoroutinesApi
@@ -70,7 +67,6 @@ class MobileIconInteractorImpl(
defaultMobileIconMapping: StateFlow<Map<String, MobileIconGroup>>,
defaultMobileIconGroup: StateFlow<MobileIconGroup>,
override val isDefaultConnectionFailed: StateFlow<Boolean>,
mobileMappingsProxy: MobileMappingsProxy,
connectionRepository: MobileConnectionRepository,
) : MobileIconInteractor {
private val mobileStatusInfo = connectionRepository.subscriptionModelFlow
@@ -86,13 +82,7 @@ class MobileIconInteractorImpl(
defaultMobileIconMapping,
defaultMobileIconGroup,
) { info, mapping, defaultGroup ->
val lookupKey =
when (val resolved = info.resolvedNetworkType) {
is DefaultNetworkType -> mobileMappingsProxy.toIconKey(resolved.type)
is OverrideNetworkType ->
mobileMappingsProxy.toIconKeyOverride(resolved.type)
}
mapping[lookupKey] ?: defaultGroup
mapping[info.resolvedNetworkType.lookupKey] ?: defaultGroup
}
.stateIn(scope, SharingStarted.WhileSubscribed(), defaultMobileIconGroup.value)

View File

@@ -27,7 +27,6 @@ import com.android.systemui.dagger.qualifiers.Application
import com.android.systemui.statusbar.pipeline.mobile.data.repository.MobileConnectionRepository
import com.android.systemui.statusbar.pipeline.mobile.data.repository.MobileConnectionsRepository
import com.android.systemui.statusbar.pipeline.mobile.data.repository.UserSetupRepository
import com.android.systemui.statusbar.pipeline.mobile.util.MobileMappingsProxy
import com.android.systemui.util.CarrierConfigTracker
import javax.inject.Inject
import kotlinx.coroutines.CoroutineScope
@@ -79,7 +78,6 @@ class MobileIconsInteractorImpl
constructor(
private val mobileConnectionsRepo: MobileConnectionsRepository,
private val carrierConfigTracker: CarrierConfigTracker,
private val mobileMappingsProxy: MobileMappingsProxy,
userSetupRepo: UserSetupRepository,
@Application private val scope: CoroutineScope,
) : MobileIconsInteractor {
@@ -154,15 +152,19 @@ constructor(
* subscription Id. This mapping is the same for every subscription.
*/
override val defaultMobileIconMapping: StateFlow<Map<String, MobileIconGroup>> =
mobileConnectionsRepo.defaultDataSubRatConfig
.mapLatest { mobileMappingsProxy.mapIconSets(it) }
.stateIn(scope, SharingStarted.WhileSubscribed(), initialValue = mapOf())
mobileConnectionsRepo.defaultMobileIconMapping.stateIn(
scope,
SharingStarted.WhileSubscribed(),
initialValue = mapOf()
)
/** If there is no mapping in [defaultMobileIconMapping], then use this default icon group */
override val defaultMobileIconGroup: StateFlow<MobileIconGroup> =
mobileConnectionsRepo.defaultDataSubRatConfig
.mapLatest { mobileMappingsProxy.getDefaultIcons(it) }
.stateIn(scope, SharingStarted.WhileSubscribed(), initialValue = TelephonyIcons.G)
mobileConnectionsRepo.defaultMobileIconGroup.stateIn(
scope,
SharingStarted.WhileSubscribed(),
initialValue = TelephonyIcons.G
)
/**
* We want to show an error state when cellular has actually failed to validate, but not if some
@@ -189,7 +191,6 @@ constructor(
defaultMobileIconMapping,
defaultMobileIconGroup,
isDefaultConnectionFailed,
mobileMappingsProxy,
mobileConnectionsRepo.getRepoForSubId(subId),
)
}

View File

@@ -19,6 +19,7 @@ package com.android.systemui.statusbar.pipeline.mobile.data.repository
import com.android.systemui.statusbar.pipeline.mobile.data.model.MobileSubscriptionModel
import kotlinx.coroutines.flow.MutableStateFlow
// TODO(b/261632894): remove this in favor of the real impl or DemoMobileConnectionRepository
class FakeMobileConnectionRepository(override val subId: Int) : MobileConnectionRepository {
private val _subscriptionsModelFlow = MutableStateFlow(MobileSubscriptionModel())
override val subscriptionModelFlow = _subscriptionsModelFlow

View File

@@ -18,20 +18,41 @@ package com.android.systemui.statusbar.pipeline.mobile.data.repository
import android.telephony.SubscriptionInfo
import android.telephony.SubscriptionManager.INVALID_SUBSCRIPTION_ID
import com.android.settingslib.mobile.MobileMappings.Config
import android.telephony.TelephonyDisplayInfo
import android.telephony.TelephonyManager
import com.android.settingslib.SignalIcon
import com.android.settingslib.mobile.TelephonyIcons
import com.android.systemui.statusbar.pipeline.mobile.data.model.MobileConnectivityModel
import com.android.systemui.statusbar.pipeline.mobile.util.MobileMappingsProxy
import kotlinx.coroutines.flow.MutableStateFlow
class FakeMobileConnectionsRepository : MobileConnectionsRepository {
// TODO(b/261632894): remove this in favor of the real impl or DemoMobileConnectionsRepository
class FakeMobileConnectionsRepository(mobileMappings: MobileMappingsProxy) :
MobileConnectionsRepository {
val GSM_KEY = mobileMappings.toIconKey(GSM)
val LTE_KEY = mobileMappings.toIconKey(LTE)
val UMTS_KEY = mobileMappings.toIconKey(UMTS)
val LTE_ADVANCED_KEY = mobileMappings.toIconKeyOverride(LTE_ADVANCED_PRO)
/**
* To avoid a reliance on [MobileMappings], we'll build a simpler map from network type to
* mobile icon. See TelephonyManager.NETWORK_TYPES for a list of types and [TelephonyIcons] for
* the exhaustive set of icons
*/
val TEST_MAPPING: Map<String, SignalIcon.MobileIconGroup> =
mapOf(
GSM_KEY to TelephonyIcons.THREE_G,
LTE_KEY to TelephonyIcons.LTE,
UMTS_KEY to TelephonyIcons.FOUR_G,
LTE_ADVANCED_KEY to TelephonyIcons.NR_5G,
)
private val _subscriptionsFlow = MutableStateFlow<List<SubscriptionInfo>>(listOf())
override val subscriptionsFlow = _subscriptionsFlow
private val _activeMobileDataSubscriptionId = MutableStateFlow(INVALID_SUBSCRIPTION_ID)
override val activeMobileDataSubscriptionId = _activeMobileDataSubscriptionId
private val _defaultDataSubRatConfig = MutableStateFlow(Config())
override val defaultDataSubRatConfig = _defaultDataSubRatConfig
private val _defaultDataSubId = MutableStateFlow(INVALID_SUBSCRIPTION_ID)
override val defaultDataSubId = _defaultDataSubId
@@ -47,14 +68,16 @@ class FakeMobileConnectionsRepository : MobileConnectionsRepository {
private val _globalMobileDataSettingChangedEvent = MutableStateFlow(Unit)
override val globalMobileDataSettingChangedEvent = _globalMobileDataSettingChangedEvent
private val _defaultMobileIconMapping = MutableStateFlow(TEST_MAPPING)
override val defaultMobileIconMapping = _defaultMobileIconMapping
private val _defaultMobileIconGroup = MutableStateFlow(DEFAULT_ICON)
override val defaultMobileIconGroup = _defaultMobileIconGroup
fun setSubscriptions(subs: List<SubscriptionInfo>) {
_subscriptionsFlow.value = subs
}
fun setDefaultDataSubRatConfig(config: Config) {
_defaultDataSubRatConfig.value = config
}
fun setDefaultDataSubId(id: Int) {
_defaultDataSubId.value = id
}
@@ -74,4 +97,14 @@ class FakeMobileConnectionsRepository : MobileConnectionsRepository {
fun setMobileConnectionRepositoryMap(connections: Map<Int, MobileConnectionRepository>) {
connections.forEach { entry -> subIdRepos[entry.key] = entry.value }
}
companion object {
val DEFAULT_ICON = TelephonyIcons.G
// Use [MobileMappings] to define some simple definitions
const val GSM = TelephonyManager.NETWORK_TYPE_GSM
const val LTE = TelephonyManager.NETWORK_TYPE_LTE
const val UMTS = TelephonyManager.NETWORK_TYPE_UMTS
const val LTE_ADVANCED_PRO = TelephonyDisplayInfo.OVERRIDE_NETWORK_TYPE_LTE_ADVANCED_PRO
}
}

View File

@@ -29,6 +29,7 @@ import com.android.systemui.statusbar.pipeline.mobile.data.repository.demo.DemoM
import com.android.systemui.statusbar.pipeline.mobile.data.repository.demo.model.FakeNetworkEventModel
import com.android.systemui.statusbar.pipeline.mobile.data.repository.demo.validMobileEvent
import com.android.systemui.statusbar.pipeline.mobile.data.repository.prod.MobileConnectionsRepositoryImpl
import com.android.systemui.statusbar.pipeline.mobile.util.FakeMobileMappingsProxy
import com.android.systemui.statusbar.pipeline.shared.ConnectivityPipelineLogger
import com.android.systemui.util.mockito.any
import com.android.systemui.util.mockito.kotlinArgumentCaptor
@@ -76,6 +77,7 @@ class MobileRepositorySwitcherTest : SysuiTestCase() {
private val globalSettings = FakeSettings()
private val fakeNetworkEventsFlow = MutableStateFlow<FakeNetworkEventModel?>(null)
private val mobileMappings = FakeMobileMappingsProxy()
private val scope = CoroutineScope(IMMEDIATE)
@@ -97,6 +99,7 @@ class MobileRepositorySwitcherTest : SysuiTestCase() {
subscriptionManager,
telephonyManager,
logger,
mobileMappings,
fakeBroadcastDispatcher,
globalSettings,
context,

View File

@@ -37,10 +37,12 @@ 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.DefaultNetworkType
import com.android.systemui.statusbar.pipeline.mobile.data.model.MobileSubscriptionModel
import com.android.systemui.statusbar.pipeline.mobile.data.model.OverrideNetworkType
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.repository.FakeMobileConnectionsRepository
import com.android.systemui.statusbar.pipeline.mobile.util.FakeMobileMappingsProxy
import com.android.systemui.statusbar.pipeline.shared.ConnectivityPipelineLogger
import com.android.systemui.util.mockito.any
import com.android.systemui.util.mockito.argumentCaptor
@@ -72,8 +74,9 @@ class MobileConnectionRepositoryTest : SysuiTestCase() {
@Mock private lateinit var logger: ConnectivityPipelineLogger
private val scope = CoroutineScope(IMMEDIATE)
private val mobileMappings = FakeMobileMappingsProxy()
private val globalSettings = FakeSettings()
private val connectionsRepo = FakeMobileConnectionsRepository()
private val connectionsRepo = FakeMobileConnectionsRepository(mobileMappings)
@Before
fun setUp() {
@@ -89,6 +92,7 @@ class MobileConnectionRepositoryTest : SysuiTestCase() {
globalSettings,
connectionsRepo.defaultDataSubId,
connectionsRepo.globalMobileDataSettingChangedEvent,
mobileMappings,
IMMEDIATE,
logger,
scope,
@@ -272,7 +276,7 @@ class MobileConnectionRepositoryTest : SysuiTestCase() {
val job = underTest.subscriptionModelFlow.onEach { latest = it }.launchIn(this)
val type = NETWORK_TYPE_UNKNOWN
val expected = DefaultNetworkType(type)
val expected = UnknownNetworkType
assertThat(latest?.resolvedNetworkType).isEqualTo(expected)
@@ -287,7 +291,7 @@ class MobileConnectionRepositoryTest : SysuiTestCase() {
val callback = getTelephonyCallbackForType<TelephonyCallback.DisplayInfoListener>()
val type = NETWORK_TYPE_LTE
val expected = DefaultNetworkType(type)
val expected = DefaultNetworkType(type, mobileMappings.toIconKey(type))
val ti = mock<TelephonyDisplayInfo>().also { whenever(it.networkType).thenReturn(type) }
callback.onDisplayInfoChanged(ti)
@@ -304,9 +308,10 @@ class MobileConnectionRepositoryTest : SysuiTestCase() {
val callback = getTelephonyCallbackForType<TelephonyCallback.DisplayInfoListener>()
val type = OVERRIDE_NETWORK_TYPE_LTE_CA
val expected = OverrideNetworkType(type)
val expected = OverrideNetworkType(type, mobileMappings.toIconKeyOverride(type))
val ti =
mock<TelephonyDisplayInfo>().also {
whenever(it.networkType).thenReturn(type)
whenever(it.overrideNetworkType).thenReturn(type)
}
callback.onDisplayInfoChanged(ti)

View File

@@ -32,6 +32,7 @@ import androidx.test.filters.SmallTest
import com.android.internal.telephony.PhoneConstants
import com.android.systemui.SysuiTestCase
import com.android.systemui.statusbar.pipeline.mobile.data.model.MobileConnectivityModel
import com.android.systemui.statusbar.pipeline.mobile.util.FakeMobileMappingsProxy
import com.android.systemui.statusbar.pipeline.shared.ConnectivityPipelineLogger
import com.android.systemui.util.mockito.any
import com.android.systemui.util.mockito.argumentCaptor
@@ -65,6 +66,8 @@ class MobileConnectionsRepositoryTest : SysuiTestCase() {
@Mock private lateinit var telephonyManager: TelephonyManager
@Mock private lateinit var logger: ConnectivityPipelineLogger
private val mobileMappings = FakeMobileMappingsProxy()
private val scope = CoroutineScope(IMMEDIATE)
private val globalSettings = FakeSettings()
@@ -78,6 +81,7 @@ class MobileConnectionsRepositoryTest : SysuiTestCase() {
subscriptionManager,
telephonyManager,
logger,
mobileMappings,
fakeBroadcastDispatcher,
globalSettings,
context,

View File

@@ -24,9 +24,9 @@ import com.android.settingslib.SignalIcon.MobileIconGroup
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.DefaultNetworkType
import com.android.systemui.statusbar.pipeline.mobile.data.model.MobileSubscriptionModel
import com.android.systemui.statusbar.pipeline.mobile.data.model.OverrideNetworkType
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
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
@@ -62,7 +62,6 @@ class MobileIconInteractorTest : SysuiTestCase() {
mobileIconsInteractor.defaultMobileIconMapping,
mobileIconsInteractor.defaultMobileIconGroup,
mobileIconsInteractor.isDefaultConnectionFailed,
mobileMappingsProxy,
connectionRepository,
)
}
@@ -138,7 +137,10 @@ class MobileIconInteractorTest : SysuiTestCase() {
fun iconGroup_three_g() =
runBlocking(IMMEDIATE) {
connectionRepository.setMobileSubscriptionModel(
MobileSubscriptionModel(resolvedNetworkType = DefaultNetworkType(THREE_G)),
MobileSubscriptionModel(
resolvedNetworkType =
DefaultNetworkType(THREE_G, mobileMappingsProxy.toIconKey(THREE_G))
),
)
var latest: MobileIconGroup? = null
@@ -153,7 +155,10 @@ class MobileIconInteractorTest : SysuiTestCase() {
fun iconGroup_updates_on_change() =
runBlocking(IMMEDIATE) {
connectionRepository.setMobileSubscriptionModel(
MobileSubscriptionModel(resolvedNetworkType = DefaultNetworkType(THREE_G)),
MobileSubscriptionModel(
resolvedNetworkType =
DefaultNetworkType(THREE_G, mobileMappingsProxy.toIconKey(THREE_G))
),
)
var latest: MobileIconGroup? = null
@@ -161,7 +166,11 @@ class MobileIconInteractorTest : SysuiTestCase() {
connectionRepository.setMobileSubscriptionModel(
MobileSubscriptionModel(
resolvedNetworkType = DefaultNetworkType(FOUR_G),
resolvedNetworkType =
DefaultNetworkType(
FOUR_G,
mobileMappingsProxy.toIconKey(FOUR_G),
),
),
)
yield()
@@ -175,7 +184,13 @@ class MobileIconInteractorTest : SysuiTestCase() {
fun iconGroup_5g_override_type() =
runBlocking(IMMEDIATE) {
connectionRepository.setMobileSubscriptionModel(
MobileSubscriptionModel(resolvedNetworkType = OverrideNetworkType(FIVE_G_OVERRIDE)),
MobileSubscriptionModel(
resolvedNetworkType =
OverrideNetworkType(
FIVE_G_OVERRIDE,
mobileMappingsProxy.toIconKeyOverride(FIVE_G_OVERRIDE)
)
),
)
var latest: MobileIconGroup? = null
@@ -191,7 +206,11 @@ class MobileIconInteractorTest : SysuiTestCase() {
runBlocking(IMMEDIATE) {
connectionRepository.setMobileSubscriptionModel(
MobileSubscriptionModel(
resolvedNetworkType = DefaultNetworkType(NETWORK_TYPE_UNKNOWN),
resolvedNetworkType =
DefaultNetworkType(
NETWORK_TYPE_UNKNOWN,
mobileMappingsProxy.toIconKey(NETWORK_TYPE_UNKNOWN)
),
),
)

View File

@@ -45,8 +45,8 @@ import org.mockito.MockitoAnnotations
class MobileIconsInteractorTest : SysuiTestCase() {
private lateinit var underTest: MobileIconsInteractor
private val userSetupRepository = FakeUserSetupRepository()
private val connectionsRepository = FakeMobileConnectionsRepository()
private val mobileMappingsProxy = FakeMobileMappingsProxy()
private val connectionsRepository = FakeMobileConnectionsRepository(mobileMappingsProxy)
private val scope = CoroutineScope(IMMEDIATE)
@Mock private lateinit var carrierConfigTracker: CarrierConfigTracker
@@ -69,7 +69,6 @@ class MobileIconsInteractorTest : SysuiTestCase() {
MobileIconsInteractorImpl(
connectionsRepository,
carrierConfigTracker,
mobileMappingsProxy,
userSetupRepository,
scope
)