Merge changes Id57cc404,Ieaf30071,Idb2b182c,I5de259d8,I5d7762b7 into tm-qpr-dev
* changes: [Sb refactor] Fix missed telephony callback events [Sb refactor] Handle telephony display info with only an override [Sb refactor][cleanup] Move testing to testScope [Sb refactor][cleanup] remove spaces from tests [Sb refactor] Filter out -1 values for ERI
This commit is contained in:
@@ -18,7 +18,6 @@ package com.android.systemui.statusbar.pipeline.mobile.data.repository.prod
|
|||||||
|
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.content.IntentFilter
|
import android.content.IntentFilter
|
||||||
import android.telephony.CellSignalStrength
|
|
||||||
import android.telephony.CellSignalStrength.SIGNAL_STRENGTH_NONE_OR_UNKNOWN
|
import android.telephony.CellSignalStrength.SIGNAL_STRENGTH_NONE_OR_UNKNOWN
|
||||||
import android.telephony.CellSignalStrengthCdma
|
import android.telephony.CellSignalStrengthCdma
|
||||||
import android.telephony.ServiceState
|
import android.telephony.ServiceState
|
||||||
@@ -28,12 +27,12 @@ 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_FLASH
|
||||||
|
import android.telephony.TelephonyManager.ERI_ON
|
||||||
import android.telephony.TelephonyManager.EXTRA_SUBSCRIPTION_ID
|
import android.telephony.TelephonyManager.EXTRA_SUBSCRIPTION_ID
|
||||||
import android.telephony.TelephonyManager.NETWORK_TYPE_UNKNOWN
|
import android.telephony.TelephonyManager.NETWORK_TYPE_UNKNOWN
|
||||||
import com.android.settingslib.Utils
|
import com.android.settingslib.Utils
|
||||||
import com.android.systemui.broadcast.BroadcastDispatcher
|
import com.android.systemui.broadcast.BroadcastDispatcher
|
||||||
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.log.table.TableLogBuffer
|
import com.android.systemui.log.table.TableLogBuffer
|
||||||
@@ -59,16 +58,14 @@ import kotlinx.coroutines.ExperimentalCoroutinesApi
|
|||||||
import kotlinx.coroutines.asExecutor
|
import kotlinx.coroutines.asExecutor
|
||||||
import kotlinx.coroutines.channels.awaitClose
|
import kotlinx.coroutines.channels.awaitClose
|
||||||
import kotlinx.coroutines.flow.Flow
|
import kotlinx.coroutines.flow.Flow
|
||||||
import kotlinx.coroutines.flow.MutableSharedFlow
|
|
||||||
import kotlinx.coroutines.flow.SharedFlow
|
|
||||||
import kotlinx.coroutines.flow.SharingStarted
|
import kotlinx.coroutines.flow.SharingStarted
|
||||||
import kotlinx.coroutines.flow.StateFlow
|
import kotlinx.coroutines.flow.StateFlow
|
||||||
|
import kotlinx.coroutines.flow.callbackFlow
|
||||||
import kotlinx.coroutines.flow.filter
|
import kotlinx.coroutines.flow.filter
|
||||||
import kotlinx.coroutines.flow.filterIsInstance
|
|
||||||
import kotlinx.coroutines.flow.map
|
import kotlinx.coroutines.flow.map
|
||||||
import kotlinx.coroutines.flow.mapLatest
|
import kotlinx.coroutines.flow.mapLatest
|
||||||
import kotlinx.coroutines.flow.mapNotNull
|
import kotlinx.coroutines.flow.mapNotNull
|
||||||
import kotlinx.coroutines.flow.shareIn
|
import kotlinx.coroutines.flow.scan
|
||||||
import kotlinx.coroutines.flow.stateIn
|
import kotlinx.coroutines.flow.stateIn
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -100,8 +97,6 @@ class MobileConnectionRepositoryImpl(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private val telephonyCallbackEvent = MutableSharedFlow<Unit>(extraBufferCapacity = 1)
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This flow defines the single shared connection to system_server via TelephonyCallback. Any
|
* This flow defines the single shared connection to system_server via TelephonyCallback. Any
|
||||||
* new callback should be added to this listener and funneled through callbackEvents via a data
|
* new callback should be added to this listener and funneled through callbackEvents via a data
|
||||||
@@ -109,9 +104,15 @@ class MobileConnectionRepositoryImpl(
|
|||||||
*
|
*
|
||||||
* The reason we need to do this is because TelephonyManager limits the number of registered
|
* The reason we need to do this is because TelephonyManager limits the number of registered
|
||||||
* listeners per-process, so we don't want to create a new listener for every callback.
|
* listeners per-process, so we don't want to create a new listener for every callback.
|
||||||
|
*
|
||||||
|
* A note on the design for back pressure here: We use the [coalesce] operator here to change
|
||||||
|
* the backpressure strategy to store exactly the last callback event of _each type_ here, as
|
||||||
|
* opposed to the default strategy which is to drop the oldest event (regardless of type). This
|
||||||
|
* means that we should never miss any single event as long as the flow has been started.
|
||||||
*/
|
*/
|
||||||
private val callbackEvents: SharedFlow<CallbackEvent> =
|
private val callbackEvents: StateFlow<TelephonyCallbackState> = run {
|
||||||
conflatedCallbackFlow {
|
val initial = TelephonyCallbackState()
|
||||||
|
callbackFlow {
|
||||||
val callback =
|
val callback =
|
||||||
object :
|
object :
|
||||||
TelephonyCallback(),
|
TelephonyCallback(),
|
||||||
@@ -165,48 +166,50 @@ class MobileConnectionRepositoryImpl(
|
|||||||
telephonyManager.registerTelephonyCallback(bgDispatcher.asExecutor(), callback)
|
telephonyManager.registerTelephonyCallback(bgDispatcher.asExecutor(), callback)
|
||||||
awaitClose { telephonyManager.unregisterTelephonyCallback(callback) }
|
awaitClose { telephonyManager.unregisterTelephonyCallback(callback) }
|
||||||
}
|
}
|
||||||
.shareIn(scope, SharingStarted.WhileSubscribed())
|
.scan(initial = initial) { state, event -> state.applyEvent(event) }
|
||||||
|
.stateIn(scope = scope, started = SharingStarted.WhileSubscribed(), initial)
|
||||||
|
}
|
||||||
|
|
||||||
override val isEmergencyOnly =
|
override val isEmergencyOnly =
|
||||||
callbackEvents
|
callbackEvents
|
||||||
.filterIsInstance<CallbackEvent.OnServiceStateChanged>()
|
.mapNotNull { it.onServiceStateChanged }
|
||||||
.map { it.serviceState.isEmergencyOnly }
|
.map { it.serviceState.isEmergencyOnly }
|
||||||
.stateIn(scope, SharingStarted.WhileSubscribed(), false)
|
.stateIn(scope, SharingStarted.WhileSubscribed(), false)
|
||||||
|
|
||||||
override val isRoaming =
|
override val isRoaming =
|
||||||
callbackEvents
|
callbackEvents
|
||||||
.filterIsInstance<CallbackEvent.OnServiceStateChanged>()
|
.mapNotNull { it.onServiceStateChanged }
|
||||||
.map { it.serviceState.roaming }
|
.map { it.serviceState.roaming }
|
||||||
.stateIn(scope, SharingStarted.WhileSubscribed(), false)
|
.stateIn(scope, SharingStarted.WhileSubscribed(), false)
|
||||||
|
|
||||||
override val operatorAlphaShort =
|
override val operatorAlphaShort =
|
||||||
callbackEvents
|
callbackEvents
|
||||||
.filterIsInstance<CallbackEvent.OnServiceStateChanged>()
|
.mapNotNull { it.onServiceStateChanged }
|
||||||
.map { it.serviceState.operatorAlphaShort }
|
.map { it.serviceState.operatorAlphaShort }
|
||||||
.stateIn(scope, SharingStarted.WhileSubscribed(), null)
|
.stateIn(scope, SharingStarted.WhileSubscribed(), null)
|
||||||
|
|
||||||
override val isInService =
|
override val isInService =
|
||||||
callbackEvents
|
callbackEvents
|
||||||
.filterIsInstance<CallbackEvent.OnServiceStateChanged>()
|
.mapNotNull { it.onServiceStateChanged }
|
||||||
.map { Utils.isInService(it.serviceState) }
|
.map { Utils.isInService(it.serviceState) }
|
||||||
.stateIn(scope, SharingStarted.WhileSubscribed(), false)
|
.stateIn(scope, SharingStarted.WhileSubscribed(), false)
|
||||||
|
|
||||||
override val isGsm =
|
override val isGsm =
|
||||||
callbackEvents
|
callbackEvents
|
||||||
.filterIsInstance<CallbackEvent.OnSignalStrengthChanged>()
|
.mapNotNull { it.onSignalStrengthChanged }
|
||||||
.map { it.signalStrength.isGsm }
|
.map { it.signalStrength.isGsm }
|
||||||
.stateIn(scope, SharingStarted.WhileSubscribed(), false)
|
.stateIn(scope, SharingStarted.WhileSubscribed(), false)
|
||||||
|
|
||||||
override val cdmaLevel =
|
override val cdmaLevel =
|
||||||
callbackEvents
|
callbackEvents
|
||||||
.filterIsInstance<CallbackEvent.OnSignalStrengthChanged>()
|
.mapNotNull { it.onSignalStrengthChanged }
|
||||||
.map {
|
.map {
|
||||||
it.signalStrength.getCellSignalStrengths(CellSignalStrengthCdma::class.java).let {
|
it.signalStrength.getCellSignalStrengths(CellSignalStrengthCdma::class.java).let {
|
||||||
strengths ->
|
strengths ->
|
||||||
if (strengths.isNotEmpty()) {
|
if (strengths.isNotEmpty()) {
|
||||||
strengths[0].level
|
strengths[0].level
|
||||||
} else {
|
} else {
|
||||||
CellSignalStrength.SIGNAL_STRENGTH_NONE_OR_UNKNOWN
|
SIGNAL_STRENGTH_NONE_OR_UNKNOWN
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -214,19 +217,19 @@ class MobileConnectionRepositoryImpl(
|
|||||||
|
|
||||||
override val primaryLevel =
|
override val primaryLevel =
|
||||||
callbackEvents
|
callbackEvents
|
||||||
.filterIsInstance<CallbackEvent.OnSignalStrengthChanged>()
|
.mapNotNull { it.onSignalStrengthChanged }
|
||||||
.map { it.signalStrength.level }
|
.map { it.signalStrength.level }
|
||||||
.stateIn(scope, SharingStarted.WhileSubscribed(), SIGNAL_STRENGTH_NONE_OR_UNKNOWN)
|
.stateIn(scope, SharingStarted.WhileSubscribed(), SIGNAL_STRENGTH_NONE_OR_UNKNOWN)
|
||||||
|
|
||||||
override val dataConnectionState =
|
override val dataConnectionState =
|
||||||
callbackEvents
|
callbackEvents
|
||||||
.filterIsInstance<CallbackEvent.OnDataConnectionStateChanged>()
|
.mapNotNull { it.onDataConnectionStateChanged }
|
||||||
.map { it.dataState.toDataConnectionType() }
|
.map { it.dataState.toDataConnectionType() }
|
||||||
.stateIn(scope, SharingStarted.WhileSubscribed(), Disconnected)
|
.stateIn(scope, SharingStarted.WhileSubscribed(), Disconnected)
|
||||||
|
|
||||||
override val dataActivityDirection =
|
override val dataActivityDirection =
|
||||||
callbackEvents
|
callbackEvents
|
||||||
.filterIsInstance<CallbackEvent.OnDataActivity>()
|
.mapNotNull { it.onDataActivity }
|
||||||
.map { it.direction.toMobileDataActivityModel() }
|
.map { it.direction.toMobileDataActivityModel() }
|
||||||
.stateIn(
|
.stateIn(
|
||||||
scope,
|
scope,
|
||||||
@@ -236,28 +239,26 @@ class MobileConnectionRepositoryImpl(
|
|||||||
|
|
||||||
override val carrierNetworkChangeActive =
|
override val carrierNetworkChangeActive =
|
||||||
callbackEvents
|
callbackEvents
|
||||||
.filterIsInstance<CallbackEvent.OnCarrierNetworkChange>()
|
.mapNotNull { it.onCarrierNetworkChange }
|
||||||
.map { it.active }
|
.map { it.active }
|
||||||
.stateIn(scope, SharingStarted.WhileSubscribed(), false)
|
.stateIn(scope, SharingStarted.WhileSubscribed(), false)
|
||||||
|
|
||||||
override val resolvedNetworkType =
|
override val resolvedNetworkType =
|
||||||
callbackEvents
|
callbackEvents
|
||||||
.filterIsInstance<CallbackEvent.OnDisplayInfoChanged>()
|
.mapNotNull { it.onDisplayInfoChanged }
|
||||||
.map {
|
.map {
|
||||||
if (it.telephonyDisplayInfo.networkType == NETWORK_TYPE_UNKNOWN) {
|
if (it.telephonyDisplayInfo.overrideNetworkType != OVERRIDE_NETWORK_TYPE_NONE) {
|
||||||
UnknownNetworkType
|
|
||||||
} else if (
|
|
||||||
it.telephonyDisplayInfo.overrideNetworkType == OVERRIDE_NETWORK_TYPE_NONE
|
|
||||||
) {
|
|
||||||
DefaultNetworkType(
|
|
||||||
mobileMappingsProxy.toIconKey(it.telephonyDisplayInfo.networkType)
|
|
||||||
)
|
|
||||||
} else {
|
|
||||||
OverrideNetworkType(
|
OverrideNetworkType(
|
||||||
mobileMappingsProxy.toIconKeyOverride(
|
mobileMappingsProxy.toIconKeyOverride(
|
||||||
it.telephonyDisplayInfo.overrideNetworkType
|
it.telephonyDisplayInfo.overrideNetworkType
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
} else if (it.telephonyDisplayInfo.networkType != NETWORK_TYPE_UNKNOWN) {
|
||||||
|
DefaultNetworkType(
|
||||||
|
mobileMappingsProxy.toIconKey(it.telephonyDisplayInfo.networkType)
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
UnknownNetworkType
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.stateIn(scope, SharingStarted.WhileSubscribed(), UnknownNetworkType)
|
.stateIn(scope, SharingStarted.WhileSubscribed(), UnknownNetworkType)
|
||||||
@@ -282,7 +283,10 @@ class MobileConnectionRepositoryImpl(
|
|||||||
|
|
||||||
override val cdmaRoaming: StateFlow<Boolean> =
|
override val cdmaRoaming: StateFlow<Boolean> =
|
||||||
telephonyPollingEvent
|
telephonyPollingEvent
|
||||||
.mapLatest { telephonyManager.cdmaEnhancedRoamingIndicatorDisplayNumber != ERI_OFF }
|
.mapLatest {
|
||||||
|
val cdmaEri = telephonyManager.cdmaEnhancedRoamingIndicatorDisplayNumber
|
||||||
|
cdmaEri == ERI_ON || cdmaEri == ERI_FLASH
|
||||||
|
}
|
||||||
.stateIn(scope, SharingStarted.WhileSubscribed(), false)
|
.stateIn(scope, SharingStarted.WhileSubscribed(), false)
|
||||||
|
|
||||||
override val networkName: StateFlow<NetworkNameModel> =
|
override val networkName: StateFlow<NetworkNameModel> =
|
||||||
@@ -300,7 +304,8 @@ class MobileConnectionRepositoryImpl(
|
|||||||
override val dataEnabled = run {
|
override val dataEnabled = run {
|
||||||
val initial = telephonyManager.isDataConnectionAllowed
|
val initial = telephonyManager.isDataConnectionAllowed
|
||||||
callbackEvents
|
callbackEvents
|
||||||
.mapNotNull { (it as? CallbackEvent.OnDataEnabledChanged)?.enabled }
|
.mapNotNull { it.onDataEnabledChanged }
|
||||||
|
.map { it.enabled }
|
||||||
.stateIn(scope, SharingStarted.WhileSubscribed(), initial)
|
.stateIn(scope, SharingStarted.WhileSubscribed(), initial)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -344,12 +349,41 @@ class MobileConnectionRepositoryImpl(
|
|||||||
* Wrap every [TelephonyCallback] we care about in a data class so we can accept them in a single
|
* Wrap every [TelephonyCallback] we care about in a data class so we can accept them in a single
|
||||||
* shared flow and then split them back out into other flows.
|
* shared flow and then split them back out into other flows.
|
||||||
*/
|
*/
|
||||||
private sealed interface CallbackEvent {
|
sealed interface CallbackEvent {
|
||||||
|
data class OnCarrierNetworkChange(val active: Boolean) : CallbackEvent
|
||||||
|
data class OnDataActivity(val direction: Int) : CallbackEvent
|
||||||
|
data class OnDataConnectionStateChanged(val dataState: Int) : CallbackEvent
|
||||||
|
data class OnDataEnabledChanged(val enabled: Boolean) : CallbackEvent
|
||||||
|
data class OnDisplayInfoChanged(val telephonyDisplayInfo: TelephonyDisplayInfo) : CallbackEvent
|
||||||
data class OnServiceStateChanged(val serviceState: ServiceState) : CallbackEvent
|
data class OnServiceStateChanged(val serviceState: ServiceState) : CallbackEvent
|
||||||
data class OnSignalStrengthChanged(val signalStrength: SignalStrength) : CallbackEvent
|
data class OnSignalStrengthChanged(val signalStrength: SignalStrength) : CallbackEvent
|
||||||
data class OnDataConnectionStateChanged(val dataState: Int) : CallbackEvent
|
}
|
||||||
data class OnDataActivity(val direction: Int) : CallbackEvent
|
|
||||||
data class OnCarrierNetworkChange(val active: Boolean) : CallbackEvent
|
/**
|
||||||
data class OnDisplayInfoChanged(val telephonyDisplayInfo: TelephonyDisplayInfo) : CallbackEvent
|
* A simple box type for 1-to-1 mapping of [CallbackEvent] to the batched event. Used in conjunction
|
||||||
data class OnDataEnabledChanged(val enabled: Boolean) : CallbackEvent
|
* with [scan] to make sure we don't drop important callbacks due to late subscribers
|
||||||
|
*/
|
||||||
|
data class TelephonyCallbackState(
|
||||||
|
val onDataActivity: CallbackEvent.OnDataActivity? = null,
|
||||||
|
val onCarrierNetworkChange: CallbackEvent.OnCarrierNetworkChange? = null,
|
||||||
|
val onDataConnectionStateChanged: CallbackEvent.OnDataConnectionStateChanged? = null,
|
||||||
|
val onDataEnabledChanged: CallbackEvent.OnDataEnabledChanged? = null,
|
||||||
|
val onDisplayInfoChanged: CallbackEvent.OnDisplayInfoChanged? = null,
|
||||||
|
val onServiceStateChanged: CallbackEvent.OnServiceStateChanged? = null,
|
||||||
|
val onSignalStrengthChanged: CallbackEvent.OnSignalStrengthChanged? = null,
|
||||||
|
) {
|
||||||
|
fun applyEvent(event: CallbackEvent): TelephonyCallbackState {
|
||||||
|
return when (event) {
|
||||||
|
is CallbackEvent.OnCarrierNetworkChange -> copy(onCarrierNetworkChange = event)
|
||||||
|
is CallbackEvent.OnDataActivity -> copy(onDataActivity = event)
|
||||||
|
is CallbackEvent.OnDataConnectionStateChanged ->
|
||||||
|
copy(onDataConnectionStateChanged = event)
|
||||||
|
is CallbackEvent.OnDataEnabledChanged -> copy(onDataEnabledChanged = event)
|
||||||
|
is CallbackEvent.OnDisplayInfoChanged -> copy(onDisplayInfoChanged = event)
|
||||||
|
is CallbackEvent.OnServiceStateChanged -> {
|
||||||
|
copy(onServiceStateChanged = event)
|
||||||
|
}
|
||||||
|
is CallbackEvent.OnSignalStrengthChanged -> copy(onSignalStrengthChanged = event)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -18,17 +18,16 @@ package com.android.systemui.statusbar.pipeline.mobile.data.repository.prod
|
|||||||
|
|
||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
import android.telephony.CarrierConfigManager.KEY_INFLATE_SIGNAL_STRENGTH_BOOL
|
import android.telephony.CarrierConfigManager.KEY_INFLATE_SIGNAL_STRENGTH_BOOL
|
||||||
import android.telephony.CellSignalStrengthCdma
|
|
||||||
import android.telephony.NetworkRegistrationInfo
|
import android.telephony.NetworkRegistrationInfo
|
||||||
import android.telephony.ServiceState
|
import android.telephony.ServiceState
|
||||||
import android.telephony.ServiceState.STATE_IN_SERVICE
|
import android.telephony.ServiceState.STATE_IN_SERVICE
|
||||||
import android.telephony.ServiceState.STATE_OUT_OF_SERVICE
|
import android.telephony.ServiceState.STATE_OUT_OF_SERVICE
|
||||||
import android.telephony.SignalStrength
|
|
||||||
import android.telephony.TelephonyCallback
|
import android.telephony.TelephonyCallback
|
||||||
import android.telephony.TelephonyCallback.DataActivityListener
|
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.TelephonyDisplayInfo.OVERRIDE_NETWORK_TYPE_NONE
|
||||||
import android.telephony.TelephonyManager
|
import android.telephony.TelephonyManager
|
||||||
import android.telephony.TelephonyManager.DATA_ACTIVITY_DORMANT
|
import android.telephony.TelephonyManager.DATA_ACTIVITY_DORMANT
|
||||||
import android.telephony.TelephonyManager.DATA_ACTIVITY_IN
|
import android.telephony.TelephonyManager.DATA_ACTIVITY_IN
|
||||||
@@ -68,6 +67,7 @@ import com.android.systemui.statusbar.pipeline.mobile.data.model.SystemUiCarrier
|
|||||||
import com.android.systemui.statusbar.pipeline.mobile.data.model.toNetworkNameModel
|
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.data.repository.MobileConnectionRepository.Companion.DEFAULT_NUM_LEVELS
|
import com.android.systemui.statusbar.pipeline.mobile.data.repository.MobileConnectionRepository.Companion.DEFAULT_NUM_LEVELS
|
||||||
|
import com.android.systemui.statusbar.pipeline.mobile.data.repository.prod.MobileTelephonyHelpers.signalStrength
|
||||||
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.data.model.DataActivityModel
|
import com.android.systemui.statusbar.pipeline.shared.data.model.DataActivityModel
|
||||||
import com.android.systemui.statusbar.pipeline.shared.data.model.toMobileDataActivityModel
|
import com.android.systemui.statusbar.pipeline.shared.data.model.toMobileDataActivityModel
|
||||||
@@ -75,14 +75,12 @@ import com.android.systemui.util.mockito.any
|
|||||||
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
|
||||||
import kotlinx.coroutines.CoroutineScope
|
|
||||||
import kotlinx.coroutines.Dispatchers
|
|
||||||
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
||||||
import kotlinx.coroutines.cancel
|
|
||||||
import kotlinx.coroutines.flow.launchIn
|
import kotlinx.coroutines.flow.launchIn
|
||||||
import kotlinx.coroutines.flow.onEach
|
import kotlinx.coroutines.flow.onEach
|
||||||
import kotlinx.coroutines.runBlocking
|
import kotlinx.coroutines.test.TestScope
|
||||||
import org.junit.After
|
import kotlinx.coroutines.test.UnconfinedTestDispatcher
|
||||||
|
import kotlinx.coroutines.test.runTest
|
||||||
import org.junit.Before
|
import org.junit.Before
|
||||||
import org.junit.Test
|
import org.junit.Test
|
||||||
import org.mockito.Mock
|
import org.mockito.Mock
|
||||||
@@ -99,7 +97,6 @@ class MobileConnectionRepositoryTest : SysuiTestCase() {
|
|||||||
@Mock private lateinit var logger: MobileInputLogger
|
@Mock private lateinit var logger: MobileInputLogger
|
||||||
@Mock private lateinit var tableLogger: TableLogBuffer
|
@Mock private lateinit var tableLogger: TableLogBuffer
|
||||||
|
|
||||||
private val scope = CoroutineScope(IMMEDIATE)
|
|
||||||
private val mobileMappings = FakeMobileMappingsProxy()
|
private val mobileMappings = FakeMobileMappingsProxy()
|
||||||
private val systemUiCarrierConfig =
|
private val systemUiCarrierConfig =
|
||||||
SystemUiCarrierConfig(
|
SystemUiCarrierConfig(
|
||||||
@@ -107,6 +104,9 @@ class MobileConnectionRepositoryTest : SysuiTestCase() {
|
|||||||
createTestConfig(),
|
createTestConfig(),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
private val testDispatcher = UnconfinedTestDispatcher()
|
||||||
|
private val testScope = TestScope(testDispatcher)
|
||||||
|
|
||||||
@Before
|
@Before
|
||||||
fun setUp() {
|
fun setUp() {
|
||||||
MockitoAnnotations.initMocks(this)
|
MockitoAnnotations.initMocks(this)
|
||||||
@@ -124,21 +124,16 @@ class MobileConnectionRepositoryTest : SysuiTestCase() {
|
|||||||
systemUiCarrierConfig,
|
systemUiCarrierConfig,
|
||||||
fakeBroadcastDispatcher,
|
fakeBroadcastDispatcher,
|
||||||
mobileMappings,
|
mobileMappings,
|
||||||
IMMEDIATE,
|
testDispatcher,
|
||||||
logger,
|
logger,
|
||||||
tableLogger,
|
tableLogger,
|
||||||
scope,
|
testScope.backgroundScope,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@After
|
|
||||||
fun tearDown() {
|
|
||||||
scope.cancel()
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun emergencyOnly() =
|
fun emergencyOnly() =
|
||||||
runBlocking(IMMEDIATE) {
|
testScope.runTest {
|
||||||
var latest: Boolean? = null
|
var latest: Boolean? = null
|
||||||
val job = underTest.isEmergencyOnly.onEach { latest = it }.launchIn(this)
|
val job = underTest.isEmergencyOnly.onEach { latest = it }.launchIn(this)
|
||||||
|
|
||||||
@@ -154,18 +149,15 @@ class MobileConnectionRepositoryTest : SysuiTestCase() {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun emergencyOnly_toggles() =
|
fun emergencyOnly_toggles() =
|
||||||
runBlocking(IMMEDIATE) {
|
testScope.runTest {
|
||||||
var latest: Boolean? = null
|
var latest: Boolean? = null
|
||||||
val job = underTest.isEmergencyOnly.onEach { latest = it }.launchIn(this)
|
val job = underTest.isEmergencyOnly.onEach { latest = it }.launchIn(this)
|
||||||
|
|
||||||
val callback = getTelephonyCallbackForType<ServiceStateListener>()
|
val callback = getTelephonyCallbackForType<ServiceStateListener>()
|
||||||
val serviceState = ServiceState()
|
callback.onServiceStateChanged(ServiceState().also { it.isEmergencyOnly = true })
|
||||||
serviceState.isEmergencyOnly = true
|
|
||||||
callback.onServiceStateChanged(serviceState)
|
|
||||||
assertThat(latest).isTrue()
|
assertThat(latest).isTrue()
|
||||||
|
|
||||||
serviceState.isEmergencyOnly = false
|
callback.onServiceStateChanged(ServiceState().also { it.isEmergencyOnly = false })
|
||||||
callback.onServiceStateChanged(serviceState)
|
|
||||||
|
|
||||||
assertThat(latest).isFalse()
|
assertThat(latest).isFalse()
|
||||||
|
|
||||||
@@ -174,7 +166,7 @@ class MobileConnectionRepositoryTest : SysuiTestCase() {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun cdmaLevelUpdates() =
|
fun cdmaLevelUpdates() =
|
||||||
runBlocking(IMMEDIATE) {
|
testScope.runTest {
|
||||||
var latest: Int? = null
|
var latest: Int? = null
|
||||||
val job = underTest.cdmaLevel.onEach { latest = it }.launchIn(this)
|
val job = underTest.cdmaLevel.onEach { latest = it }.launchIn(this)
|
||||||
|
|
||||||
@@ -194,7 +186,7 @@ class MobileConnectionRepositoryTest : SysuiTestCase() {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun gsmLevelUpdates() =
|
fun gsmLevelUpdates() =
|
||||||
runBlocking(IMMEDIATE) {
|
testScope.runTest {
|
||||||
var latest: Int? = null
|
var latest: Int? = null
|
||||||
val job = underTest.primaryLevel.onEach { latest = it }.launchIn(this)
|
val job = underTest.primaryLevel.onEach { latest = it }.launchIn(this)
|
||||||
|
|
||||||
@@ -214,7 +206,7 @@ class MobileConnectionRepositoryTest : SysuiTestCase() {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun isGsm() =
|
fun isGsm() =
|
||||||
runBlocking(IMMEDIATE) {
|
testScope.runTest {
|
||||||
var latest: Boolean? = null
|
var latest: Boolean? = null
|
||||||
val job = underTest.isGsm.onEach { latest = it }.launchIn(this)
|
val job = underTest.isGsm.onEach { latest = it }.launchIn(this)
|
||||||
|
|
||||||
@@ -234,7 +226,7 @@ class MobileConnectionRepositoryTest : SysuiTestCase() {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun dataConnectionState_connected() =
|
fun dataConnectionState_connected() =
|
||||||
runBlocking(IMMEDIATE) {
|
testScope.runTest {
|
||||||
var latest: DataConnectionState? = null
|
var latest: DataConnectionState? = null
|
||||||
val job = underTest.dataConnectionState.onEach { latest = it }.launchIn(this)
|
val job = underTest.dataConnectionState.onEach { latest = it }.launchIn(this)
|
||||||
|
|
||||||
@@ -249,7 +241,7 @@ class MobileConnectionRepositoryTest : SysuiTestCase() {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun dataConnectionState_connecting() =
|
fun dataConnectionState_connecting() =
|
||||||
runBlocking(IMMEDIATE) {
|
testScope.runTest {
|
||||||
var latest: DataConnectionState? = null
|
var latest: DataConnectionState? = null
|
||||||
val job = underTest.dataConnectionState.onEach { latest = it }.launchIn(this)
|
val job = underTest.dataConnectionState.onEach { latest = it }.launchIn(this)
|
||||||
|
|
||||||
@@ -264,7 +256,7 @@ class MobileConnectionRepositoryTest : SysuiTestCase() {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun dataConnectionState_disconnected() =
|
fun dataConnectionState_disconnected() =
|
||||||
runBlocking(IMMEDIATE) {
|
testScope.runTest {
|
||||||
var latest: DataConnectionState? = null
|
var latest: DataConnectionState? = null
|
||||||
val job = underTest.dataConnectionState.onEach { latest = it }.launchIn(this)
|
val job = underTest.dataConnectionState.onEach { latest = it }.launchIn(this)
|
||||||
|
|
||||||
@@ -279,7 +271,7 @@ class MobileConnectionRepositoryTest : SysuiTestCase() {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun dataConnectionState_disconnecting() =
|
fun dataConnectionState_disconnecting() =
|
||||||
runBlocking(IMMEDIATE) {
|
testScope.runTest {
|
||||||
var latest: DataConnectionState? = null
|
var latest: DataConnectionState? = null
|
||||||
val job = underTest.dataConnectionState.onEach { latest = it }.launchIn(this)
|
val job = underTest.dataConnectionState.onEach { latest = it }.launchIn(this)
|
||||||
|
|
||||||
@@ -294,7 +286,7 @@ class MobileConnectionRepositoryTest : SysuiTestCase() {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun dataConnectionState_suspended() =
|
fun dataConnectionState_suspended() =
|
||||||
runBlocking(IMMEDIATE) {
|
testScope.runTest {
|
||||||
var latest: DataConnectionState? = null
|
var latest: DataConnectionState? = null
|
||||||
val job = underTest.dataConnectionState.onEach { latest = it }.launchIn(this)
|
val job = underTest.dataConnectionState.onEach { latest = it }.launchIn(this)
|
||||||
|
|
||||||
@@ -309,7 +301,7 @@ class MobileConnectionRepositoryTest : SysuiTestCase() {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun dataConnectionState_handoverInProgress() =
|
fun dataConnectionState_handoverInProgress() =
|
||||||
runBlocking(IMMEDIATE) {
|
testScope.runTest {
|
||||||
var latest: DataConnectionState? = null
|
var latest: DataConnectionState? = null
|
||||||
val job = underTest.dataConnectionState.onEach { latest = it }.launchIn(this)
|
val job = underTest.dataConnectionState.onEach { latest = it }.launchIn(this)
|
||||||
|
|
||||||
@@ -324,7 +316,7 @@ class MobileConnectionRepositoryTest : SysuiTestCase() {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun dataConnectionState_unknown() =
|
fun dataConnectionState_unknown() =
|
||||||
runBlocking(IMMEDIATE) {
|
testScope.runTest {
|
||||||
var latest: DataConnectionState? = null
|
var latest: DataConnectionState? = null
|
||||||
val job = underTest.dataConnectionState.onEach { latest = it }.launchIn(this)
|
val job = underTest.dataConnectionState.onEach { latest = it }.launchIn(this)
|
||||||
|
|
||||||
@@ -339,7 +331,7 @@ class MobileConnectionRepositoryTest : SysuiTestCase() {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun dataConnectionState_invalid() =
|
fun dataConnectionState_invalid() =
|
||||||
runBlocking(IMMEDIATE) {
|
testScope.runTest {
|
||||||
var latest: DataConnectionState? = null
|
var latest: DataConnectionState? = null
|
||||||
val job = underTest.dataConnectionState.onEach { latest = it }.launchIn(this)
|
val job = underTest.dataConnectionState.onEach { latest = it }.launchIn(this)
|
||||||
|
|
||||||
@@ -354,7 +346,7 @@ class MobileConnectionRepositoryTest : SysuiTestCase() {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun dataActivity() =
|
fun dataActivity() =
|
||||||
runBlocking(IMMEDIATE) {
|
testScope.runTest {
|
||||||
var latest: DataActivityModel? = null
|
var latest: DataActivityModel? = null
|
||||||
val job = underTest.dataActivityDirection.onEach { latest = it }.launchIn(this)
|
val job = underTest.dataActivityDirection.onEach { latest = it }.launchIn(this)
|
||||||
|
|
||||||
@@ -368,7 +360,7 @@ class MobileConnectionRepositoryTest : SysuiTestCase() {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun carrierNetworkChange() =
|
fun carrierNetworkChange() =
|
||||||
runBlocking(IMMEDIATE) {
|
testScope.runTest {
|
||||||
var latest: Boolean? = null
|
var latest: Boolean? = null
|
||||||
val job = underTest.carrierNetworkChangeActive.onEach { latest = it }.launchIn(this)
|
val job = underTest.carrierNetworkChangeActive.onEach { latest = it }.launchIn(this)
|
||||||
|
|
||||||
@@ -382,7 +374,7 @@ class MobileConnectionRepositoryTest : SysuiTestCase() {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun networkType_default() =
|
fun networkType_default() =
|
||||||
runBlocking(IMMEDIATE) {
|
testScope.runTest {
|
||||||
var latest: ResolvedNetworkType? = null
|
var latest: ResolvedNetworkType? = null
|
||||||
val job = underTest.resolvedNetworkType.onEach { latest = it }.launchIn(this)
|
val job = underTest.resolvedNetworkType.onEach { latest = it }.launchIn(this)
|
||||||
|
|
||||||
@@ -395,7 +387,7 @@ class MobileConnectionRepositoryTest : SysuiTestCase() {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun networkType_unknown_hasCorrectKey() =
|
fun networkType_unknown_hasCorrectKey() =
|
||||||
runBlocking(IMMEDIATE) {
|
testScope.runTest {
|
||||||
var latest: ResolvedNetworkType? = null
|
var latest: ResolvedNetworkType? = null
|
||||||
val job = underTest.resolvedNetworkType.onEach { latest = it }.launchIn(this)
|
val job = underTest.resolvedNetworkType.onEach { latest = it }.launchIn(this)
|
||||||
|
|
||||||
@@ -413,14 +405,19 @@ class MobileConnectionRepositoryTest : SysuiTestCase() {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun networkType_updatesUsingDefault() =
|
fun networkType_updatesUsingDefault() =
|
||||||
runBlocking(IMMEDIATE) {
|
testScope.runTest {
|
||||||
var latest: ResolvedNetworkType? = null
|
var latest: ResolvedNetworkType? = null
|
||||||
val job = underTest.resolvedNetworkType.onEach { latest = it }.launchIn(this)
|
val job = underTest.resolvedNetworkType.onEach { latest = it }.launchIn(this)
|
||||||
|
|
||||||
val callback = getTelephonyCallbackForType<TelephonyCallback.DisplayInfoListener>()
|
val callback = getTelephonyCallbackForType<TelephonyCallback.DisplayInfoListener>()
|
||||||
|
val overrideType = OVERRIDE_NETWORK_TYPE_NONE
|
||||||
val type = NETWORK_TYPE_LTE
|
val type = NETWORK_TYPE_LTE
|
||||||
val expected = DefaultNetworkType(mobileMappings.toIconKey(type))
|
val expected = DefaultNetworkType(mobileMappings.toIconKey(type))
|
||||||
val ti = mock<TelephonyDisplayInfo>().also { whenever(it.networkType).thenReturn(type) }
|
val ti =
|
||||||
|
mock<TelephonyDisplayInfo>().also {
|
||||||
|
whenever(it.overrideNetworkType).thenReturn(overrideType)
|
||||||
|
whenever(it.networkType).thenReturn(type)
|
||||||
|
}
|
||||||
callback.onDisplayInfoChanged(ti)
|
callback.onDisplayInfoChanged(ti)
|
||||||
|
|
||||||
assertThat(latest).isEqualTo(expected)
|
assertThat(latest).isEqualTo(expected)
|
||||||
@@ -430,7 +427,7 @@ class MobileConnectionRepositoryTest : SysuiTestCase() {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun networkType_updatesUsingOverride() =
|
fun networkType_updatesUsingOverride() =
|
||||||
runBlocking(IMMEDIATE) {
|
testScope.runTest {
|
||||||
var latest: ResolvedNetworkType? = null
|
var latest: ResolvedNetworkType? = null
|
||||||
val job = underTest.resolvedNetworkType.onEach { latest = it }.launchIn(this)
|
val job = underTest.resolvedNetworkType.onEach { latest = it }.launchIn(this)
|
||||||
|
|
||||||
@@ -449,17 +446,39 @@ class MobileConnectionRepositoryTest : SysuiTestCase() {
|
|||||||
job.cancel()
|
job.cancel()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun networkType_unknownNetworkWithOverride_usesOverrideKey() =
|
||||||
|
testScope.runTest {
|
||||||
|
var latest: ResolvedNetworkType? = null
|
||||||
|
val job = underTest.resolvedNetworkType.onEach { latest = it }.launchIn(this)
|
||||||
|
|
||||||
|
val callback = getTelephonyCallbackForType<TelephonyCallback.DisplayInfoListener>()
|
||||||
|
val unknown = NETWORK_TYPE_UNKNOWN
|
||||||
|
val type = OVERRIDE_NETWORK_TYPE_LTE_CA
|
||||||
|
val expected = OverrideNetworkType(mobileMappings.toIconKeyOverride(type))
|
||||||
|
val ti =
|
||||||
|
mock<TelephonyDisplayInfo>().also {
|
||||||
|
whenever(it.networkType).thenReturn(unknown)
|
||||||
|
whenever(it.overrideNetworkType).thenReturn(type)
|
||||||
|
}
|
||||||
|
callback.onDisplayInfoChanged(ti)
|
||||||
|
|
||||||
|
assertThat(latest).isEqualTo(expected)
|
||||||
|
|
||||||
|
job.cancel()
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun dataEnabled_initial_false() =
|
fun dataEnabled_initial_false() =
|
||||||
runBlocking(IMMEDIATE) {
|
testScope.runTest {
|
||||||
whenever(telephonyManager.isDataConnectionAllowed).thenReturn(false)
|
whenever(telephonyManager.isDataConnectionAllowed).thenReturn(false)
|
||||||
|
|
||||||
assertThat(underTest.dataEnabled.value).isFalse()
|
assertThat(underTest.dataEnabled.value).isFalse()
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `is data enabled - tracks telephony callback`() =
|
fun isDataEnabled_tracksTelephonyCallback() =
|
||||||
runBlocking(IMMEDIATE) {
|
testScope.runTest {
|
||||||
var latest: Boolean? = null
|
var latest: Boolean? = null
|
||||||
val job = underTest.dataEnabled.onEach { latest = it }.launchIn(this)
|
val job = underTest.dataEnabled.onEach { latest = it }.launchIn(this)
|
||||||
|
|
||||||
@@ -479,7 +498,7 @@ class MobileConnectionRepositoryTest : SysuiTestCase() {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun numberOfLevels_isDefault() =
|
fun numberOfLevels_isDefault() =
|
||||||
runBlocking(IMMEDIATE) {
|
testScope.runTest {
|
||||||
var latest: Int? = null
|
var latest: Int? = null
|
||||||
val job = underTest.numberOfLevels.onEach { latest = it }.launchIn(this)
|
val job = underTest.numberOfLevels.onEach { latest = it }.launchIn(this)
|
||||||
|
|
||||||
@@ -489,51 +508,68 @@ class MobileConnectionRepositoryTest : SysuiTestCase() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `roaming - cdma - queries telephony manager`() =
|
fun roaming_cdma_queriesTelephonyManager() =
|
||||||
runBlocking(IMMEDIATE) {
|
testScope.runTest {
|
||||||
var latest: Boolean? = null
|
var latest: Boolean? = null
|
||||||
val job = underTest.cdmaRoaming.onEach { latest = it }.launchIn(this)
|
val job = underTest.cdmaRoaming.onEach { latest = it }.launchIn(this)
|
||||||
|
|
||||||
val cb = getTelephonyCallbackForType<ServiceStateListener>()
|
val cb = getTelephonyCallbackForType<ServiceStateListener>()
|
||||||
|
|
||||||
val serviceState = ServiceState()
|
// CDMA roaming is off, GSM roaming is on
|
||||||
serviceState.roaming = false
|
|
||||||
|
|
||||||
// CDMA roaming is off, GSM roaming is off
|
|
||||||
whenever(telephonyManager.cdmaEnhancedRoamingIndicatorDisplayNumber).thenReturn(ERI_OFF)
|
whenever(telephonyManager.cdmaEnhancedRoamingIndicatorDisplayNumber).thenReturn(ERI_OFF)
|
||||||
cb.onServiceStateChanged(serviceState)
|
cb.onServiceStateChanged(ServiceState().also { it.roaming = true })
|
||||||
|
|
||||||
assertThat(latest).isFalse()
|
assertThat(latest).isFalse()
|
||||||
|
|
||||||
// CDMA roaming is off, GSM roaming is on
|
// CDMA roaming is on, GSM roaming is off
|
||||||
whenever(telephonyManager.cdmaEnhancedRoamingIndicatorDisplayNumber).thenReturn(ERI_ON)
|
whenever(telephonyManager.cdmaEnhancedRoamingIndicatorDisplayNumber).thenReturn(ERI_ON)
|
||||||
cb.onServiceStateChanged(serviceState)
|
cb.onServiceStateChanged(ServiceState().also { it.roaming = false })
|
||||||
|
|
||||||
assertThat(latest).isTrue()
|
assertThat(latest).isTrue()
|
||||||
|
|
||||||
job.cancel()
|
job.cancel()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* [TelephonyManager.getCdmaEnhancedRoamingIndicatorDisplayNumber] returns -1 if the service is
|
||||||
|
* not running or if there is an error while retrieving the cdma ERI
|
||||||
|
*/
|
||||||
@Test
|
@Test
|
||||||
fun `roaming - gsm - queries service state`() =
|
fun cdmaRoaming_ignoresNegativeOne() =
|
||||||
runBlocking(IMMEDIATE) {
|
testScope.runTest {
|
||||||
var latest: Boolean? = null
|
var latest: Boolean? = null
|
||||||
val job = underTest.isRoaming.onEach { latest = it }.launchIn(this)
|
val job = underTest.cdmaRoaming.onEach { latest = it }.launchIn(this)
|
||||||
|
|
||||||
val serviceState = ServiceState()
|
val serviceState = ServiceState()
|
||||||
serviceState.roaming = false
|
serviceState.roaming = false
|
||||||
|
|
||||||
val cb = getTelephonyCallbackForType<ServiceStateListener>()
|
val cb = getTelephonyCallbackForType<ServiceStateListener>()
|
||||||
|
|
||||||
// CDMA roaming is off, GSM roaming is off
|
// CDMA roaming is unavailable (-1), GSM roaming is off
|
||||||
whenever(telephonyManager.cdmaEnhancedRoamingIndicatorDisplayNumber).thenReturn(ERI_OFF)
|
whenever(telephonyManager.cdmaEnhancedRoamingIndicatorDisplayNumber).thenReturn(-1)
|
||||||
cb.onServiceStateChanged(serviceState)
|
cb.onServiceStateChanged(serviceState)
|
||||||
|
|
||||||
assertThat(latest).isFalse()
|
assertThat(latest).isFalse()
|
||||||
|
|
||||||
|
job.cancel()
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun roaming_gsm_queriesServiceState() =
|
||||||
|
testScope.runTest {
|
||||||
|
var latest: Boolean? = null
|
||||||
|
val job = underTest.isRoaming.onEach { latest = it }.launchIn(this)
|
||||||
|
|
||||||
|
val cb = getTelephonyCallbackForType<ServiceStateListener>()
|
||||||
|
|
||||||
|
// CDMA roaming is off, GSM roaming is off
|
||||||
|
whenever(telephonyManager.cdmaEnhancedRoamingIndicatorDisplayNumber).thenReturn(ERI_OFF)
|
||||||
|
cb.onServiceStateChanged(ServiceState().also { it.roaming = false })
|
||||||
|
|
||||||
|
assertThat(latest).isFalse()
|
||||||
|
|
||||||
// CDMA roaming is off, GSM roaming is on
|
// CDMA roaming is off, GSM roaming is on
|
||||||
serviceState.roaming = true
|
cb.onServiceStateChanged(ServiceState().also { it.roaming = true })
|
||||||
cb.onServiceStateChanged(serviceState)
|
|
||||||
|
|
||||||
assertThat(latest).isTrue()
|
assertThat(latest).isTrue()
|
||||||
|
|
||||||
@@ -541,8 +577,8 @@ class MobileConnectionRepositoryTest : SysuiTestCase() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `activity - updates from callback`() =
|
fun activity_updatesFromCallback() =
|
||||||
runBlocking(IMMEDIATE) {
|
testScope.runTest {
|
||||||
var latest: DataActivityModel? = null
|
var latest: DataActivityModel? = null
|
||||||
val job = underTest.dataActivityDirection.onEach { latest = it }.launchIn(this)
|
val job = underTest.dataActivityDirection.onEach { latest = it }.launchIn(this)
|
||||||
|
|
||||||
@@ -578,8 +614,8 @@ class MobileConnectionRepositoryTest : SysuiTestCase() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `network name - default`() =
|
fun networkName_default() =
|
||||||
runBlocking(IMMEDIATE) {
|
testScope.runTest {
|
||||||
var latest: NetworkNameModel? = null
|
var latest: NetworkNameModel? = null
|
||||||
val job = underTest.networkName.onEach { latest = it }.launchIn(this)
|
val job = underTest.networkName.onEach { latest = it }.launchIn(this)
|
||||||
|
|
||||||
@@ -589,8 +625,8 @@ class MobileConnectionRepositoryTest : SysuiTestCase() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `network name - uses broadcast info - returns derived`() =
|
fun networkName_usesBroadcastInfo_returnsDerived() =
|
||||||
runBlocking(IMMEDIATE) {
|
testScope.runTest {
|
||||||
var latest: NetworkNameModel? = null
|
var latest: NetworkNameModel? = null
|
||||||
val job = underTest.networkName.onEach { latest = it }.launchIn(this)
|
val job = underTest.networkName.onEach { latest = it }.launchIn(this)
|
||||||
|
|
||||||
@@ -606,8 +642,8 @@ class MobileConnectionRepositoryTest : SysuiTestCase() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `network name - broadcast not for this sub id - keeps old value`() =
|
fun networkName_broadcastNotForThisSubId_keepsOldValue() =
|
||||||
runBlocking(IMMEDIATE) {
|
testScope.runTest {
|
||||||
var latest: NetworkNameModel? = null
|
var latest: NetworkNameModel? = null
|
||||||
val job = underTest.networkName.onEach { latest = it }.launchIn(this)
|
val job = underTest.networkName.onEach { latest = it }.launchIn(this)
|
||||||
|
|
||||||
@@ -631,8 +667,8 @@ class MobileConnectionRepositoryTest : SysuiTestCase() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `network name - broadcast has no data - updates to default`() =
|
fun networkName_broadcastHasNoData_updatesToDefault() =
|
||||||
runBlocking(IMMEDIATE) {
|
testScope.runTest {
|
||||||
var latest: NetworkNameModel? = null
|
var latest: NetworkNameModel? = null
|
||||||
val job = underTest.networkName.onEach { latest = it }.launchIn(this)
|
val job = underTest.networkName.onEach { latest = it }.launchIn(this)
|
||||||
|
|
||||||
@@ -658,8 +694,8 @@ class MobileConnectionRepositoryTest : SysuiTestCase() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `operatorAlphaShort - tracked`() =
|
fun operatorAlphaShort_tracked() =
|
||||||
runBlocking(IMMEDIATE) {
|
testScope.runTest {
|
||||||
var latest: String? = null
|
var latest: String? = null
|
||||||
|
|
||||||
val job = underTest.operatorAlphaShort.onEach { latest = it }.launchIn(this)
|
val job = underTest.operatorAlphaShort.onEach { latest = it }.launchIn(this)
|
||||||
@@ -680,33 +716,45 @@ class MobileConnectionRepositoryTest : SysuiTestCase() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `connection model - isInService - not iwlan`() =
|
fun isInService_notIwlan() =
|
||||||
runBlocking(IMMEDIATE) {
|
testScope.runTest {
|
||||||
var latest: Boolean? = null
|
var latest: Boolean? = null
|
||||||
val job = underTest.isInService.onEach { latest = it }.launchIn(this)
|
val job = underTest.isInService.onEach { latest = it }.launchIn(this)
|
||||||
|
|
||||||
val serviceState = ServiceState()
|
getTelephonyCallbackForType<ServiceStateListener>()
|
||||||
serviceState.voiceRegState = STATE_IN_SERVICE
|
.onServiceStateChanged(
|
||||||
serviceState.dataRegState = STATE_IN_SERVICE
|
ServiceState().also {
|
||||||
|
it.voiceRegState = STATE_IN_SERVICE
|
||||||
getTelephonyCallbackForType<ServiceStateListener>().onServiceStateChanged(serviceState)
|
it.dataRegState = STATE_IN_SERVICE
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
assertThat(latest).isTrue()
|
assertThat(latest).isTrue()
|
||||||
|
|
||||||
serviceState.voiceRegState = STATE_OUT_OF_SERVICE
|
getTelephonyCallbackForType<ServiceStateListener>()
|
||||||
getTelephonyCallbackForType<ServiceStateListener>().onServiceStateChanged(serviceState)
|
.onServiceStateChanged(
|
||||||
|
ServiceState().also {
|
||||||
|
it.dataRegState = STATE_IN_SERVICE
|
||||||
|
it.voiceRegState = STATE_OUT_OF_SERVICE
|
||||||
|
}
|
||||||
|
)
|
||||||
assertThat(latest).isTrue()
|
assertThat(latest).isTrue()
|
||||||
|
|
||||||
serviceState.dataRegState = STATE_OUT_OF_SERVICE
|
getTelephonyCallbackForType<ServiceStateListener>()
|
||||||
getTelephonyCallbackForType<ServiceStateListener>().onServiceStateChanged(serviceState)
|
.onServiceStateChanged(
|
||||||
|
ServiceState().also {
|
||||||
|
it.voiceRegState = STATE_OUT_OF_SERVICE
|
||||||
|
it.dataRegState = STATE_OUT_OF_SERVICE
|
||||||
|
}
|
||||||
|
)
|
||||||
assertThat(latest).isFalse()
|
assertThat(latest).isFalse()
|
||||||
|
|
||||||
job.cancel()
|
job.cancel()
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `connection model - isInService - is iwlan - voice out of service - data in service`() =
|
fun isInService_isIwlan_voiceOutOfService_dataInService() =
|
||||||
runBlocking(IMMEDIATE) {
|
testScope.runTest {
|
||||||
var latest: Boolean? = null
|
var latest: Boolean? = null
|
||||||
val job = underTest.isInService.onEach { latest = it }.launchIn(this)
|
val job = underTest.isInService.onEach { latest = it }.launchIn(this)
|
||||||
|
|
||||||
@@ -730,8 +778,8 @@ class MobileConnectionRepositoryTest : SysuiTestCase() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `number of levels - uses carrier config`() =
|
fun numberOfLevels_usesCarrierConfig() =
|
||||||
runBlocking(IMMEDIATE) {
|
testScope.runTest {
|
||||||
var latest: Int? = null
|
var latest: Int? = null
|
||||||
val job = underTest.numberOfLevels.onEach { latest = it }.launchIn(this)
|
val job = underTest.numberOfLevels.onEach { latest = it }.launchIn(this)
|
||||||
|
|
||||||
@@ -756,19 +804,6 @@ class MobileConnectionRepositoryTest : SysuiTestCase() {
|
|||||||
return MobileTelephonyHelpers.getTelephonyCallbackForType(telephonyManager)
|
return MobileTelephonyHelpers.getTelephonyCallbackForType(telephonyManager)
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Convenience constructor for SignalStrength */
|
|
||||||
private fun signalStrength(gsmLevel: Int, cdmaLevel: Int, isGsm: Boolean): SignalStrength {
|
|
||||||
val signalStrength = mock<SignalStrength>()
|
|
||||||
whenever(signalStrength.isGsm).thenReturn(isGsm)
|
|
||||||
whenever(signalStrength.level).thenReturn(gsmLevel)
|
|
||||||
val cdmaStrength =
|
|
||||||
mock<CellSignalStrengthCdma>().also { whenever(it.level).thenReturn(cdmaLevel) }
|
|
||||||
whenever(signalStrength.getCellSignalStrengths(CellSignalStrengthCdma::class.java))
|
|
||||||
.thenReturn(listOf(cdmaStrength))
|
|
||||||
|
|
||||||
return signalStrength
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun spnIntent(
|
private fun spnIntent(
|
||||||
subId: Int = SUB_1_ID,
|
subId: Int = SUB_1_ID,
|
||||||
showSpn: Boolean = true,
|
showSpn: Boolean = true,
|
||||||
@@ -785,7 +820,6 @@ class MobileConnectionRepositoryTest : SysuiTestCase() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
private val IMMEDIATE = Dispatchers.Main.immediate
|
|
||||||
private const val SUB_1_ID = 1
|
private const val SUB_1_ID = 1
|
||||||
|
|
||||||
private val DEFAULT_NAME = NetworkNameModel.Default("default name")
|
private val DEFAULT_NAME = NetworkNameModel.Default("default name")
|
||||||
|
|||||||
@@ -0,0 +1,341 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2023 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.repository.prod
|
||||||
|
|
||||||
|
import android.telephony.ServiceState
|
||||||
|
import android.telephony.TelephonyCallback
|
||||||
|
import android.telephony.TelephonyCallback.CarrierNetworkListener
|
||||||
|
import android.telephony.TelephonyCallback.DataActivityListener
|
||||||
|
import android.telephony.TelephonyCallback.DataConnectionStateListener
|
||||||
|
import android.telephony.TelephonyCallback.DataEnabledListener
|
||||||
|
import android.telephony.TelephonyCallback.DisplayInfoListener
|
||||||
|
import android.telephony.TelephonyCallback.ServiceStateListener
|
||||||
|
import android.telephony.TelephonyDisplayInfo
|
||||||
|
import android.telephony.TelephonyManager
|
||||||
|
import android.telephony.TelephonyManager.DATA_ACTIVITY_INOUT
|
||||||
|
import android.telephony.TelephonyManager.NETWORK_TYPE_LTE
|
||||||
|
import android.telephony.TelephonyManager.NETWORK_TYPE_UNKNOWN
|
||||||
|
import androidx.test.filters.SmallTest
|
||||||
|
import com.android.systemui.SysuiTestCase
|
||||||
|
import com.android.systemui.log.table.TableLogBuffer
|
||||||
|
import com.android.systemui.statusbar.pipeline.mobile.data.MobileInputLogger
|
||||||
|
import com.android.systemui.statusbar.pipeline.mobile.data.model.DataConnectionState
|
||||||
|
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.SystemUiCarrierConfig
|
||||||
|
import com.android.systemui.statusbar.pipeline.mobile.data.model.SystemUiCarrierConfigTest
|
||||||
|
import com.android.systemui.statusbar.pipeline.mobile.data.repository.FakeMobileConnectionsRepository
|
||||||
|
import com.android.systemui.statusbar.pipeline.mobile.data.repository.prod.MobileTelephonyHelpers.getTelephonyCallbackForType
|
||||||
|
import com.android.systemui.statusbar.pipeline.mobile.data.repository.prod.MobileTelephonyHelpers.signalStrength
|
||||||
|
import com.android.systemui.statusbar.pipeline.mobile.util.FakeMobileMappingsProxy
|
||||||
|
import com.android.systemui.statusbar.pipeline.shared.data.model.DataActivityModel
|
||||||
|
import com.android.systemui.util.mockito.mock
|
||||||
|
import com.android.systemui.util.mockito.whenever
|
||||||
|
import com.google.common.truth.Truth.assertThat
|
||||||
|
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
||||||
|
import kotlinx.coroutines.flow.launchIn
|
||||||
|
import kotlinx.coroutines.flow.onEach
|
||||||
|
import kotlinx.coroutines.test.TestScope
|
||||||
|
import kotlinx.coroutines.test.UnconfinedTestDispatcher
|
||||||
|
import kotlinx.coroutines.test.runTest
|
||||||
|
import org.junit.Before
|
||||||
|
import org.junit.Test
|
||||||
|
import org.mockito.Mock
|
||||||
|
import org.mockito.MockitoAnnotations
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test class to stress test the TelephonyCallbacks that we listen to. In particular, the callbacks
|
||||||
|
* all come back in on a single listener (for reasons defined in the system). This test is built to
|
||||||
|
* ensure that we don't miss any important callbacks.
|
||||||
|
*
|
||||||
|
* Kind of like an interaction test case build just for [TelephonyCallback]
|
||||||
|
*
|
||||||
|
* The list of telephony callbacks we use is: [TelephonyCallback.CarrierNetworkListener]
|
||||||
|
* [TelephonyCallback.DataActivityListener] [TelephonyCallback.DataConnectionStateListener]
|
||||||
|
* [TelephonyCallback.DataEnabledListener] [TelephonyCallback.DisplayInfoListener]
|
||||||
|
* [TelephonyCallback.ServiceStateListener] [TelephonyCallback.SignalStrengthsListener]
|
||||||
|
*
|
||||||
|
* Because each of these callbacks comes in on the same callbackFlow, collecting on a field backed
|
||||||
|
* by only a single callback can immediately create backpressure on the other fields related to a
|
||||||
|
* mobile connection.
|
||||||
|
*
|
||||||
|
* This test should be designed to test _at least_ each individual callback in a smoke-test fashion.
|
||||||
|
* The way we will achieve this is as follows:
|
||||||
|
* 1. Start up a listener (A) collecting on a field which is _not under test_
|
||||||
|
* 2. Send a single event to a telephony callback which supports the field under test (B)
|
||||||
|
* 3. Send many (may be as few as 2) events to the callback backing A to ensure we start seeing
|
||||||
|
* backpressure on other fields NOTE: poor handling of backpressure here would normally cause B
|
||||||
|
* to get dropped
|
||||||
|
* 4. Start up a new collector for B
|
||||||
|
* 5. Assert that B has the state sent in step #2
|
||||||
|
*/
|
||||||
|
@Suppress("EXPERIMENTAL_IS_NOT_ENABLED")
|
||||||
|
@OptIn(ExperimentalCoroutinesApi::class)
|
||||||
|
@SmallTest
|
||||||
|
class MobileConnectionTelephonySmokeTests : SysuiTestCase() {
|
||||||
|
private lateinit var underTest: MobileConnectionRepositoryImpl
|
||||||
|
private lateinit var connectionsRepo: FakeMobileConnectionsRepository
|
||||||
|
|
||||||
|
@Mock private lateinit var telephonyManager: TelephonyManager
|
||||||
|
@Mock private lateinit var logger: MobileInputLogger
|
||||||
|
@Mock private lateinit var tableLogger: TableLogBuffer
|
||||||
|
|
||||||
|
private val mobileMappings = FakeMobileMappingsProxy()
|
||||||
|
private val systemUiCarrierConfig =
|
||||||
|
SystemUiCarrierConfig(
|
||||||
|
SUB_1_ID,
|
||||||
|
SystemUiCarrierConfigTest.createTestConfig(),
|
||||||
|
)
|
||||||
|
|
||||||
|
private val testDispatcher = UnconfinedTestDispatcher()
|
||||||
|
private val testScope = TestScope(testDispatcher)
|
||||||
|
|
||||||
|
@Before
|
||||||
|
fun setUp() {
|
||||||
|
MockitoAnnotations.initMocks(this)
|
||||||
|
whenever(telephonyManager.subscriptionId).thenReturn(SUB_1_ID)
|
||||||
|
|
||||||
|
connectionsRepo = FakeMobileConnectionsRepository(mobileMappings, tableLogger)
|
||||||
|
|
||||||
|
underTest =
|
||||||
|
MobileConnectionRepositoryImpl(
|
||||||
|
context,
|
||||||
|
SUB_1_ID,
|
||||||
|
DEFAULT_NAME,
|
||||||
|
SEP,
|
||||||
|
telephonyManager,
|
||||||
|
systemUiCarrierConfig,
|
||||||
|
fakeBroadcastDispatcher,
|
||||||
|
mobileMappings,
|
||||||
|
testDispatcher,
|
||||||
|
logger,
|
||||||
|
tableLogger,
|
||||||
|
testScope.backgroundScope,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun carrierNetworkChangeListener_noisyActivity() =
|
||||||
|
testScope.runTest {
|
||||||
|
var latest: Boolean? = null
|
||||||
|
|
||||||
|
// Start collecting data activity; don't care about the result
|
||||||
|
val activityJob = underTest.dataActivityDirection.launchIn(this)
|
||||||
|
val activityCallback = getTelephonyCallbackForType<DataActivityListener>()
|
||||||
|
|
||||||
|
val callback = getTelephonyCallbackForType<CarrierNetworkListener>()
|
||||||
|
callback.onCarrierNetworkChange(true)
|
||||||
|
|
||||||
|
flipActivity(100, activityCallback)
|
||||||
|
|
||||||
|
val job = underTest.carrierNetworkChangeActive.onEach { latest = it }.launchIn(this)
|
||||||
|
|
||||||
|
assertThat(latest).isTrue()
|
||||||
|
|
||||||
|
activityJob.cancel()
|
||||||
|
job.cancel()
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun dataActivityLate_noisyDisplayInfo() =
|
||||||
|
testScope.runTest {
|
||||||
|
var latest: DataActivityModel? = null
|
||||||
|
|
||||||
|
// start collecting displayInfo; don't care about the result
|
||||||
|
val displayInfoJob = underTest.resolvedNetworkType.launchIn(this)
|
||||||
|
|
||||||
|
val activityCallback = getTelephonyCallbackForType<DataActivityListener>()
|
||||||
|
activityCallback.onDataActivity(DATA_ACTIVITY_INOUT)
|
||||||
|
|
||||||
|
val displayInfoCallback = getTelephonyCallbackForType<DisplayInfoListener>()
|
||||||
|
val type1 = NETWORK_TYPE_UNKNOWN
|
||||||
|
val type2 = NETWORK_TYPE_LTE
|
||||||
|
val t1 =
|
||||||
|
mock<TelephonyDisplayInfo>().also { whenever(it.networkType).thenReturn(type1) }
|
||||||
|
val t2 =
|
||||||
|
mock<TelephonyDisplayInfo>().also { whenever(it.networkType).thenReturn(type2) }
|
||||||
|
|
||||||
|
flipDisplayInfo(100, listOf(t1, t2), displayInfoCallback)
|
||||||
|
|
||||||
|
val job = underTest.dataActivityDirection.onEach { latest = it }.launchIn(this)
|
||||||
|
|
||||||
|
assertThat(latest)
|
||||||
|
.isEqualTo(
|
||||||
|
DataActivityModel(
|
||||||
|
hasActivityIn = true,
|
||||||
|
hasActivityOut = true,
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
displayInfoJob.cancel()
|
||||||
|
job.cancel()
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun dataConnectionStateListener_noisyActivity() =
|
||||||
|
testScope.runTest {
|
||||||
|
var latest: DataConnectionState? = null
|
||||||
|
|
||||||
|
// Start collecting data activity; don't care about the result
|
||||||
|
val activityJob = underTest.dataActivityDirection.launchIn(this)
|
||||||
|
|
||||||
|
val connectionCallback = getTelephonyCallbackForType<DataConnectionStateListener>()
|
||||||
|
val activityCallback = getTelephonyCallbackForType<DataActivityListener>()
|
||||||
|
|
||||||
|
connectionCallback.onDataConnectionStateChanged(
|
||||||
|
TelephonyManager.DATA_CONNECTED,
|
||||||
|
200 /* unused */
|
||||||
|
)
|
||||||
|
|
||||||
|
// Send a bunch of events that we don't care about, to overrun the replay buffer
|
||||||
|
flipActivity(100, activityCallback)
|
||||||
|
|
||||||
|
val connectionJob = underTest.dataConnectionState.onEach { latest = it }.launchIn(this)
|
||||||
|
|
||||||
|
assertThat(latest).isEqualTo(DataConnectionState.Connected)
|
||||||
|
|
||||||
|
activityJob.cancel()
|
||||||
|
connectionJob.cancel()
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun dataEnabledLate_noisyActivity() =
|
||||||
|
testScope.runTest {
|
||||||
|
var latest: Boolean? = null
|
||||||
|
|
||||||
|
// Start collecting data activity; don't care about the result
|
||||||
|
val activityJob = underTest.dataActivityDirection.launchIn(this)
|
||||||
|
|
||||||
|
val enabledCallback = getTelephonyCallbackForType<DataEnabledListener>()
|
||||||
|
val activityCallback = getTelephonyCallbackForType<DataActivityListener>()
|
||||||
|
|
||||||
|
enabledCallback.onDataEnabledChanged(true, 1 /* unused */)
|
||||||
|
|
||||||
|
// Send a bunch of events that we don't care about, to overrun the replay buffer
|
||||||
|
flipActivity(100, activityCallback)
|
||||||
|
|
||||||
|
val job = underTest.dataEnabled.onEach { latest = it }.launchIn(this)
|
||||||
|
|
||||||
|
assertThat(latest).isTrue()
|
||||||
|
|
||||||
|
activityJob.cancel()
|
||||||
|
job.cancel()
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun displayInfoLate_noisyActivity() =
|
||||||
|
testScope.runTest {
|
||||||
|
var latest: ResolvedNetworkType? = null
|
||||||
|
|
||||||
|
// Start collecting data activity; don't care about the result
|
||||||
|
val activityJob = underTest.dataActivityDirection.launchIn(this)
|
||||||
|
|
||||||
|
val displayInfoCallback = getTelephonyCallbackForType<DisplayInfoListener>()
|
||||||
|
val activityCallback = getTelephonyCallbackForType<DataActivityListener>()
|
||||||
|
|
||||||
|
val type = NETWORK_TYPE_LTE
|
||||||
|
val expected = ResolvedNetworkType.DefaultNetworkType(mobileMappings.toIconKey(type))
|
||||||
|
val ti = mock<TelephonyDisplayInfo>().also { whenever(it.networkType).thenReturn(type) }
|
||||||
|
displayInfoCallback.onDisplayInfoChanged(ti)
|
||||||
|
|
||||||
|
// Send a bunch of events that we don't care about, to overrun the replay buffer
|
||||||
|
flipActivity(100, activityCallback)
|
||||||
|
|
||||||
|
val job = underTest.resolvedNetworkType.onEach { latest = it }.launchIn(this)
|
||||||
|
|
||||||
|
assertThat(latest).isEqualTo(expected)
|
||||||
|
|
||||||
|
activityJob.cancel()
|
||||||
|
job.cancel()
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun serviceStateListener_noisyActivity() =
|
||||||
|
testScope.runTest {
|
||||||
|
var latest: Boolean? = null
|
||||||
|
|
||||||
|
// Start collecting data activity; don't care about the result
|
||||||
|
val activityJob = underTest.dataActivityDirection.launchIn(this)
|
||||||
|
|
||||||
|
val serviceStateCallback = getTelephonyCallbackForType<ServiceStateListener>()
|
||||||
|
val activityCallback = getTelephonyCallbackForType<DataActivityListener>()
|
||||||
|
|
||||||
|
// isEmergencyOnly comes in
|
||||||
|
val serviceState = ServiceState()
|
||||||
|
serviceState.isEmergencyOnly = true
|
||||||
|
serviceStateCallback.onServiceStateChanged(serviceState)
|
||||||
|
|
||||||
|
flipActivity(100, activityCallback)
|
||||||
|
|
||||||
|
val job = underTest.isEmergencyOnly.onEach { latest = it }.launchIn(this)
|
||||||
|
|
||||||
|
assertThat(latest).isTrue()
|
||||||
|
|
||||||
|
activityJob.cancel()
|
||||||
|
job.cancel()
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun signalStrengthsListenerLate_noisyActivity() =
|
||||||
|
testScope.runTest {
|
||||||
|
var latest: Int? = null
|
||||||
|
|
||||||
|
// Start collecting data activity; don't care about the result
|
||||||
|
val activityJob = underTest.dataActivityDirection.launchIn(this)
|
||||||
|
val activityCallback = getTelephonyCallbackForType<DataActivityListener>()
|
||||||
|
|
||||||
|
val callback = getTelephonyCallbackForType<TelephonyCallback.SignalStrengthsListener>()
|
||||||
|
val strength = signalStrength(gsmLevel = 1, cdmaLevel = 2, isGsm = true)
|
||||||
|
callback.onSignalStrengthsChanged(strength)
|
||||||
|
|
||||||
|
flipActivity(100, activityCallback)
|
||||||
|
|
||||||
|
val job = underTest.cdmaLevel.onEach { latest = it }.launchIn(this)
|
||||||
|
|
||||||
|
assertThat(latest).isEqualTo(2)
|
||||||
|
|
||||||
|
activityJob.cancel()
|
||||||
|
job.cancel()
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun flipActivity(
|
||||||
|
times: Int,
|
||||||
|
callback: DataActivityListener,
|
||||||
|
) {
|
||||||
|
repeat(times) { index -> callback.onDataActivity(index % 4) }
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun flipDisplayInfo(
|
||||||
|
times: Int,
|
||||||
|
infos: List<TelephonyDisplayInfo>,
|
||||||
|
callback: DisplayInfoListener,
|
||||||
|
) {
|
||||||
|
val len = infos.size
|
||||||
|
repeat(times) { index -> callback.onDisplayInfoChanged(infos[index % len]) }
|
||||||
|
}
|
||||||
|
|
||||||
|
private inline fun <reified T> getTelephonyCallbackForType(): T {
|
||||||
|
return getTelephonyCallbackForType(telephonyManager)
|
||||||
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
private const val SUB_1_ID = 1
|
||||||
|
|
||||||
|
private val DEFAULT_NAME = NetworkNameModel.Default("default name")
|
||||||
|
private const val SEP = "-"
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -16,10 +16,14 @@
|
|||||||
|
|
||||||
package com.android.systemui.statusbar.pipeline.mobile.data.repository.prod
|
package com.android.systemui.statusbar.pipeline.mobile.data.repository.prod
|
||||||
|
|
||||||
|
import android.telephony.CellSignalStrengthCdma
|
||||||
|
import android.telephony.SignalStrength
|
||||||
import android.telephony.TelephonyCallback
|
import android.telephony.TelephonyCallback
|
||||||
import android.telephony.TelephonyManager
|
import android.telephony.TelephonyManager
|
||||||
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.whenever
|
||||||
import com.google.common.truth.Truth.assertThat
|
import com.google.common.truth.Truth.assertThat
|
||||||
import org.mockito.Mockito.verify
|
import org.mockito.Mockito.verify
|
||||||
|
|
||||||
@@ -31,6 +35,19 @@ object MobileTelephonyHelpers {
|
|||||||
return callbackCaptor.allValues
|
return callbackCaptor.allValues
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Convenience constructor for SignalStrength */
|
||||||
|
fun signalStrength(gsmLevel: Int, cdmaLevel: Int, isGsm: Boolean): SignalStrength {
|
||||||
|
val signalStrength = mock<SignalStrength>()
|
||||||
|
whenever(signalStrength.isGsm).thenReturn(isGsm)
|
||||||
|
whenever(signalStrength.level).thenReturn(gsmLevel)
|
||||||
|
val cdmaStrength =
|
||||||
|
mock<CellSignalStrengthCdma>().also { whenever(it.level).thenReturn(cdmaLevel) }
|
||||||
|
whenever(signalStrength.getCellSignalStrengths(CellSignalStrengthCdma::class.java))
|
||||||
|
.thenReturn(listOf(cdmaStrength))
|
||||||
|
|
||||||
|
return signalStrength
|
||||||
|
}
|
||||||
|
|
||||||
inline fun <reified T> getTelephonyCallbackForType(mockTelephonyManager: TelephonyManager): T {
|
inline fun <reified T> getTelephonyCallbackForType(mockTelephonyManager: TelephonyManager): T {
|
||||||
val cbs = getTelephonyCallbacks(mockTelephonyManager).filterIsInstance<T>()
|
val cbs = getTelephonyCallbacks(mockTelephonyManager).filterIsInstance<T>()
|
||||||
assertThat(cbs.size).isEqualTo(1)
|
assertThat(cbs.size).isEqualTo(1)
|
||||||
|
|||||||
Reference in New Issue
Block a user