summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/MobileConnectionRepository.kt56
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/MobileConnectionsRepository.kt72
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconInteractor.kt14
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconsInteractor.kt18
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/ui/viewmodel/MobileIconViewModel.kt20
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/FakeMobileConnectionRepository.kt7
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/FakeMobileConnectionsRepository.kt19
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/MobileConnectionRepositoryTest.kt61
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/MobileConnectionsRepositoryTest.kt69
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/FakeMobileIconInteractor.kt14
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/FakeMobileIconsInteractor.kt6
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconInteractorTest.kt16
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconsInteractorTest.kt47
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/ui/viewmodel/MobileIconViewModelTest.kt27
14 files changed, 390 insertions, 56 deletions
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/MobileConnectionRepository.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/MobileConnectionRepository.kt
index 06e8f467ee0b..41bcab1be2d5 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/MobileConnectionRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/MobileConnectionRepository.kt
@@ -16,11 +16,15 @@
package com.android.systemui.statusbar.pipeline.mobile.data.repository
+import android.content.Context
+import android.database.ContentObserver
+import android.provider.Settings.Global
import android.telephony.CellSignalStrength
import android.telephony.CellSignalStrengthCdma
import android.telephony.ServiceState
import android.telephony.SignalStrength
import android.telephony.SubscriptionInfo
+import android.telephony.SubscriptionManager
import android.telephony.TelephonyCallback
import android.telephony.TelephonyDisplayInfo
import android.telephony.TelephonyDisplayInfo.OVERRIDE_NETWORK_TYPE_NONE
@@ -34,6 +38,7 @@ import com.android.systemui.statusbar.pipeline.mobile.data.model.OverrideNetwork
import com.android.systemui.statusbar.pipeline.mobile.data.model.toDataConnectionType
import com.android.systemui.statusbar.pipeline.shared.ConnectivityPipelineLogger
import com.android.systemui.statusbar.pipeline.shared.ConnectivityPipelineLogger.Companion.logOutputChange
+import com.android.systemui.util.settings.GlobalSettings
import java.lang.IllegalStateException
import javax.inject.Inject
import kotlinx.coroutines.CoroutineDispatcher
@@ -45,6 +50,7 @@ import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.SharingStarted
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.map
+import kotlinx.coroutines.flow.merge
import kotlinx.coroutines.flow.stateIn
/**
@@ -66,13 +72,22 @@ interface MobileConnectionRepository {
val subscriptionModelFlow: Flow<MobileSubscriptionModel>
/** Observable tracking [TelephonyManager.isDataConnectionAllowed] */
val dataEnabled: Flow<Boolean>
+ /**
+ * True if this connection represents the default subscription per
+ * [SubscriptionManager.getDefaultDataSubscriptionId]
+ */
+ val isDefaultDataSubscription: Flow<Boolean>
}
@Suppress("EXPERIMENTAL_IS_NOT_ENABLED")
@OptIn(ExperimentalCoroutinesApi::class)
class MobileConnectionRepositoryImpl(
+ private val context: Context,
private val subId: Int,
private val telephonyManager: TelephonyManager,
+ private val globalSettings: GlobalSettings,
+ defaultDataSubId: Flow<Int>,
+ globalMobileDataSettingChangedEvent: Flow<Unit>,
bgDispatcher: CoroutineDispatcher,
logger: ConnectivityPipelineLogger,
scope: CoroutineScope,
@@ -169,29 +184,66 @@ class MobileConnectionRepositoryImpl(
.stateIn(scope, SharingStarted.WhileSubscribed(), state)
}
+ private val telephonyCallbackEvent = subscriptionModelFlow.map {}
+
+ /** Produces whenever the mobile data setting changes for this subId */
+ private val localMobileDataSettingChangedEvent: Flow<Unit> = conflatedCallbackFlow {
+ val observer =
+ object : ContentObserver(null) {
+ override fun onChange(selfChange: Boolean) {
+ trySend(Unit)
+ }
+ }
+
+ globalSettings.registerContentObserver(
+ globalSettings.getUriFor("${Global.MOBILE_DATA}$subId"),
+ /* notifyForDescendants */ true,
+ observer
+ )
+
+ awaitClose { context.contentResolver.unregisterContentObserver(observer) }
+ }
+
/**
* There are a few cases where we will need to poll [TelephonyManager] so we can update some
* internal state where callbacks aren't provided. Any of those events should be merged into
* this flow, which can be used to trigger the polling.
*/
- private val telephonyPollingEvent: Flow<Unit> = subscriptionModelFlow.map {}
+ private val telephonyPollingEvent: Flow<Unit> =
+ merge(
+ telephonyCallbackEvent,
+ localMobileDataSettingChangedEvent,
+ globalMobileDataSettingChangedEvent,
+ )
override val dataEnabled: Flow<Boolean> = telephonyPollingEvent.map { dataConnectionAllowed() }
private fun dataConnectionAllowed(): Boolean = telephonyManager.isDataConnectionAllowed
+ override val isDefaultDataSubscription: Flow<Boolean> = defaultDataSubId.map { it == subId }
+
class Factory
@Inject
constructor(
+ private val context: Context,
private val telephonyManager: TelephonyManager,
private val logger: ConnectivityPipelineLogger,
+ private val globalSettings: GlobalSettings,
@Background private val bgDispatcher: CoroutineDispatcher,
@Application private val scope: CoroutineScope,
) {
- fun build(subId: Int): MobileConnectionRepository {
+ fun build(
+ subId: Int,
+ defaultDataSubId: Flow<Int>,
+ globalMobileDataSettingChangedEvent: Flow<Unit>,
+ ): MobileConnectionRepository {
return MobileConnectionRepositoryImpl(
+ context,
subId,
telephonyManager.createForSubscriptionId(subId),
+ globalSettings,
+ defaultDataSubId,
+ globalMobileDataSettingChangedEvent,
bgDispatcher,
logger,
scope,
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/MobileConnectionsRepository.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/MobileConnectionsRepository.kt
index 0e2428ae393a..bd9f85ee9dcb 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/MobileConnectionsRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/MobileConnectionsRepository.kt
@@ -18,13 +18,18 @@ package com.android.systemui.statusbar.pipeline.mobile.data.repository
import android.content.Context
import android.content.IntentFilter
+import android.database.ContentObserver
+import android.provider.Settings
+import android.provider.Settings.Global.MOBILE_DATA
import android.telephony.CarrierConfigManager
import android.telephony.SubscriptionInfo
import android.telephony.SubscriptionManager
+import android.telephony.SubscriptionManager.INVALID_SUBSCRIPTION_ID
import android.telephony.TelephonyCallback
import android.telephony.TelephonyCallback.ActiveDataSubscriptionIdListener
import android.telephony.TelephonyManager
import androidx.annotation.VisibleForTesting
+import com.android.internal.telephony.PhoneConstants
import com.android.settingslib.mobile.MobileMappings
import com.android.settingslib.mobile.MobileMappings.Config
import com.android.systemui.broadcast.BroadcastDispatcher
@@ -33,6 +38,7 @@ 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.shared.ConnectivityPipelineLogger
+import com.android.systemui.util.settings.GlobalSettings
import javax.inject.Inject
import kotlinx.coroutines.CoroutineDispatcher
import kotlinx.coroutines.CoroutineScope
@@ -40,10 +46,12 @@ import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.asExecutor
import kotlinx.coroutines.channels.awaitClose
import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.MutableSharedFlow
import kotlinx.coroutines.flow.SharingStarted
import kotlinx.coroutines.flow.StateFlow
-import kotlinx.coroutines.flow.combine
+import kotlinx.coroutines.flow.distinctUntilChanged
import kotlinx.coroutines.flow.mapLatest
+import kotlinx.coroutines.flow.merge
import kotlinx.coroutines.flow.onEach
import kotlinx.coroutines.flow.stateIn
import kotlinx.coroutines.withContext
@@ -62,8 +70,14 @@ interface MobileConnectionsRepository {
/** Observable for [MobileMappings.Config] tracking the defaults */
val defaultDataSubRatConfig: StateFlow<Config>
+ /** Tracks [SubscriptionManager.getDefaultDataSubscriptionId] */
+ val defaultDataSubId: StateFlow<Int>
+
/** Get or create a repository for the line of service for the given subscription ID */
fun getRepoForSubId(subId: Int): MobileConnectionRepository
+
+ /** Observe changes to the [Settings.Global.MOBILE_DATA] setting */
+ val globalMobileDataSettingChangedEvent: Flow<Unit>
}
@Suppress("EXPERIMENTAL_IS_NOT_ENABLED")
@@ -76,6 +90,7 @@ constructor(
private val telephonyManager: TelephonyManager,
private val logger: ConnectivityPipelineLogger,
broadcastDispatcher: BroadcastDispatcher,
+ private val globalSettings: GlobalSettings,
private val context: Context,
@Background private val bgDispatcher: CoroutineDispatcher,
@Application private val scope: CoroutineScope,
@@ -121,17 +136,26 @@ constructor(
telephonyManager.registerTelephonyCallback(bgDispatcher.asExecutor(), callback)
awaitClose { telephonyManager.unregisterTelephonyCallback(callback) }
}
+ .stateIn(scope, started = SharingStarted.WhileSubscribed(), INVALID_SUBSCRIPTION_ID)
+
+ private val defaultDataSubIdChangeEvent: MutableSharedFlow<Unit> =
+ MutableSharedFlow(extraBufferCapacity = 1)
+
+ override val defaultDataSubId: StateFlow<Int> =
+ broadcastDispatcher
+ .broadcastFlow(
+ IntentFilter(TelephonyManager.ACTION_DEFAULT_DATA_SUBSCRIPTION_CHANGED)
+ ) { intent, _ ->
+ intent.getIntExtra(PhoneConstants.SUBSCRIPTION_KEY, INVALID_SUBSCRIPTION_ID)
+ }
+ .distinctUntilChanged()
+ .onEach { defaultDataSubIdChangeEvent.tryEmit(Unit) }
.stateIn(
scope,
- started = SharingStarted.WhileSubscribed(),
- SubscriptionManager.INVALID_SUBSCRIPTION_ID
+ SharingStarted.WhileSubscribed(),
+ SubscriptionManager.getDefaultDataSubscriptionId()
)
- private val defaultDataSubChangedEvent =
- broadcastDispatcher.broadcastFlow(
- IntentFilter(TelephonyManager.ACTION_DEFAULT_DATA_SUBSCRIPTION_CHANGED)
- )
-
private val carrierConfigChangedEvent =
broadcastDispatcher.broadcastFlow(
IntentFilter(CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED)
@@ -148,9 +172,8 @@ constructor(
* 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)
- }
+ merge(defaultDataSubIdChangeEvent, carrierConfigChangedEvent)
+ .mapLatest { Config.readConfig(context) }
.stateIn(
scope,
SharingStarted.WhileSubscribed(),
@@ -168,6 +191,27 @@ constructor(
?: createRepositoryForSubId(subId).also { subIdRepositoryCache[subId] = it }
}
+ /**
+ * In single-SIM devices, the [MOBILE_DATA] setting is phone-wide. For multi-SIM, the individual
+ * connection repositories also observe the URI for [MOBILE_DATA] + subId.
+ */
+ override val globalMobileDataSettingChangedEvent: Flow<Unit> = conflatedCallbackFlow {
+ val observer =
+ object : ContentObserver(null) {
+ override fun onChange(selfChange: Boolean) {
+ trySend(Unit)
+ }
+ }
+
+ globalSettings.registerContentObserver(
+ globalSettings.getUriFor(MOBILE_DATA),
+ true,
+ observer
+ )
+
+ awaitClose { context.contentResolver.unregisterContentObserver(observer) }
+ }
+
private fun isValidSubId(subId: Int): Boolean {
subscriptionsFlow.value.forEach {
if (it.subscriptionId == subId) {
@@ -181,7 +225,11 @@ constructor(
@VisibleForTesting fun getSubIdRepoCache() = subIdRepositoryCache
private fun createRepositoryForSubId(subId: Int): MobileConnectionRepository {
- return mobileConnectionRepositoryFactory.build(subId)
+ return mobileConnectionRepositoryFactory.build(
+ subId,
+ defaultDataSubId,
+ globalMobileDataSettingChangedEvent,
+ )
}
private fun dropUnusedReposFromCache(newInfos: List<SubscriptionInfo>) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconInteractor.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconInteractor.kt
index f99d278c3903..cdd4982f0a79 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconInteractor.kt
@@ -29,6 +29,10 @@ import kotlinx.coroutines.flow.flowOf
import kotlinx.coroutines.flow.map
interface MobileIconInteractor {
+ // TODO(b/256839546): clarify naming of default vs active
+ /** True if we want to consider the data connection enabled */
+ val isDefaultDataEnabled: Flow<Boolean>
+
/** Observable for the data enabled state of this connection */
val isDataEnabled: Flow<Boolean>
@@ -43,13 +47,11 @@ interface MobileIconInteractor {
/** 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(
+ defaultSubscriptionHasDataEnabled: Flow<Boolean>,
defaultMobileIconMapping: Flow<Map<String, MobileIconGroup>>,
defaultMobileIconGroup: Flow<MobileIconGroup>,
mobileMappingsProxy: MobileMappingsProxy,
@@ -59,6 +61,8 @@ class MobileIconInteractorImpl(
override val isDataEnabled: Flow<Boolean> = connectionRepository.dataEnabled
+ override val isDefaultDataEnabled = defaultSubscriptionHasDataEnabled
+
/** Observable for the current RAT indicator icon ([MobileIconGroup]) */
override val networkTypeIconGroup: Flow<MobileIconGroup> =
combine(
@@ -91,8 +95,4 @@ class MobileIconInteractorImpl(
* once it's wired up inside of [CarrierConfigTracker]
*/
override val numberOfLevels: Flow<Int> = flowOf(4)
-
- /** Whether or not to draw the mobile triangle as "cut out", i.e., with the exclamation mark */
- // TODO: find a better name for this?
- override val cutOut: Flow<Boolean> = flowOf(false)
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconsInteractor.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconsInteractor.kt
index 614d583c3c48..31cb21f7720f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconsInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconsInteractor.kt
@@ -19,6 +19,7 @@ package com.android.systemui.statusbar.pipeline.mobile.domain.interactor
import android.telephony.CarrierConfigManager
import android.telephony.SubscriptionInfo
import android.telephony.SubscriptionManager
+import android.telephony.SubscriptionManager.INVALID_SUBSCRIPTION_ID
import com.android.settingslib.SignalIcon.MobileIconGroup
import com.android.settingslib.mobile.TelephonyIcons
import com.android.systemui.dagger.SysUISingleton
@@ -35,6 +36,8 @@ import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.SharingStarted
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.combine
+import kotlinx.coroutines.flow.flatMapLatest
+import kotlinx.coroutines.flow.flowOf
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.stateIn
@@ -51,6 +54,8 @@ import kotlinx.coroutines.flow.stateIn
interface MobileIconsInteractor {
/** List of subscriptions, potentially filtered for CBRS */
val filteredSubscriptions: Flow<List<SubscriptionInfo>>
+ /** True if the active mobile data subscription has data enabled */
+ val activeDataConnectionHasDataEnabled: Flow<Boolean>
/** The icon mapping from network type to [MobileIconGroup] for the default subscription */
val defaultMobileIconMapping: Flow<Map<String, MobileIconGroup>>
/** Fallback [MobileIconGroup] in the case where there is no icon in the mapping */
@@ -79,6 +84,18 @@ constructor(
private val activeMobileDataSubscriptionId =
mobileConnectionsRepo.activeMobileDataSubscriptionId
+ private val activeMobileDataConnectionRepo: Flow<MobileConnectionRepository?> =
+ activeMobileDataSubscriptionId.map { activeId ->
+ if (activeId == INVALID_SUBSCRIPTION_ID) {
+ null
+ } else {
+ mobileConnectionsRepo.getRepoForSubId(activeId)
+ }
+ }
+
+ override val activeDataConnectionHasDataEnabled: Flow<Boolean> =
+ activeMobileDataConnectionRepo.flatMapLatest { it?.dataEnabled ?: flowOf(false) }
+
private val unfilteredSubscriptions: Flow<List<SubscriptionInfo>> =
mobileConnectionsRepo.subscriptionsFlow
@@ -146,6 +163,7 @@ constructor(
/** Vends out new [MobileIconInteractor] for a particular subId */
override fun createMobileConnectionInteractorForSubId(subId: Int): MobileIconInteractor =
MobileIconInteractorImpl(
+ activeDataConnectionHasDataEnabled,
defaultMobileIconMapping,
defaultMobileIconGroup,
mobileMappingsProxy,
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/ui/viewmodel/MobileIconViewModel.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/ui/viewmodel/MobileIconViewModel.kt
index 81317398f086..b256665358d4 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/ui/viewmodel/MobileIconViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/ui/viewmodel/MobileIconViewModel.kt
@@ -24,10 +24,12 @@ import com.android.systemui.statusbar.pipeline.mobile.domain.interactor.MobileIc
import com.android.systemui.statusbar.pipeline.mobile.domain.interactor.MobileIconsInteractor
import com.android.systemui.statusbar.pipeline.shared.ConnectivityPipelineLogger
import com.android.systemui.statusbar.pipeline.shared.ConnectivityPipelineLogger.Companion.logOutputChange
+import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.flow.distinctUntilChanged
import kotlinx.coroutines.flow.flowOf
+import kotlinx.coroutines.flow.mapLatest
/**
* View model for the state of a single mobile icon. Each [MobileIconViewModel] will keep watch over
@@ -39,25 +41,31 @@ import kotlinx.coroutines.flow.flowOf
*
* TODO: figure out where carrier merged and VCN models go (probably here?)
*/
+@Suppress("EXPERIMENTAL_IS_NOT_ENABLED")
+@OptIn(ExperimentalCoroutinesApi::class)
class MobileIconViewModel
constructor(
val subscriptionId: Int,
iconInteractor: MobileIconInteractor,
logger: ConnectivityPipelineLogger,
) {
+ /** Whether or not to show the error state of [SignalDrawable] */
+ private val showExclamationMark: Flow<Boolean> =
+ iconInteractor.isDefaultDataEnabled.mapLatest { !it }
+
/** An int consumable by [SignalDrawable] for display */
- var iconId: Flow<Int> =
- combine(iconInteractor.level, iconInteractor.numberOfLevels, iconInteractor.cutOut) {
+ val iconId: Flow<Int> =
+ combine(iconInteractor.level, iconInteractor.numberOfLevels, showExclamationMark) {
level,
numberOfLevels,
- cutOut ->
- SignalDrawable.getState(level, numberOfLevels, cutOut)
+ showExclamationMark ->
+ SignalDrawable.getState(level, numberOfLevels, showExclamationMark)
}
.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?> =
+ val networkTypeIcon: Flow<Icon?> =
combine(iconInteractor.networkTypeIconGroup, iconInteractor.isDataEnabled) {
networkTypeIconGroup,
isDataEnabled ->
@@ -72,5 +80,5 @@ constructor(
}
}
- var tint: Flow<Int> = flowOf(Color.CYAN)
+ val tint: Flow<Int> = flowOf(Color.CYAN)
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/FakeMobileConnectionRepository.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/FakeMobileConnectionRepository.kt
index de1fec85360b..4c7f7eab981d 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/FakeMobileConnectionRepository.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/FakeMobileConnectionRepository.kt
@@ -27,6 +27,9 @@ class FakeMobileConnectionRepository : MobileConnectionRepository {
private val _dataEnabled = MutableStateFlow(true)
override val dataEnabled = _dataEnabled
+ private val _isDefaultDataSubscription = MutableStateFlow(true)
+ override val isDefaultDataSubscription = _isDefaultDataSubscription
+
fun setMobileSubscriptionModel(model: MobileSubscriptionModel) {
_subscriptionsModelFlow.value = model
}
@@ -34,4 +37,8 @@ class FakeMobileConnectionRepository : MobileConnectionRepository {
fun setDataEnabled(enabled: Boolean) {
_dataEnabled.value = enabled
}
+
+ fun setIsDefaultDataSubscription(isDefault: Boolean) {
+ _isDefaultDataSubscription.value = isDefault
+ }
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/FakeMobileConnectionsRepository.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/FakeMobileConnectionsRepository.kt
index 813e750684a0..8488effd22ee 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/FakeMobileConnectionsRepository.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/FakeMobileConnectionsRepository.kt
@@ -17,7 +17,7 @@
package com.android.systemui.statusbar.pipeline.mobile.data.repository
import android.telephony.SubscriptionInfo
-import android.telephony.SubscriptionManager
+import android.telephony.SubscriptionManager.INVALID_SUBSCRIPTION_ID
import com.android.settingslib.mobile.MobileMappings.Config
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.MutableStateFlow
@@ -26,18 +26,23 @@ class FakeMobileConnectionsRepository : MobileConnectionsRepository {
private val _subscriptionsFlow = MutableStateFlow<List<SubscriptionInfo>>(listOf())
override val subscriptionsFlow: Flow<List<SubscriptionInfo>> = _subscriptionsFlow
- private val _activeMobileDataSubscriptionId =
- MutableStateFlow(SubscriptionManager.INVALID_SUBSCRIPTION_ID)
+ private val _activeMobileDataSubscriptionId = MutableStateFlow(INVALID_SUBSCRIPTION_ID)
override val activeMobileDataSubscriptionId = _activeMobileDataSubscriptionId
private val _defaultDataSubRatConfig = MutableStateFlow(Config())
override val defaultDataSubRatConfig = _defaultDataSubRatConfig
+ private val _defaultDataSubId = MutableStateFlow(INVALID_SUBSCRIPTION_ID)
+ override val defaultDataSubId = _defaultDataSubId
+
private val subIdRepos = mutableMapOf<Int, MobileConnectionRepository>()
override fun getRepoForSubId(subId: Int): MobileConnectionRepository {
return subIdRepos[subId] ?: FakeMobileConnectionRepository().also { subIdRepos[subId] = it }
}
+ private val _globalMobileDataSettingChangedEvent = MutableStateFlow(Unit)
+ override val globalMobileDataSettingChangedEvent = _globalMobileDataSettingChangedEvent
+
fun setSubscriptions(subs: List<SubscriptionInfo>) {
_subscriptionsFlow.value = subs
}
@@ -46,6 +51,14 @@ class FakeMobileConnectionsRepository : MobileConnectionsRepository {
_defaultDataSubRatConfig.value = config
}
+ fun setDefaultDataSubId(id: Int) {
+ _defaultDataSubId.value = id
+ }
+
+ suspend fun triggerGlobalMobileDataSettingChangedEvent() {
+ _globalMobileDataSettingChangedEvent.emit(Unit)
+ }
+
fun setActiveMobileDataSubscriptionId(subId: Int) {
_activeMobileDataSubscriptionId.value = subId
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/MobileConnectionRepositoryTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/MobileConnectionRepositoryTest.kt
index 093936444789..ed3eda5beaf3 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/MobileConnectionRepositoryTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/MobileConnectionRepositoryTest.kt
@@ -16,6 +16,8 @@
package com.android.systemui.statusbar.pipeline.mobile.data.repository
+import android.os.UserHandle
+import android.provider.Settings
import android.telephony.CellSignalStrengthCdma
import android.telephony.ServiceState
import android.telephony.SignalStrength
@@ -42,6 +44,7 @@ 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.whenever
+import com.android.systemui.util.settings.FakeSettings
import com.google.common.truth.Truth.assertThat
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
@@ -67,16 +70,23 @@ class MobileConnectionRepositoryTest : SysuiTestCase() {
@Mock private lateinit var logger: ConnectivityPipelineLogger
private val scope = CoroutineScope(IMMEDIATE)
+ private val globalSettings = FakeSettings()
+ private val connectionsRepo = FakeMobileConnectionsRepository()
@Before
fun setUp() {
MockitoAnnotations.initMocks(this)
+ globalSettings.userId = UserHandle.USER_ALL
whenever(telephonyManager.subscriptionId).thenReturn(SUB_1_ID)
underTest =
MobileConnectionRepositoryImpl(
+ context,
SUB_1_ID,
telephonyManager,
+ globalSettings,
+ connectionsRepo.defaultDataSubId,
+ connectionsRepo.globalMobileDataSettingChangedEvent,
IMMEDIATE,
logger,
scope,
@@ -315,6 +325,57 @@ class MobileConnectionRepositoryTest : SysuiTestCase() {
job.cancel()
}
+ @Test
+ fun isDefaultDataSubscription_isDefault() =
+ runBlocking(IMMEDIATE) {
+ connectionsRepo.setDefaultDataSubId(SUB_1_ID)
+
+ var latest: Boolean? = null
+ val job = underTest.isDefaultDataSubscription.onEach { latest = it }.launchIn(this)
+
+ assertThat(latest).isTrue()
+
+ job.cancel()
+ }
+
+ @Test
+ fun isDefaultDataSubscription_isNotDefault() =
+ runBlocking(IMMEDIATE) {
+ // Our subId is SUB_1_ID
+ connectionsRepo.setDefaultDataSubId(123)
+
+ var latest: Boolean? = null
+ val job = underTest.isDefaultDataSubscription.onEach { latest = it }.launchIn(this)
+
+ assertThat(latest).isFalse()
+
+ job.cancel()
+ }
+
+ @Test
+ fun isDataConnectionAllowed_subIdSettingUpdate_valueUpdated() =
+ runBlocking(IMMEDIATE) {
+ val subIdSettingName = "${Settings.Global.MOBILE_DATA}$SUB_1_ID"
+
+ var latest: Boolean? = null
+ val job = underTest.dataEnabled.onEach { latest = it }.launchIn(this)
+
+ // We don't read the setting directly, we query telephony when changes happen
+ whenever(telephonyManager.isDataConnectionAllowed).thenReturn(false)
+ globalSettings.putInt(subIdSettingName, 0)
+ assertThat(latest).isFalse()
+
+ whenever(telephonyManager.isDataConnectionAllowed).thenReturn(true)
+ globalSettings.putInt(subIdSettingName, 1)
+ assertThat(latest).isTrue()
+
+ whenever(telephonyManager.isDataConnectionAllowed).thenReturn(false)
+ globalSettings.putInt(subIdSettingName, 0)
+ assertThat(latest).isFalse()
+
+ job.cancel()
+ }
+
private fun getTelephonyCallbacks(): List<TelephonyCallback> {
val callbackCaptor = argumentCaptor<TelephonyCallback>()
Mockito.verify(telephonyManager).registerTelephonyCallback(any(), callbackCaptor.capture())
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/MobileConnectionsRepositoryTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/MobileConnectionsRepositoryTest.kt
index 326e0d28166f..27c7357cb995 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/MobileConnectionsRepositoryTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/MobileConnectionsRepositoryTest.kt
@@ -16,26 +16,27 @@
package com.android.systemui.statusbar.pipeline.mobile.data.repository
+import android.content.Intent
+import android.provider.Settings
import android.telephony.SubscriptionInfo
import android.telephony.SubscriptionManager
import android.telephony.TelephonyCallback
import android.telephony.TelephonyCallback.ActiveDataSubscriptionIdListener
import android.telephony.TelephonyManager
import androidx.test.filters.SmallTest
+import com.android.internal.telephony.PhoneConstants
import com.android.systemui.SysuiTestCase
-import com.android.systemui.broadcast.BroadcastDispatcher
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.android.systemui.util.settings.FakeSettings
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
@@ -43,7 +44,6 @@ import org.junit.After
import org.junit.Assert.assertThrows
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
@@ -57,29 +57,21 @@ class MobileConnectionsRepositoryTest : 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 globalSettings = FakeSettings()
@Before
fun setUp() {
MockitoAnnotations.initMocks(this)
- whenever(
- broadcastDispatcher.broadcastFlow(
- any(),
- nullable(),
- ArgumentMatchers.anyInt(),
- nullable(),
- )
- )
- .thenReturn(flowOf(Unit))
underTest =
MobileConnectionsRepositoryImpl(
subscriptionManager,
telephonyManager,
logger,
- broadcastDispatcher,
+ fakeBroadcastDispatcher,
+ globalSettings,
context,
IMMEDIATE,
scope,
@@ -214,6 +206,53 @@ class MobileConnectionsRepositoryTest : SysuiTestCase() {
job.cancel()
}
+ @Test
+ fun testDefaultDataSubId_updatesOnBroadcast() =
+ runBlocking(IMMEDIATE) {
+ var latest: Int? = null
+ val job = underTest.defaultDataSubId.onEach { latest = it }.launchIn(this)
+
+ fakeBroadcastDispatcher.registeredReceivers.forEach { receiver ->
+ receiver.onReceive(
+ context,
+ Intent(TelephonyManager.ACTION_DEFAULT_DATA_SUBSCRIPTION_CHANGED)
+ .putExtra(PhoneConstants.SUBSCRIPTION_KEY, SUB_2_ID)
+ )
+ }
+
+ assertThat(latest).isEqualTo(SUB_2_ID)
+
+ fakeBroadcastDispatcher.registeredReceivers.forEach { receiver ->
+ receiver.onReceive(
+ context,
+ Intent(TelephonyManager.ACTION_DEFAULT_DATA_SUBSCRIPTION_CHANGED)
+ .putExtra(PhoneConstants.SUBSCRIPTION_KEY, SUB_1_ID)
+ )
+ }
+
+ assertThat(latest).isEqualTo(SUB_1_ID)
+
+ job.cancel()
+ }
+
+ @Test
+ fun globalMobileDataSettingsChangedEvent_producesOnSettingChange() =
+ runBlocking(IMMEDIATE) {
+ var produced = false
+ val job =
+ underTest.globalMobileDataSettingChangedEvent
+ .onEach { produced = true }
+ .launchIn(this)
+
+ assertThat(produced).isFalse()
+
+ globalSettings.putInt(Settings.Global.MOBILE_DATA, 0)
+
+ assertThat(produced).isTrue()
+
+ job.cancel()
+ }
+
private fun getSubscriptionCallback(): SubscriptionManager.OnSubscriptionsChangedListener {
val callbackCaptor = argumentCaptor<SubscriptionManager.OnSubscriptionsChangedListener>()
verify(subscriptionManager)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/FakeMobileIconInteractor.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/FakeMobileIconInteractor.kt
index 5611c448c550..ea3faa0dff1a 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/FakeMobileIconInteractor.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/FakeMobileIconInteractor.kt
@@ -31,15 +31,15 @@ class FakeMobileIconInteractor : MobileIconInteractor {
private val _isDataEnabled = MutableStateFlow(true)
override val isDataEnabled = _isDataEnabled
+ private val _isDefaultDataEnabled = MutableStateFlow(true)
+ override val isDefaultDataEnabled = _isDefaultDataEnabled
+
private val _level = MutableStateFlow(CellSignalStrength.SIGNAL_STRENGTH_NONE_OR_UNKNOWN)
override val level = _level
private val _numberOfLevels = MutableStateFlow(4)
override val numberOfLevels = _numberOfLevels
- private val _cutOut = MutableStateFlow(false)
- override val cutOut = _cutOut
-
fun setIconGroup(group: SignalIcon.MobileIconGroup) {
_iconGroup.value = group
}
@@ -52,6 +52,10 @@ class FakeMobileIconInteractor : MobileIconInteractor {
_isDataEnabled.value = enabled
}
+ fun setIsDefaultDataEnabled(disabled: Boolean) {
+ _isDefaultDataEnabled.value = disabled
+ }
+
fun setLevel(level: Int) {
_level.value = level
}
@@ -59,8 +63,4 @@ class FakeMobileIconInteractor : MobileIconInteractor {
fun setNumberOfLevels(num: Int) {
_numberOfLevels.value = num
}
-
- fun setCutOut(cutOut: Boolean) {
- _cutOut.value = cutOut
- }
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/FakeMobileIconsInteractor.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/FakeMobileIconsInteractor.kt
index 2bd228603cb0..cf95bf736bab 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/FakeMobileIconsInteractor.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/FakeMobileIconsInteractor.kt
@@ -26,8 +26,7 @@ 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 {
+class FakeMobileIconsInteractor(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)
@@ -49,6 +48,9 @@ class FakeMobileIconsInteractor(private val mobileMappings: MobileMappingsProxy)
private val _filteredSubscriptions = MutableStateFlow<List<SubscriptionInfo>>(listOf())
override val filteredSubscriptions = _filteredSubscriptions
+ private val _activeDataConnectionHasDataEnabled = MutableStateFlow(false)
+ override val activeDataConnectionHasDataEnabled = _activeDataConnectionHasDataEnabled
+
private val _defaultMobileIconMapping = MutableStateFlow(TEST_MAPPING)
override val defaultMobileIconMapping = _defaultMobileIconMapping
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconInteractorTest.kt
index ff44af4c9204..4d6ed2fc7493 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconInteractorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconInteractorTest.kt
@@ -53,6 +53,7 @@ class MobileIconInteractorTest : SysuiTestCase() {
fun setUp() {
underTest =
MobileIconInteractorImpl(
+ mobileIconsInteractor.activeDataConnectionHasDataEnabled,
mobileIconsInteractor.defaultMobileIconMapping,
mobileIconsInteractor.defaultMobileIconGroup,
mobileMappingsProxy,
@@ -196,6 +197,21 @@ class MobileIconInteractorTest : SysuiTestCase() {
job.cancel()
}
+ @Test
+ fun test_isDefaultDataEnabled_matchesParent() =
+ runBlocking(IMMEDIATE) {
+ var latest: Boolean? = null
+ val job = underTest.isDefaultDataEnabled.onEach { latest = it }.launchIn(this)
+
+ mobileIconsInteractor.activeDataConnectionHasDataEnabled.value = true
+ assertThat(latest).isTrue()
+
+ mobileIconsInteractor.activeDataConnectionHasDataEnabled.value = false
+ assertThat(latest).isFalse()
+
+ job.cancel()
+ }
+
companion object {
private val IMMEDIATE = Dispatchers.Main.immediate
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconsInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconsInteractorTest.kt
index 877ce0e6b351..799d0a3f1cc7 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconsInteractorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconsInteractorTest.kt
@@ -17,6 +17,7 @@
package com.android.systemui.statusbar.pipeline.mobile.domain.interactor
import android.telephony.SubscriptionInfo
+import android.telephony.SubscriptionManager.INVALID_SUBSCRIPTION_ID
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.statusbar.pipeline.mobile.data.repository.FakeMobileConnectionRepository
@@ -32,6 +33,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.After
import org.junit.Before
import org.junit.Test
@@ -168,6 +170,51 @@ class MobileIconsInteractorTest : SysuiTestCase() {
job.cancel()
}
+ @Test
+ fun activeDataConnection_turnedOn() =
+ runBlocking(IMMEDIATE) {
+ CONNECTION_1.setDataEnabled(true)
+ var latest: Boolean? = null
+ val job =
+ underTest.activeDataConnectionHasDataEnabled.onEach { latest = it }.launchIn(this)
+
+ assertThat(latest).isTrue()
+
+ job.cancel()
+ }
+
+ @Test
+ fun activeDataConnection_turnedOff() =
+ runBlocking(IMMEDIATE) {
+ CONNECTION_1.setDataEnabled(true)
+ var latest: Boolean? = null
+ val job =
+ underTest.activeDataConnectionHasDataEnabled.onEach { latest = it }.launchIn(this)
+
+ CONNECTION_1.setDataEnabled(false)
+ yield()
+
+ assertThat(latest).isFalse()
+
+ job.cancel()
+ }
+
+ @Test
+ fun activeDataConnection_invalidSubId() =
+ runBlocking(IMMEDIATE) {
+ var latest: Boolean? = null
+ val job =
+ underTest.activeDataConnectionHasDataEnabled.onEach { latest = it }.launchIn(this)
+
+ connectionsRepository.setActiveMobileDataSubscriptionId(INVALID_SUBSCRIPTION_ID)
+ yield()
+
+ // An invalid active subId should tell us that data is off
+ assertThat(latest).isFalse()
+
+ job.cancel()
+ }
+
companion object {
private val IMMEDIATE = Dispatchers.Main.immediate
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/ui/viewmodel/MobileIconViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/ui/viewmodel/MobileIconViewModelTest.kt
index ce0f33f400ab..da0bf5c27485 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/ui/viewmodel/MobileIconViewModelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/ui/viewmodel/MobileIconViewModelTest.kt
@@ -46,7 +46,7 @@ class MobileIconViewModelTest : SysuiTestCase() {
MockitoAnnotations.initMocks(this)
interactor.apply {
setLevel(1)
- setCutOut(false)
+ setIsDefaultDataEnabled(true)
setIconGroup(THREE_G)
setIsEmergencyOnly(false)
setNumberOfLevels(4)
@@ -59,8 +59,23 @@ class MobileIconViewModelTest : SysuiTestCase() {
runBlocking(IMMEDIATE) {
var latest: Int? = null
val job = underTest.iconId.onEach { latest = it }.launchIn(this)
+ val expected = defaultSignal()
- assertThat(latest).isEqualTo(SignalDrawable.getState(1, 4, false))
+ assertThat(latest).isEqualTo(expected)
+
+ job.cancel()
+ }
+
+ @Test
+ fun iconId_cutout_whenDefaultDataDisabled() =
+ runBlocking(IMMEDIATE) {
+ interactor.setIsDefaultDataEnabled(false)
+
+ var latest: Int? = null
+ val job = underTest.iconId.onEach { latest = it }.launchIn(this)
+ val expected = defaultSignal(level = 1, connected = false)
+
+ assertThat(latest).isEqualTo(expected)
job.cancel()
}
@@ -119,6 +134,14 @@ class MobileIconViewModelTest : SysuiTestCase() {
job.cancel()
}
+ /** Convenience constructor for these tests */
+ private fun defaultSignal(
+ level: Int = 1,
+ connected: Boolean = true,
+ ): Int {
+ return SignalDrawable.getState(level, /* numLevels */ 4, !connected)
+ }
+
companion object {
private val IMMEDIATE = Dispatchers.Main.immediate
private const val SUB_1_ID = 1