[Status bar refactor] Implement the lookup from network type to RAT icon
This CL adds the ability to map from network type to icon used to display the RAT indicator (LTE, 3G, etc.). This process starts by consuming TelephonyDisplayInfo and using the SettingsLib MobileMappings.java utilities to map all of the telephony Network Types to TelephonyIcons.java. 1. Add an injectable MobileMappings proxy 2. Add support for generating the MobileMappings.Config class under the same conditions that NetworkController does. 3. Thread all of the mobile mappings to the MobileIconGroup in MobileIconViewModel 4. A bunch of tests Test: atest MobileIconInteractorTest Bug: 240492102 Change-Id: I38e917cfa1c98bd86258061defa89cc8705816e0
This commit is contained in:
@@ -22,6 +22,10 @@ import com.android.systemui.statusbar.pipeline.mobile.data.repository.MobileSubs
|
||||
import com.android.systemui.statusbar.pipeline.mobile.data.repository.MobileSubscriptionRepositoryImpl
|
||||
import com.android.systemui.statusbar.pipeline.mobile.data.repository.UserSetupRepository
|
||||
import com.android.systemui.statusbar.pipeline.mobile.data.repository.UserSetupRepositoryImpl
|
||||
import com.android.systemui.statusbar.pipeline.mobile.domain.interactor.MobileIconsInteractor
|
||||
import com.android.systemui.statusbar.pipeline.mobile.domain.interactor.MobileIconsInteractorImpl
|
||||
import com.android.systemui.statusbar.pipeline.mobile.util.MobileMappingsProxy
|
||||
import com.android.systemui.statusbar.pipeline.mobile.util.MobileMappingsProxyImpl
|
||||
import com.android.systemui.statusbar.pipeline.shared.data.repository.ConnectivityRepository
|
||||
import com.android.systemui.statusbar.pipeline.shared.data.repository.ConnectivityRepositoryImpl
|
||||
import com.android.systemui.statusbar.pipeline.wifi.data.repository.WifiRepository
|
||||
@@ -47,4 +51,10 @@ abstract class StatusBarPipelineModule {
|
||||
|
||||
@Binds
|
||||
abstract fun userSetupRepository(impl: UserSetupRepositoryImpl): UserSetupRepository
|
||||
|
||||
@Binds
|
||||
abstract fun mobileMappingsProxy(impl: MobileMappingsProxyImpl): MobileMappingsProxy
|
||||
|
||||
@Binds
|
||||
abstract fun mobileIconsInteractor(impl: MobileIconsInteractorImpl): MobileIconsInteractor
|
||||
}
|
||||
|
||||
@@ -27,6 +27,7 @@ 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
|
||||
|
||||
/**
|
||||
* Data class containing all of the relevant information for a particular line of service, known as
|
||||
@@ -57,6 +58,11 @@ data class MobileSubscriptionModel(
|
||||
/** From [CarrierNetworkListener.onCarrierNetworkChange] */
|
||||
val carrierNetworkChangeActive: Boolean? = null,
|
||||
|
||||
/** From [DisplayInfoListener.onDisplayInfoChanged] */
|
||||
val displayInfo: TelephonyDisplayInfo? = null
|
||||
/**
|
||||
* 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
|
||||
*/
|
||||
val resolvedNetworkType: ResolvedNetworkType = DefaultNetworkType(NETWORK_TYPE_UNKNOWN),
|
||||
)
|
||||
|
||||
@@ -0,0 +1,33 @@
|
||||
/*
|
||||
* 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.telephony.Annotation.NetworkType
|
||||
import com.android.systemui.statusbar.pipeline.mobile.util.MobileMappingsProxy
|
||||
|
||||
/**
|
||||
* A SysUI type to represent the [NetworkType] that we pull out of [TelephonyDisplayInfo]. Depending
|
||||
* on whether or not the display info contains an override type, we may have to call different
|
||||
* methods on [MobileMappingsProxy] to generate an icon lookup key.
|
||||
*/
|
||||
sealed interface ResolvedNetworkType {
|
||||
@NetworkType val type: Int
|
||||
}
|
||||
|
||||
data class DefaultNetworkType(@NetworkType override val type: Int) : ResolvedNetworkType
|
||||
|
||||
data class OverrideNetworkType(@NetworkType override val type: Int) : ResolvedNetworkType
|
||||
@@ -16,6 +16,9 @@
|
||||
|
||||
package com.android.systemui.statusbar.pipeline.mobile.data.repository
|
||||
|
||||
import android.content.Context
|
||||
import android.content.IntentFilter
|
||||
import android.telephony.CarrierConfigManager
|
||||
import android.telephony.CellSignalStrength
|
||||
import android.telephony.CellSignalStrengthCdma
|
||||
import android.telephony.ServiceState
|
||||
@@ -31,13 +34,21 @@ import android.telephony.TelephonyCallback.DisplayInfoListener
|
||||
import android.telephony.TelephonyCallback.ServiceStateListener
|
||||
import android.telephony.TelephonyCallback.SignalStrengthsListener
|
||||
import android.telephony.TelephonyDisplayInfo
|
||||
import android.telephony.TelephonyDisplayInfo.OVERRIDE_NETWORK_TYPE_NONE
|
||||
import android.telephony.TelephonyManager
|
||||
import androidx.annotation.VisibleForTesting
|
||||
import com.android.settingslib.mobile.MobileMappings
|
||||
import com.android.settingslib.mobile.MobileMappings.Config
|
||||
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.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.util.MobileMappingsProxy
|
||||
import com.android.systemui.statusbar.pipeline.shared.ConnectivityPipelineLogger
|
||||
import javax.inject.Inject
|
||||
import kotlinx.coroutines.CoroutineDispatcher
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
@@ -47,7 +58,9 @@ import kotlinx.coroutines.channels.awaitClose
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.SharingStarted
|
||||
import kotlinx.coroutines.flow.StateFlow
|
||||
import kotlinx.coroutines.flow.combine
|
||||
import kotlinx.coroutines.flow.mapLatest
|
||||
import kotlinx.coroutines.flow.onEach
|
||||
import kotlinx.coroutines.flow.stateIn
|
||||
import kotlinx.coroutines.withContext
|
||||
|
||||
@@ -62,6 +75,9 @@ interface MobileSubscriptionRepository {
|
||||
/** Observable for the subscriptionId of the current mobile data connection */
|
||||
val activeMobileDataSubscriptionId: Flow<Int>
|
||||
|
||||
/** Observable for [MobileMappings.Config] tracking the defaults */
|
||||
val defaultDataSubRatConfig: StateFlow<Config>
|
||||
|
||||
/** Get or create an observable for the given subscription ID */
|
||||
fun getFlowForSubId(subId: Int): Flow<MobileSubscriptionModel>
|
||||
}
|
||||
@@ -74,6 +90,10 @@ class MobileSubscriptionRepositoryImpl
|
||||
constructor(
|
||||
private val subscriptionManager: SubscriptionManager,
|
||||
private val telephonyManager: TelephonyManager,
|
||||
private val logger: ConnectivityPipelineLogger,
|
||||
broadcastDispatcher: BroadcastDispatcher,
|
||||
private val context: Context,
|
||||
private val mobileMappings: MobileMappingsProxy,
|
||||
@Background private val bgDispatcher: CoroutineDispatcher,
|
||||
@Application private val scope: CoroutineScope,
|
||||
) : MobileSubscriptionRepository {
|
||||
@@ -122,6 +142,36 @@ constructor(
|
||||
SubscriptionManager.INVALID_SUBSCRIPTION_ID
|
||||
)
|
||||
|
||||
private val defaultDataSubChangedEvent =
|
||||
broadcastDispatcher.broadcastFlow(
|
||||
IntentFilter(TelephonyManager.ACTION_DEFAULT_DATA_SUBSCRIPTION_CHANGED)
|
||||
)
|
||||
|
||||
private val carrierConfigChangedEvent =
|
||||
broadcastDispatcher.broadcastFlow(
|
||||
IntentFilter(CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED)
|
||||
)
|
||||
|
||||
/**
|
||||
* [Config] is an object that tracks relevant configuration flags for a given subscription ID.
|
||||
* In the case of [MobileMappings], it's hard-coded to check the default data subscription's
|
||||
* config, so this will apply to every icon that we care about.
|
||||
*
|
||||
* Relevant bits in the config are things like
|
||||
* [CarrierConfigManager.KEY_SHOW_4G_FOR_LTE_DATA_ICON_BOOL]
|
||||
*
|
||||
* This flow will produce whenever the default data subscription or the carrier config changes.
|
||||
*/
|
||||
override val defaultDataSubRatConfig: StateFlow<Config> =
|
||||
combine(defaultDataSubChangedEvent, carrierConfigChangedEvent) { _, _ ->
|
||||
Config.readConfig(context)
|
||||
}
|
||||
.stateIn(
|
||||
scope,
|
||||
SharingStarted.WhileSubscribed(),
|
||||
initialValue = Config.readConfig(context)
|
||||
)
|
||||
|
||||
/**
|
||||
* Each mobile subscription needs its own flow, which comes from registering listeners on the
|
||||
* system. Use this method to create those flows and cache them for reuse
|
||||
@@ -151,6 +201,7 @@ constructor(
|
||||
state = state.copy(isEmergencyOnly = serviceState.isEmergencyOnly)
|
||||
trySend(state)
|
||||
}
|
||||
|
||||
override fun onSignalStrengthsChanged(signalStrength: SignalStrength) {
|
||||
val cdmaLevel =
|
||||
signalStrength
|
||||
@@ -173,6 +224,7 @@ constructor(
|
||||
)
|
||||
trySend(state)
|
||||
}
|
||||
|
||||
override fun onDataConnectionStateChanged(
|
||||
dataState: Int,
|
||||
networkType: Int
|
||||
@@ -180,18 +232,31 @@ constructor(
|
||||
state = state.copy(dataConnectionState = dataState)
|
||||
trySend(state)
|
||||
}
|
||||
|
||||
override fun onDataActivity(direction: Int) {
|
||||
state = state.copy(dataActivityDirection = direction)
|
||||
trySend(state)
|
||||
}
|
||||
|
||||
override fun onCarrierNetworkChange(active: Boolean) {
|
||||
state = state.copy(carrierNetworkChangeActive = active)
|
||||
trySend(state)
|
||||
}
|
||||
|
||||
override fun onDisplayInfoChanged(
|
||||
telephonyDisplayInfo: TelephonyDisplayInfo
|
||||
) {
|
||||
state = state.copy(displayInfo = telephonyDisplayInfo)
|
||||
val networkType =
|
||||
if (
|
||||
telephonyDisplayInfo.overrideNetworkType ==
|
||||
OVERRIDE_NETWORK_TYPE_NONE
|
||||
) {
|
||||
DefaultNetworkType(telephonyDisplayInfo.networkType)
|
||||
} else {
|
||||
OverrideNetworkType(telephonyDisplayInfo.overrideNetworkType)
|
||||
}
|
||||
|
||||
state = state.copy(resolvedNetworkType = networkType)
|
||||
trySend(state)
|
||||
}
|
||||
}
|
||||
@@ -202,6 +267,7 @@ constructor(
|
||||
subIdFlowCache.remove(subId)
|
||||
}
|
||||
}
|
||||
.onEach { logger.logOutputChange("mobileSubscriptionModel", it.toString()) }
|
||||
.stateIn(scope, SharingStarted.WhileSubscribed(), state)
|
||||
}
|
||||
|
||||
|
||||
@@ -17,32 +17,56 @@
|
||||
package com.android.systemui.statusbar.pipeline.mobile.domain.interactor
|
||||
|
||||
import android.telephony.CarrierConfigManager
|
||||
import com.android.settingslib.SignalIcon
|
||||
import com.android.settingslib.mobile.TelephonyIcons
|
||||
import com.android.settingslib.SignalIcon.MobileIconGroup
|
||||
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.util.MobileMappingsProxy
|
||||
import com.android.systemui.util.CarrierConfigTracker
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.combine
|
||||
import kotlinx.coroutines.flow.flowOf
|
||||
import kotlinx.coroutines.flow.map
|
||||
|
||||
interface MobileIconInteractor {
|
||||
/** Identifier for RAT type indicator */
|
||||
val iconGroup: Flow<SignalIcon.MobileIconGroup>
|
||||
/** Observable for RAT type (network type) indicator */
|
||||
val networkTypeIconGroup: Flow<MobileIconGroup>
|
||||
|
||||
/** True if this line of service is emergency-only */
|
||||
val isEmergencyOnly: Flow<Boolean>
|
||||
|
||||
/** Int describing the connection strength. 0-4 OR 1-5. See [numberOfLevels] */
|
||||
val level: Flow<Int>
|
||||
|
||||
/** Based on [CarrierConfigManager.KEY_INFLATE_SIGNAL_STRENGTH_BOOL], either 4 or 5 */
|
||||
val numberOfLevels: Flow<Int>
|
||||
|
||||
/** True when we want to draw an icon that makes room for the exclamation mark */
|
||||
val cutOut: Flow<Boolean>
|
||||
}
|
||||
|
||||
/** Interactor for a single mobile connection. This connection _should_ have one subscription ID */
|
||||
class MobileIconInteractorImpl(
|
||||
defaultMobileIconMapping: Flow<Map<String, MobileIconGroup>>,
|
||||
defaultMobileIconGroup: Flow<MobileIconGroup>,
|
||||
mobileMappingsProxy: MobileMappingsProxy,
|
||||
mobileStatusInfo: Flow<MobileSubscriptionModel>,
|
||||
) : MobileIconInteractor {
|
||||
override val iconGroup: Flow<SignalIcon.MobileIconGroup> = flowOf(TelephonyIcons.THREE_G)
|
||||
/** Observable for the current RAT indicator icon ([MobileIconGroup]) */
|
||||
override val networkTypeIconGroup: Flow<MobileIconGroup> =
|
||||
combine(
|
||||
mobileStatusInfo,
|
||||
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
|
||||
}
|
||||
|
||||
override val isEmergencyOnly: Flow<Boolean> = mobileStatusInfo.map { it.isEmergencyOnly }
|
||||
|
||||
override val level: Flow<Int> =
|
||||
|
||||
@@ -19,29 +19,52 @@ package com.android.systemui.statusbar.pipeline.mobile.domain.interactor
|
||||
import android.telephony.CarrierConfigManager
|
||||
import android.telephony.SubscriptionInfo
|
||||
import android.telephony.SubscriptionManager
|
||||
import com.android.settingslib.SignalIcon.MobileIconGroup
|
||||
import com.android.settingslib.mobile.TelephonyIcons
|
||||
import com.android.systemui.dagger.SysUISingleton
|
||||
import com.android.systemui.dagger.qualifiers.Application
|
||||
import com.android.systemui.statusbar.pipeline.mobile.data.model.MobileSubscriptionModel
|
||||
import com.android.systemui.statusbar.pipeline.mobile.data.repository.MobileSubscriptionRepository
|
||||
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
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.SharingStarted
|
||||
import kotlinx.coroutines.flow.StateFlow
|
||||
import kotlinx.coroutines.flow.combine
|
||||
import kotlinx.coroutines.flow.map
|
||||
import kotlinx.coroutines.flow.stateIn
|
||||
|
||||
/**
|
||||
* Business layer logic for mobile subscription icons
|
||||
* Business layer logic for the set of mobile subscription icons.
|
||||
*
|
||||
* Mobile indicators represent the UI for the (potentially filtered) list of [SubscriptionInfo]s
|
||||
* that the system knows about. They obey policy that depends on OEM, carrier, and locale configs
|
||||
* This interactor represents known set of mobile subscriptions (represented by [SubscriptionInfo]).
|
||||
* The list of subscriptions is filtered based on the opportunistic flags on the infos.
|
||||
*
|
||||
* It provides the default mapping between the telephony display info and the icon group that
|
||||
* represents each RAT (LTE, 3G, etc.), as well as can produce an interactor for each individual
|
||||
* icon
|
||||
*/
|
||||
interface MobileIconsInteractor {
|
||||
val filteredSubscriptions: Flow<List<SubscriptionInfo>>
|
||||
val defaultMobileIconMapping: Flow<Map<String, MobileIconGroup>>
|
||||
val defaultMobileIconGroup: Flow<MobileIconGroup>
|
||||
val isUserSetup: Flow<Boolean>
|
||||
fun createMobileConnectionInteractorForSubId(subId: Int): MobileIconInteractor
|
||||
}
|
||||
|
||||
@SysUISingleton
|
||||
class MobileIconsInteractor
|
||||
class MobileIconsInteractorImpl
|
||||
@Inject
|
||||
constructor(
|
||||
private val mobileSubscriptionRepo: MobileSubscriptionRepository,
|
||||
private val carrierConfigTracker: CarrierConfigTracker,
|
||||
private val mobileMappingsProxy: MobileMappingsProxy,
|
||||
userSetupRepo: UserSetupRepository,
|
||||
) {
|
||||
@Application private val scope: CoroutineScope,
|
||||
) : MobileIconsInteractor {
|
||||
private val activeMobileDataSubscriptionId =
|
||||
mobileSubscriptionRepo.activeMobileDataSubscriptionId
|
||||
|
||||
@@ -61,7 +84,7 @@ constructor(
|
||||
* [CarrierConfigManager.KEY_ALWAYS_SHOW_PRIMARY_SIGNAL_BAR_IN_OPPORTUNISTIC_NETWORK_BOOLEAN],
|
||||
* and by checking which subscription is opportunistic, or which one is active.
|
||||
*/
|
||||
val filteredSubscriptions: Flow<List<SubscriptionInfo>> =
|
||||
override val filteredSubscriptions: Flow<List<SubscriptionInfo>> =
|
||||
combine(unfilteredSubscriptions, activeMobileDataSubscriptionId) { unfilteredSubs, activeId
|
||||
->
|
||||
// Based on the old logic,
|
||||
@@ -92,11 +115,31 @@ constructor(
|
||||
}
|
||||
}
|
||||
|
||||
val isUserSetup: Flow<Boolean> = userSetupRepo.isUserSetupFlow
|
||||
/**
|
||||
* Mapping from network type to [MobileIconGroup] using the config generated for the default
|
||||
* subscription Id. This mapping is the same for every subscription.
|
||||
*/
|
||||
override val defaultMobileIconMapping: StateFlow<Map<String, MobileIconGroup>> =
|
||||
mobileSubscriptionRepo.defaultDataSubRatConfig
|
||||
.map { mobileMappingsProxy.mapIconSets(it) }
|
||||
.stateIn(scope, SharingStarted.WhileSubscribed(), initialValue = mapOf())
|
||||
|
||||
/** If there is no mapping in [defaultMobileIconMapping], then use this default icon group */
|
||||
override val defaultMobileIconGroup: StateFlow<MobileIconGroup> =
|
||||
mobileSubscriptionRepo.defaultDataSubRatConfig
|
||||
.map { mobileMappingsProxy.getDefaultIcons(it) }
|
||||
.stateIn(scope, SharingStarted.WhileSubscribed(), initialValue = TelephonyIcons.G)
|
||||
|
||||
override val isUserSetup: Flow<Boolean> = userSetupRepo.isUserSetupFlow
|
||||
|
||||
/** Vends out new [MobileIconInteractor] for a particular subId */
|
||||
fun createMobileConnectionInteractorForSubId(subId: Int): MobileIconInteractor =
|
||||
MobileIconInteractorImpl(mobileSubscriptionFlowForSubId(subId))
|
||||
override fun createMobileConnectionInteractorForSubId(subId: Int): MobileIconInteractor =
|
||||
MobileIconInteractorImpl(
|
||||
defaultMobileIconMapping,
|
||||
defaultMobileIconGroup,
|
||||
mobileMappingsProxy,
|
||||
mobileSubscriptionFlowForSubId(subId),
|
||||
)
|
||||
|
||||
/**
|
||||
* Create a new flow for a given subscription ID, which usually maps 1:1 with mobile connections
|
||||
|
||||
@@ -17,6 +17,8 @@
|
||||
package com.android.systemui.statusbar.pipeline.mobile.ui.binder
|
||||
|
||||
import android.content.res.ColorStateList
|
||||
import android.view.View.GONE
|
||||
import android.view.View.VISIBLE
|
||||
import android.view.ViewGroup
|
||||
import android.widget.ImageView
|
||||
import androidx.core.view.isVisible
|
||||
@@ -24,6 +26,7 @@ import androidx.lifecycle.Lifecycle
|
||||
import androidx.lifecycle.repeatOnLifecycle
|
||||
import com.android.settingslib.graph.SignalDrawable
|
||||
import com.android.systemui.R
|
||||
import com.android.systemui.common.ui.binder.IconViewBinder
|
||||
import com.android.systemui.lifecycle.repeatWhenAttached
|
||||
import com.android.systemui.statusbar.pipeline.mobile.ui.viewmodel.MobileIconViewModel
|
||||
import kotlinx.coroutines.flow.collect
|
||||
@@ -37,6 +40,7 @@ object MobileIconBinder {
|
||||
view: ViewGroup,
|
||||
viewModel: MobileIconViewModel,
|
||||
) {
|
||||
val networkTypeView = view.requireViewById<ImageView>(R.id.mobile_type)
|
||||
val iconView = view.requireViewById<ImageView>(R.id.mobile_signal)
|
||||
val mobileDrawable = SignalDrawable(view.context).also { iconView.setImageDrawable(it) }
|
||||
|
||||
@@ -52,10 +56,20 @@ object MobileIconBinder {
|
||||
}
|
||||
}
|
||||
|
||||
// Set the network type icon
|
||||
launch {
|
||||
viewModel.networkTypeIcon.distinctUntilChanged().collect { dataTypeId ->
|
||||
dataTypeId?.let { IconViewBinder.bind(dataTypeId, networkTypeView) }
|
||||
networkTypeView.visibility = if (dataTypeId != null) VISIBLE else GONE
|
||||
}
|
||||
}
|
||||
|
||||
// Set the tint
|
||||
launch {
|
||||
viewModel.tint.collect { tint ->
|
||||
iconView.imageTintList = ColorStateList.valueOf(tint)
|
||||
val tintList = ColorStateList.valueOf(tint)
|
||||
iconView.imageTintList = tintList
|
||||
networkTypeView.imageTintList = tintList
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,6 +18,8 @@ package com.android.systemui.statusbar.pipeline.mobile.ui.viewmodel
|
||||
|
||||
import android.graphics.Color
|
||||
import com.android.settingslib.graph.SignalDrawable
|
||||
import com.android.systemui.common.shared.model.ContentDescription
|
||||
import com.android.systemui.common.shared.model.Icon
|
||||
import com.android.systemui.statusbar.pipeline.mobile.domain.interactor.MobileIconInteractor
|
||||
import com.android.systemui.statusbar.pipeline.mobile.domain.interactor.MobileIconsInteractor
|
||||
import com.android.systemui.statusbar.pipeline.shared.ConnectivityPipelineLogger
|
||||
@@ -26,6 +28,7 @@ import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.combine
|
||||
import kotlinx.coroutines.flow.distinctUntilChanged
|
||||
import kotlinx.coroutines.flow.flowOf
|
||||
import kotlinx.coroutines.flow.map
|
||||
|
||||
/**
|
||||
* View model for the state of a single mobile icon. Each [MobileIconViewModel] will keep watch over
|
||||
@@ -54,5 +57,15 @@ constructor(
|
||||
.distinctUntilChanged()
|
||||
.logOutputChange(logger, "iconId($subscriptionId)")
|
||||
|
||||
/** The RAT icon (LTE, 3G, 5G, etc) to be displayed. Null if we shouldn't show anything */
|
||||
var networkTypeIcon: Flow<Icon?> =
|
||||
iconInteractor.networkTypeIconGroup.map {
|
||||
val desc =
|
||||
if (it.dataContentDescription != 0)
|
||||
ContentDescription.Resource(it.dataContentDescription)
|
||||
else null
|
||||
Icon.Resource(it.dataType, desc)
|
||||
}
|
||||
|
||||
var tint: Flow<Int> = flowOf(Color.CYAN)
|
||||
}
|
||||
|
||||
@@ -0,0 +1,52 @@
|
||||
/*
|
||||
* 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.util
|
||||
|
||||
import android.telephony.Annotation.NetworkType
|
||||
import android.telephony.TelephonyDisplayInfo
|
||||
import com.android.settingslib.SignalIcon.MobileIconGroup
|
||||
import com.android.settingslib.mobile.MobileMappings
|
||||
import com.android.settingslib.mobile.MobileMappings.Config
|
||||
import javax.inject.Inject
|
||||
|
||||
/**
|
||||
* [MobileMappings] owns the logic on creating the map from [TelephonyDisplayInfo] to
|
||||
* [MobileIconGroup]. It creates that hash map and also manages the creation of lookup keys. This
|
||||
* interface allows us to proxy those calls to the static java methods in SettingsLib and also fake
|
||||
* them out in tests
|
||||
*/
|
||||
interface MobileMappingsProxy {
|
||||
fun mapIconSets(config: Config): Map<String, MobileIconGroup>
|
||||
fun getDefaultIcons(config: Config): MobileIconGroup
|
||||
fun toIconKey(@NetworkType networkType: Int): String
|
||||
fun toIconKeyOverride(@NetworkType networkType: Int): String
|
||||
}
|
||||
|
||||
/** Injectable wrapper class for [MobileMappings] */
|
||||
class MobileMappingsProxyImpl @Inject constructor() : MobileMappingsProxy {
|
||||
override fun mapIconSets(config: Config): Map<String, MobileIconGroup> =
|
||||
MobileMappings.mapIconSets(config)
|
||||
|
||||
override fun getDefaultIcons(config: Config): MobileIconGroup =
|
||||
MobileMappings.getDefaultIcons(config)
|
||||
|
||||
override fun toIconKey(@NetworkType networkType: Int): String =
|
||||
MobileMappings.toIconKey(networkType)
|
||||
|
||||
override fun toIconKeyOverride(networkType: Int): String =
|
||||
MobileMappings.toDisplayIconKey(networkType)
|
||||
}
|
||||
@@ -18,6 +18,7 @@ package com.android.systemui.statusbar.pipeline.mobile.data.repository
|
||||
|
||||
import android.telephony.SubscriptionInfo
|
||||
import android.telephony.SubscriptionManager
|
||||
import com.android.settingslib.mobile.MobileMappings.Config
|
||||
import com.android.systemui.statusbar.pipeline.mobile.data.model.MobileSubscriptionModel
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
@@ -30,6 +31,9 @@ class FakeMobileSubscriptionRepository : MobileSubscriptionRepository {
|
||||
MutableStateFlow(SubscriptionManager.INVALID_SUBSCRIPTION_ID)
|
||||
override val activeMobileDataSubscriptionId = _activeMobileDataSubscriptionId
|
||||
|
||||
private val _defaultDataSubRatConfig = MutableStateFlow(Config())
|
||||
override val defaultDataSubRatConfig = _defaultDataSubRatConfig
|
||||
|
||||
private val subIdFlows = mutableMapOf<Int, MutableStateFlow<MobileSubscriptionModel>>()
|
||||
override fun getFlowForSubId(subId: Int): Flow<MobileSubscriptionModel> {
|
||||
return subIdFlows[subId]
|
||||
@@ -40,6 +44,10 @@ class FakeMobileSubscriptionRepository : MobileSubscriptionRepository {
|
||||
_subscriptionsFlow.value = subs
|
||||
}
|
||||
|
||||
fun setDefaultDataSubRatConfig(config: Config) {
|
||||
_defaultDataSubRatConfig.value = config
|
||||
}
|
||||
|
||||
fun setActiveMobileDataSubscriptionId(subId: Int) {
|
||||
_activeMobileDataSubscriptionId.value = subId
|
||||
}
|
||||
|
||||
@@ -30,25 +30,36 @@ import android.telephony.TelephonyCallback.DisplayInfoListener
|
||||
import android.telephony.TelephonyCallback.ServiceStateListener
|
||||
import android.telephony.TelephonyCallback.SignalStrengthsListener
|
||||
import android.telephony.TelephonyDisplayInfo
|
||||
import android.telephony.TelephonyDisplayInfo.OVERRIDE_NETWORK_TYPE_LTE_CA
|
||||
import android.telephony.TelephonyManager
|
||||
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.broadcast.BroadcastDispatcher
|
||||
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.util.FakeMobileMappingsProxy
|
||||
import com.android.systemui.statusbar.pipeline.shared.ConnectivityPipelineLogger
|
||||
import com.android.systemui.util.mockito.any
|
||||
import com.android.systemui.util.mockito.argumentCaptor
|
||||
import com.android.systemui.util.mockito.mock
|
||||
import com.android.systemui.util.mockito.nullable
|
||||
import com.android.systemui.util.mockito.whenever
|
||||
import com.google.common.truth.Truth.assertThat
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
||||
import kotlinx.coroutines.cancel
|
||||
import kotlinx.coroutines.flow.flowOf
|
||||
import kotlinx.coroutines.flow.launchIn
|
||||
import kotlinx.coroutines.flow.onEach
|
||||
import kotlinx.coroutines.runBlocking
|
||||
import org.junit.After
|
||||
import org.junit.Before
|
||||
import org.junit.Test
|
||||
import org.mockito.ArgumentMatchers
|
||||
import org.mockito.Mock
|
||||
import org.mockito.Mockito.verify
|
||||
import org.mockito.MockitoAnnotations
|
||||
@@ -61,16 +72,33 @@ class MobileSubscriptionRepositoryTest : SysuiTestCase() {
|
||||
|
||||
@Mock private lateinit var subscriptionManager: SubscriptionManager
|
||||
@Mock private lateinit var telephonyManager: TelephonyManager
|
||||
@Mock private lateinit var logger: ConnectivityPipelineLogger
|
||||
@Mock private lateinit var broadcastDispatcher: BroadcastDispatcher
|
||||
|
||||
private val scope = CoroutineScope(IMMEDIATE)
|
||||
private val mobileMappings = FakeMobileMappingsProxy()
|
||||
|
||||
@Before
|
||||
fun setUp() {
|
||||
MockitoAnnotations.initMocks(this)
|
||||
whenever(
|
||||
broadcastDispatcher.broadcastFlow(
|
||||
any(),
|
||||
nullable(),
|
||||
ArgumentMatchers.anyInt(),
|
||||
nullable(),
|
||||
)
|
||||
)
|
||||
.thenReturn(flowOf(Unit))
|
||||
|
||||
underTest =
|
||||
MobileSubscriptionRepositoryImpl(
|
||||
subscriptionManager,
|
||||
telephonyManager,
|
||||
logger,
|
||||
broadcastDispatcher,
|
||||
context,
|
||||
mobileMappings,
|
||||
IMMEDIATE,
|
||||
scope,
|
||||
)
|
||||
@@ -266,7 +294,23 @@ class MobileSubscriptionRepositoryTest : SysuiTestCase() {
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testFlowForSubId_displayInfo() =
|
||||
fun testFlowForSubId_defaultNetworkType() =
|
||||
runBlocking(IMMEDIATE) {
|
||||
whenever(telephonyManager.createForSubscriptionId(any())).thenReturn(telephonyManager)
|
||||
|
||||
var latest: MobileSubscriptionModel? = null
|
||||
val job = underTest.getFlowForSubId(SUB_1_ID).onEach { latest = it }.launchIn(this)
|
||||
|
||||
val type = NETWORK_TYPE_UNKNOWN
|
||||
val expected = DefaultNetworkType(type)
|
||||
|
||||
assertThat(latest?.resolvedNetworkType).isEqualTo(expected)
|
||||
|
||||
job.cancel()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testFlowForSubId_networkTypeUpdates_default() =
|
||||
runBlocking(IMMEDIATE) {
|
||||
whenever(telephonyManager.createForSubscriptionId(any())).thenReturn(telephonyManager)
|
||||
|
||||
@@ -274,10 +318,34 @@ class MobileSubscriptionRepositoryTest : SysuiTestCase() {
|
||||
val job = underTest.getFlowForSubId(SUB_1_ID).onEach { latest = it }.launchIn(this)
|
||||
|
||||
val callback = getTelephonyCallbackForType<DisplayInfoListener>()
|
||||
val ti = mock<TelephonyDisplayInfo>()
|
||||
val type = NETWORK_TYPE_LTE
|
||||
val expected = DefaultNetworkType(type)
|
||||
val ti = mock<TelephonyDisplayInfo>().also { whenever(it.networkType).thenReturn(type) }
|
||||
callback.onDisplayInfoChanged(ti)
|
||||
|
||||
assertThat(latest?.displayInfo).isEqualTo(ti)
|
||||
assertThat(latest?.resolvedNetworkType).isEqualTo(expected)
|
||||
|
||||
job.cancel()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testFlowForSubId_networkTypeUpdates_override() =
|
||||
runBlocking(IMMEDIATE) {
|
||||
whenever(telephonyManager.createForSubscriptionId(any())).thenReturn(telephonyManager)
|
||||
|
||||
var latest: MobileSubscriptionModel? = null
|
||||
val job = underTest.getFlowForSubId(SUB_1_ID).onEach { latest = it }.launchIn(this)
|
||||
|
||||
val callback = getTelephonyCallbackForType<DisplayInfoListener>()
|
||||
val type = OVERRIDE_NETWORK_TYPE_LTE_CA
|
||||
val expected = OverrideNetworkType(type)
|
||||
val ti =
|
||||
mock<TelephonyDisplayInfo>().also {
|
||||
whenever(it.overrideNetworkType).thenReturn(type)
|
||||
}
|
||||
callback.onDisplayInfoChanged(ti)
|
||||
|
||||
assertThat(latest?.resolvedNetworkType).isEqualTo(expected)
|
||||
|
||||
job.cancel()
|
||||
}
|
||||
|
||||
@@ -23,7 +23,7 @@ import kotlinx.coroutines.flow.MutableStateFlow
|
||||
|
||||
class FakeMobileIconInteractor : MobileIconInteractor {
|
||||
private val _iconGroup = MutableStateFlow<SignalIcon.MobileIconGroup>(TelephonyIcons.UNKNOWN)
|
||||
override val iconGroup = _iconGroup
|
||||
override val networkTypeIconGroup = _iconGroup
|
||||
|
||||
private val _isEmergencyOnly = MutableStateFlow<Boolean>(false)
|
||||
override val isEmergencyOnly = _isEmergencyOnly
|
||||
|
||||
@@ -0,0 +1,75 @@
|
||||
/*
|
||||
* 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.domain.interactor
|
||||
|
||||
import android.telephony.SubscriptionInfo
|
||||
import android.telephony.TelephonyDisplayInfo.OVERRIDE_NETWORK_TYPE_LTE_ADVANCED_PRO
|
||||
import android.telephony.TelephonyManager.NETWORK_TYPE_GSM
|
||||
import android.telephony.TelephonyManager.NETWORK_TYPE_LTE
|
||||
import android.telephony.TelephonyManager.NETWORK_TYPE_UMTS
|
||||
import com.android.settingslib.SignalIcon.MobileIconGroup
|
||||
import com.android.settingslib.mobile.TelephonyIcons
|
||||
import com.android.systemui.statusbar.pipeline.mobile.util.MobileMappingsProxy
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
|
||||
class FakeMobileIconsInteractor(private val mobileMappings: MobileMappingsProxy) :
|
||||
MobileIconsInteractor {
|
||||
val THREE_G_KEY = mobileMappings.toIconKey(THREE_G)
|
||||
val LTE_KEY = mobileMappings.toIconKey(LTE)
|
||||
val FOUR_G_KEY = mobileMappings.toIconKey(FOUR_G)
|
||||
val FIVE_G_OVERRIDE_KEY = mobileMappings.toIconKeyOverride(FIVE_G_OVERRIDE)
|
||||
|
||||
/**
|
||||
* 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, MobileIconGroup> =
|
||||
mapOf(
|
||||
THREE_G_KEY to TelephonyIcons.THREE_G,
|
||||
LTE_KEY to TelephonyIcons.LTE,
|
||||
FOUR_G_KEY to TelephonyIcons.FOUR_G,
|
||||
FIVE_G_OVERRIDE_KEY to TelephonyIcons.NR_5G,
|
||||
)
|
||||
|
||||
private val _filteredSubscriptions = MutableStateFlow<List<SubscriptionInfo>>(listOf())
|
||||
override val filteredSubscriptions = _filteredSubscriptions
|
||||
|
||||
private val _defaultMobileIconMapping = MutableStateFlow(TEST_MAPPING)
|
||||
override val defaultMobileIconMapping = _defaultMobileIconMapping
|
||||
|
||||
private val _defaultMobileIconGroup = MutableStateFlow(DEFAULT_ICON)
|
||||
override val defaultMobileIconGroup = _defaultMobileIconGroup
|
||||
|
||||
private val _isUserSetup = MutableStateFlow(true)
|
||||
override val isUserSetup = _isUserSetup
|
||||
|
||||
/** Always returns a new fake interactor */
|
||||
override fun createMobileConnectionInteractorForSubId(subId: Int): MobileIconInteractor {
|
||||
return FakeMobileIconInteractor()
|
||||
}
|
||||
|
||||
companion object {
|
||||
val DEFAULT_ICON = TelephonyIcons.G
|
||||
|
||||
// Use [MobileMappings] to define some simple definitions
|
||||
const val THREE_G = NETWORK_TYPE_GSM
|
||||
const val LTE = NETWORK_TYPE_LTE
|
||||
const val FOUR_G = NETWORK_TYPE_UMTS
|
||||
const val FIVE_G_OVERRIDE = OVERRIDE_NETWORK_TYPE_LTE_ADVANCED_PRO
|
||||
}
|
||||
}
|
||||
@@ -18,10 +18,19 @@ package com.android.systemui.statusbar.pipeline.mobile.domain.interactor
|
||||
|
||||
import android.telephony.CellSignalStrength
|
||||
import android.telephony.SubscriptionInfo
|
||||
import android.telephony.TelephonyManager.NETWORK_TYPE_UNKNOWN
|
||||
import androidx.test.filters.SmallTest
|
||||
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.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.repository.FakeMobileSubscriptionRepository
|
||||
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
|
||||
import com.android.systemui.statusbar.pipeline.mobile.domain.interactor.FakeMobileIconsInteractor.Companion.THREE_G
|
||||
import com.android.systemui.statusbar.pipeline.mobile.util.FakeMobileMappingsProxy
|
||||
import com.android.systemui.util.mockito.mock
|
||||
import com.android.systemui.util.mockito.whenever
|
||||
import com.google.common.truth.Truth.assertThat
|
||||
@@ -29,6 +38,7 @@ import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.flow.launchIn
|
||||
import kotlinx.coroutines.flow.onEach
|
||||
import kotlinx.coroutines.runBlocking
|
||||
import kotlinx.coroutines.yield
|
||||
import org.junit.Before
|
||||
import org.junit.Test
|
||||
|
||||
@@ -36,11 +46,19 @@ import org.junit.Test
|
||||
class MobileIconInteractorTest : SysuiTestCase() {
|
||||
private lateinit var underTest: MobileIconInteractor
|
||||
private val mobileSubscriptionRepository = FakeMobileSubscriptionRepository()
|
||||
private val mobileMappingsProxy = FakeMobileMappingsProxy()
|
||||
private val mobileIconsInteractor = FakeMobileIconsInteractor(mobileMappingsProxy)
|
||||
private val sub1Flow = mobileSubscriptionRepository.getFlowForSubId(SUB_1_ID)
|
||||
|
||||
@Before
|
||||
fun setUp() {
|
||||
underTest = MobileIconInteractorImpl(sub1Flow)
|
||||
underTest =
|
||||
MobileIconInteractorImpl(
|
||||
mobileIconsInteractor.defaultMobileIconMapping,
|
||||
mobileIconsInteractor.defaultMobileIconGroup,
|
||||
mobileMappingsProxy,
|
||||
sub1Flow,
|
||||
)
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -114,6 +132,80 @@ class MobileIconInteractorTest : SysuiTestCase() {
|
||||
job.cancel()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun iconGroup_three_g() =
|
||||
runBlocking(IMMEDIATE) {
|
||||
mobileSubscriptionRepository.setMobileSubscriptionModel(
|
||||
MobileSubscriptionModel(resolvedNetworkType = DefaultNetworkType(THREE_G)),
|
||||
SUB_1_ID
|
||||
)
|
||||
|
||||
var latest: MobileIconGroup? = null
|
||||
val job = underTest.networkTypeIconGroup.onEach { latest = it }.launchIn(this)
|
||||
|
||||
assertThat(latest).isEqualTo(TelephonyIcons.THREE_G)
|
||||
|
||||
job.cancel()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun iconGroup_updates_on_change() =
|
||||
runBlocking(IMMEDIATE) {
|
||||
mobileSubscriptionRepository.setMobileSubscriptionModel(
|
||||
MobileSubscriptionModel(resolvedNetworkType = DefaultNetworkType(THREE_G)),
|
||||
SUB_1_ID
|
||||
)
|
||||
|
||||
var latest: MobileIconGroup? = null
|
||||
val job = underTest.networkTypeIconGroup.onEach { latest = it }.launchIn(this)
|
||||
|
||||
mobileSubscriptionRepository.setMobileSubscriptionModel(
|
||||
MobileSubscriptionModel(
|
||||
resolvedNetworkType = DefaultNetworkType(FOUR_G),
|
||||
),
|
||||
SUB_1_ID
|
||||
)
|
||||
yield()
|
||||
|
||||
assertThat(latest).isEqualTo(TelephonyIcons.FOUR_G)
|
||||
|
||||
job.cancel()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun iconGroup_5g_override_type() =
|
||||
runBlocking(IMMEDIATE) {
|
||||
mobileSubscriptionRepository.setMobileSubscriptionModel(
|
||||
MobileSubscriptionModel(resolvedNetworkType = OverrideNetworkType(FIVE_G_OVERRIDE)),
|
||||
SUB_1_ID
|
||||
)
|
||||
|
||||
var latest: MobileIconGroup? = null
|
||||
val job = underTest.networkTypeIconGroup.onEach { latest = it }.launchIn(this)
|
||||
|
||||
assertThat(latest).isEqualTo(TelephonyIcons.NR_5G)
|
||||
|
||||
job.cancel()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun iconGroup_default_if_no_lookup() =
|
||||
runBlocking(IMMEDIATE) {
|
||||
mobileSubscriptionRepository.setMobileSubscriptionModel(
|
||||
MobileSubscriptionModel(
|
||||
resolvedNetworkType = DefaultNetworkType(NETWORK_TYPE_UNKNOWN),
|
||||
),
|
||||
SUB_1_ID
|
||||
)
|
||||
|
||||
var latest: MobileIconGroup? = null
|
||||
val job = underTest.networkTypeIconGroup.onEach { latest = it }.launchIn(this)
|
||||
|
||||
assertThat(latest).isEqualTo(FakeMobileIconsInteractor.DEFAULT_ICON)
|
||||
|
||||
job.cancel()
|
||||
}
|
||||
|
||||
companion object {
|
||||
private val IMMEDIATE = Dispatchers.Main.immediate
|
||||
|
||||
|
||||
@@ -21,10 +21,12 @@ import androidx.test.filters.SmallTest
|
||||
import com.android.systemui.SysuiTestCase
|
||||
import com.android.systemui.statusbar.pipeline.mobile.data.repository.FakeMobileSubscriptionRepository
|
||||
import com.android.systemui.statusbar.pipeline.mobile.data.repository.FakeUserSetupRepository
|
||||
import com.android.systemui.statusbar.pipeline.mobile.util.FakeMobileMappingsProxy
|
||||
import com.android.systemui.util.CarrierConfigTracker
|
||||
import com.android.systemui.util.mockito.mock
|
||||
import com.android.systemui.util.mockito.whenever
|
||||
import com.google.common.truth.Truth.assertThat
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.flow.launchIn
|
||||
import kotlinx.coroutines.flow.onEach
|
||||
@@ -40,6 +42,8 @@ class MobileIconsInteractorTest : SysuiTestCase() {
|
||||
private lateinit var underTest: MobileIconsInteractor
|
||||
private val userSetupRepository = FakeUserSetupRepository()
|
||||
private val subscriptionsRepository = FakeMobileSubscriptionRepository()
|
||||
private val mobileMappingsProxy = FakeMobileMappingsProxy()
|
||||
private val scope = CoroutineScope(IMMEDIATE)
|
||||
|
||||
@Mock private lateinit var carrierConfigTracker: CarrierConfigTracker
|
||||
|
||||
@@ -47,10 +51,12 @@ class MobileIconsInteractorTest : SysuiTestCase() {
|
||||
fun setUp() {
|
||||
MockitoAnnotations.initMocks(this)
|
||||
underTest =
|
||||
MobileIconsInteractor(
|
||||
MobileIconsInteractorImpl(
|
||||
subscriptionsRepository,
|
||||
carrierConfigTracker,
|
||||
mobileMappingsProxy,
|
||||
userSetupRepository,
|
||||
scope
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,46 @@
|
||||
/*
|
||||
* 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.util
|
||||
|
||||
import com.android.settingslib.SignalIcon.MobileIconGroup
|
||||
import com.android.settingslib.mobile.MobileMappings.Config
|
||||
import com.android.settingslib.mobile.TelephonyIcons
|
||||
|
||||
class FakeMobileMappingsProxy : MobileMappingsProxy {
|
||||
private var iconMap = mapOf<String, MobileIconGroup>()
|
||||
private var defaultIcons = TelephonyIcons.THREE_G
|
||||
|
||||
fun setIconMap(map: Map<String, MobileIconGroup>) {
|
||||
iconMap = map
|
||||
}
|
||||
override fun mapIconSets(config: Config): Map<String, MobileIconGroup> = iconMap
|
||||
fun getIconMap() = iconMap
|
||||
|
||||
fun setDefaultIcons(group: MobileIconGroup) {
|
||||
defaultIcons = group
|
||||
}
|
||||
override fun getDefaultIcons(config: Config): MobileIconGroup = defaultIcons
|
||||
fun getDefaultIcons(): MobileIconGroup = defaultIcons
|
||||
|
||||
override fun toIconKey(networkType: Int): String {
|
||||
return networkType.toString()
|
||||
}
|
||||
|
||||
override fun toIconKeyOverride(networkType: Int): String {
|
||||
return toIconKey(networkType) + "_override"
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user