Merge changes I04fa90bf,Id413d57d into tm-qpr-dev

* changes:
  [Sb refactor] Support NetworkName in new mobile pipeline
  [Sb refactor] show data activity in Mobile view
This commit is contained in:
Evan Laird
2022-12-21 15:11:36 +00:00
committed by Android (Google) Code Review
23 changed files with 576 additions and 33 deletions

View File

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

View File

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

View File

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

View File

@@ -18,6 +18,7 @@ package com.android.systemui.statusbar.pipeline.mobile.data.repository.demo
import android.content.Context import android.content.Context
import android.telephony.SubscriptionManager.INVALID_SUBSCRIPTION_ID import android.telephony.SubscriptionManager.INVALID_SUBSCRIPTION_ID
import android.telephony.TelephonyManager.DATA_ACTIVITY_NONE
import android.util.Log import android.util.Log
import com.android.settingslib.SignalIcon import com.android.settingslib.SignalIcon
import com.android.settingslib.mobile.MobileMappings import com.android.settingslib.mobile.MobileMappings
@@ -26,6 +27,7 @@ import com.android.systemui.dagger.qualifiers.Application
import com.android.systemui.statusbar.pipeline.mobile.data.model.DataConnectionState import com.android.systemui.statusbar.pipeline.mobile.data.model.DataConnectionState
import com.android.systemui.statusbar.pipeline.mobile.data.model.MobileConnectionModel import com.android.systemui.statusbar.pipeline.mobile.data.model.MobileConnectionModel
import com.android.systemui.statusbar.pipeline.mobile.data.model.MobileConnectivityModel import com.android.systemui.statusbar.pipeline.mobile.data.model.MobileConnectivityModel
import com.android.systemui.statusbar.pipeline.mobile.data.model.NetworkNameModel
import com.android.systemui.statusbar.pipeline.mobile.data.model.ResolvedNetworkType import com.android.systemui.statusbar.pipeline.mobile.data.model.ResolvedNetworkType
import com.android.systemui.statusbar.pipeline.mobile.data.model.ResolvedNetworkType.DefaultNetworkType import com.android.systemui.statusbar.pipeline.mobile.data.model.ResolvedNetworkType.DefaultNetworkType
import com.android.systemui.statusbar.pipeline.mobile.data.model.SubscriptionModel import com.android.systemui.statusbar.pipeline.mobile.data.model.SubscriptionModel
@@ -34,6 +36,7 @@ import com.android.systemui.statusbar.pipeline.mobile.data.repository.MobileConn
import com.android.systemui.statusbar.pipeline.mobile.data.repository.demo.model.FakeNetworkEventModel import com.android.systemui.statusbar.pipeline.mobile.data.repository.demo.model.FakeNetworkEventModel
import com.android.systemui.statusbar.pipeline.mobile.data.repository.demo.model.FakeNetworkEventModel.Mobile import com.android.systemui.statusbar.pipeline.mobile.data.repository.demo.model.FakeNetworkEventModel.Mobile
import com.android.systemui.statusbar.pipeline.mobile.data.repository.demo.model.FakeNetworkEventModel.MobileDisabled import com.android.systemui.statusbar.pipeline.mobile.data.repository.demo.model.FakeNetworkEventModel.MobileDisabled
import com.android.systemui.statusbar.pipeline.shared.data.model.toMobileDataActivityModel
import javax.inject.Inject import javax.inject.Inject
import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.ExperimentalCoroutinesApi
@@ -185,6 +188,7 @@ constructor(
// This is always true here, because we split out disabled states at the data-source level // This is always true here, because we split out disabled states at the data-source level
connection.dataEnabled.value = true connection.dataEnabled.value = true
connection.isDefaultDataSubscription.value = state.dataType != null connection.isDefaultDataSubscription.value = state.dataType != null
connection.networkName.value = NetworkNameModel.Derived(state.name)
connection.cdmaRoaming.value = state.roaming connection.cdmaRoaming.value = state.roaming
connection.connectionInfo.value = state.toMobileConnectionModel() connection.connectionInfo.value = state.toMobileConnectionModel()
@@ -236,7 +240,7 @@ constructor(
primaryLevel = level ?: 0, primaryLevel = level ?: 0,
dataConnectionState = dataConnectionState =
DataConnectionState.Connected, // TODO(b/261029387): not yet supported DataConnectionState.Connected, // TODO(b/261029387): not yet supported
dataActivityDirection = activity, dataActivityDirection = (activity ?: DATA_ACTIVITY_NONE).toMobileDataActivityModel(),
carrierNetworkChangeActive = carrierNetworkChange, carrierNetworkChangeActive = carrierNetworkChange,
resolvedNetworkType = dataType.toResolvedNetworkType() resolvedNetworkType = dataType.toResolvedNetworkType()
) )
@@ -264,4 +268,6 @@ class DemoMobileConnectionRepository(override val subId: Int) : MobileConnection
override val isDefaultDataSubscription = MutableStateFlow(true) override val isDefaultDataSubscription = MutableStateFlow(true)
override val cdmaRoaming = MutableStateFlow(false) override val cdmaRoaming = MutableStateFlow(false)
override val networkName = MutableStateFlow(NetworkNameModel.Derived("demo network"))
} }

View File

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

View File

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

View File

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

View File

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

View File

@@ -20,10 +20,13 @@ import android.telephony.CarrierConfigManager
import com.android.settingslib.SignalIcon.MobileIconGroup import com.android.settingslib.SignalIcon.MobileIconGroup
import com.android.systemui.dagger.qualifiers.Application 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.DataConnectionState.Connected
import com.android.systemui.statusbar.pipeline.mobile.data.model.NetworkNameModel
import com.android.systemui.statusbar.pipeline.mobile.data.repository.MobileConnectionRepository import com.android.systemui.statusbar.pipeline.mobile.data.repository.MobileConnectionRepository
import com.android.systemui.statusbar.pipeline.shared.data.model.DataActivityModel
import com.android.systemui.util.CarrierConfigTracker import com.android.systemui.util.CarrierConfigTracker
import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.SharingStarted import kotlinx.coroutines.flow.SharingStarted
import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.StateFlow
@@ -32,6 +35,9 @@ import kotlinx.coroutines.flow.mapLatest
import kotlinx.coroutines.flow.stateIn import kotlinx.coroutines.flow.stateIn
interface MobileIconInteractor { interface MobileIconInteractor {
/** The current mobile data activity */
val activity: Flow<DataActivityModel>
/** Only true if mobile is the default transport but is not validated, otherwise false */ /** Only true if mobile is the default transport but is not validated, otherwise false */
val isDefaultConnectionFailed: StateFlow<Boolean> val isDefaultConnectionFailed: StateFlow<Boolean>
@@ -51,6 +57,15 @@ interface MobileIconInteractor {
/** Observable for RAT type (network type) indicator */ /** Observable for RAT type (network type) indicator */
val networkTypeIconGroup: StateFlow<MobileIconGroup> val networkTypeIconGroup: StateFlow<MobileIconGroup>
/**
* Provider name for this network connection. The name can be one of 3 values:
* 1. The default network name, if one is configured
* 2. A derived name based off of the intent [ACTION_SERVICE_PROVIDERS_UPDATED]
* 3. Or, in the case where the repository sends us the default network name, we check for an
* override in [connectionInfo.operatorAlphaShort], a value that is derived from [ServiceState]
*/
val networkName: StateFlow<NetworkNameModel>
/** True if this line of service is emergency-only */ /** True if this line of service is emergency-only */
val isEmergencyOnly: StateFlow<Boolean> val isEmergencyOnly: StateFlow<Boolean>
@@ -82,10 +97,28 @@ class MobileIconInteractorImpl(
) : MobileIconInteractor { ) : MobileIconInteractor {
private val connectionInfo = connectionRepository.connectionInfo private val connectionInfo = connectionRepository.connectionInfo
override val activity = connectionInfo.mapLatest { it.dataActivityDirection }
override val isDataEnabled: StateFlow<Boolean> = connectionRepository.dataEnabled override val isDataEnabled: StateFlow<Boolean> = connectionRepository.dataEnabled
override val isDefaultDataEnabled = defaultSubscriptionHasDataEnabled override val isDefaultDataEnabled = defaultSubscriptionHasDataEnabled
override val networkName =
combine(connectionInfo, connectionRepository.networkName) { connection, networkName ->
if (
networkName is NetworkNameModel.Default && connection.operatorAlphaShort != null
) {
NetworkNameModel.Derived(connection.operatorAlphaShort)
} else {
networkName
}
}
.stateIn(
scope,
SharingStarted.WhileSubscribed(),
connectionRepository.networkName.value
)
/** Observable for the current RAT indicator icon ([MobileIconGroup]) */ /** Observable for the current RAT indicator icon ([MobileIconGroup]) */
override val networkTypeIconGroup: StateFlow<MobileIconGroup> = override val networkTypeIconGroup: StateFlow<MobileIconGroup> =
combine( combine(

View File

@@ -17,6 +17,7 @@
package com.android.systemui.statusbar.pipeline.mobile.ui.binder package com.android.systemui.statusbar.pipeline.mobile.ui.binder
import android.content.res.ColorStateList import android.content.res.ColorStateList
import android.view.View
import android.view.View.GONE import android.view.View.GONE
import android.view.View.VISIBLE import android.view.View.VISIBLE
import android.view.ViewGroup import android.view.ViewGroup
@@ -40,6 +41,9 @@ object MobileIconBinder {
view: ViewGroup, view: ViewGroup,
viewModel: MobileIconViewModel, viewModel: MobileIconViewModel,
) { ) {
val activityContainer = view.requireViewById<View>(R.id.inout_container)
val activityIn = view.requireViewById<ImageView>(R.id.mobile_in)
val activityOut = view.requireViewById<ImageView>(R.id.mobile_out)
val networkTypeView = view.requireViewById<ImageView>(R.id.mobile_type) val networkTypeView = view.requireViewById<ImageView>(R.id.mobile_type)
val iconView = view.requireViewById<ImageView>(R.id.mobile_signal) val iconView = view.requireViewById<ImageView>(R.id.mobile_signal)
val mobileDrawable = SignalDrawable(view.context).also { iconView.setImageDrawable(it) } val mobileDrawable = SignalDrawable(view.context).also { iconView.setImageDrawable(it) }
@@ -74,6 +78,15 @@ object MobileIconBinder {
} }
} }
// Set the activity indicators
launch { viewModel.activityInVisible.collect { activityIn.isVisible = it } }
launch { viewModel.activityOutVisible.collect { activityOut.isVisible = it } }
launch {
viewModel.activityContainerVisible.collect { activityContainer.isVisible = it }
}
// Set the tint // Set the tint
launch { launch {
viewModel.tint.collect { tint -> viewModel.tint.collect { tint ->
@@ -81,6 +94,8 @@ object MobileIconBinder {
iconView.imageTintList = tintList iconView.imageTintList = tintList
networkTypeView.imageTintList = tintList networkTypeView.imageTintList = tintList
roamingView.imageTintList = tintList roamingView.imageTintList = tintList
activityIn.imageTintList = tintList
activityOut.imageTintList = tintList
} }
} }
} }

View File

@@ -22,13 +22,16 @@ import com.android.systemui.common.shared.model.ContentDescription
import com.android.systemui.common.shared.model.Icon 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.MobileIconInteractor
import com.android.systemui.statusbar.pipeline.mobile.domain.interactor.MobileIconsInteractor import com.android.systemui.statusbar.pipeline.mobile.domain.interactor.MobileIconsInteractor
import com.android.systemui.statusbar.pipeline.shared.ConnectivityConstants
import com.android.systemui.statusbar.pipeline.shared.ConnectivityPipelineLogger import com.android.systemui.statusbar.pipeline.shared.ConnectivityPipelineLogger
import com.android.systemui.statusbar.pipeline.shared.ConnectivityPipelineLogger.Companion.logOutputChange import com.android.systemui.statusbar.pipeline.shared.ConnectivityPipelineLogger.Companion.logOutputChange
import com.android.systemui.statusbar.pipeline.shared.data.model.DataActivityModel
import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.combine import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.flow.distinctUntilChanged import kotlinx.coroutines.flow.distinctUntilChanged
import kotlinx.coroutines.flow.flowOf import kotlinx.coroutines.flow.flowOf
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.mapLatest import kotlinx.coroutines.flow.mapLatest
/** /**
@@ -48,6 +51,7 @@ constructor(
val subscriptionId: Int, val subscriptionId: Int,
iconInteractor: MobileIconInteractor, iconInteractor: MobileIconInteractor,
logger: ConnectivityPipelineLogger, logger: ConnectivityPipelineLogger,
constants: ConnectivityConstants,
) { ) {
/** Whether or not to show the error state of [SignalDrawable] */ /** Whether or not to show the error state of [SignalDrawable] */
private val showExclamationMark: Flow<Boolean> = private val showExclamationMark: Flow<Boolean> =
@@ -89,5 +93,17 @@ constructor(
val roaming: Flow<Boolean> = iconInteractor.isRoaming val roaming: Flow<Boolean> = iconInteractor.isRoaming
private val activity: Flow<DataActivityModel?> =
if (!constants.shouldShowActivityConfig) {
flowOf(null)
} else {
iconInteractor.activity
}
val activityInVisible: Flow<Boolean> = activity.map { it?.hasActivityIn ?: false }
val activityOutVisible: Flow<Boolean> = activity.map { it?.hasActivityOut ?: false }
val activityContainerVisible: Flow<Boolean> =
activity.map { it != null && (it.hasActivityIn || it.hasActivityOut) }
val tint: Flow<Int> = flowOf(Color.CYAN) val tint: Flow<Int> = flowOf(Color.CYAN)
} }

View File

@@ -20,6 +20,7 @@ package com.android.systemui.statusbar.pipeline.mobile.ui.viewmodel
import com.android.systemui.statusbar.pipeline.mobile.domain.interactor.MobileIconsInteractor import com.android.systemui.statusbar.pipeline.mobile.domain.interactor.MobileIconsInteractor
import com.android.systemui.statusbar.pipeline.mobile.ui.view.ModernStatusBarMobileView import com.android.systemui.statusbar.pipeline.mobile.ui.view.ModernStatusBarMobileView
import com.android.systemui.statusbar.pipeline.shared.ConnectivityConstants
import com.android.systemui.statusbar.pipeline.shared.ConnectivityPipelineLogger import com.android.systemui.statusbar.pipeline.shared.ConnectivityPipelineLogger
import javax.inject.Inject import javax.inject.Inject
import kotlinx.coroutines.InternalCoroutinesApi import kotlinx.coroutines.InternalCoroutinesApi
@@ -36,13 +37,15 @@ constructor(
val subscriptionIdsFlow: StateFlow<List<Int>>, val subscriptionIdsFlow: StateFlow<List<Int>>,
private val interactor: MobileIconsInteractor, private val interactor: MobileIconsInteractor,
private val logger: ConnectivityPipelineLogger, private val logger: ConnectivityPipelineLogger,
private val constants: ConnectivityConstants,
) { ) {
/** TODO: do we need to cache these? */ /** TODO: do we need to cache these? */
fun viewModelForSub(subId: Int): MobileIconViewModel = fun viewModelForSub(subId: Int): MobileIconViewModel =
MobileIconViewModel( MobileIconViewModel(
subId, subId,
interactor.createMobileConnectionInteractorForSubId(subId), interactor.createMobileConnectionInteractorForSubId(subId),
logger logger,
constants,
) )
class Factory class Factory
@@ -50,12 +53,14 @@ constructor(
constructor( constructor(
private val interactor: MobileIconsInteractor, private val interactor: MobileIconsInteractor,
private val logger: ConnectivityPipelineLogger, private val logger: ConnectivityPipelineLogger,
private val constants: ConnectivityConstants,
) { ) {
fun create(subscriptionIdsFlow: StateFlow<List<Int>>): MobileIconsViewModel { fun create(subscriptionIdsFlow: StateFlow<List<Int>>): MobileIconsViewModel {
return MobileIconsViewModel( return MobileIconsViewModel(
subscriptionIdsFlow, subscriptionIdsFlow,
interactor, interactor,
logger, logger,
constants,
) )
} }
} }

View File

@@ -16,8 +16,10 @@
package com.android.systemui.statusbar.pipeline.shared package com.android.systemui.statusbar.pipeline.shared
import android.content.Context
import android.telephony.TelephonyManager import android.telephony.TelephonyManager
import com.android.systemui.Dumpable import com.android.systemui.Dumpable
import com.android.systemui.R
import com.android.systemui.dagger.SysUISingleton import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dump.DumpManager import com.android.systemui.dump.DumpManager
import com.android.systemui.statusbar.pipeline.shared.ConnectivityPipelineLogger.Companion.SB_LOGGING_TAG import com.android.systemui.statusbar.pipeline.shared.ConnectivityPipelineLogger.Companion.SB_LOGGING_TAG
@@ -32,15 +34,25 @@ import javax.inject.Inject
@SysUISingleton @SysUISingleton
class ConnectivityConstants class ConnectivityConstants
@Inject @Inject
constructor(dumpManager: DumpManager, telephonyManager: TelephonyManager) : Dumpable { constructor(
context: Context,
dumpManager: DumpManager,
telephonyManager: TelephonyManager,
) : Dumpable {
init { init {
dumpManager.registerDumpable("${SB_LOGGING_TAG}Constants", this) dumpManager.registerNormalDumpable("${SB_LOGGING_TAG}Constants", this)
} }
/** True if this device has the capability for data connections and false otherwise. */ /** True if this device has the capability for data connections and false otherwise. */
val hasDataCapabilities = telephonyManager.isDataCapable val hasDataCapabilities = telephonyManager.isDataCapable
/** True if we should show the activityIn/activityOut icons and false otherwise */
val shouldShowActivityConfig = context.resources.getBoolean(R.bool.config_showActivity)
override fun dump(pw: PrintWriter, args: Array<out String>) { override fun dump(pw: PrintWriter, args: Array<out String>) {
pw.apply { println("hasDataCapabilities=$hasDataCapabilities") } pw.apply {
println("hasDataCapabilities=$hasDataCapabilities")
println("shouldShowActivityConfig=$shouldShowActivityConfig")
}
} }
} }

View File

@@ -16,6 +16,9 @@
package com.android.systemui.statusbar.pipeline.shared.data.model package com.android.systemui.statusbar.pipeline.shared.data.model
import android.net.wifi.WifiManager
import android.telephony.Annotation
import android.telephony.TelephonyManager
import com.android.systemui.log.table.Diffable import com.android.systemui.log.table.Diffable
import com.android.systemui.log.table.TableRowLogger import com.android.systemui.log.table.TableRowLogger
@@ -44,3 +47,25 @@ data class DataActivityModel(
const val ACTIVITY_PREFIX = "dataActivity" const val ACTIVITY_PREFIX = "dataActivity"
private const val COL_ACTIVITY_IN = "in" private const val COL_ACTIVITY_IN = "in"
private const val COL_ACTIVITY_OUT = "out" private const val COL_ACTIVITY_OUT = "out"
fun @receiver:Annotation.DataActivityType Int.toMobileDataActivityModel(): DataActivityModel =
when (this) {
TelephonyManager.DATA_ACTIVITY_IN ->
DataActivityModel(hasActivityIn = true, hasActivityOut = false)
TelephonyManager.DATA_ACTIVITY_OUT ->
DataActivityModel(hasActivityIn = false, hasActivityOut = true)
TelephonyManager.DATA_ACTIVITY_INOUT ->
DataActivityModel(hasActivityIn = true, hasActivityOut = true)
else -> DataActivityModel(hasActivityIn = false, hasActivityOut = false)
}
fun Int.toWifiDataActivityModel(): DataActivityModel =
when (this) {
WifiManager.TrafficStateCallback.DATA_ACTIVITY_IN ->
DataActivityModel(hasActivityIn = true, hasActivityOut = false)
WifiManager.TrafficStateCallback.DATA_ACTIVITY_OUT ->
DataActivityModel(hasActivityIn = false, hasActivityOut = true)
WifiManager.TrafficStateCallback.DATA_ACTIVITY_INOUT ->
DataActivityModel(hasActivityIn = true, hasActivityOut = true)
else -> DataActivityModel(hasActivityIn = false, hasActivityOut = false)
}

View File

@@ -43,6 +43,7 @@ import com.android.systemui.statusbar.pipeline.shared.ConnectivityPipelineLogger
import com.android.systemui.statusbar.pipeline.shared.ConnectivityPipelineLogger.Companion.SB_LOGGING_TAG import com.android.systemui.statusbar.pipeline.shared.ConnectivityPipelineLogger.Companion.SB_LOGGING_TAG
import com.android.systemui.statusbar.pipeline.shared.ConnectivityPipelineLogger.Companion.logInputChange import com.android.systemui.statusbar.pipeline.shared.ConnectivityPipelineLogger.Companion.logInputChange
import com.android.systemui.statusbar.pipeline.shared.data.model.DataActivityModel import com.android.systemui.statusbar.pipeline.shared.data.model.DataActivityModel
import com.android.systemui.statusbar.pipeline.shared.data.model.toWifiDataActivityModel
import com.android.systemui.statusbar.pipeline.wifi.data.model.WifiNetworkModel import com.android.systemui.statusbar.pipeline.wifi.data.model.WifiNetworkModel
import java.util.concurrent.Executor import java.util.concurrent.Executor
import javax.inject.Inject import javax.inject.Inject
@@ -237,7 +238,7 @@ class WifiRepositoryImpl @Inject constructor(
conflatedCallbackFlow { conflatedCallbackFlow {
val callback = TrafficStateCallback { state -> val callback = TrafficStateCallback { state ->
logger.logInputChange("onTrafficStateChange", prettyPrintActivity(state)) logger.logInputChange("onTrafficStateChange", prettyPrintActivity(state))
trySend(trafficStateToDataActivityModel(state)) trySend(state.toWifiDataActivityModel())
} }
wifiManager.registerTrafficStateCallback(mainExecutor, callback) wifiManager.registerTrafficStateCallback(mainExecutor, callback)
awaitClose { wifiManager.unregisterTrafficStateCallback(callback) } awaitClose { wifiManager.unregisterTrafficStateCallback(callback) }
@@ -266,15 +267,6 @@ class WifiRepositoryImpl @Inject constructor(
// NetworkCallback inside [wifiNetwork] for our wifi network information. // NetworkCallback inside [wifiNetwork] for our wifi network information.
val WIFI_NETWORK_DEFAULT = WifiNetworkModel.Inactive val WIFI_NETWORK_DEFAULT = WifiNetworkModel.Inactive
private fun trafficStateToDataActivityModel(state: Int): DataActivityModel {
return DataActivityModel(
hasActivityIn = state == TrafficStateCallback.DATA_ACTIVITY_IN ||
state == TrafficStateCallback.DATA_ACTIVITY_INOUT,
hasActivityOut = state == TrafficStateCallback.DATA_ACTIVITY_OUT ||
state == TrafficStateCallback.DATA_ACTIVITY_INOUT,
)
}
private fun networkCapabilitiesToWifiInfo( private fun networkCapabilitiesToWifiInfo(
networkCapabilities: NetworkCapabilities networkCapabilities: NetworkCapabilities
): WifiInfo? { ): WifiInfo? {

View File

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

View File

@@ -18,13 +18,16 @@ package com.android.systemui.statusbar.pipeline.mobile.data.repository.demo
import android.telephony.Annotation import android.telephony.Annotation
import android.telephony.TelephonyManager import android.telephony.TelephonyManager
import android.telephony.TelephonyManager.DATA_ACTIVITY_NONE
import androidx.test.filters.SmallTest import androidx.test.filters.SmallTest
import com.android.settingslib.SignalIcon import com.android.settingslib.SignalIcon
import com.android.settingslib.mobile.TelephonyIcons import com.android.settingslib.mobile.TelephonyIcons
import com.android.systemui.SysuiTestCase import com.android.systemui.SysuiTestCase
import com.android.systemui.statusbar.pipeline.mobile.data.model.DataConnectionState import com.android.systemui.statusbar.pipeline.mobile.data.model.DataConnectionState
import com.android.systemui.statusbar.pipeline.mobile.data.model.MobileConnectionModel import com.android.systemui.statusbar.pipeline.mobile.data.model.MobileConnectionModel
import com.android.systemui.statusbar.pipeline.mobile.data.model.NetworkNameModel
import com.android.systemui.statusbar.pipeline.mobile.data.repository.demo.model.FakeNetworkEventModel import com.android.systemui.statusbar.pipeline.mobile.data.repository.demo.model.FakeNetworkEventModel
import com.android.systemui.statusbar.pipeline.shared.data.model.toMobileDataActivityModel
import com.android.systemui.util.mockito.mock import com.android.systemui.util.mockito.mock
import com.android.systemui.util.mockito.whenever import com.android.systemui.util.mockito.whenever
import com.google.common.truth.Truth.assertThat import com.google.common.truth.Truth.assertThat
@@ -96,6 +99,7 @@ internal class DemoMobileConnectionParameterizedTest(private val testCase: TestC
activity = testCase.activity, activity = testCase.activity,
carrierNetworkChange = testCase.carrierNetworkChange, carrierNetworkChange = testCase.carrierNetworkChange,
roaming = testCase.roaming, roaming = testCase.roaming,
name = "demo name",
) )
fakeNetworkEventFlow.value = networkModel fakeNetworkEventFlow.value = networkModel
@@ -114,10 +118,12 @@ internal class DemoMobileConnectionParameterizedTest(private val testCase: TestC
assertThat(conn.subId).isEqualTo(model.subId) assertThat(conn.subId).isEqualTo(model.subId)
assertThat(connectionInfo.cdmaLevel).isEqualTo(model.level) assertThat(connectionInfo.cdmaLevel).isEqualTo(model.level)
assertThat(connectionInfo.primaryLevel).isEqualTo(model.level) assertThat(connectionInfo.primaryLevel).isEqualTo(model.level)
assertThat(connectionInfo.dataActivityDirection).isEqualTo(model.activity) assertThat(connectionInfo.dataActivityDirection)
.isEqualTo((model.activity ?: DATA_ACTIVITY_NONE).toMobileDataActivityModel())
assertThat(connectionInfo.carrierNetworkChangeActive) assertThat(connectionInfo.carrierNetworkChangeActive)
.isEqualTo(model.carrierNetworkChange) .isEqualTo(model.carrierNetworkChange)
assertThat(connectionInfo.isRoaming).isEqualTo(model.roaming) assertThat(connectionInfo.isRoaming).isEqualTo(model.roaming)
assertThat(conn.networkName.value).isEqualTo(NetworkNameModel.Derived(model.name))
// TODO(b/261029387): check these once we start handling them // TODO(b/261029387): check these once we start handling them
assertThat(connectionInfo.isEmergencyOnly).isFalse() assertThat(connectionInfo.isEmergencyOnly).isFalse()
@@ -141,6 +147,7 @@ internal class DemoMobileConnectionParameterizedTest(private val testCase: TestC
@Annotation.DataActivityType val activity: Int, @Annotation.DataActivityType val activity: Int,
val carrierNetworkChange: Boolean, val carrierNetworkChange: Boolean,
val roaming: Boolean, val roaming: Boolean,
val name: String,
) { ) {
override fun toString(): String { override fun toString(): String {
return "INPUT(level=$level, " + return "INPUT(level=$level, " +
@@ -150,7 +157,8 @@ internal class DemoMobileConnectionParameterizedTest(private val testCase: TestC
"inflateStrength=$inflateStrength, " + "inflateStrength=$inflateStrength, " +
"activity=$activity, " + "activity=$activity, " +
"carrierNetworkChange=$carrierNetworkChange, " + "carrierNetworkChange=$carrierNetworkChange, " +
"roaming=$roaming)" "roaming=$roaming, " +
"name=$name)"
} }
// Convenience for iterating test data and creating new cases // Convenience for iterating test data and creating new cases
@@ -163,6 +171,7 @@ internal class DemoMobileConnectionParameterizedTest(private val testCase: TestC
@Annotation.DataActivityType activity: Int? = null, @Annotation.DataActivityType activity: Int? = null,
carrierNetworkChange: Boolean? = null, carrierNetworkChange: Boolean? = null,
roaming: Boolean? = null, roaming: Boolean? = null,
name: String? = null,
): TestCase = ): TestCase =
TestCase( TestCase(
level = level ?: this.level, level = level ?: this.level,
@@ -173,6 +182,7 @@ internal class DemoMobileConnectionParameterizedTest(private val testCase: TestC
activity = activity ?: this.activity, activity = activity ?: this.activity,
carrierNetworkChange = carrierNetworkChange ?: this.carrierNetworkChange, carrierNetworkChange = carrierNetworkChange ?: this.carrierNetworkChange,
roaming = roaming ?: this.roaming, roaming = roaming ?: this.roaming,
name = name ?: this.name,
) )
} }
@@ -201,6 +211,7 @@ internal class DemoMobileConnectionParameterizedTest(private val testCase: TestC
private val carrierNetworkChange = booleanList private val carrierNetworkChange = booleanList
// false first so the base case doesn't have roaming set (more common) // false first so the base case doesn't have roaming set (more common)
private val roaming = listOf(false, true) private val roaming = listOf(false, true)
private val names = listOf("name 1", "name 2")
@Parameters(name = "{0}") @JvmStatic fun data() = testData() @Parameters(name = "{0}") @JvmStatic fun data() = testData()
@@ -236,6 +247,7 @@ internal class DemoMobileConnectionParameterizedTest(private val testCase: TestC
activity.first(), activity.first(),
carrierNetworkChange.first(), carrierNetworkChange.first(),
roaming.first(), roaming.first(),
names.first(),
) )
val tail = val tail =
@@ -246,7 +258,8 @@ internal class DemoMobileConnectionParameterizedTest(private val testCase: TestC
inflateStrength.map { baseCase.modifiedBy(inflateStrength = it) }, inflateStrength.map { baseCase.modifiedBy(inflateStrength = it) },
activity.map { baseCase.modifiedBy(activity = it) }, activity.map { baseCase.modifiedBy(activity = it) },
carrierNetworkChange.map { baseCase.modifiedBy(carrierNetworkChange = it) }, carrierNetworkChange.map { baseCase.modifiedBy(carrierNetworkChange = it) },
roaming.map { baseCase.modifiedBy(roaming = it) } roaming.map { baseCase.modifiedBy(roaming = it) },
names.map { baseCase.modifiedBy(name = it) },
) )
.flatten() .flatten()

View File

@@ -17,6 +17,7 @@
package com.android.systemui.statusbar.pipeline.mobile.data.repository.demo package com.android.systemui.statusbar.pipeline.mobile.data.repository.demo
import android.telephony.TelephonyManager.DATA_ACTIVITY_INOUT import android.telephony.TelephonyManager.DATA_ACTIVITY_INOUT
import android.telephony.TelephonyManager.DATA_ACTIVITY_NONE
import android.telephony.TelephonyManager.UNKNOWN_CARRIER_ID import android.telephony.TelephonyManager.UNKNOWN_CARRIER_ID
import androidx.test.filters.SmallTest import androidx.test.filters.SmallTest
import com.android.settingslib.SignalIcon import com.android.settingslib.SignalIcon
@@ -24,9 +25,11 @@ import com.android.settingslib.mobile.TelephonyIcons.THREE_G
import com.android.systemui.SysuiTestCase import com.android.systemui.SysuiTestCase
import com.android.systemui.statusbar.pipeline.mobile.data.model.DataConnectionState import com.android.systemui.statusbar.pipeline.mobile.data.model.DataConnectionState
import com.android.systemui.statusbar.pipeline.mobile.data.model.MobileConnectionModel import com.android.systemui.statusbar.pipeline.mobile.data.model.MobileConnectionModel
import com.android.systemui.statusbar.pipeline.mobile.data.model.NetworkNameModel
import com.android.systemui.statusbar.pipeline.mobile.data.model.SubscriptionModel import com.android.systemui.statusbar.pipeline.mobile.data.model.SubscriptionModel
import com.android.systemui.statusbar.pipeline.mobile.data.repository.demo.model.FakeNetworkEventModel import com.android.systemui.statusbar.pipeline.mobile.data.repository.demo.model.FakeNetworkEventModel
import com.android.systemui.statusbar.pipeline.mobile.data.repository.demo.model.FakeNetworkEventModel.MobileDisabled import com.android.systemui.statusbar.pipeline.mobile.data.repository.demo.model.FakeNetworkEventModel.MobileDisabled
import com.android.systemui.statusbar.pipeline.shared.data.model.toMobileDataActivityModel
import com.android.systemui.util.mockito.mock import com.android.systemui.util.mockito.mock
import com.android.systemui.util.mockito.whenever import com.android.systemui.util.mockito.whenever
import com.google.common.truth.Truth.assertThat import com.google.common.truth.Truth.assertThat
@@ -289,10 +292,12 @@ class DemoMobileConnectionsRepositoryTest : SysuiTestCase() {
assertThat(conn.subId).isEqualTo(model.subId) assertThat(conn.subId).isEqualTo(model.subId)
assertThat(connectionInfo.cdmaLevel).isEqualTo(model.level) assertThat(connectionInfo.cdmaLevel).isEqualTo(model.level)
assertThat(connectionInfo.primaryLevel).isEqualTo(model.level) assertThat(connectionInfo.primaryLevel).isEqualTo(model.level)
assertThat(connectionInfo.dataActivityDirection).isEqualTo(model.activity) assertThat(connectionInfo.dataActivityDirection)
.isEqualTo((model.activity ?: DATA_ACTIVITY_NONE).toMobileDataActivityModel())
assertThat(connectionInfo.carrierNetworkChangeActive) assertThat(connectionInfo.carrierNetworkChangeActive)
.isEqualTo(model.carrierNetworkChange) .isEqualTo(model.carrierNetworkChange)
assertThat(connectionInfo.isRoaming).isEqualTo(model.roaming) assertThat(connectionInfo.isRoaming).isEqualTo(model.roaming)
assertThat(conn.networkName.value).isEqualTo(NetworkNameModel.Derived(model.name))
// TODO(b/261029387) check these once we start handling them // TODO(b/261029387) check these once we start handling them
assertThat(connectionInfo.isEmergencyOnly).isFalse() assertThat(connectionInfo.isEmergencyOnly).isFalse()
@@ -325,4 +330,5 @@ fun validMobileEvent(
activity = activity, activity = activity,
carrierNetworkChange = carrierNetworkChange, carrierNetworkChange = carrierNetworkChange,
roaming = roaming, roaming = roaming,
name = "demo name",
) )

View File

@@ -16,6 +16,7 @@
package com.android.systemui.statusbar.pipeline.mobile.data.repository.prod package com.android.systemui.statusbar.pipeline.mobile.data.repository.prod
import android.content.Intent
import android.os.UserHandle import android.os.UserHandle
import android.provider.Settings import android.provider.Settings
import android.telephony.CellSignalStrengthCdma import android.telephony.CellSignalStrengthCdma
@@ -23,10 +24,16 @@ import android.telephony.ServiceState
import android.telephony.SignalStrength import android.telephony.SignalStrength
import android.telephony.SubscriptionInfo import android.telephony.SubscriptionInfo
import android.telephony.TelephonyCallback import android.telephony.TelephonyCallback
import android.telephony.TelephonyCallback.DataActivityListener
import android.telephony.TelephonyCallback.ServiceStateListener import android.telephony.TelephonyCallback.ServiceStateListener
import android.telephony.TelephonyDisplayInfo import android.telephony.TelephonyDisplayInfo
import android.telephony.TelephonyDisplayInfo.OVERRIDE_NETWORK_TYPE_LTE_CA import android.telephony.TelephonyDisplayInfo.OVERRIDE_NETWORK_TYPE_LTE_CA
import android.telephony.TelephonyManager import android.telephony.TelephonyManager
import android.telephony.TelephonyManager.DATA_ACTIVITY_DORMANT
import android.telephony.TelephonyManager.DATA_ACTIVITY_IN
import android.telephony.TelephonyManager.DATA_ACTIVITY_INOUT
import android.telephony.TelephonyManager.DATA_ACTIVITY_NONE
import android.telephony.TelephonyManager.DATA_ACTIVITY_OUT
import android.telephony.TelephonyManager.DATA_CONNECTED import android.telephony.TelephonyManager.DATA_CONNECTED
import android.telephony.TelephonyManager.DATA_CONNECTING import android.telephony.TelephonyManager.DATA_CONNECTING
import android.telephony.TelephonyManager.DATA_DISCONNECTED import android.telephony.TelephonyManager.DATA_DISCONNECTED
@@ -34,18 +41,27 @@ import android.telephony.TelephonyManager.DATA_DISCONNECTING
import android.telephony.TelephonyManager.DATA_UNKNOWN import android.telephony.TelephonyManager.DATA_UNKNOWN
import android.telephony.TelephonyManager.ERI_OFF import android.telephony.TelephonyManager.ERI_OFF
import android.telephony.TelephonyManager.ERI_ON import android.telephony.TelephonyManager.ERI_ON
import android.telephony.TelephonyManager.EXTRA_PLMN
import android.telephony.TelephonyManager.EXTRA_SHOW_PLMN
import android.telephony.TelephonyManager.EXTRA_SHOW_SPN
import android.telephony.TelephonyManager.EXTRA_SPN
import android.telephony.TelephonyManager.EXTRA_SUBSCRIPTION_ID
import android.telephony.TelephonyManager.NETWORK_TYPE_LTE import android.telephony.TelephonyManager.NETWORK_TYPE_LTE
import android.telephony.TelephonyManager.NETWORK_TYPE_UNKNOWN import android.telephony.TelephonyManager.NETWORK_TYPE_UNKNOWN
import androidx.test.filters.SmallTest import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase import com.android.systemui.SysuiTestCase
import com.android.systemui.statusbar.pipeline.mobile.data.model.DataConnectionState import com.android.systemui.statusbar.pipeline.mobile.data.model.DataConnectionState
import com.android.systemui.statusbar.pipeline.mobile.data.model.MobileConnectionModel import com.android.systemui.statusbar.pipeline.mobile.data.model.MobileConnectionModel
import com.android.systemui.statusbar.pipeline.mobile.data.model.NetworkNameModel
import com.android.systemui.statusbar.pipeline.mobile.data.model.ResolvedNetworkType.DefaultNetworkType import com.android.systemui.statusbar.pipeline.mobile.data.model.ResolvedNetworkType.DefaultNetworkType
import com.android.systemui.statusbar.pipeline.mobile.data.model.ResolvedNetworkType.OverrideNetworkType 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.ResolvedNetworkType.UnknownNetworkType
import com.android.systemui.statusbar.pipeline.mobile.data.model.toNetworkNameModel
import com.android.systemui.statusbar.pipeline.mobile.data.repository.FakeMobileConnectionsRepository import com.android.systemui.statusbar.pipeline.mobile.data.repository.FakeMobileConnectionsRepository
import com.android.systemui.statusbar.pipeline.mobile.util.FakeMobileMappingsProxy import com.android.systemui.statusbar.pipeline.mobile.util.FakeMobileMappingsProxy
import com.android.systemui.statusbar.pipeline.shared.ConnectivityPipelineLogger import com.android.systemui.statusbar.pipeline.shared.ConnectivityPipelineLogger
import com.android.systemui.statusbar.pipeline.shared.data.model.DataActivityModel
import com.android.systemui.statusbar.pipeline.shared.data.model.toMobileDataActivityModel
import com.android.systemui.util.mockito.any import com.android.systemui.util.mockito.any
import com.android.systemui.util.mockito.argumentCaptor import com.android.systemui.util.mockito.argumentCaptor
import com.android.systemui.util.mockito.mock import com.android.systemui.util.mockito.mock
@@ -90,8 +106,11 @@ class MobileConnectionRepositoryTest : SysuiTestCase() {
MobileConnectionRepositoryImpl( MobileConnectionRepositoryImpl(
context, context,
SUB_1_ID, SUB_1_ID,
DEFAULT_NAME,
SEP,
telephonyManager, telephonyManager,
globalSettings, globalSettings,
fakeBroadcastDispatcher,
connectionsRepo.defaultDataSubId, connectionsRepo.defaultDataSubId,
connectionsRepo.globalMobileDataSettingChangedEvent, connectionsRepo.globalMobileDataSettingChangedEvent,
mobileMappings, mobileMappings,
@@ -249,10 +268,11 @@ class MobileConnectionRepositoryTest : SysuiTestCase() {
var latest: MobileConnectionModel? = null var latest: MobileConnectionModel? = null
val job = underTest.connectionInfo.onEach { latest = it }.launchIn(this) val job = underTest.connectionInfo.onEach { latest = it }.launchIn(this)
val callback = getTelephonyCallbackForType<TelephonyCallback.DataActivityListener>() val callback = getTelephonyCallbackForType<DataActivityListener>()
callback.onDataActivity(3) callback.onDataActivity(DATA_ACTIVITY_INOUT)
assertThat(latest?.dataActivityDirection).isEqualTo(3) assertThat(latest?.dataActivityDirection)
.isEqualTo(DATA_ACTIVITY_INOUT.toMobileDataActivityModel())
job.cancel() job.cancel()
} }
@@ -459,6 +479,112 @@ class MobileConnectionRepositoryTest : SysuiTestCase() {
job.cancel() job.cancel()
} }
@Test
fun `activity - updates from callback`() =
runBlocking(IMMEDIATE) {
var latest: DataActivityModel? = null
val job =
underTest.connectionInfo.onEach { latest = it.dataActivityDirection }.launchIn(this)
assertThat(latest)
.isEqualTo(DataActivityModel(hasActivityIn = false, hasActivityOut = false))
val cb = getTelephonyCallbackForType<DataActivityListener>()
cb.onDataActivity(DATA_ACTIVITY_IN)
assertThat(latest)
.isEqualTo(DataActivityModel(hasActivityIn = true, hasActivityOut = false))
cb.onDataActivity(DATA_ACTIVITY_OUT)
assertThat(latest)
.isEqualTo(DataActivityModel(hasActivityIn = false, hasActivityOut = true))
cb.onDataActivity(DATA_ACTIVITY_INOUT)
assertThat(latest)
.isEqualTo(DataActivityModel(hasActivityIn = true, hasActivityOut = true))
cb.onDataActivity(DATA_ACTIVITY_NONE)
assertThat(latest)
.isEqualTo(DataActivityModel(hasActivityIn = false, hasActivityOut = false))
cb.onDataActivity(DATA_ACTIVITY_DORMANT)
assertThat(latest)
.isEqualTo(DataActivityModel(hasActivityIn = false, hasActivityOut = false))
cb.onDataActivity(1234)
assertThat(latest)
.isEqualTo(DataActivityModel(hasActivityIn = false, hasActivityOut = false))
job.cancel()
}
@Test
fun `network name - default`() =
runBlocking(IMMEDIATE) {
var latest: NetworkNameModel? = null
val job = underTest.networkName.onEach { latest = it }.launchIn(this)
assertThat(latest).isEqualTo(DEFAULT_NAME)
job.cancel()
}
@Test
fun `network name - uses broadcast info - returns derived`() =
runBlocking(IMMEDIATE) {
var latest: NetworkNameModel? = null
val job = underTest.networkName.onEach { latest = it }.launchIn(this)
val intent = spnIntent()
fakeBroadcastDispatcher.registeredReceivers.forEach { receiver ->
receiver.onReceive(context, intent)
}
assertThat(latest).isEqualTo(intent.toNetworkNameModel(SEP))
job.cancel()
}
@Test
fun `network name - broadcast not for this sub id - returns default`() =
runBlocking(IMMEDIATE) {
var latest: NetworkNameModel? = null
val job = underTest.networkName.onEach { latest = it }.launchIn(this)
val intent = spnIntent(subId = 101)
fakeBroadcastDispatcher.registeredReceivers.forEach { receiver ->
receiver.onReceive(context, intent)
}
assertThat(latest).isEqualTo(DEFAULT_NAME)
job.cancel()
}
@Test
fun `network name - operatorAlphaShort - tracked`() =
runBlocking(IMMEDIATE) {
var latest: String? = null
val job =
underTest.connectionInfo.onEach { latest = it.operatorAlphaShort }.launchIn(this)
val shortName = "short name"
val serviceState = ServiceState()
serviceState.setOperatorName(
/* longName */ "long name",
/* shortName */ shortName,
/* numeric */ "12345",
)
getTelephonyCallbackForType<ServiceStateListener>().onServiceStateChanged(serviceState)
assertThat(latest).isEqualTo(shortName)
job.cancel()
}
private fun getTelephonyCallbacks(): List<TelephonyCallback> { private fun getTelephonyCallbacks(): List<TelephonyCallback> {
val callbackCaptor = argumentCaptor<TelephonyCallback>() val callbackCaptor = argumentCaptor<TelephonyCallback>()
Mockito.verify(telephonyManager).registerTelephonyCallback(any(), callbackCaptor.capture()) Mockito.verify(telephonyManager).registerTelephonyCallback(any(), callbackCaptor.capture())
@@ -484,10 +610,31 @@ class MobileConnectionRepositoryTest : SysuiTestCase() {
return signalStrength return signalStrength
} }
private fun spnIntent(
subId: Int = SUB_1_ID,
showSpn: Boolean = true,
spn: String = SPN,
showPlmn: Boolean = true,
plmn: String = PLMN,
): Intent =
Intent(TelephonyManager.ACTION_SERVICE_PROVIDERS_UPDATED).apply {
putExtra(EXTRA_SUBSCRIPTION_ID, subId)
putExtra(EXTRA_SHOW_SPN, showSpn)
putExtra(EXTRA_SPN, spn)
putExtra(EXTRA_SHOW_PLMN, showPlmn)
putExtra(EXTRA_PLMN, plmn)
}
companion object { companion object {
private val IMMEDIATE = Dispatchers.Main.immediate private val IMMEDIATE = Dispatchers.Main.immediate
private const val SUB_1_ID = 1 private const val SUB_1_ID = 1
private val SUB_1 = private val SUB_1 =
mock<SubscriptionInfo>().also { whenever(it.subscriptionId).thenReturn(SUB_1_ID) } mock<SubscriptionInfo>().also { whenever(it.subscriptionId).thenReturn(SUB_1_ID) }
private val DEFAULT_NAME = NetworkNameModel.Default("default name")
private const val SEP = "-"
private const val SPN = "testSpn"
private const val PLMN = "testPlmn"
} }
} }

View File

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

View File

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

View File

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

View File

@@ -23,7 +23,10 @@ import com.android.systemui.SysuiTestCase
import com.android.systemui.common.shared.model.ContentDescription import com.android.systemui.common.shared.model.ContentDescription
import com.android.systemui.common.shared.model.Icon import com.android.systemui.common.shared.model.Icon
import com.android.systemui.statusbar.pipeline.mobile.domain.interactor.FakeMobileIconInteractor import com.android.systemui.statusbar.pipeline.mobile.domain.interactor.FakeMobileIconInteractor
import com.android.systemui.statusbar.pipeline.shared.ConnectivityConstants
import com.android.systemui.statusbar.pipeline.shared.ConnectivityPipelineLogger import com.android.systemui.statusbar.pipeline.shared.ConnectivityPipelineLogger
import com.android.systemui.statusbar.pipeline.shared.data.model.DataActivityModel
import com.android.systemui.util.mockito.whenever
import com.google.common.truth.Truth.assertThat import com.google.common.truth.Truth.assertThat
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.flow.launchIn import kotlinx.coroutines.flow.launchIn
@@ -40,6 +43,7 @@ class MobileIconViewModelTest : SysuiTestCase() {
private lateinit var underTest: MobileIconViewModel private lateinit var underTest: MobileIconViewModel
private val interactor = FakeMobileIconInteractor() private val interactor = FakeMobileIconInteractor()
@Mock private lateinit var logger: ConnectivityPipelineLogger @Mock private lateinit var logger: ConnectivityPipelineLogger
@Mock private lateinit var constants: ConnectivityConstants
@Before @Before
fun setUp() { fun setUp() {
@@ -53,7 +57,7 @@ class MobileIconViewModelTest : SysuiTestCase() {
setNumberOfLevels(4) setNumberOfLevels(4)
isDataConnected.value = true isDataConnected.value = true
} }
underTest = MobileIconViewModel(SUB_1_ID, interactor, logger) underTest = MobileIconViewModel(SUB_1_ID, interactor, logger, constants)
} }
@Test @Test
@@ -250,6 +254,92 @@ class MobileIconViewModelTest : SysuiTestCase() {
job.cancel() job.cancel()
} }
@Test
fun `data activity - null when config is off`() =
runBlocking(IMMEDIATE) {
// Create a new view model here so the constants are properly read
whenever(constants.shouldShowActivityConfig).thenReturn(false)
underTest = MobileIconViewModel(SUB_1_ID, interactor, logger, constants)
var inVisible: Boolean? = null
val inJob = underTest.activityInVisible.onEach { inVisible = it }.launchIn(this)
var outVisible: Boolean? = null
val outJob = underTest.activityInVisible.onEach { outVisible = it }.launchIn(this)
var containerVisible: Boolean? = null
val containerJob =
underTest.activityInVisible.onEach { containerVisible = it }.launchIn(this)
interactor.activity.value =
DataActivityModel(
hasActivityIn = true,
hasActivityOut = true,
)
assertThat(inVisible).isFalse()
assertThat(outVisible).isFalse()
assertThat(containerVisible).isFalse()
inJob.cancel()
outJob.cancel()
containerJob.cancel()
}
@Test
fun `data activity - config on - test indicators`() =
runBlocking(IMMEDIATE) {
// Create a new view model here so the constants are properly read
whenever(constants.shouldShowActivityConfig).thenReturn(true)
underTest = MobileIconViewModel(SUB_1_ID, interactor, logger, constants)
var inVisible: Boolean? = null
val inJob = underTest.activityInVisible.onEach { inVisible = it }.launchIn(this)
var outVisible: Boolean? = null
val outJob = underTest.activityOutVisible.onEach { outVisible = it }.launchIn(this)
var containerVisible: Boolean? = null
val containerJob =
underTest.activityContainerVisible.onEach { containerVisible = it }.launchIn(this)
interactor.activity.value =
DataActivityModel(
hasActivityIn = true,
hasActivityOut = false,
)
yield()
assertThat(inVisible).isTrue()
assertThat(outVisible).isFalse()
assertThat(containerVisible).isTrue()
interactor.activity.value =
DataActivityModel(
hasActivityIn = false,
hasActivityOut = true,
)
assertThat(inVisible).isFalse()
assertThat(outVisible).isTrue()
assertThat(containerVisible).isTrue()
interactor.activity.value =
DataActivityModel(
hasActivityIn = false,
hasActivityOut = false,
)
assertThat(inVisible).isFalse()
assertThat(outVisible).isFalse()
assertThat(containerVisible).isFalse()
inJob.cancel()
outJob.cancel()
containerJob.cancel()
}
/** Convenience constructor for these tests */ /** Convenience constructor for these tests */
private fun defaultSignal( private fun defaultSignal(
level: Int = 1, level: Int = 1,