[Sb refactor] show data activity in Mobile view
Adds support for reading the config `config_showActivity`, and uses the new `DataActivityModel` type to show the data activity in the mobile view model / view binder Test: MobileIconViewModelTest Test: MobileConnectionRepositoryTest Test: DemoMobileConnectionParameterizedTest Test: manual demo mode Bug: 238425913 Change-Id: Id413d57d6c694ea6f324b022f6d215ae71b22074
This commit is contained in:
@@ -17,7 +17,6 @@
|
||||
package com.android.systemui.statusbar.pipeline.mobile.data.model
|
||||
|
||||
import android.annotation.IntRange
|
||||
import android.telephony.Annotation.DataActivityType
|
||||
import android.telephony.CellSignalStrength
|
||||
import android.telephony.TelephonyCallback.CarrierNetworkListener
|
||||
import android.telephony.TelephonyCallback.DataActivityListener
|
||||
@@ -28,6 +27,7 @@ import android.telephony.TelephonyCallback.SignalStrengthsListener
|
||||
import android.telephony.TelephonyDisplayInfo
|
||||
import android.telephony.TelephonyManager
|
||||
import com.android.systemui.statusbar.pipeline.mobile.data.model.DataConnectionState.Disconnected
|
||||
import com.android.systemui.statusbar.pipeline.shared.data.model.DataActivityModel
|
||||
|
||||
/**
|
||||
* Data class containing all of the relevant information for a particular line of service, known as
|
||||
@@ -54,7 +54,11 @@ data class MobileConnectionModel(
|
||||
val dataConnectionState: DataConnectionState = Disconnected,
|
||||
|
||||
/** From [DataActivityListener.onDataActivity]. See [TelephonyManager] for the values */
|
||||
@DataActivityType val dataActivityDirection: Int? = null,
|
||||
val dataActivityDirection: DataActivityModel =
|
||||
DataActivityModel(
|
||||
hasActivityIn = false,
|
||||
hasActivityOut = false,
|
||||
),
|
||||
|
||||
/** From [CarrierNetworkListener.onCarrierNetworkChange] */
|
||||
val carrierNetworkChangeActive: Boolean = false,
|
||||
|
||||
@@ -18,6 +18,7 @@ package com.android.systemui.statusbar.pipeline.mobile.data.repository.demo
|
||||
|
||||
import android.content.Context
|
||||
import android.telephony.SubscriptionManager.INVALID_SUBSCRIPTION_ID
|
||||
import android.telephony.TelephonyManager.DATA_ACTIVITY_NONE
|
||||
import android.util.Log
|
||||
import com.android.settingslib.SignalIcon
|
||||
import com.android.settingslib.mobile.MobileMappings
|
||||
@@ -34,6 +35,7 @@ import com.android.systemui.statusbar.pipeline.mobile.data.repository.MobileConn
|
||||
import com.android.systemui.statusbar.pipeline.mobile.data.repository.demo.model.FakeNetworkEventModel
|
||||
import com.android.systemui.statusbar.pipeline.mobile.data.repository.demo.model.FakeNetworkEventModel.Mobile
|
||||
import com.android.systemui.statusbar.pipeline.mobile.data.repository.demo.model.FakeNetworkEventModel.MobileDisabled
|
||||
import com.android.systemui.statusbar.pipeline.shared.data.model.toMobileDataActivityModel
|
||||
import javax.inject.Inject
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
||||
@@ -236,7 +238,7 @@ constructor(
|
||||
primaryLevel = level ?: 0,
|
||||
dataConnectionState =
|
||||
DataConnectionState.Connected, // TODO(b/261029387): not yet supported
|
||||
dataActivityDirection = activity,
|
||||
dataActivityDirection = (activity ?: DATA_ACTIVITY_NONE).toMobileDataActivityModel(),
|
||||
carrierNetworkChangeActive = carrierNetworkChange,
|
||||
resolvedNetworkType = dataType.toResolvedNetworkType()
|
||||
)
|
||||
|
||||
@@ -41,6 +41,7 @@ import com.android.systemui.statusbar.pipeline.mobile.data.repository.MobileConn
|
||||
import com.android.systemui.statusbar.pipeline.mobile.util.MobileMappingsProxy
|
||||
import com.android.systemui.statusbar.pipeline.shared.ConnectivityPipelineLogger
|
||||
import com.android.systemui.statusbar.pipeline.shared.ConnectivityPipelineLogger.Companion.logOutputChange
|
||||
import com.android.systemui.statusbar.pipeline.shared.data.model.toMobileDataActivityModel
|
||||
import com.android.systemui.util.settings.GlobalSettings
|
||||
import javax.inject.Inject
|
||||
import kotlinx.coroutines.CoroutineDispatcher
|
||||
@@ -137,7 +138,10 @@ class MobileConnectionRepositoryImpl(
|
||||
}
|
||||
|
||||
override fun onDataActivity(direction: Int) {
|
||||
state = state.copy(dataActivityDirection = direction)
|
||||
state =
|
||||
state.copy(
|
||||
dataActivityDirection = direction.toMobileDataActivityModel()
|
||||
)
|
||||
trySend(state)
|
||||
}
|
||||
|
||||
|
||||
@@ -21,9 +21,11 @@ import com.android.settingslib.SignalIcon.MobileIconGroup
|
||||
import com.android.systemui.dagger.qualifiers.Application
|
||||
import com.android.systemui.statusbar.pipeline.mobile.data.model.DataConnectionState.Connected
|
||||
import com.android.systemui.statusbar.pipeline.mobile.data.repository.MobileConnectionRepository
|
||||
import com.android.systemui.statusbar.pipeline.shared.data.model.DataActivityModel
|
||||
import com.android.systemui.util.CarrierConfigTracker
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.flow.SharingStarted
|
||||
import kotlinx.coroutines.flow.StateFlow
|
||||
@@ -32,6 +34,9 @@ import kotlinx.coroutines.flow.mapLatest
|
||||
import kotlinx.coroutines.flow.stateIn
|
||||
|
||||
interface MobileIconInteractor {
|
||||
/** The current mobile data activity */
|
||||
val activity: Flow<DataActivityModel>
|
||||
|
||||
/** Only true if mobile is the default transport but is not validated, otherwise false */
|
||||
val isDefaultConnectionFailed: StateFlow<Boolean>
|
||||
|
||||
@@ -82,6 +87,8 @@ class MobileIconInteractorImpl(
|
||||
) : MobileIconInteractor {
|
||||
private val connectionInfo = connectionRepository.connectionInfo
|
||||
|
||||
override val activity = connectionInfo.mapLatest { it.dataActivityDirection }
|
||||
|
||||
override val isDataEnabled: StateFlow<Boolean> = connectionRepository.dataEnabled
|
||||
|
||||
override val isDefaultDataEnabled = defaultSubscriptionHasDataEnabled
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
package com.android.systemui.statusbar.pipeline.mobile.ui.binder
|
||||
|
||||
import android.content.res.ColorStateList
|
||||
import android.view.View
|
||||
import android.view.View.GONE
|
||||
import android.view.View.VISIBLE
|
||||
import android.view.ViewGroup
|
||||
@@ -40,6 +41,9 @@ object MobileIconBinder {
|
||||
view: ViewGroup,
|
||||
viewModel: MobileIconViewModel,
|
||||
) {
|
||||
val activityContainer = view.requireViewById<View>(R.id.inout_container)
|
||||
val activityIn = view.requireViewById<ImageView>(R.id.mobile_in)
|
||||
val activityOut = view.requireViewById<ImageView>(R.id.mobile_out)
|
||||
val networkTypeView = view.requireViewById<ImageView>(R.id.mobile_type)
|
||||
val iconView = view.requireViewById<ImageView>(R.id.mobile_signal)
|
||||
val mobileDrawable = SignalDrawable(view.context).also { iconView.setImageDrawable(it) }
|
||||
@@ -74,6 +78,15 @@ object MobileIconBinder {
|
||||
}
|
||||
}
|
||||
|
||||
// Set the activity indicators
|
||||
launch { viewModel.activityInVisible.collect { activityIn.isVisible = it } }
|
||||
|
||||
launch { viewModel.activityOutVisible.collect { activityOut.isVisible = it } }
|
||||
|
||||
launch {
|
||||
viewModel.activityContainerVisible.collect { activityContainer.isVisible = it }
|
||||
}
|
||||
|
||||
// Set the tint
|
||||
launch {
|
||||
viewModel.tint.collect { tint ->
|
||||
@@ -81,6 +94,8 @@ object MobileIconBinder {
|
||||
iconView.imageTintList = tintList
|
||||
networkTypeView.imageTintList = tintList
|
||||
roamingView.imageTintList = tintList
|
||||
activityIn.imageTintList = tintList
|
||||
activityOut.imageTintList = tintList
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -22,13 +22,16 @@ import com.android.systemui.common.shared.model.ContentDescription
|
||||
import com.android.systemui.common.shared.model.Icon
|
||||
import com.android.systemui.statusbar.pipeline.mobile.domain.interactor.MobileIconInteractor
|
||||
import com.android.systemui.statusbar.pipeline.mobile.domain.interactor.MobileIconsInteractor
|
||||
import com.android.systemui.statusbar.pipeline.shared.ConnectivityConstants
|
||||
import com.android.systemui.statusbar.pipeline.shared.ConnectivityPipelineLogger
|
||||
import com.android.systemui.statusbar.pipeline.shared.ConnectivityPipelineLogger.Companion.logOutputChange
|
||||
import com.android.systemui.statusbar.pipeline.shared.data.model.DataActivityModel
|
||||
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.map
|
||||
import kotlinx.coroutines.flow.mapLatest
|
||||
|
||||
/**
|
||||
@@ -48,6 +51,7 @@ constructor(
|
||||
val subscriptionId: Int,
|
||||
iconInteractor: MobileIconInteractor,
|
||||
logger: ConnectivityPipelineLogger,
|
||||
constants: ConnectivityConstants,
|
||||
) {
|
||||
/** Whether or not to show the error state of [SignalDrawable] */
|
||||
private val showExclamationMark: Flow<Boolean> =
|
||||
@@ -89,5 +93,17 @@ constructor(
|
||||
|
||||
val roaming: Flow<Boolean> = iconInteractor.isRoaming
|
||||
|
||||
private val activity: Flow<DataActivityModel?> =
|
||||
if (!constants.shouldShowActivityConfig) {
|
||||
flowOf(null)
|
||||
} else {
|
||||
iconInteractor.activity
|
||||
}
|
||||
|
||||
val activityInVisible: Flow<Boolean> = activity.map { it?.hasActivityIn ?: false }
|
||||
val activityOutVisible: Flow<Boolean> = activity.map { it?.hasActivityOut ?: false }
|
||||
val activityContainerVisible: Flow<Boolean> =
|
||||
activity.map { it != null && (it.hasActivityIn || it.hasActivityOut) }
|
||||
|
||||
val tint: Flow<Int> = flowOf(Color.CYAN)
|
||||
}
|
||||
|
||||
@@ -20,6 +20,7 @@ package com.android.systemui.statusbar.pipeline.mobile.ui.viewmodel
|
||||
|
||||
import com.android.systemui.statusbar.pipeline.mobile.domain.interactor.MobileIconsInteractor
|
||||
import com.android.systemui.statusbar.pipeline.mobile.ui.view.ModernStatusBarMobileView
|
||||
import com.android.systemui.statusbar.pipeline.shared.ConnectivityConstants
|
||||
import com.android.systemui.statusbar.pipeline.shared.ConnectivityPipelineLogger
|
||||
import javax.inject.Inject
|
||||
import kotlinx.coroutines.InternalCoroutinesApi
|
||||
@@ -36,13 +37,15 @@ constructor(
|
||||
val subscriptionIdsFlow: StateFlow<List<Int>>,
|
||||
private val interactor: MobileIconsInteractor,
|
||||
private val logger: ConnectivityPipelineLogger,
|
||||
private val constants: ConnectivityConstants,
|
||||
) {
|
||||
/** TODO: do we need to cache these? */
|
||||
fun viewModelForSub(subId: Int): MobileIconViewModel =
|
||||
MobileIconViewModel(
|
||||
subId,
|
||||
interactor.createMobileConnectionInteractorForSubId(subId),
|
||||
logger
|
||||
logger,
|
||||
constants,
|
||||
)
|
||||
|
||||
class Factory
|
||||
@@ -50,12 +53,14 @@ constructor(
|
||||
constructor(
|
||||
private val interactor: MobileIconsInteractor,
|
||||
private val logger: ConnectivityPipelineLogger,
|
||||
private val constants: ConnectivityConstants,
|
||||
) {
|
||||
fun create(subscriptionIdsFlow: StateFlow<List<Int>>): MobileIconsViewModel {
|
||||
return MobileIconsViewModel(
|
||||
subscriptionIdsFlow,
|
||||
interactor,
|
||||
logger,
|
||||
constants,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,8 +16,10 @@
|
||||
|
||||
package com.android.systemui.statusbar.pipeline.shared
|
||||
|
||||
import android.content.Context
|
||||
import android.telephony.TelephonyManager
|
||||
import com.android.systemui.Dumpable
|
||||
import com.android.systemui.R
|
||||
import com.android.systemui.dagger.SysUISingleton
|
||||
import com.android.systemui.dump.DumpManager
|
||||
import com.android.systemui.statusbar.pipeline.shared.ConnectivityPipelineLogger.Companion.SB_LOGGING_TAG
|
||||
@@ -32,15 +34,25 @@ import javax.inject.Inject
|
||||
@SysUISingleton
|
||||
class ConnectivityConstants
|
||||
@Inject
|
||||
constructor(dumpManager: DumpManager, telephonyManager: TelephonyManager) : Dumpable {
|
||||
constructor(
|
||||
context: Context,
|
||||
dumpManager: DumpManager,
|
||||
telephonyManager: TelephonyManager,
|
||||
) : Dumpable {
|
||||
init {
|
||||
dumpManager.registerDumpable("${SB_LOGGING_TAG}Constants", this)
|
||||
dumpManager.registerNormalDumpable("${SB_LOGGING_TAG}Constants", this)
|
||||
}
|
||||
|
||||
/** True if this device has the capability for data connections and false otherwise. */
|
||||
val hasDataCapabilities = telephonyManager.isDataCapable
|
||||
|
||||
/** True if we should show the activityIn/activityOut icons and false otherwise */
|
||||
val shouldShowActivityConfig = context.resources.getBoolean(R.bool.config_showActivity)
|
||||
|
||||
override fun dump(pw: PrintWriter, args: Array<out String>) {
|
||||
pw.apply { println("hasDataCapabilities=$hasDataCapabilities") }
|
||||
pw.apply {
|
||||
println("hasDataCapabilities=$hasDataCapabilities")
|
||||
println("shouldShowActivityConfig=$shouldShowActivityConfig")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,6 +16,9 @@
|
||||
|
||||
package com.android.systemui.statusbar.pipeline.shared.data.model
|
||||
|
||||
import android.net.wifi.WifiManager
|
||||
import android.telephony.Annotation
|
||||
import android.telephony.TelephonyManager
|
||||
import com.android.systemui.log.table.Diffable
|
||||
import com.android.systemui.log.table.TableRowLogger
|
||||
|
||||
@@ -44,3 +47,25 @@ data class DataActivityModel(
|
||||
const val ACTIVITY_PREFIX = "dataActivity"
|
||||
private const val COL_ACTIVITY_IN = "in"
|
||||
private const val COL_ACTIVITY_OUT = "out"
|
||||
|
||||
fun @receiver:Annotation.DataActivityType Int.toMobileDataActivityModel(): DataActivityModel =
|
||||
when (this) {
|
||||
TelephonyManager.DATA_ACTIVITY_IN ->
|
||||
DataActivityModel(hasActivityIn = true, hasActivityOut = false)
|
||||
TelephonyManager.DATA_ACTIVITY_OUT ->
|
||||
DataActivityModel(hasActivityIn = false, hasActivityOut = true)
|
||||
TelephonyManager.DATA_ACTIVITY_INOUT ->
|
||||
DataActivityModel(hasActivityIn = true, hasActivityOut = true)
|
||||
else -> DataActivityModel(hasActivityIn = false, hasActivityOut = false)
|
||||
}
|
||||
|
||||
fun Int.toWifiDataActivityModel(): DataActivityModel =
|
||||
when (this) {
|
||||
WifiManager.TrafficStateCallback.DATA_ACTIVITY_IN ->
|
||||
DataActivityModel(hasActivityIn = true, hasActivityOut = false)
|
||||
WifiManager.TrafficStateCallback.DATA_ACTIVITY_OUT ->
|
||||
DataActivityModel(hasActivityIn = false, hasActivityOut = true)
|
||||
WifiManager.TrafficStateCallback.DATA_ACTIVITY_INOUT ->
|
||||
DataActivityModel(hasActivityIn = true, hasActivityOut = true)
|
||||
else -> DataActivityModel(hasActivityIn = false, hasActivityOut = false)
|
||||
}
|
||||
|
||||
@@ -43,6 +43,7 @@ import com.android.systemui.statusbar.pipeline.shared.ConnectivityPipelineLogger
|
||||
import com.android.systemui.statusbar.pipeline.shared.ConnectivityPipelineLogger.Companion.SB_LOGGING_TAG
|
||||
import com.android.systemui.statusbar.pipeline.shared.ConnectivityPipelineLogger.Companion.logInputChange
|
||||
import com.android.systemui.statusbar.pipeline.shared.data.model.DataActivityModel
|
||||
import com.android.systemui.statusbar.pipeline.shared.data.model.toWifiDataActivityModel
|
||||
import com.android.systemui.statusbar.pipeline.wifi.data.model.WifiNetworkModel
|
||||
import java.util.concurrent.Executor
|
||||
import javax.inject.Inject
|
||||
@@ -237,7 +238,7 @@ class WifiRepositoryImpl @Inject constructor(
|
||||
conflatedCallbackFlow {
|
||||
val callback = TrafficStateCallback { state ->
|
||||
logger.logInputChange("onTrafficStateChange", prettyPrintActivity(state))
|
||||
trySend(trafficStateToDataActivityModel(state))
|
||||
trySend(state.toWifiDataActivityModel())
|
||||
}
|
||||
wifiManager.registerTrafficStateCallback(mainExecutor, callback)
|
||||
awaitClose { wifiManager.unregisterTrafficStateCallback(callback) }
|
||||
@@ -266,15 +267,6 @@ class WifiRepositoryImpl @Inject constructor(
|
||||
// NetworkCallback inside [wifiNetwork] for our wifi network information.
|
||||
val WIFI_NETWORK_DEFAULT = WifiNetworkModel.Inactive
|
||||
|
||||
private fun trafficStateToDataActivityModel(state: Int): DataActivityModel {
|
||||
return DataActivityModel(
|
||||
hasActivityIn = state == TrafficStateCallback.DATA_ACTIVITY_IN ||
|
||||
state == TrafficStateCallback.DATA_ACTIVITY_INOUT,
|
||||
hasActivityOut = state == TrafficStateCallback.DATA_ACTIVITY_OUT ||
|
||||
state == TrafficStateCallback.DATA_ACTIVITY_INOUT,
|
||||
)
|
||||
}
|
||||
|
||||
private fun networkCapabilitiesToWifiInfo(
|
||||
networkCapabilities: NetworkCapabilities
|
||||
): WifiInfo? {
|
||||
|
||||
@@ -18,6 +18,7 @@ package com.android.systemui.statusbar.pipeline.mobile.data.repository.demo
|
||||
|
||||
import android.telephony.Annotation
|
||||
import android.telephony.TelephonyManager
|
||||
import android.telephony.TelephonyManager.DATA_ACTIVITY_NONE
|
||||
import androidx.test.filters.SmallTest
|
||||
import com.android.settingslib.SignalIcon
|
||||
import com.android.settingslib.mobile.TelephonyIcons
|
||||
@@ -25,6 +26,7 @@ import com.android.systemui.SysuiTestCase
|
||||
import com.android.systemui.statusbar.pipeline.mobile.data.model.DataConnectionState
|
||||
import com.android.systemui.statusbar.pipeline.mobile.data.model.MobileConnectionModel
|
||||
import com.android.systemui.statusbar.pipeline.mobile.data.repository.demo.model.FakeNetworkEventModel
|
||||
import com.android.systemui.statusbar.pipeline.shared.data.model.toMobileDataActivityModel
|
||||
import com.android.systemui.util.mockito.mock
|
||||
import com.android.systemui.util.mockito.whenever
|
||||
import com.google.common.truth.Truth.assertThat
|
||||
@@ -114,7 +116,8 @@ internal class DemoMobileConnectionParameterizedTest(private val testCase: TestC
|
||||
assertThat(conn.subId).isEqualTo(model.subId)
|
||||
assertThat(connectionInfo.cdmaLevel).isEqualTo(model.level)
|
||||
assertThat(connectionInfo.primaryLevel).isEqualTo(model.level)
|
||||
assertThat(connectionInfo.dataActivityDirection).isEqualTo(model.activity)
|
||||
assertThat(connectionInfo.dataActivityDirection)
|
||||
.isEqualTo((model.activity ?: DATA_ACTIVITY_NONE).toMobileDataActivityModel())
|
||||
assertThat(connectionInfo.carrierNetworkChangeActive)
|
||||
.isEqualTo(model.carrierNetworkChange)
|
||||
assertThat(connectionInfo.isRoaming).isEqualTo(model.roaming)
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
package com.android.systemui.statusbar.pipeline.mobile.data.repository.demo
|
||||
|
||||
import android.telephony.TelephonyManager.DATA_ACTIVITY_INOUT
|
||||
import android.telephony.TelephonyManager.DATA_ACTIVITY_NONE
|
||||
import android.telephony.TelephonyManager.UNKNOWN_CARRIER_ID
|
||||
import androidx.test.filters.SmallTest
|
||||
import com.android.settingslib.SignalIcon
|
||||
@@ -27,6 +28,7 @@ import com.android.systemui.statusbar.pipeline.mobile.data.model.MobileConnectio
|
||||
import com.android.systemui.statusbar.pipeline.mobile.data.model.SubscriptionModel
|
||||
import com.android.systemui.statusbar.pipeline.mobile.data.repository.demo.model.FakeNetworkEventModel
|
||||
import com.android.systemui.statusbar.pipeline.mobile.data.repository.demo.model.FakeNetworkEventModel.MobileDisabled
|
||||
import com.android.systemui.statusbar.pipeline.shared.data.model.toMobileDataActivityModel
|
||||
import com.android.systemui.util.mockito.mock
|
||||
import com.android.systemui.util.mockito.whenever
|
||||
import com.google.common.truth.Truth.assertThat
|
||||
@@ -289,7 +291,8 @@ class DemoMobileConnectionsRepositoryTest : SysuiTestCase() {
|
||||
assertThat(conn.subId).isEqualTo(model.subId)
|
||||
assertThat(connectionInfo.cdmaLevel).isEqualTo(model.level)
|
||||
assertThat(connectionInfo.primaryLevel).isEqualTo(model.level)
|
||||
assertThat(connectionInfo.dataActivityDirection).isEqualTo(model.activity)
|
||||
assertThat(connectionInfo.dataActivityDirection)
|
||||
.isEqualTo((model.activity ?: DATA_ACTIVITY_NONE).toMobileDataActivityModel())
|
||||
assertThat(connectionInfo.carrierNetworkChangeActive)
|
||||
.isEqualTo(model.carrierNetworkChange)
|
||||
assertThat(connectionInfo.isRoaming).isEqualTo(model.roaming)
|
||||
|
||||
@@ -23,10 +23,16 @@ import android.telephony.ServiceState
|
||||
import android.telephony.SignalStrength
|
||||
import android.telephony.SubscriptionInfo
|
||||
import android.telephony.TelephonyCallback
|
||||
import android.telephony.TelephonyCallback.DataActivityListener
|
||||
import android.telephony.TelephonyCallback.ServiceStateListener
|
||||
import android.telephony.TelephonyDisplayInfo
|
||||
import android.telephony.TelephonyDisplayInfo.OVERRIDE_NETWORK_TYPE_LTE_CA
|
||||
import android.telephony.TelephonyManager
|
||||
import android.telephony.TelephonyManager.DATA_ACTIVITY_DORMANT
|
||||
import android.telephony.TelephonyManager.DATA_ACTIVITY_IN
|
||||
import android.telephony.TelephonyManager.DATA_ACTIVITY_INOUT
|
||||
import android.telephony.TelephonyManager.DATA_ACTIVITY_NONE
|
||||
import android.telephony.TelephonyManager.DATA_ACTIVITY_OUT
|
||||
import android.telephony.TelephonyManager.DATA_CONNECTED
|
||||
import android.telephony.TelephonyManager.DATA_CONNECTING
|
||||
import android.telephony.TelephonyManager.DATA_DISCONNECTED
|
||||
@@ -46,6 +52,8 @@ import com.android.systemui.statusbar.pipeline.mobile.data.model.ResolvedNetwork
|
||||
import com.android.systemui.statusbar.pipeline.mobile.data.repository.FakeMobileConnectionsRepository
|
||||
import com.android.systemui.statusbar.pipeline.mobile.util.FakeMobileMappingsProxy
|
||||
import com.android.systemui.statusbar.pipeline.shared.ConnectivityPipelineLogger
|
||||
import com.android.systemui.statusbar.pipeline.shared.data.model.DataActivityModel
|
||||
import com.android.systemui.statusbar.pipeline.shared.data.model.toMobileDataActivityModel
|
||||
import com.android.systemui.util.mockito.any
|
||||
import com.android.systemui.util.mockito.argumentCaptor
|
||||
import com.android.systemui.util.mockito.mock
|
||||
@@ -249,10 +257,11 @@ class MobileConnectionRepositoryTest : SysuiTestCase() {
|
||||
var latest: MobileConnectionModel? = null
|
||||
val job = underTest.connectionInfo.onEach { latest = it }.launchIn(this)
|
||||
|
||||
val callback = getTelephonyCallbackForType<TelephonyCallback.DataActivityListener>()
|
||||
callback.onDataActivity(3)
|
||||
val callback = getTelephonyCallbackForType<DataActivityListener>()
|
||||
callback.onDataActivity(DATA_ACTIVITY_INOUT)
|
||||
|
||||
assertThat(latest?.dataActivityDirection).isEqualTo(3)
|
||||
assertThat(latest?.dataActivityDirection)
|
||||
.isEqualTo(DATA_ACTIVITY_INOUT.toMobileDataActivityModel())
|
||||
|
||||
job.cancel()
|
||||
}
|
||||
@@ -459,6 +468,44 @@ class MobileConnectionRepositoryTest : SysuiTestCase() {
|
||||
job.cancel()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `activity - updates from callback`() =
|
||||
runBlocking(IMMEDIATE) {
|
||||
var latest: DataActivityModel? = null
|
||||
val job =
|
||||
underTest.connectionInfo.onEach { latest = it.dataActivityDirection }.launchIn(this)
|
||||
|
||||
assertThat(latest)
|
||||
.isEqualTo(DataActivityModel(hasActivityIn = false, hasActivityOut = false))
|
||||
|
||||
val cb = getTelephonyCallbackForType<DataActivityListener>()
|
||||
cb.onDataActivity(DATA_ACTIVITY_IN)
|
||||
assertThat(latest)
|
||||
.isEqualTo(DataActivityModel(hasActivityIn = true, hasActivityOut = false))
|
||||
|
||||
cb.onDataActivity(DATA_ACTIVITY_OUT)
|
||||
assertThat(latest)
|
||||
.isEqualTo(DataActivityModel(hasActivityIn = false, hasActivityOut = true))
|
||||
|
||||
cb.onDataActivity(DATA_ACTIVITY_INOUT)
|
||||
assertThat(latest)
|
||||
.isEqualTo(DataActivityModel(hasActivityIn = true, hasActivityOut = true))
|
||||
|
||||
cb.onDataActivity(DATA_ACTIVITY_NONE)
|
||||
assertThat(latest)
|
||||
.isEqualTo(DataActivityModel(hasActivityIn = false, hasActivityOut = false))
|
||||
|
||||
cb.onDataActivity(DATA_ACTIVITY_DORMANT)
|
||||
assertThat(latest)
|
||||
.isEqualTo(DataActivityModel(hasActivityIn = false, hasActivityOut = false))
|
||||
|
||||
cb.onDataActivity(1234)
|
||||
assertThat(latest)
|
||||
.isEqualTo(DataActivityModel(hasActivityIn = false, hasActivityOut = false))
|
||||
|
||||
job.cancel()
|
||||
}
|
||||
|
||||
private fun getTelephonyCallbacks(): List<TelephonyCallback> {
|
||||
val callbackCaptor = argumentCaptor<TelephonyCallback>()
|
||||
Mockito.verify(telephonyManager).registerTelephonyCallback(any(), callbackCaptor.capture())
|
||||
|
||||
@@ -19,11 +19,20 @@ package com.android.systemui.statusbar.pipeline.mobile.domain.interactor
|
||||
import android.telephony.CellSignalStrength
|
||||
import com.android.settingslib.SignalIcon
|
||||
import com.android.settingslib.mobile.TelephonyIcons
|
||||
import com.android.systemui.statusbar.pipeline.shared.data.model.DataActivityModel
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
|
||||
class FakeMobileIconInteractor : MobileIconInteractor {
|
||||
override val alwaysShowDataRatIcon = MutableStateFlow(false)
|
||||
|
||||
override val activity =
|
||||
MutableStateFlow(
|
||||
DataActivityModel(
|
||||
hasActivityIn = false,
|
||||
hasActivityOut = false,
|
||||
)
|
||||
)
|
||||
|
||||
private val _iconGroup = MutableStateFlow<SignalIcon.MobileIconGroup>(TelephonyIcons.THREE_G)
|
||||
override val networkTypeIconGroup = _iconGroup
|
||||
|
||||
|
||||
@@ -23,7 +23,10 @@ import com.android.systemui.SysuiTestCase
|
||||
import com.android.systemui.common.shared.model.ContentDescription
|
||||
import com.android.systemui.common.shared.model.Icon
|
||||
import com.android.systemui.statusbar.pipeline.mobile.domain.interactor.FakeMobileIconInteractor
|
||||
import com.android.systemui.statusbar.pipeline.shared.ConnectivityConstants
|
||||
import com.android.systemui.statusbar.pipeline.shared.ConnectivityPipelineLogger
|
||||
import com.android.systemui.statusbar.pipeline.shared.data.model.DataActivityModel
|
||||
import com.android.systemui.util.mockito.whenever
|
||||
import com.google.common.truth.Truth.assertThat
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.flow.launchIn
|
||||
@@ -40,6 +43,7 @@ class MobileIconViewModelTest : SysuiTestCase() {
|
||||
private lateinit var underTest: MobileIconViewModel
|
||||
private val interactor = FakeMobileIconInteractor()
|
||||
@Mock private lateinit var logger: ConnectivityPipelineLogger
|
||||
@Mock private lateinit var constants: ConnectivityConstants
|
||||
|
||||
@Before
|
||||
fun setUp() {
|
||||
@@ -53,7 +57,7 @@ class MobileIconViewModelTest : SysuiTestCase() {
|
||||
setNumberOfLevels(4)
|
||||
isDataConnected.value = true
|
||||
}
|
||||
underTest = MobileIconViewModel(SUB_1_ID, interactor, logger)
|
||||
underTest = MobileIconViewModel(SUB_1_ID, interactor, logger, constants)
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -250,6 +254,92 @@ class MobileIconViewModelTest : SysuiTestCase() {
|
||||
job.cancel()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `data activity - null when config is off`() =
|
||||
runBlocking(IMMEDIATE) {
|
||||
// Create a new view model here so the constants are properly read
|
||||
whenever(constants.shouldShowActivityConfig).thenReturn(false)
|
||||
underTest = MobileIconViewModel(SUB_1_ID, interactor, logger, constants)
|
||||
|
||||
var inVisible: Boolean? = null
|
||||
val inJob = underTest.activityInVisible.onEach { inVisible = it }.launchIn(this)
|
||||
|
||||
var outVisible: Boolean? = null
|
||||
val outJob = underTest.activityInVisible.onEach { outVisible = it }.launchIn(this)
|
||||
|
||||
var containerVisible: Boolean? = null
|
||||
val containerJob =
|
||||
underTest.activityInVisible.onEach { containerVisible = it }.launchIn(this)
|
||||
|
||||
interactor.activity.value =
|
||||
DataActivityModel(
|
||||
hasActivityIn = true,
|
||||
hasActivityOut = true,
|
||||
)
|
||||
|
||||
assertThat(inVisible).isFalse()
|
||||
assertThat(outVisible).isFalse()
|
||||
assertThat(containerVisible).isFalse()
|
||||
|
||||
inJob.cancel()
|
||||
outJob.cancel()
|
||||
containerJob.cancel()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `data activity - config on - test indicators`() =
|
||||
runBlocking(IMMEDIATE) {
|
||||
// Create a new view model here so the constants are properly read
|
||||
whenever(constants.shouldShowActivityConfig).thenReturn(true)
|
||||
underTest = MobileIconViewModel(SUB_1_ID, interactor, logger, constants)
|
||||
|
||||
var inVisible: Boolean? = null
|
||||
val inJob = underTest.activityInVisible.onEach { inVisible = it }.launchIn(this)
|
||||
|
||||
var outVisible: Boolean? = null
|
||||
val outJob = underTest.activityOutVisible.onEach { outVisible = it }.launchIn(this)
|
||||
|
||||
var containerVisible: Boolean? = null
|
||||
val containerJob =
|
||||
underTest.activityContainerVisible.onEach { containerVisible = it }.launchIn(this)
|
||||
|
||||
interactor.activity.value =
|
||||
DataActivityModel(
|
||||
hasActivityIn = true,
|
||||
hasActivityOut = false,
|
||||
)
|
||||
|
||||
yield()
|
||||
|
||||
assertThat(inVisible).isTrue()
|
||||
assertThat(outVisible).isFalse()
|
||||
assertThat(containerVisible).isTrue()
|
||||
|
||||
interactor.activity.value =
|
||||
DataActivityModel(
|
||||
hasActivityIn = false,
|
||||
hasActivityOut = true,
|
||||
)
|
||||
|
||||
assertThat(inVisible).isFalse()
|
||||
assertThat(outVisible).isTrue()
|
||||
assertThat(containerVisible).isTrue()
|
||||
|
||||
interactor.activity.value =
|
||||
DataActivityModel(
|
||||
hasActivityIn = false,
|
||||
hasActivityOut = false,
|
||||
)
|
||||
|
||||
assertThat(inVisible).isFalse()
|
||||
assertThat(outVisible).isFalse()
|
||||
assertThat(containerVisible).isFalse()
|
||||
|
||||
inJob.cancel()
|
||||
outJob.cancel()
|
||||
containerJob.cancel()
|
||||
}
|
||||
|
||||
/** Convenience constructor for these tests */
|
||||
private fun defaultSignal(
|
||||
level: Int = 1,
|
||||
|
||||
Reference in New Issue
Block a user