From f58969d7c195debdc319e40151230bd377fbaf42 Mon Sep 17 00:00:00 2001 From: Evan Laird Date: Fri, 2 Dec 2022 12:33:12 -0500 Subject: [PATCH] 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 --- .../data/model/MobileSubscriptionModel.kt | 3 +- .../mobile/data/model/ResolvedNetworkType.kt | 21 ++++- .../repository/MobileConnectionsRepository.kt | 12 ++- .../repository/MobileRepositorySwitcher.kt | 15 ++- .../demo/DemoMobileConnectionsRepository.kt | 92 ++++++++++--------- .../prod/MobileConnectionRepositoryImpl.kt | 30 ++++-- .../prod/MobileConnectionsRepositoryImpl.kt | 12 ++- .../domain/interactor/MobileIconInteractor.kt | 12 +-- .../interactor/MobileIconsInteractor.kt | 19 ++-- .../FakeMobileConnectionRepository.kt | 1 + .../FakeMobileConnectionsRepository.kt | 51 ++++++++-- .../MobileRepositorySwitcherTest.kt | 3 + .../prod/MobileConnectionRepositoryTest.kt | 17 ++-- .../prod/MobileConnectionsRepositoryTest.kt | 4 + .../interactor/MobileIconInteractorTest.kt | 35 +++++-- .../interactor/MobileIconsInteractorTest.kt | 3 +- 16 files changed, 215 insertions(+), 115 deletions(-) diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/model/MobileSubscriptionModel.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/model/MobileSubscriptionModel.kt index 6341a114112c5..797a7285f877d 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/model/MobileSubscriptionModel.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/model/MobileSubscriptionModel.kt @@ -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, ) diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/model/ResolvedNetworkType.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/model/ResolvedNetworkType.kt index f385806c1b223..dd93541d7c8f7 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/model/ResolvedNetworkType.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/model/ResolvedNetworkType.kt @@ -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 diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/MobileConnectionsRepository.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/MobileConnectionsRepository.kt index 7684b762fe552..58ad423616e11 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/MobileConnectionsRepository.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/MobileConnectionsRepository.kt @@ -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 - /** Observable for [MobileMappings.Config] tracking the defaults */ - val defaultDataSubRatConfig: StateFlow - /** Tracks [SubscriptionManager.getDefaultDataSubscriptionId] */ val defaultDataSubId: StateFlow @@ -50,4 +46,10 @@ interface MobileConnectionsRepository { /** Observe changes to the [Settings.Global.MOBILE_DATA] setting */ val globalMobileDataSettingChangedEvent: Flow + + /** The icon mapping from network type to [MobileIconGroup] for the default subscription */ + val defaultMobileIconMapping: Flow> + + /** Fallback [MobileIconGroup] in the case where there is no icon in the mapping */ + val defaultMobileIconGroup: Flow } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/MobileRepositorySwitcher.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/MobileRepositorySwitcher.kt index e21400525f00b..628f898abb236 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/MobileRepositorySwitcher.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/MobileRepositorySwitcher.kt @@ -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 = - activeRepo - .flatMapLatest { it.defaultDataSubRatConfig } - .stateIn( - scope, - SharingStarted.WhileSubscribed(), - realRepository.defaultDataSubRatConfig.value - ) + override val defaultMobileIconMapping: Flow> = + activeRepo.flatMapLatest { it.defaultMobileIconMapping } + + override val defaultMobileIconGroup: Flow = + activeRepo.flatMapLatest { it.defaultMobileIconGroup } override val defaultDataSubId: StateFlow = activeRepo diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/demo/DemoMobileConnectionsRepository.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/demo/DemoMobileConnectionsRepository.kt index eeb68e778ad9a..45b2c36021212 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/demo/DemoMobileConnectionsRepository.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/demo/DemoMobileConnectionsRepository.kt @@ -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> = + defaultMobileIconMapping + .mapLatest { networkToIconMap -> networkToIconMap.reverse() } + .stateIn( + scope, + SharingStarted.WhileSubscribed(), + defaultMobileIconMapping.value.reverse() + ) + + private fun Map.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()) diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionRepositoryImpl.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionRepositoryImpl.kt index fc0eefe0599a5..f6be228e0ea66 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionRepositoryImpl.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionRepositoryImpl.kt @@ -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, globalMobileDataSettingChangedEvent: Flow, + 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, diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionsRepositoryImpl.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionsRepositoryImpl.kt index 08d6010f0d99d..6582c03d36d9e 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionsRepositoryImpl.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionsRepositoryImpl.kt @@ -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 = + private val defaultDataSubRatConfig: StateFlow = merge(defaultDataSubIdChangeEvent, carrierConfigChangedEvent) .mapLatest { Config.readConfig(context) } .stateIn( @@ -166,6 +170,12 @@ constructor( initialValue = Config.readConfig(context) ) + override val defaultMobileIconMapping: Flow> = + defaultDataSubRatConfig.map { mobileMappingsProxy.mapIconSets(it) } + + override val defaultMobileIconGroup: Flow = + defaultDataSubRatConfig.map { mobileMappingsProxy.getDefaultIcons(it) } + override fun getRepoForSubId(subId: Int): MobileConnectionRepository { if (!isValidSubId(subId)) { throw IllegalArgumentException( diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconInteractor.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconInteractor.kt index 0da84f0bec9cd..96c5597762578 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconInteractor.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconInteractor.kt @@ -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>, defaultMobileIconGroup: StateFlow, override val isDefaultConnectionFailed: StateFlow, - 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) diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconsInteractor.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconsInteractor.kt index a4175c3a6ab19..ada3b39620864 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconsInteractor.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconsInteractor.kt @@ -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> = - 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 = - 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), ) } diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/FakeMobileConnectionRepository.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/FakeMobileConnectionRepository.kt index b06d41b8d5965..fcd0f2b126ae1 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/FakeMobileConnectionRepository.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/FakeMobileConnectionRepository.kt @@ -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 diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/FakeMobileConnectionsRepository.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/FakeMobileConnectionsRepository.kt index e21ab21de6f0c..af2dfb015e0be 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/FakeMobileConnectionsRepository.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/FakeMobileConnectionsRepository.kt @@ -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 = + 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>(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) { _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) { 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 + } } diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/MobileRepositorySwitcherTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/MobileRepositorySwitcherTest.kt index 96a280a296edf..516896099491c 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/MobileRepositorySwitcherTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/MobileRepositorySwitcherTest.kt @@ -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(null) + private val mobileMappings = FakeMobileMappingsProxy() private val scope = CoroutineScope(IMMEDIATE) @@ -97,6 +99,7 @@ class MobileRepositorySwitcherTest : SysuiTestCase() { subscriptionManager, telephonyManager, logger, + mobileMappings, fakeBroadcastDispatcher, globalSettings, context, diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionRepositoryTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionRepositoryTest.kt index c8df5ac17dff4..099cb660f6595 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionRepositoryTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionRepositoryTest.kt @@ -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() val type = NETWORK_TYPE_LTE - val expected = DefaultNetworkType(type) + val expected = DefaultNetworkType(type, mobileMappings.toIconKey(type)) val ti = mock().also { whenever(it.networkType).thenReturn(type) } callback.onDisplayInfoChanged(ti) @@ -304,9 +308,10 @@ class MobileConnectionRepositoryTest : SysuiTestCase() { val callback = getTelephonyCallbackForType() val type = OVERRIDE_NETWORK_TYPE_LTE_CA - val expected = OverrideNetworkType(type) + val expected = OverrideNetworkType(type, mobileMappings.toIconKeyOverride(type)) val ti = mock().also { + whenever(it.networkType).thenReturn(type) whenever(it.overrideNetworkType).thenReturn(type) } callback.onDisplayInfoChanged(ti) diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionsRepositoryTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionsRepositoryTest.kt index 359ea18fcb840..68d85ccca9760 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionsRepositoryTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionsRepositoryTest.kt @@ -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, diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconInteractorTest.kt index 9d7d0ed0db084..b20f8fb4c5022 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconInteractorTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconInteractorTest.kt @@ -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) + ), ), ) diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconsInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconsInteractorTest.kt index 5cdfcfd6d1e69..4e950f5211ace 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconsInteractorTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconsInteractorTest.kt @@ -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 )