[Sb refactor] Move DemoMobileConnectionRepository to its own file

This class has outgrown being a small data class defined in the same
file as its parent repo.

Test: DemoMobileConnectionsRepositoryTest; DemoMobileConnectionParameterizedTest
Bug: 270300839
Change-Id: I4981e641c0d4c8346ec46a5a832044df62051a8f
This commit is contained in:
Evan Laird
2023-02-28 17:26:27 -05:00
parent 5cbcba28d6
commit 49f1e9e05a
4 changed files with 278 additions and 120 deletions

View File

@@ -0,0 +1,231 @@
/*
* 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.demo
import android.telephony.CellSignalStrength
import android.telephony.TelephonyManager
import com.android.systemui.log.table.TableLogBuffer
import com.android.systemui.log.table.logDiffsForTable
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.repository.MobileConnectionRepository
import com.android.systemui.statusbar.pipeline.mobile.data.repository.demo.model.FakeNetworkEventModel
import com.android.systemui.statusbar.pipeline.mobile.data.repository.prod.FullMobileConnectionRepository.Companion.COL_CARRIER_NETWORK_CHANGE
import com.android.systemui.statusbar.pipeline.mobile.data.repository.prod.FullMobileConnectionRepository.Companion.COL_CDMA_LEVEL
import com.android.systemui.statusbar.pipeline.mobile.data.repository.prod.FullMobileConnectionRepository.Companion.COL_EMERGENCY
import com.android.systemui.statusbar.pipeline.mobile.data.repository.prod.FullMobileConnectionRepository.Companion.COL_IS_GSM
import com.android.systemui.statusbar.pipeline.mobile.data.repository.prod.FullMobileConnectionRepository.Companion.COL_IS_IN_SERVICE
import com.android.systemui.statusbar.pipeline.mobile.data.repository.prod.FullMobileConnectionRepository.Companion.COL_OPERATOR
import com.android.systemui.statusbar.pipeline.mobile.data.repository.prod.FullMobileConnectionRepository.Companion.COL_PRIMARY_LEVEL
import com.android.systemui.statusbar.pipeline.mobile.data.repository.prod.FullMobileConnectionRepository.Companion.COL_ROAMING
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.wifi.data.repository.demo.model.FakeWifiEventModel
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.SharingStarted
import kotlinx.coroutines.flow.stateIn
/**
* Demo version of [MobileConnectionRepository]. Note that this class shares all of its flows using
* [SharingStarted.WhileSubscribed()] to give the same semantics as using a regular
* [MutableStateFlow] while still logging all of the inputs in the same manor as the production
* repos.
*/
class DemoMobileConnectionRepository(
override val subId: Int,
override val tableLogBuffer: TableLogBuffer,
val scope: CoroutineScope,
) : MobileConnectionRepository {
private val _isEmergencyOnly = MutableStateFlow(false)
override val isEmergencyOnly =
_isEmergencyOnly
.logDiffsForTable(
tableLogBuffer,
columnPrefix = "",
columnName = COL_EMERGENCY,
_isEmergencyOnly.value
)
.stateIn(scope, SharingStarted.WhileSubscribed(), _isEmergencyOnly.value)
private val _isRoaming = MutableStateFlow(false)
override val isRoaming =
_isRoaming
.logDiffsForTable(
tableLogBuffer,
columnPrefix = "",
columnName = COL_ROAMING,
_isRoaming.value
)
.stateIn(scope, SharingStarted.WhileSubscribed(), _isRoaming.value)
private val _operatorAlphaShort: MutableStateFlow<String?> = MutableStateFlow(null)
override val operatorAlphaShort =
_operatorAlphaShort
.logDiffsForTable(
tableLogBuffer,
columnPrefix = "",
columnName = COL_OPERATOR,
_operatorAlphaShort.value
)
.stateIn(scope, SharingStarted.WhileSubscribed(), _operatorAlphaShort.value)
private val _isInService = MutableStateFlow(false)
override val isInService =
_isInService
.logDiffsForTable(
tableLogBuffer,
columnPrefix = "",
columnName = COL_IS_IN_SERVICE,
_isInService.value
)
.stateIn(scope, SharingStarted.WhileSubscribed(), _isInService.value)
private val _isGsm = MutableStateFlow(false)
override val isGsm =
_isGsm
.logDiffsForTable(
tableLogBuffer,
columnPrefix = "",
columnName = COL_IS_GSM,
_isGsm.value
)
.stateIn(scope, SharingStarted.WhileSubscribed(), _isGsm.value)
private val _cdmaLevel = MutableStateFlow(CellSignalStrength.SIGNAL_STRENGTH_NONE_OR_UNKNOWN)
override val cdmaLevel =
_cdmaLevel
.logDiffsForTable(
tableLogBuffer,
columnPrefix = "",
columnName = COL_CDMA_LEVEL,
_cdmaLevel.value
)
.stateIn(scope, SharingStarted.WhileSubscribed(), _cdmaLevel.value)
private val _primaryLevel = MutableStateFlow(CellSignalStrength.SIGNAL_STRENGTH_NONE_OR_UNKNOWN)
override val primaryLevel =
_primaryLevel
.logDiffsForTable(
tableLogBuffer,
columnPrefix = "",
columnName = COL_PRIMARY_LEVEL,
_primaryLevel.value
)
.stateIn(scope, SharingStarted.WhileSubscribed(), _primaryLevel.value)
private val _dataConnectionState = MutableStateFlow(DataConnectionState.Disconnected)
override val dataConnectionState =
_dataConnectionState
.logDiffsForTable(tableLogBuffer, columnPrefix = "", _dataConnectionState.value)
.stateIn(scope, SharingStarted.WhileSubscribed(), _dataConnectionState.value)
private val _dataActivityDirection =
MutableStateFlow(
DataActivityModel(
hasActivityIn = false,
hasActivityOut = false,
)
)
override val dataActivityDirection =
_dataActivityDirection
.logDiffsForTable(tableLogBuffer, columnPrefix = "", _dataActivityDirection.value)
.stateIn(scope, SharingStarted.WhileSubscribed(), _dataActivityDirection.value)
private val _carrierNetworkChangeActive = MutableStateFlow(false)
override val carrierNetworkChangeActive =
_carrierNetworkChangeActive
.logDiffsForTable(
tableLogBuffer,
columnPrefix = "",
columnName = COL_CARRIER_NETWORK_CHANGE,
_carrierNetworkChangeActive.value
)
.stateIn(scope, SharingStarted.WhileSubscribed(), _carrierNetworkChangeActive.value)
private val _resolvedNetworkType: MutableStateFlow<ResolvedNetworkType> =
MutableStateFlow(ResolvedNetworkType.UnknownNetworkType)
override val resolvedNetworkType =
_resolvedNetworkType
.logDiffsForTable(tableLogBuffer, columnPrefix = "", _resolvedNetworkType.value)
.stateIn(scope, SharingStarted.WhileSubscribed(), _resolvedNetworkType.value)
override val numberOfLevels = MutableStateFlow(MobileConnectionRepository.DEFAULT_NUM_LEVELS)
override val dataEnabled = MutableStateFlow(true)
override val cdmaRoaming = MutableStateFlow(false)
override val networkName = MutableStateFlow(NetworkNameModel.IntentDerived("demo network"))
/**
* Process a new demo mobile event. Note that [resolvedNetworkType] must be passed in separately
* from the event, due to the requirement to reverse the mobile mappings lookup in the top-level
* repository.
*/
fun processDemoMobileEvent(
event: FakeNetworkEventModel.Mobile,
resolvedNetworkType: ResolvedNetworkType,
) {
// This is always true here, because we split out disabled states at the data-source level
dataEnabled.value = true
networkName.value = NetworkNameModel.IntentDerived(event.name)
cdmaRoaming.value = event.roaming
_isRoaming.value = event.roaming
// TODO(b/261029387): not yet supported
_isEmergencyOnly.value = false
_operatorAlphaShort.value = event.name
_isInService.value = (event.level ?: 0) > 0
// TODO(b/261029387): not yet supported
_isGsm.value = false
_cdmaLevel.value = event.level ?: 0
_primaryLevel.value = event.level ?: 0
// TODO(b/261029387): not yet supported
_dataConnectionState.value = DataConnectionState.Connected
_dataActivityDirection.value =
(event.activity ?: TelephonyManager.DATA_ACTIVITY_NONE).toMobileDataActivityModel()
_carrierNetworkChangeActive.value = event.carrierNetworkChange
_resolvedNetworkType.value = resolvedNetworkType
}
fun processCarrierMergedEvent(event: FakeWifiEventModel.CarrierMerged) {
// This is always true here, because we split out disabled states at the data-source level
dataEnabled.value = true
networkName.value = NetworkNameModel.IntentDerived(CARRIER_MERGED_NAME)
numberOfLevels.value = event.numberOfLevels
cdmaRoaming.value = false
_primaryLevel.value = event.level
_cdmaLevel.value = event.level
_dataActivityDirection.value = event.activity.toMobileDataActivityModel()
// These fields are always the same for carrier-merged networks
_resolvedNetworkType.value = ResolvedNetworkType.CarrierMergedNetworkType
_dataConnectionState.value = DataConnectionState.Connected
_isRoaming.value = false
_isEmergencyOnly.value = false
_operatorAlphaShort.value = null
_isInService.value = true
_isGsm.value = false
_carrierNetworkChangeActive.value = false
}
companion object {
private const val CARRIER_MERGED_NAME = "Carrier Merged Network"
}
}

View File

@@ -17,19 +17,14 @@
package com.android.systemui.statusbar.pipeline.mobile.data.repository.demo
import android.content.Context
import android.telephony.CellSignalStrength
import android.telephony.SubscriptionManager.INVALID_SUBSCRIPTION_ID
import android.telephony.TelephonyManager
import android.util.Log
import com.android.settingslib.SignalIcon
import com.android.settingslib.mobile.MobileMappings
import com.android.settingslib.mobile.TelephonyIcons
import com.android.systemui.dagger.qualifiers.Application
import com.android.systemui.log.table.TableLogBuffer
import com.android.systemui.log.table.TableLogBufferFactory
import com.android.systemui.statusbar.pipeline.mobile.data.model.DataConnectionState
import com.android.systemui.statusbar.pipeline.mobile.data.model.MobileConnectivityModel
import com.android.systemui.statusbar.pipeline.mobile.data.model.NetworkNameModel
import com.android.systemui.statusbar.pipeline.mobile.data.model.ResolvedNetworkType
import com.android.systemui.statusbar.pipeline.mobile.data.model.ResolvedNetworkType.DefaultNetworkType
import com.android.systemui.statusbar.pipeline.mobile.data.model.SubscriptionModel
@@ -39,8 +34,6 @@ import com.android.systemui.statusbar.pipeline.mobile.data.repository.demo.model
import com.android.systemui.statusbar.pipeline.mobile.data.repository.demo.model.FakeNetworkEventModel.Mobile
import com.android.systemui.statusbar.pipeline.mobile.data.repository.demo.model.FakeNetworkEventModel.MobileDisabled
import com.android.systemui.statusbar.pipeline.mobile.data.repository.prod.FullMobileConnectionRepository.Factory.Companion.MOBILE_CONNECTION_BUFFER_SIZE
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.wifi.data.repository.demo.DemoModeWifiDataSource
import com.android.systemui.statusbar.pipeline.wifi.data.repository.demo.model.FakeWifiEventModel
import javax.inject.Inject
@@ -52,7 +45,6 @@ import kotlinx.coroutines.flow.MutableSharedFlow
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.SharingStarted
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.asStateFlow
import kotlinx.coroutines.flow.filterNotNull
import kotlinx.coroutines.flow.flowOf
import kotlinx.coroutines.flow.map
@@ -191,6 +183,7 @@ constructor(
DemoMobileConnectionRepository(
subId,
tableLogBuffer,
scope,
)
return CacheContainer(repo, lastMobileState = null)
}
@@ -338,112 +331,3 @@ class CacheContainer(
/** The last received [Mobile] event. Used when switching from carrier merged back to mobile. */
var lastMobileState: Mobile?,
)
class DemoMobileConnectionRepository(
override val subId: Int,
override val tableLogBuffer: TableLogBuffer,
) : MobileConnectionRepository {
private val _isEmergencyOnly = MutableStateFlow(false)
override val isEmergencyOnly = _isEmergencyOnly.asStateFlow()
private val _isRoaming = MutableStateFlow(false)
override val isRoaming = _isRoaming.asStateFlow()
private val _operatorAlphaShort: MutableStateFlow<String?> = MutableStateFlow(null)
override val operatorAlphaShort = _operatorAlphaShort.asStateFlow()
private val _isInService = MutableStateFlow(false)
override val isInService = _isInService.asStateFlow()
private val _isGsm = MutableStateFlow(false)
override val isGsm = _isGsm.asStateFlow()
private val _cdmaLevel = MutableStateFlow(CellSignalStrength.SIGNAL_STRENGTH_NONE_OR_UNKNOWN)
override val cdmaLevel = _cdmaLevel.asStateFlow()
private val _primaryLevel = MutableStateFlow(CellSignalStrength.SIGNAL_STRENGTH_NONE_OR_UNKNOWN)
override val primaryLevel = _primaryLevel.asStateFlow()
private val _dataConnectionState = MutableStateFlow(DataConnectionState.Disconnected)
override val dataConnectionState = _dataConnectionState.asStateFlow()
private val _dataActivityDirection =
MutableStateFlow(
DataActivityModel(
hasActivityIn = false,
hasActivityOut = false,
)
)
override val dataActivityDirection = _dataActivityDirection.asStateFlow()
private val _carrierNetworkChangeActive = MutableStateFlow(false)
override val carrierNetworkChangeActive = _carrierNetworkChangeActive.asStateFlow()
private val _resolvedNetworkType: MutableStateFlow<ResolvedNetworkType> =
MutableStateFlow(ResolvedNetworkType.UnknownNetworkType)
override val resolvedNetworkType = _resolvedNetworkType.asStateFlow()
override val numberOfLevels = MutableStateFlow(MobileConnectionRepository.DEFAULT_NUM_LEVELS)
override val dataEnabled = MutableStateFlow(true)
override val cdmaRoaming = MutableStateFlow(false)
override val networkName = MutableStateFlow(NetworkNameModel.IntentDerived("demo network"))
/**
* Process a new demo mobile event. Note that [resolvedNetworkType] must be passed in separately
* from the event, due to the requirement to reverse the mobile mappings lookup in the top-level
* repository.
*/
fun processDemoMobileEvent(
event: FakeNetworkEventModel.Mobile,
resolvedNetworkType: ResolvedNetworkType,
) {
// This is always true here, because we split out disabled states at the data-source level
dataEnabled.value = true
networkName.value = NetworkNameModel.IntentDerived(event.name)
cdmaRoaming.value = event.roaming
_isRoaming.value = event.roaming
// TODO(b/261029387): not yet supported
_isEmergencyOnly.value = false
_operatorAlphaShort.value = event.name
_isInService.value = (event.level ?: 0) > 0
// TODO(b/261029387): not yet supported
_isGsm.value = false
_cdmaLevel.value = event.level ?: 0
_primaryLevel.value = event.level ?: 0
// TODO(b/261029387): not yet supported
_dataConnectionState.value = DataConnectionState.Connected
_dataActivityDirection.value =
(event.activity ?: TelephonyManager.DATA_ACTIVITY_NONE).toMobileDataActivityModel()
_carrierNetworkChangeActive.value = event.carrierNetworkChange
_resolvedNetworkType.value = resolvedNetworkType
}
fun processCarrierMergedEvent(event: FakeWifiEventModel.CarrierMerged) {
// This is always true here, because we split out disabled states at the data-source level
dataEnabled.value = true
networkName.value = NetworkNameModel.IntentDerived(CARRIER_MERGED_NAME)
numberOfLevels.value = event.numberOfLevels
cdmaRoaming.value = false
_primaryLevel.value = event.level
_cdmaLevel.value = event.level
_dataActivityDirection.value = event.activity.toMobileDataActivityModel()
// These fields are always the same for carrier-merged networks
_resolvedNetworkType.value = ResolvedNetworkType.CarrierMergedNetworkType
_dataConnectionState.value = DataConnectionState.Connected
_isRoaming.value = false
_isEmergencyOnly.value = false
_operatorAlphaShort.value = null
_isInService.value = true
_isGsm.value = false
_carrierNetworkChangeActive.value = false
}
companion object {
private const val CARRIER_MERGED_NAME = "Carrier Merged Network"
}
}

View File

@@ -35,8 +35,11 @@ import com.android.systemui.util.mockito.whenever
import com.android.systemui.util.time.FakeSystemClock
import com.google.common.truth.Truth.assertThat
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.Job
import kotlinx.coroutines.cancel
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.collect
import kotlinx.coroutines.launch
import kotlinx.coroutines.test.TestScope
import kotlinx.coroutines.test.UnconfinedTestDispatcher
import kotlinx.coroutines.test.runTest
@@ -122,10 +125,25 @@ internal class DemoMobileConnectionParameterizedTest(private val testCase: TestC
assertConnection(underTest, networkModel)
}
private fun assertConnection(
private fun TestScope.startCollection(conn: DemoMobileConnectionRepository): Job {
val job = launch {
launch { conn.cdmaLevel.collect {} }
launch { conn.primaryLevel.collect {} }
launch { conn.dataActivityDirection.collect {} }
launch { conn.carrierNetworkChangeActive.collect {} }
launch { conn.isRoaming.collect {} }
launch { conn.networkName.collect {} }
launch { conn.isEmergencyOnly.collect {} }
launch { conn.dataConnectionState.collect {} }
}
return job
}
private fun TestScope.assertConnection(
conn: DemoMobileConnectionRepository,
model: FakeNetworkEventModel
) {
val job = startCollection(underTest)
when (model) {
is FakeNetworkEventModel.Mobile -> {
assertThat(conn.subId).isEqualTo(model.subId)
@@ -148,6 +166,8 @@ internal class DemoMobileConnectionParameterizedTest(private val testCase: TestC
// DemoMobileConnectionsRepositoryTest.kt
else -> {}
}
job.cancel()
}
/** Matches [FakeNetworkEventModel] */

View File

@@ -39,9 +39,11 @@ import com.android.systemui.util.time.FakeSystemClock
import com.google.common.truth.Truth.assertThat
import junit.framework.Assert
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.Job
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.onEach
import kotlinx.coroutines.launch
import kotlinx.coroutines.test.TestScope
import kotlinx.coroutines.test.UnconfinedTestDispatcher
import kotlinx.coroutines.test.runTest
@@ -523,10 +525,27 @@ class DemoMobileConnectionsRepositoryTest : SysuiTestCase() {
job.cancel()
}
private fun assertConnection(
private fun TestScope.startCollection(conn: DemoMobileConnectionRepository): Job {
val job = launch {
launch { conn.cdmaLevel.collect {} }
launch { conn.primaryLevel.collect {} }
launch { conn.dataActivityDirection.collect {} }
launch { conn.carrierNetworkChangeActive.collect {} }
launch { conn.isRoaming.collect {} }
launch { conn.networkName.collect {} }
launch { conn.isEmergencyOnly.collect {} }
launch { conn.dataConnectionState.collect {} }
}
return job
}
private fun TestScope.assertConnection(
conn: DemoMobileConnectionRepository,
model: FakeNetworkEventModel,
) {
val job = startCollection(conn)
// Assert the fields using the `MutableStateFlow` so that we don't have to start up
// a collector for every field for every test
when (model) {
is FakeNetworkEventModel.Mobile -> {
assertThat(conn.subId).isEqualTo(model.subId)
@@ -547,12 +566,15 @@ class DemoMobileConnectionsRepositoryTest : SysuiTestCase() {
}
else -> {}
}
job.cancel()
}
private fun assertCarrierMergedConnection(
private fun TestScope.assertCarrierMergedConnection(
conn: DemoMobileConnectionRepository,
model: FakeWifiEventModel.CarrierMerged,
) {
val job = startCollection(conn)
assertThat(conn.subId).isEqualTo(model.subscriptionId)
assertThat(conn.cdmaLevel.value).isEqualTo(model.level)
assertThat(conn.primaryLevel.value).isEqualTo(model.level)
@@ -561,6 +583,7 @@ class DemoMobileConnectionsRepositoryTest : SysuiTestCase() {
assertThat(conn.isEmergencyOnly.value).isFalse()
assertThat(conn.isGsm.value).isFalse()
assertThat(conn.dataConnectionState.value).isEqualTo(DataConnectionState.Connected)
job.cancel()
}
}