Merge changes I9414c0b2,I649b9198 into tm-qpr-dev am: aa972051b0
Original change: https://googleplex-android-review.googlesource.com/c/platform/frameworks/base/+/20855888 Change-Id: I481e4d25d72536f7829b9d3da9bd9f7e6cfb1196 Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
This commit is contained in:
@@ -17,6 +17,8 @@
|
|||||||
package com.android.systemui.statusbar.pipeline.mobile.data.model
|
package com.android.systemui.statusbar.pipeline.mobile.data.model
|
||||||
|
|
||||||
import android.telephony.Annotation.NetworkType
|
import android.telephony.Annotation.NetworkType
|
||||||
|
import com.android.settingslib.SignalIcon
|
||||||
|
import com.android.settingslib.mobile.TelephonyIcons
|
||||||
import com.android.systemui.statusbar.pipeline.mobile.util.MobileMappingsProxy
|
import com.android.systemui.statusbar.pipeline.mobile.util.MobileMappingsProxy
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -38,4 +40,12 @@ sealed interface ResolvedNetworkType {
|
|||||||
data class OverrideNetworkType(
|
data class OverrideNetworkType(
|
||||||
override val lookupKey: String,
|
override val lookupKey: String,
|
||||||
) : ResolvedNetworkType
|
) : ResolvedNetworkType
|
||||||
|
|
||||||
|
/** Represents the carrier merged network. See [CarrierMergedConnectionRepository]. */
|
||||||
|
object CarrierMergedNetworkType : ResolvedNetworkType {
|
||||||
|
// Effectively unused since [iconGroupOverride] is used instead.
|
||||||
|
override val lookupKey: String = "cwf"
|
||||||
|
|
||||||
|
val iconGroupOverride: SignalIcon.MobileIconGroup = TelephonyIcons.CARRIER_MERGED_WIFI
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -22,7 +22,6 @@ import android.telephony.TelephonyManager
|
|||||||
import com.android.systemui.log.table.TableLogBuffer
|
import com.android.systemui.log.table.TableLogBuffer
|
||||||
import com.android.systemui.statusbar.pipeline.mobile.data.model.MobileConnectionModel
|
import com.android.systemui.statusbar.pipeline.mobile.data.model.MobileConnectionModel
|
||||||
import com.android.systemui.statusbar.pipeline.mobile.data.model.NetworkNameModel
|
import com.android.systemui.statusbar.pipeline.mobile.data.model.NetworkNameModel
|
||||||
import kotlinx.coroutines.flow.Flow
|
|
||||||
import kotlinx.coroutines.flow.StateFlow
|
import kotlinx.coroutines.flow.StateFlow
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -50,7 +49,7 @@ interface MobileConnectionRepository {
|
|||||||
* A flow that aggregates all necessary callbacks from [TelephonyCallback] into a single
|
* A flow that aggregates all necessary callbacks from [TelephonyCallback] into a single
|
||||||
* listener + model.
|
* listener + model.
|
||||||
*/
|
*/
|
||||||
val connectionInfo: Flow<MobileConnectionModel>
|
val connectionInfo: StateFlow<MobileConnectionModel>
|
||||||
|
|
||||||
/** The total number of levels. Used with [SignalDrawable]. */
|
/** The total number of levels. Used with [SignalDrawable]. */
|
||||||
val numberOfLevels: StateFlow<Int>
|
val numberOfLevels: StateFlow<Int>
|
||||||
|
|||||||
@@ -39,7 +39,11 @@ import com.android.systemui.statusbar.pipeline.mobile.data.repository.MobileConn
|
|||||||
import com.android.systemui.statusbar.pipeline.mobile.data.repository.demo.model.FakeNetworkEventModel
|
import com.android.systemui.statusbar.pipeline.mobile.data.repository.demo.model.FakeNetworkEventModel
|
||||||
import com.android.systemui.statusbar.pipeline.mobile.data.repository.demo.model.FakeNetworkEventModel.Mobile
|
import com.android.systemui.statusbar.pipeline.mobile.data.repository.demo.model.FakeNetworkEventModel.Mobile
|
||||||
import com.android.systemui.statusbar.pipeline.mobile.data.repository.demo.model.FakeNetworkEventModel.MobileDisabled
|
import com.android.systemui.statusbar.pipeline.mobile.data.repository.demo.model.FakeNetworkEventModel.MobileDisabled
|
||||||
|
import com.android.systemui.statusbar.pipeline.mobile.data.repository.prod.CarrierMergedConnectionRepository.Companion.createCarrierMergedConnectionModel
|
||||||
|
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.toMobileDataActivityModel
|
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
|
import javax.inject.Inject
|
||||||
import kotlinx.coroutines.CoroutineScope
|
import kotlinx.coroutines.CoroutineScope
|
||||||
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
||||||
@@ -60,15 +64,19 @@ import kotlinx.coroutines.launch
|
|||||||
class DemoMobileConnectionsRepository
|
class DemoMobileConnectionsRepository
|
||||||
@Inject
|
@Inject
|
||||||
constructor(
|
constructor(
|
||||||
private val dataSource: DemoModeMobileConnectionDataSource,
|
private val mobileDataSource: DemoModeMobileConnectionDataSource,
|
||||||
|
private val wifiDataSource: DemoModeWifiDataSource,
|
||||||
@Application private val scope: CoroutineScope,
|
@Application private val scope: CoroutineScope,
|
||||||
context: Context,
|
context: Context,
|
||||||
private val logFactory: TableLogBufferFactory,
|
private val logFactory: TableLogBufferFactory,
|
||||||
) : MobileConnectionsRepository {
|
) : MobileConnectionsRepository {
|
||||||
|
|
||||||
private var demoCommandJob: Job? = null
|
private var mobileDemoCommandJob: Job? = null
|
||||||
|
private var wifiDemoCommandJob: Job? = null
|
||||||
|
|
||||||
private var connectionRepoCache = mutableMapOf<Int, DemoMobileConnectionRepository>()
|
private var carrierMergedSubId: Int? = null
|
||||||
|
|
||||||
|
private var connectionRepoCache = mutableMapOf<Int, CacheContainer>()
|
||||||
private val subscriptionInfoCache = mutableMapOf<Int, SubscriptionModel>()
|
private val subscriptionInfoCache = mutableMapOf<Int, SubscriptionModel>()
|
||||||
val demoModeFinishedEvent = MutableSharedFlow<Unit>(extraBufferCapacity = 1)
|
val demoModeFinishedEvent = MutableSharedFlow<Unit>(extraBufferCapacity = 1)
|
||||||
|
|
||||||
@@ -144,52 +152,83 @@ constructor(
|
|||||||
override val defaultMobileNetworkConnectivity = MutableStateFlow(MobileConnectivityModel())
|
override val defaultMobileNetworkConnectivity = MutableStateFlow(MobileConnectivityModel())
|
||||||
|
|
||||||
override fun getRepoForSubId(subId: Int): DemoMobileConnectionRepository {
|
override fun getRepoForSubId(subId: Int): DemoMobileConnectionRepository {
|
||||||
return connectionRepoCache[subId]
|
val current = connectionRepoCache[subId]?.repo
|
||||||
?: createDemoMobileConnectionRepo(subId).also { connectionRepoCache[subId] = it }
|
if (current != null) {
|
||||||
|
return current
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun createDemoMobileConnectionRepo(subId: Int): DemoMobileConnectionRepository {
|
val new = createDemoMobileConnectionRepo(subId)
|
||||||
val tableLogBuffer = logFactory.getOrCreate("DemoMobileConnectionLog [$subId]", 100)
|
connectionRepoCache[subId] = new
|
||||||
|
return new.repo
|
||||||
|
}
|
||||||
|
|
||||||
return DemoMobileConnectionRepository(
|
private fun createDemoMobileConnectionRepo(subId: Int): CacheContainer {
|
||||||
|
val tableLogBuffer =
|
||||||
|
logFactory.getOrCreate(
|
||||||
|
"DemoMobileConnectionLog [$subId]",
|
||||||
|
MOBILE_CONNECTION_BUFFER_SIZE,
|
||||||
|
)
|
||||||
|
|
||||||
|
val repo =
|
||||||
|
DemoMobileConnectionRepository(
|
||||||
subId,
|
subId,
|
||||||
tableLogBuffer,
|
tableLogBuffer,
|
||||||
)
|
)
|
||||||
|
return CacheContainer(repo, lastMobileState = null)
|
||||||
}
|
}
|
||||||
|
|
||||||
override val globalMobileDataSettingChangedEvent = MutableStateFlow(Unit)
|
override val globalMobileDataSettingChangedEvent = MutableStateFlow(Unit)
|
||||||
|
|
||||||
fun startProcessingCommands() {
|
fun startProcessingCommands() {
|
||||||
demoCommandJob =
|
mobileDemoCommandJob =
|
||||||
scope.launch {
|
scope.launch {
|
||||||
dataSource.mobileEvents.filterNotNull().collect { event -> processEvent(event) }
|
mobileDataSource.mobileEvents.filterNotNull().collect { event ->
|
||||||
|
processMobileEvent(event)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
wifiDemoCommandJob =
|
||||||
|
scope.launch {
|
||||||
|
wifiDataSource.wifiEvents.filterNotNull().collect { event ->
|
||||||
|
processWifiEvent(event)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun stopProcessingCommands() {
|
fun stopProcessingCommands() {
|
||||||
demoCommandJob?.cancel()
|
mobileDemoCommandJob?.cancel()
|
||||||
|
wifiDemoCommandJob?.cancel()
|
||||||
_subscriptions.value = listOf()
|
_subscriptions.value = listOf()
|
||||||
connectionRepoCache.clear()
|
connectionRepoCache.clear()
|
||||||
subscriptionInfoCache.clear()
|
subscriptionInfoCache.clear()
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun processEvent(event: FakeNetworkEventModel) {
|
private fun processMobileEvent(event: FakeNetworkEventModel) {
|
||||||
when (event) {
|
when (event) {
|
||||||
is Mobile -> {
|
is Mobile -> {
|
||||||
processEnabledMobileState(event)
|
processEnabledMobileState(event)
|
||||||
}
|
}
|
||||||
is MobileDisabled -> {
|
is MobileDisabled -> {
|
||||||
processDisabledMobileState(event)
|
maybeRemoveSubscription(event.subId)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun processWifiEvent(event: FakeWifiEventModel) {
|
||||||
|
when (event) {
|
||||||
|
is FakeWifiEventModel.WifiDisabled -> disableCarrierMerged()
|
||||||
|
is FakeWifiEventModel.Wifi -> disableCarrierMerged()
|
||||||
|
is FakeWifiEventModel.CarrierMerged -> processCarrierMergedWifiState(event)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private fun processEnabledMobileState(state: Mobile) {
|
private fun processEnabledMobileState(state: Mobile) {
|
||||||
// get or create the connection repo, and set its values
|
// get or create the connection repo, and set its values
|
||||||
val subId = state.subId ?: DEFAULT_SUB_ID
|
val subId = state.subId ?: DEFAULT_SUB_ID
|
||||||
maybeCreateSubscription(subId)
|
maybeCreateSubscription(subId)
|
||||||
|
|
||||||
val connection = getRepoForSubId(subId)
|
val connection = getRepoForSubId(subId)
|
||||||
|
connectionRepoCache[subId]?.lastMobileState = state
|
||||||
|
|
||||||
// This is always true here, because we split out disabled states at the data-source level
|
// This is always true here, because we split out disabled states at the data-source level
|
||||||
connection.dataEnabled.value = true
|
connection.dataEnabled.value = true
|
||||||
connection.networkName.value = NetworkNameModel.Derived(state.name)
|
connection.networkName.value = NetworkNameModel.Derived(state.name)
|
||||||
@@ -198,14 +237,36 @@ constructor(
|
|||||||
connection.connectionInfo.value = state.toMobileConnectionModel()
|
connection.connectionInfo.value = state.toMobileConnectionModel()
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun processDisabledMobileState(state: MobileDisabled) {
|
private fun processCarrierMergedWifiState(event: FakeWifiEventModel.CarrierMerged) {
|
||||||
|
// The new carrier merged connection is for a different sub ID, so disable carrier merged
|
||||||
|
// for the current (now old) sub
|
||||||
|
if (carrierMergedSubId != event.subscriptionId) {
|
||||||
|
disableCarrierMerged()
|
||||||
|
}
|
||||||
|
|
||||||
|
// get or create the connection repo, and set its values
|
||||||
|
val subId = event.subscriptionId
|
||||||
|
maybeCreateSubscription(subId)
|
||||||
|
carrierMergedSubId = subId
|
||||||
|
|
||||||
|
val connection = getRepoForSubId(subId)
|
||||||
|
// This is always true here, because we split out disabled states at the data-source level
|
||||||
|
connection.dataEnabled.value = true
|
||||||
|
connection.networkName.value = NetworkNameModel.Derived(CARRIER_MERGED_NAME)
|
||||||
|
connection.numberOfLevels.value = event.numberOfLevels
|
||||||
|
connection.cdmaRoaming.value = false
|
||||||
|
connection.connectionInfo.value = event.toMobileConnectionModel()
|
||||||
|
Log.e("CCS", "output connection info = ${connection.connectionInfo.value}")
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun maybeRemoveSubscription(subId: Int?) {
|
||||||
if (_subscriptions.value.isEmpty()) {
|
if (_subscriptions.value.isEmpty()) {
|
||||||
// Nothing to do here
|
// Nothing to do here
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
val subId =
|
val finalSubId =
|
||||||
state.subId
|
subId
|
||||||
?: run {
|
?: run {
|
||||||
// For sake of usability, we can allow for no subId arg if there is only one
|
// For sake of usability, we can allow for no subId arg if there is only one
|
||||||
// subscription
|
// subscription
|
||||||
@@ -223,7 +284,21 @@ constructor(
|
|||||||
_subscriptions.value[0].subscriptionId
|
_subscriptions.value[0].subscriptionId
|
||||||
}
|
}
|
||||||
|
|
||||||
removeSubscription(subId)
|
removeSubscription(finalSubId)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun disableCarrierMerged() {
|
||||||
|
val currentCarrierMergedSubId = carrierMergedSubId ?: return
|
||||||
|
|
||||||
|
// If this sub ID was previously not carrier merged, we should reset it to its previous
|
||||||
|
// connection.
|
||||||
|
val lastMobileState = connectionRepoCache[carrierMergedSubId]?.lastMobileState
|
||||||
|
if (lastMobileState != null) {
|
||||||
|
processEnabledMobileState(lastMobileState)
|
||||||
|
} else {
|
||||||
|
// Otherwise, just remove the subscription entirely
|
||||||
|
removeSubscription(currentCarrierMergedSubId)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun removeSubscription(subId: Int) {
|
private fun removeSubscription(subId: Int) {
|
||||||
@@ -251,6 +326,10 @@ constructor(
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun FakeWifiEventModel.CarrierMerged.toMobileConnectionModel(): MobileConnectionModel {
|
||||||
|
return createCarrierMergedConnectionModel(this.level)
|
||||||
|
}
|
||||||
|
|
||||||
private fun SignalIcon.MobileIconGroup?.toResolvedNetworkType(): ResolvedNetworkType {
|
private fun SignalIcon.MobileIconGroup?.toResolvedNetworkType(): ResolvedNetworkType {
|
||||||
val key = mobileMappingsReverseLookup.value[this] ?: "dis"
|
val key = mobileMappingsReverseLookup.value[this] ?: "dis"
|
||||||
return DefaultNetworkType(key)
|
return DefaultNetworkType(key)
|
||||||
@@ -260,9 +339,17 @@ constructor(
|
|||||||
private const val TAG = "DemoMobileConnectionsRepo"
|
private const val TAG = "DemoMobileConnectionsRepo"
|
||||||
|
|
||||||
private const val DEFAULT_SUB_ID = 1
|
private const val DEFAULT_SUB_ID = 1
|
||||||
|
|
||||||
|
private const val CARRIER_MERGED_NAME = "Carrier Merged Network"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class CacheContainer(
|
||||||
|
var repo: DemoMobileConnectionRepository,
|
||||||
|
/** The last received [Mobile] event. Used when switching from carrier merged back to mobile. */
|
||||||
|
var lastMobileState: Mobile?,
|
||||||
|
)
|
||||||
|
|
||||||
class DemoMobileConnectionRepository(
|
class DemoMobileConnectionRepository(
|
||||||
override val subId: Int,
|
override val subId: Int,
|
||||||
override val tableLogBuffer: TableLogBuffer,
|
override val tableLogBuffer: TableLogBuffer,
|
||||||
|
|||||||
@@ -0,0 +1,181 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2022 The Android Open Source Project
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.android.systemui.statusbar.pipeline.mobile.data.repository.prod
|
||||||
|
|
||||||
|
import android.util.Log
|
||||||
|
import com.android.systemui.dagger.SysUISingleton
|
||||||
|
import com.android.systemui.dagger.qualifiers.Application
|
||||||
|
import com.android.systemui.log.table.TableLogBuffer
|
||||||
|
import com.android.systemui.statusbar.pipeline.mobile.data.model.DataConnectionState
|
||||||
|
import com.android.systemui.statusbar.pipeline.mobile.data.model.MobileConnectionModel
|
||||||
|
import com.android.systemui.statusbar.pipeline.mobile.data.model.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.MobileConnectionRepository.Companion.DEFAULT_NUM_LEVELS
|
||||||
|
import com.android.systemui.statusbar.pipeline.shared.data.model.DataActivityModel
|
||||||
|
import com.android.systemui.statusbar.pipeline.wifi.data.model.WifiNetworkModel
|
||||||
|
import com.android.systemui.statusbar.pipeline.wifi.data.repository.WifiRepository
|
||||||
|
import javax.inject.Inject
|
||||||
|
import kotlinx.coroutines.CoroutineScope
|
||||||
|
import kotlinx.coroutines.flow.Flow
|
||||||
|
import kotlinx.coroutines.flow.MutableStateFlow
|
||||||
|
import kotlinx.coroutines.flow.SharingStarted
|
||||||
|
import kotlinx.coroutines.flow.StateFlow
|
||||||
|
import kotlinx.coroutines.flow.asStateFlow
|
||||||
|
import kotlinx.coroutines.flow.combine
|
||||||
|
import kotlinx.coroutines.flow.flowOf
|
||||||
|
import kotlinx.coroutines.flow.map
|
||||||
|
import kotlinx.coroutines.flow.stateIn
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A repository implementation for a carrier merged (aka VCN) network. A carrier merged network is
|
||||||
|
* delivered to SysUI as a wifi network (see [WifiNetworkModel.CarrierMerged], but is visually
|
||||||
|
* displayed as a mobile network triangle.
|
||||||
|
*
|
||||||
|
* See [android.net.wifi.WifiInfo.isCarrierMerged] for more information.
|
||||||
|
*
|
||||||
|
* See [MobileConnectionRepositoryImpl] for a repository implementation of a typical mobile
|
||||||
|
* connection.
|
||||||
|
*/
|
||||||
|
class CarrierMergedConnectionRepository(
|
||||||
|
override val subId: Int,
|
||||||
|
override val tableLogBuffer: TableLogBuffer,
|
||||||
|
defaultNetworkName: NetworkNameModel,
|
||||||
|
@Application private val scope: CoroutineScope,
|
||||||
|
val wifiRepository: WifiRepository,
|
||||||
|
) : MobileConnectionRepository {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Outputs the carrier merged network to use, or null if we don't have a valid carrier merged
|
||||||
|
* network.
|
||||||
|
*/
|
||||||
|
private val network: Flow<WifiNetworkModel.CarrierMerged?> =
|
||||||
|
combine(
|
||||||
|
wifiRepository.isWifiEnabled,
|
||||||
|
wifiRepository.isWifiDefault,
|
||||||
|
wifiRepository.wifiNetwork,
|
||||||
|
) { isEnabled, isDefault, network ->
|
||||||
|
when {
|
||||||
|
!isEnabled -> null
|
||||||
|
!isDefault -> null
|
||||||
|
network !is WifiNetworkModel.CarrierMerged -> null
|
||||||
|
network.subscriptionId != subId -> {
|
||||||
|
Log.w(
|
||||||
|
TAG,
|
||||||
|
"Connection repo subId=$subId " +
|
||||||
|
"does not equal wifi repo subId=${network.subscriptionId}; " +
|
||||||
|
"not showing carrier merged"
|
||||||
|
)
|
||||||
|
null
|
||||||
|
}
|
||||||
|
else -> network
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override val connectionInfo: StateFlow<MobileConnectionModel> =
|
||||||
|
network
|
||||||
|
.map { it.toMobileConnectionModel() }
|
||||||
|
.stateIn(scope, SharingStarted.WhileSubscribed(), MobileConnectionModel())
|
||||||
|
|
||||||
|
// TODO(b/238425913): Add logging to this class.
|
||||||
|
// TODO(b/238425913): Make sure SignalStrength.getEmptyState is used when appropriate.
|
||||||
|
|
||||||
|
// Carrier merged is never roaming.
|
||||||
|
override val cdmaRoaming: StateFlow<Boolean> = MutableStateFlow(false).asStateFlow()
|
||||||
|
|
||||||
|
// TODO(b/238425913): Fetch the carrier merged network name.
|
||||||
|
override val networkName: StateFlow<NetworkNameModel> =
|
||||||
|
flowOf(defaultNetworkName)
|
||||||
|
.stateIn(scope, SharingStarted.WhileSubscribed(), defaultNetworkName)
|
||||||
|
|
||||||
|
override val numberOfLevels: StateFlow<Int> =
|
||||||
|
wifiRepository.wifiNetwork
|
||||||
|
.map {
|
||||||
|
if (it is WifiNetworkModel.CarrierMerged) {
|
||||||
|
it.numberOfLevels
|
||||||
|
} else {
|
||||||
|
DEFAULT_NUM_LEVELS
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.stateIn(scope, SharingStarted.WhileSubscribed(), DEFAULT_NUM_LEVELS)
|
||||||
|
|
||||||
|
override val dataEnabled: StateFlow<Boolean> = wifiRepository.isWifiEnabled
|
||||||
|
|
||||||
|
private fun WifiNetworkModel.CarrierMerged?.toMobileConnectionModel(): MobileConnectionModel {
|
||||||
|
if (this == null) {
|
||||||
|
return MobileConnectionModel()
|
||||||
|
}
|
||||||
|
|
||||||
|
return createCarrierMergedConnectionModel(level)
|
||||||
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
/**
|
||||||
|
* Creates an instance of [MobileConnectionModel] that represents a carrier merged network
|
||||||
|
* with the given [level].
|
||||||
|
*/
|
||||||
|
fun createCarrierMergedConnectionModel(level: Int): MobileConnectionModel {
|
||||||
|
return MobileConnectionModel(
|
||||||
|
primaryLevel = level,
|
||||||
|
cdmaLevel = level,
|
||||||
|
// A [WifiNetworkModel.CarrierMerged] instance is always connected.
|
||||||
|
// (A [WifiNetworkModel.Inactive] represents a disconnected network.)
|
||||||
|
dataConnectionState = DataConnectionState.Connected,
|
||||||
|
// TODO(b/238425913): This should come from [WifiRepository.wifiActivity].
|
||||||
|
dataActivityDirection =
|
||||||
|
DataActivityModel(
|
||||||
|
hasActivityIn = false,
|
||||||
|
hasActivityOut = false,
|
||||||
|
),
|
||||||
|
resolvedNetworkType = ResolvedNetworkType.CarrierMergedNetworkType,
|
||||||
|
// Carrier merged is never roaming
|
||||||
|
isRoaming = false,
|
||||||
|
|
||||||
|
// TODO(b/238425913): Verify that these fields never change for carrier merged.
|
||||||
|
isEmergencyOnly = false,
|
||||||
|
operatorAlphaShort = null,
|
||||||
|
isInService = true,
|
||||||
|
isGsm = false,
|
||||||
|
carrierNetworkChangeActive = false,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@SysUISingleton
|
||||||
|
class Factory
|
||||||
|
@Inject
|
||||||
|
constructor(
|
||||||
|
@Application private val scope: CoroutineScope,
|
||||||
|
private val wifiRepository: WifiRepository,
|
||||||
|
) {
|
||||||
|
fun build(
|
||||||
|
subId: Int,
|
||||||
|
mobileLogger: TableLogBuffer,
|
||||||
|
defaultNetworkName: NetworkNameModel,
|
||||||
|
): MobileConnectionRepository {
|
||||||
|
return CarrierMergedConnectionRepository(
|
||||||
|
subId,
|
||||||
|
mobileLogger,
|
||||||
|
defaultNetworkName,
|
||||||
|
scope,
|
||||||
|
wifiRepository,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private const val TAG = "CarrierMergedConnectionRepository"
|
||||||
@@ -0,0 +1,179 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2022 The Android Open Source Project
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.android.systemui.statusbar.pipeline.mobile.data.repository.prod
|
||||||
|
|
||||||
|
import androidx.annotation.VisibleForTesting
|
||||||
|
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.log.table.logDiffsForTable
|
||||||
|
import com.android.systemui.statusbar.pipeline.mobile.data.model.NetworkNameModel
|
||||||
|
import com.android.systemui.statusbar.pipeline.mobile.data.repository.MobileConnectionRepository
|
||||||
|
import javax.inject.Inject
|
||||||
|
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
|
||||||
|
import kotlinx.coroutines.flow.flatMapLatest
|
||||||
|
import kotlinx.coroutines.flow.mapLatest
|
||||||
|
import kotlinx.coroutines.flow.stateIn
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A repository that fully implements a mobile connection.
|
||||||
|
*
|
||||||
|
* This connection could either be a typical mobile connection (see [MobileConnectionRepositoryImpl]
|
||||||
|
* or a carrier merged connection (see [CarrierMergedConnectionRepository]). This repository
|
||||||
|
* switches between the two types of connections based on whether the connection is currently
|
||||||
|
* carrier merged (see [setIsCarrierMerged]).
|
||||||
|
*/
|
||||||
|
@Suppress("EXPERIMENTAL_IS_NOT_ENABLED")
|
||||||
|
@OptIn(ExperimentalCoroutinesApi::class)
|
||||||
|
class FullMobileConnectionRepository(
|
||||||
|
override val subId: Int,
|
||||||
|
startingIsCarrierMerged: Boolean,
|
||||||
|
override val tableLogBuffer: TableLogBuffer,
|
||||||
|
private val defaultNetworkName: NetworkNameModel,
|
||||||
|
private val networkNameSeparator: String,
|
||||||
|
private val globalMobileDataSettingChangedEvent: Flow<Unit>,
|
||||||
|
@Application scope: CoroutineScope,
|
||||||
|
private val mobileRepoFactory: MobileConnectionRepositoryImpl.Factory,
|
||||||
|
private val carrierMergedRepoFactory: CarrierMergedConnectionRepository.Factory,
|
||||||
|
) : MobileConnectionRepository {
|
||||||
|
/**
|
||||||
|
* Sets whether this connection is a typical mobile connection or a carrier merged connection.
|
||||||
|
*/
|
||||||
|
fun setIsCarrierMerged(isCarrierMerged: Boolean) {
|
||||||
|
_isCarrierMerged.value = isCarrierMerged
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns true if this repo is currently for a carrier merged connection and false otherwise.
|
||||||
|
*/
|
||||||
|
@VisibleForTesting fun getIsCarrierMerged() = _isCarrierMerged.value
|
||||||
|
|
||||||
|
private val _isCarrierMerged = MutableStateFlow(startingIsCarrierMerged)
|
||||||
|
private val isCarrierMerged: StateFlow<Boolean> =
|
||||||
|
_isCarrierMerged
|
||||||
|
.logDiffsForTable(
|
||||||
|
tableLogBuffer,
|
||||||
|
columnPrefix = "",
|
||||||
|
columnName = "isCarrierMerged",
|
||||||
|
initialValue = startingIsCarrierMerged,
|
||||||
|
)
|
||||||
|
.stateIn(scope, SharingStarted.WhileSubscribed(), startingIsCarrierMerged)
|
||||||
|
|
||||||
|
private val mobileRepo: MobileConnectionRepository by lazy {
|
||||||
|
mobileRepoFactory.build(
|
||||||
|
subId,
|
||||||
|
tableLogBuffer,
|
||||||
|
defaultNetworkName,
|
||||||
|
networkNameSeparator,
|
||||||
|
globalMobileDataSettingChangedEvent,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
private val carrierMergedRepo: MobileConnectionRepository by lazy {
|
||||||
|
carrierMergedRepoFactory.build(subId, tableLogBuffer, defaultNetworkName)
|
||||||
|
}
|
||||||
|
|
||||||
|
@VisibleForTesting
|
||||||
|
internal val activeRepo: StateFlow<MobileConnectionRepository> = run {
|
||||||
|
val initial =
|
||||||
|
if (startingIsCarrierMerged) {
|
||||||
|
carrierMergedRepo
|
||||||
|
} else {
|
||||||
|
mobileRepo
|
||||||
|
}
|
||||||
|
|
||||||
|
this.isCarrierMerged
|
||||||
|
.mapLatest { isCarrierMerged ->
|
||||||
|
if (isCarrierMerged) {
|
||||||
|
carrierMergedRepo
|
||||||
|
} else {
|
||||||
|
mobileRepo
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.stateIn(scope, SharingStarted.WhileSubscribed(), initial)
|
||||||
|
}
|
||||||
|
|
||||||
|
override val cdmaRoaming =
|
||||||
|
activeRepo
|
||||||
|
.flatMapLatest { it.cdmaRoaming }
|
||||||
|
.stateIn(scope, SharingStarted.WhileSubscribed(), activeRepo.value.cdmaRoaming.value)
|
||||||
|
|
||||||
|
override val connectionInfo =
|
||||||
|
activeRepo
|
||||||
|
.flatMapLatest { it.connectionInfo }
|
||||||
|
.stateIn(scope, SharingStarted.WhileSubscribed(), activeRepo.value.connectionInfo.value)
|
||||||
|
|
||||||
|
override val dataEnabled =
|
||||||
|
activeRepo
|
||||||
|
.flatMapLatest { it.dataEnabled }
|
||||||
|
.stateIn(scope, SharingStarted.WhileSubscribed(), activeRepo.value.dataEnabled.value)
|
||||||
|
|
||||||
|
override val numberOfLevels =
|
||||||
|
activeRepo
|
||||||
|
.flatMapLatest { it.numberOfLevels }
|
||||||
|
.stateIn(scope, SharingStarted.WhileSubscribed(), activeRepo.value.numberOfLevels.value)
|
||||||
|
|
||||||
|
override val networkName =
|
||||||
|
activeRepo
|
||||||
|
.flatMapLatest { it.networkName }
|
||||||
|
.stateIn(scope, SharingStarted.WhileSubscribed(), activeRepo.value.networkName.value)
|
||||||
|
|
||||||
|
class Factory
|
||||||
|
@Inject
|
||||||
|
constructor(
|
||||||
|
@Application private val scope: CoroutineScope,
|
||||||
|
private val logFactory: TableLogBufferFactory,
|
||||||
|
private val mobileRepoFactory: MobileConnectionRepositoryImpl.Factory,
|
||||||
|
private val carrierMergedRepoFactory: CarrierMergedConnectionRepository.Factory,
|
||||||
|
) {
|
||||||
|
fun build(
|
||||||
|
subId: Int,
|
||||||
|
startingIsCarrierMerged: Boolean,
|
||||||
|
defaultNetworkName: NetworkNameModel,
|
||||||
|
networkNameSeparator: String,
|
||||||
|
globalMobileDataSettingChangedEvent: Flow<Unit>,
|
||||||
|
): FullMobileConnectionRepository {
|
||||||
|
val mobileLogger =
|
||||||
|
logFactory.getOrCreate(tableBufferLogName(subId), MOBILE_CONNECTION_BUFFER_SIZE)
|
||||||
|
|
||||||
|
return FullMobileConnectionRepository(
|
||||||
|
subId,
|
||||||
|
startingIsCarrierMerged,
|
||||||
|
mobileLogger,
|
||||||
|
defaultNetworkName,
|
||||||
|
networkNameSeparator,
|
||||||
|
globalMobileDataSettingChangedEvent,
|
||||||
|
scope,
|
||||||
|
mobileRepoFactory,
|
||||||
|
carrierMergedRepoFactory,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
/** The buffer size to use for logging. */
|
||||||
|
const val MOBILE_CONNECTION_BUFFER_SIZE = 100
|
||||||
|
|
||||||
|
/** Returns a log buffer name for a mobile connection with the given [subId]. */
|
||||||
|
fun tableBufferLogName(subId: Int): String = "MobileConnectionLog [$subId]"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -38,7 +38,6 @@ import com.android.systemui.common.coroutine.ConflatedCallbackFlow.conflatedCall
|
|||||||
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
|
||||||
import com.android.systemui.log.table.TableLogBufferFactory
|
|
||||||
import com.android.systemui.log.table.logDiffsForTable
|
import com.android.systemui.log.table.logDiffsForTable
|
||||||
import com.android.systemui.statusbar.pipeline.mobile.data.model.MobileConnectionModel
|
import com.android.systemui.statusbar.pipeline.mobile.data.model.MobileConnectionModel
|
||||||
import com.android.systemui.statusbar.pipeline.mobile.data.model.NetworkNameModel
|
import com.android.systemui.statusbar.pipeline.mobile.data.model.NetworkNameModel
|
||||||
@@ -70,6 +69,10 @@ import kotlinx.coroutines.flow.merge
|
|||||||
import kotlinx.coroutines.flow.onEach
|
import kotlinx.coroutines.flow.onEach
|
||||||
import kotlinx.coroutines.flow.stateIn
|
import kotlinx.coroutines.flow.stateIn
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A repository implementation for a typical mobile connection (as opposed to a carrier merged
|
||||||
|
* connection -- see [CarrierMergedConnectionRepository]).
|
||||||
|
*/
|
||||||
@Suppress("EXPERIMENTAL_IS_NOT_ENABLED")
|
@Suppress("EXPERIMENTAL_IS_NOT_ENABLED")
|
||||||
@OptIn(ExperimentalCoroutinesApi::class)
|
@OptIn(ExperimentalCoroutinesApi::class)
|
||||||
class MobileConnectionRepositoryImpl(
|
class MobileConnectionRepositoryImpl(
|
||||||
@@ -298,18 +301,16 @@ class MobileConnectionRepositoryImpl(
|
|||||||
private val logger: ConnectivityPipelineLogger,
|
private val logger: ConnectivityPipelineLogger,
|
||||||
private val globalSettings: GlobalSettings,
|
private val globalSettings: GlobalSettings,
|
||||||
private val mobileMappingsProxy: MobileMappingsProxy,
|
private val mobileMappingsProxy: MobileMappingsProxy,
|
||||||
private val logFactory: TableLogBufferFactory,
|
|
||||||
@Background private val bgDispatcher: CoroutineDispatcher,
|
@Background private val bgDispatcher: CoroutineDispatcher,
|
||||||
@Application private val scope: CoroutineScope,
|
@Application private val scope: CoroutineScope,
|
||||||
) {
|
) {
|
||||||
fun build(
|
fun build(
|
||||||
subId: Int,
|
subId: Int,
|
||||||
|
mobileLogger: TableLogBuffer,
|
||||||
defaultNetworkName: NetworkNameModel,
|
defaultNetworkName: NetworkNameModel,
|
||||||
networkNameSeparator: String,
|
networkNameSeparator: String,
|
||||||
globalMobileDataSettingChangedEvent: Flow<Unit>,
|
globalMobileDataSettingChangedEvent: Flow<Unit>,
|
||||||
): MobileConnectionRepository {
|
): MobileConnectionRepository {
|
||||||
val mobileLogger = logFactory.getOrCreate(tableBufferLogName(subId), 100)
|
|
||||||
|
|
||||||
return MobileConnectionRepositoryImpl(
|
return MobileConnectionRepositoryImpl(
|
||||||
context,
|
context,
|
||||||
subId,
|
subId,
|
||||||
@@ -327,8 +328,4 @@ class MobileConnectionRepositoryImpl(
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
companion object {
|
|
||||||
fun tableBufferLogName(subId: Int): String = "MobileConnectionLog [$subId]"
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -46,11 +46,12 @@ import com.android.systemui.dagger.qualifiers.Background
|
|||||||
import com.android.systemui.statusbar.pipeline.mobile.data.model.MobileConnectivityModel
|
import com.android.systemui.statusbar.pipeline.mobile.data.model.MobileConnectivityModel
|
||||||
import com.android.systemui.statusbar.pipeline.mobile.data.model.NetworkNameModel
|
import com.android.systemui.statusbar.pipeline.mobile.data.model.NetworkNameModel
|
||||||
import com.android.systemui.statusbar.pipeline.mobile.data.model.SubscriptionModel
|
import com.android.systemui.statusbar.pipeline.mobile.data.model.SubscriptionModel
|
||||||
import com.android.systemui.statusbar.pipeline.mobile.data.repository.MobileConnectionRepository
|
|
||||||
import com.android.systemui.statusbar.pipeline.mobile.data.repository.MobileConnectionsRepository
|
import com.android.systemui.statusbar.pipeline.mobile.data.repository.MobileConnectionsRepository
|
||||||
import com.android.systemui.statusbar.pipeline.mobile.util.MobileMappingsProxy
|
import com.android.systemui.statusbar.pipeline.mobile.util.MobileMappingsProxy
|
||||||
import com.android.systemui.statusbar.pipeline.shared.ConnectivityPipelineLogger
|
import com.android.systemui.statusbar.pipeline.shared.ConnectivityPipelineLogger
|
||||||
import com.android.systemui.statusbar.pipeline.shared.ConnectivityPipelineLogger.Companion.logInputChange
|
import com.android.systemui.statusbar.pipeline.shared.ConnectivityPipelineLogger.Companion.logInputChange
|
||||||
|
import com.android.systemui.statusbar.pipeline.wifi.data.model.WifiNetworkModel
|
||||||
|
import com.android.systemui.statusbar.pipeline.wifi.data.repository.WifiRepository
|
||||||
import com.android.systemui.util.settings.GlobalSettings
|
import com.android.systemui.util.settings.GlobalSettings
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
import kotlinx.coroutines.CoroutineDispatcher
|
import kotlinx.coroutines.CoroutineDispatcher
|
||||||
@@ -85,9 +86,14 @@ constructor(
|
|||||||
private val context: Context,
|
private val context: Context,
|
||||||
@Background private val bgDispatcher: CoroutineDispatcher,
|
@Background private val bgDispatcher: CoroutineDispatcher,
|
||||||
@Application private val scope: CoroutineScope,
|
@Application private val scope: CoroutineScope,
|
||||||
private val mobileConnectionRepositoryFactory: MobileConnectionRepositoryImpl.Factory
|
// Some "wifi networks" should be rendered as a mobile connection, which is why the wifi
|
||||||
|
// repository is an input to the mobile repository.
|
||||||
|
// See [CarrierMergedConnectionRepository] for details.
|
||||||
|
wifiRepository: WifiRepository,
|
||||||
|
private val fullMobileRepoFactory: FullMobileConnectionRepository.Factory,
|
||||||
) : MobileConnectionsRepository {
|
) : MobileConnectionsRepository {
|
||||||
private var subIdRepositoryCache: MutableMap<Int, MobileConnectionRepository> = mutableMapOf()
|
private var subIdRepositoryCache: MutableMap<Int, FullMobileConnectionRepository> =
|
||||||
|
mutableMapOf()
|
||||||
|
|
||||||
private val defaultNetworkName =
|
private val defaultNetworkName =
|
||||||
NetworkNameModel.Default(
|
NetworkNameModel.Default(
|
||||||
@@ -97,13 +103,19 @@ constructor(
|
|||||||
private val networkNameSeparator: String =
|
private val networkNameSeparator: String =
|
||||||
context.getString(R.string.status_bar_network_name_separator)
|
context.getString(R.string.status_bar_network_name_separator)
|
||||||
|
|
||||||
/**
|
private val carrierMergedSubId: StateFlow<Int?> =
|
||||||
* State flow that emits the set of mobile data subscriptions, each represented by its own
|
wifiRepository.wifiNetwork
|
||||||
* [SubscriptionInfo]. We probably only need the [SubscriptionInfo.getSubscriptionId] of each
|
.mapLatest {
|
||||||
* info object, but for now we keep track of the infos themselves.
|
if (it is WifiNetworkModel.CarrierMerged) {
|
||||||
*/
|
it.subscriptionId
|
||||||
override val subscriptions: StateFlow<List<SubscriptionModel>> =
|
} else {
|
||||||
conflatedCallbackFlow {
|
null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.distinctUntilChanged()
|
||||||
|
.stateIn(scope, started = SharingStarted.WhileSubscribed(), null)
|
||||||
|
|
||||||
|
private val mobileSubscriptionsChangeEvent: Flow<Unit> = conflatedCallbackFlow {
|
||||||
val callback =
|
val callback =
|
||||||
object : SubscriptionManager.OnSubscriptionsChangedListener() {
|
object : SubscriptionManager.OnSubscriptionsChangedListener() {
|
||||||
override fun onSubscriptionsChanged() {
|
override fun onSubscriptionsChanged() {
|
||||||
@@ -118,9 +130,16 @@ constructor(
|
|||||||
|
|
||||||
awaitClose { subscriptionManager.removeOnSubscriptionsChangedListener(callback) }
|
awaitClose { subscriptionManager.removeOnSubscriptionsChangedListener(callback) }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* State flow that emits the set of mobile data subscriptions, each represented by its own
|
||||||
|
* [SubscriptionModel].
|
||||||
|
*/
|
||||||
|
override val subscriptions: StateFlow<List<SubscriptionModel>> =
|
||||||
|
merge(mobileSubscriptionsChangeEvent, carrierMergedSubId)
|
||||||
.mapLatest { fetchSubscriptionsList().map { it.toSubscriptionModel() } }
|
.mapLatest { fetchSubscriptionsList().map { it.toSubscriptionModel() } }
|
||||||
.logInputChange(logger, "onSubscriptionsChanged")
|
.logInputChange(logger, "onSubscriptionsChanged")
|
||||||
.onEach { infos -> dropUnusedReposFromCache(infos) }
|
.onEach { infos -> updateRepos(infos) }
|
||||||
.stateIn(scope, started = SharingStarted.WhileSubscribed(), listOf())
|
.stateIn(scope, started = SharingStarted.WhileSubscribed(), listOf())
|
||||||
|
|
||||||
/** StateFlow that keeps track of the current active mobile data subscription */
|
/** StateFlow that keeps track of the current active mobile data subscription */
|
||||||
@@ -173,7 +192,7 @@ constructor(
|
|||||||
.distinctUntilChanged()
|
.distinctUntilChanged()
|
||||||
.logInputChange(logger, "defaultMobileIconGroup")
|
.logInputChange(logger, "defaultMobileIconGroup")
|
||||||
|
|
||||||
override fun getRepoForSubId(subId: Int): MobileConnectionRepository {
|
override fun getRepoForSubId(subId: Int): FullMobileConnectionRepository {
|
||||||
if (!isValidSubId(subId)) {
|
if (!isValidSubId(subId)) {
|
||||||
throw IllegalArgumentException(
|
throw IllegalArgumentException(
|
||||||
"subscriptionId $subId is not in the list of valid subscriptions"
|
"subscriptionId $subId is not in the list of valid subscriptions"
|
||||||
@@ -251,15 +270,27 @@ constructor(
|
|||||||
|
|
||||||
@VisibleForTesting fun getSubIdRepoCache() = subIdRepositoryCache
|
@VisibleForTesting fun getSubIdRepoCache() = subIdRepositoryCache
|
||||||
|
|
||||||
private fun createRepositoryForSubId(subId: Int): MobileConnectionRepository {
|
private fun createRepositoryForSubId(subId: Int): FullMobileConnectionRepository {
|
||||||
return mobileConnectionRepositoryFactory.build(
|
return fullMobileRepoFactory.build(
|
||||||
subId,
|
subId,
|
||||||
|
isCarrierMerged(subId),
|
||||||
defaultNetworkName,
|
defaultNetworkName,
|
||||||
networkNameSeparator,
|
networkNameSeparator,
|
||||||
globalMobileDataSettingChangedEvent,
|
globalMobileDataSettingChangedEvent,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun updateRepos(newInfos: List<SubscriptionModel>) {
|
||||||
|
dropUnusedReposFromCache(newInfos)
|
||||||
|
subIdRepositoryCache.forEach { (subId, repo) ->
|
||||||
|
repo.setIsCarrierMerged(isCarrierMerged(subId))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun isCarrierMerged(subId: Int): Boolean {
|
||||||
|
return subId == carrierMergedSubId.value
|
||||||
|
}
|
||||||
|
|
||||||
private fun dropUnusedReposFromCache(newInfos: List<SubscriptionModel>) {
|
private fun dropUnusedReposFromCache(newInfos: List<SubscriptionModel>) {
|
||||||
// Remove any connection repository from the cache that isn't in the new set of IDs. They
|
// Remove any connection repository from the cache that isn't in the new set of IDs. They
|
||||||
// will get garbage collected once their subscribers go away
|
// will get garbage collected once their subscribers go away
|
||||||
|
|||||||
@@ -22,8 +22,8 @@ import com.android.systemui.dagger.qualifiers.Application
|
|||||||
import com.android.systemui.log.table.TableLogBuffer
|
import com.android.systemui.log.table.TableLogBuffer
|
||||||
import com.android.systemui.statusbar.pipeline.mobile.data.model.DataConnectionState.Connected
|
import com.android.systemui.statusbar.pipeline.mobile.data.model.DataConnectionState.Connected
|
||||||
import com.android.systemui.statusbar.pipeline.mobile.data.model.NetworkNameModel
|
import com.android.systemui.statusbar.pipeline.mobile.data.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.MobileConnectionRepository
|
||||||
import com.android.systemui.statusbar.pipeline.mobile.data.repository.MobileConnectionRepository.Companion.DEFAULT_NUM_LEVELS
|
|
||||||
import com.android.systemui.statusbar.pipeline.shared.data.model.DataActivityModel
|
import com.android.systemui.statusbar.pipeline.shared.data.model.DataActivityModel
|
||||||
import kotlinx.coroutines.CoroutineScope
|
import kotlinx.coroutines.CoroutineScope
|
||||||
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
||||||
@@ -138,7 +138,11 @@ class MobileIconInteractorImpl(
|
|||||||
defaultMobileIconMapping,
|
defaultMobileIconMapping,
|
||||||
defaultMobileIconGroup,
|
defaultMobileIconGroup,
|
||||||
) { info, mapping, defaultGroup ->
|
) { info, mapping, defaultGroup ->
|
||||||
mapping[info.resolvedNetworkType.lookupKey] ?: defaultGroup
|
when (info.resolvedNetworkType) {
|
||||||
|
is ResolvedNetworkType.CarrierMergedNetworkType ->
|
||||||
|
info.resolvedNetworkType.iconGroupOverride
|
||||||
|
else -> mapping[info.resolvedNetworkType.lookupKey] ?: defaultGroup
|
||||||
|
}
|
||||||
}
|
}
|
||||||
.stateIn(scope, SharingStarted.WhileSubscribed(), defaultMobileIconGroup.value)
|
.stateIn(scope, SharingStarted.WhileSubscribed(), defaultMobileIconGroup.value)
|
||||||
|
|
||||||
|
|||||||
@@ -16,13 +16,18 @@
|
|||||||
|
|
||||||
package com.android.systemui.statusbar.pipeline.wifi.data.model
|
package com.android.systemui.statusbar.pipeline.wifi.data.model
|
||||||
|
|
||||||
|
import android.telephony.SubscriptionManager.INVALID_SUBSCRIPTION_ID
|
||||||
import androidx.annotation.VisibleForTesting
|
import androidx.annotation.VisibleForTesting
|
||||||
import com.android.systemui.log.table.TableRowLogger
|
import com.android.systemui.log.table.TableRowLogger
|
||||||
import com.android.systemui.log.table.Diffable
|
import com.android.systemui.log.table.Diffable
|
||||||
|
import com.android.systemui.statusbar.pipeline.mobile.data.repository.MobileConnectionRepository.Companion.DEFAULT_NUM_LEVELS
|
||||||
|
|
||||||
/** Provides information about the current wifi network. */
|
/** Provides information about the current wifi network. */
|
||||||
sealed class WifiNetworkModel : Diffable<WifiNetworkModel> {
|
sealed class WifiNetworkModel : Diffable<WifiNetworkModel> {
|
||||||
|
|
||||||
|
// TODO(b/238425913): Have a better, more unified strategy for diff-logging instead of
|
||||||
|
// copy-pasting the column names for each sub-object.
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A model representing that we couldn't fetch any wifi information.
|
* A model representing that we couldn't fetch any wifi information.
|
||||||
*
|
*
|
||||||
@@ -41,8 +46,43 @@ sealed class WifiNetworkModel : Diffable<WifiNetworkModel> {
|
|||||||
override fun logFull(row: TableRowLogger) {
|
override fun logFull(row: TableRowLogger) {
|
||||||
row.logChange(COL_NETWORK_TYPE, TYPE_UNAVAILABLE)
|
row.logChange(COL_NETWORK_TYPE, TYPE_UNAVAILABLE)
|
||||||
row.logChange(COL_NETWORK_ID, NETWORK_ID_DEFAULT)
|
row.logChange(COL_NETWORK_ID, NETWORK_ID_DEFAULT)
|
||||||
|
row.logChange(COL_SUB_ID, SUB_ID_DEFAULT)
|
||||||
row.logChange(COL_VALIDATED, false)
|
row.logChange(COL_VALIDATED, false)
|
||||||
row.logChange(COL_LEVEL, LEVEL_DEFAULT)
|
row.logChange(COL_LEVEL, LEVEL_DEFAULT)
|
||||||
|
row.logChange(COL_NUM_LEVELS, NUM_LEVELS_DEFAULT)
|
||||||
|
row.logChange(COL_SSID, null)
|
||||||
|
row.logChange(COL_PASSPOINT_ACCESS_POINT, false)
|
||||||
|
row.logChange(COL_ONLINE_SIGN_UP, false)
|
||||||
|
row.logChange(COL_PASSPOINT_NAME, null)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A model representing that the wifi information we received was invalid in some way.
|
||||||
|
*/
|
||||||
|
data class Invalid(
|
||||||
|
/** A description of why the wifi information was invalid. */
|
||||||
|
val invalidReason: String,
|
||||||
|
) : WifiNetworkModel() {
|
||||||
|
override fun toString() = "WifiNetwork.Invalid[$invalidReason]"
|
||||||
|
override fun logDiffs(prevVal: WifiNetworkModel, row: TableRowLogger) {
|
||||||
|
if (prevVal !is Invalid) {
|
||||||
|
logFull(row)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if (invalidReason != prevVal.invalidReason) {
|
||||||
|
row.logChange(COL_NETWORK_TYPE, "$TYPE_UNAVAILABLE $invalidReason")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun logFull(row: TableRowLogger) {
|
||||||
|
row.logChange(COL_NETWORK_TYPE, "$TYPE_UNAVAILABLE $invalidReason")
|
||||||
|
row.logChange(COL_NETWORK_ID, NETWORK_ID_DEFAULT)
|
||||||
|
row.logChange(COL_SUB_ID, SUB_ID_DEFAULT)
|
||||||
|
row.logChange(COL_VALIDATED, false)
|
||||||
|
row.logChange(COL_LEVEL, LEVEL_DEFAULT)
|
||||||
|
row.logChange(COL_NUM_LEVELS, NUM_LEVELS_DEFAULT)
|
||||||
row.logChange(COL_SSID, null)
|
row.logChange(COL_SSID, null)
|
||||||
row.logChange(COL_PASSPOINT_ACCESS_POINT, false)
|
row.logChange(COL_PASSPOINT_ACCESS_POINT, false)
|
||||||
row.logChange(COL_ONLINE_SIGN_UP, false)
|
row.logChange(COL_ONLINE_SIGN_UP, false)
|
||||||
@@ -59,18 +99,21 @@ sealed class WifiNetworkModel : Diffable<WifiNetworkModel> {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if (prevVal is CarrierMerged) {
|
// When changing to Inactive, we need to log diffs to all the fields.
|
||||||
// The only difference between CarrierMerged and Inactive is the type
|
logFull(row)
|
||||||
row.logChange(COL_NETWORK_TYPE, TYPE_INACTIVE)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// When changing from Active to Inactive, we need to log diffs to all the fields.
|
|
||||||
logFullNonActiveNetwork(TYPE_INACTIVE, row)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun logFull(row: TableRowLogger) {
|
override fun logFull(row: TableRowLogger) {
|
||||||
logFullNonActiveNetwork(TYPE_INACTIVE, row)
|
row.logChange(COL_NETWORK_TYPE, TYPE_INACTIVE)
|
||||||
|
row.logChange(COL_NETWORK_ID, NETWORK_ID_DEFAULT)
|
||||||
|
row.logChange(COL_SUB_ID, SUB_ID_DEFAULT)
|
||||||
|
row.logChange(COL_VALIDATED, false)
|
||||||
|
row.logChange(COL_LEVEL, LEVEL_DEFAULT)
|
||||||
|
row.logChange(COL_NUM_LEVELS, NUM_LEVELS_DEFAULT)
|
||||||
|
row.logChange(COL_SSID, null)
|
||||||
|
row.logChange(COL_PASSPOINT_ACCESS_POINT, false)
|
||||||
|
row.logChange(COL_ONLINE_SIGN_UP, false)
|
||||||
|
row.logChange(COL_PASSPOINT_NAME, null)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -80,22 +123,75 @@ sealed class WifiNetworkModel : Diffable<WifiNetworkModel> {
|
|||||||
*
|
*
|
||||||
* See [android.net.wifi.WifiInfo.isCarrierMerged] for more information.
|
* See [android.net.wifi.WifiInfo.isCarrierMerged] for more information.
|
||||||
*/
|
*/
|
||||||
object CarrierMerged : WifiNetworkModel() {
|
data class CarrierMerged(
|
||||||
override fun toString() = "WifiNetwork.CarrierMerged"
|
/**
|
||||||
|
* The [android.net.Network.netId] we received from
|
||||||
|
* [android.net.ConnectivityManager.NetworkCallback] in association with this wifi network.
|
||||||
|
*
|
||||||
|
* Importantly, **not** [android.net.wifi.WifiInfo.getNetworkId].
|
||||||
|
*/
|
||||||
|
val networkId: Int,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The subscription ID that this connection represents.
|
||||||
|
*
|
||||||
|
* Comes from [android.net.wifi.WifiInfo.getSubscriptionId].
|
||||||
|
*
|
||||||
|
* Per that method, this value must not be [INVALID_SUBSCRIPTION_ID] (if it was invalid,
|
||||||
|
* then this is *not* a carrier merged network).
|
||||||
|
*/
|
||||||
|
val subscriptionId: Int,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The signal level, guaranteed to be 0 <= level <= numberOfLevels.
|
||||||
|
*/
|
||||||
|
val level: Int,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The maximum possible level.
|
||||||
|
*/
|
||||||
|
val numberOfLevels: Int = DEFAULT_NUM_LEVELS,
|
||||||
|
) : WifiNetworkModel() {
|
||||||
|
init {
|
||||||
|
require(level in MIN_VALID_LEVEL..numberOfLevels) {
|
||||||
|
"0 <= wifi level <= $numberOfLevels required; level was $level"
|
||||||
|
}
|
||||||
|
require(subscriptionId != INVALID_SUBSCRIPTION_ID) {
|
||||||
|
"subscription ID cannot be invalid"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
override fun logDiffs(prevVal: WifiNetworkModel, row: TableRowLogger) {
|
override fun logDiffs(prevVal: WifiNetworkModel, row: TableRowLogger) {
|
||||||
if (prevVal is CarrierMerged) {
|
if (prevVal !is CarrierMerged) {
|
||||||
|
logFull(row)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if (prevVal is Inactive) {
|
if (prevVal.networkId != networkId) {
|
||||||
// The only difference between CarrierMerged and Inactive is the type.
|
row.logChange(COL_NETWORK_ID, networkId)
|
||||||
|
}
|
||||||
|
if (prevVal.subscriptionId != subscriptionId) {
|
||||||
|
row.logChange(COL_SUB_ID, subscriptionId)
|
||||||
|
}
|
||||||
|
if (prevVal.level != level) {
|
||||||
|
row.logChange(COL_LEVEL, level)
|
||||||
|
}
|
||||||
|
if (prevVal.numberOfLevels != numberOfLevels) {
|
||||||
|
row.logChange(COL_NUM_LEVELS, numberOfLevels)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun logFull(row: TableRowLogger) {
|
||||||
row.logChange(COL_NETWORK_TYPE, TYPE_CARRIER_MERGED)
|
row.logChange(COL_NETWORK_TYPE, TYPE_CARRIER_MERGED)
|
||||||
return
|
row.logChange(COL_NETWORK_ID, networkId)
|
||||||
}
|
row.logChange(COL_SUB_ID, subscriptionId)
|
||||||
|
row.logChange(COL_VALIDATED, true)
|
||||||
// When changing from Active to CarrierMerged, we need to log diffs to all the fields.
|
row.logChange(COL_LEVEL, level)
|
||||||
logFullNonActiveNetwork(TYPE_CARRIER_MERGED, row)
|
row.logChange(COL_NUM_LEVELS, numberOfLevels)
|
||||||
|
row.logChange(COL_SSID, null)
|
||||||
|
row.logChange(COL_PASSPOINT_ACCESS_POINT, false)
|
||||||
|
row.logChange(COL_ONLINE_SIGN_UP, false)
|
||||||
|
row.logChange(COL_PASSPOINT_NAME, null)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -137,38 +233,50 @@ sealed class WifiNetworkModel : Diffable<WifiNetworkModel> {
|
|||||||
|
|
||||||
override fun logDiffs(prevVal: WifiNetworkModel, row: TableRowLogger) {
|
override fun logDiffs(prevVal: WifiNetworkModel, row: TableRowLogger) {
|
||||||
if (prevVal !is Active) {
|
if (prevVal !is Active) {
|
||||||
row.logChange(COL_NETWORK_TYPE, TYPE_ACTIVE)
|
logFull(row)
|
||||||
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if (prevVal !is Active || prevVal.networkId != networkId) {
|
if (prevVal.networkId != networkId) {
|
||||||
row.logChange(COL_NETWORK_ID, networkId)
|
row.logChange(COL_NETWORK_ID, networkId)
|
||||||
}
|
}
|
||||||
if (prevVal !is Active || prevVal.isValidated != isValidated) {
|
if (prevVal.isValidated != isValidated) {
|
||||||
row.logChange(COL_VALIDATED, isValidated)
|
row.logChange(COL_VALIDATED, isValidated)
|
||||||
}
|
}
|
||||||
if (prevVal !is Active || prevVal.level != level) {
|
if (prevVal.level != level) {
|
||||||
row.logChange(COL_LEVEL, level)
|
row.logChange(COL_LEVEL, level)
|
||||||
}
|
}
|
||||||
if (prevVal !is Active || prevVal.ssid != ssid) {
|
if (prevVal.ssid != ssid) {
|
||||||
row.logChange(COL_SSID, ssid)
|
row.logChange(COL_SSID, ssid)
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO(b/238425913): The passpoint-related values are frequently never used, so it
|
// TODO(b/238425913): The passpoint-related values are frequently never used, so it
|
||||||
// would be great to not log them when they're not used.
|
// would be great to not log them when they're not used.
|
||||||
if (prevVal !is Active || prevVal.isPasspointAccessPoint != isPasspointAccessPoint) {
|
if (prevVal.isPasspointAccessPoint != isPasspointAccessPoint) {
|
||||||
row.logChange(COL_PASSPOINT_ACCESS_POINT, isPasspointAccessPoint)
|
row.logChange(COL_PASSPOINT_ACCESS_POINT, isPasspointAccessPoint)
|
||||||
}
|
}
|
||||||
if (prevVal !is Active ||
|
if (prevVal.isOnlineSignUpForPasspointAccessPoint !=
|
||||||
prevVal.isOnlineSignUpForPasspointAccessPoint !=
|
|
||||||
isOnlineSignUpForPasspointAccessPoint) {
|
isOnlineSignUpForPasspointAccessPoint) {
|
||||||
row.logChange(COL_ONLINE_SIGN_UP, isOnlineSignUpForPasspointAccessPoint)
|
row.logChange(COL_ONLINE_SIGN_UP, isOnlineSignUpForPasspointAccessPoint)
|
||||||
}
|
}
|
||||||
if (prevVal !is Active ||
|
if (prevVal.passpointProviderFriendlyName != passpointProviderFriendlyName) {
|
||||||
prevVal.passpointProviderFriendlyName != passpointProviderFriendlyName) {
|
|
||||||
row.logChange(COL_PASSPOINT_NAME, passpointProviderFriendlyName)
|
row.logChange(COL_PASSPOINT_NAME, passpointProviderFriendlyName)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun logFull(row: TableRowLogger) {
|
||||||
|
row.logChange(COL_NETWORK_TYPE, TYPE_ACTIVE)
|
||||||
|
row.logChange(COL_NETWORK_ID, networkId)
|
||||||
|
row.logChange(COL_SUB_ID, null)
|
||||||
|
row.logChange(COL_VALIDATED, isValidated)
|
||||||
|
row.logChange(COL_LEVEL, level)
|
||||||
|
row.logChange(COL_NUM_LEVELS, null)
|
||||||
|
row.logChange(COL_SSID, ssid)
|
||||||
|
row.logChange(COL_PASSPOINT_ACCESS_POINT, isPasspointAccessPoint)
|
||||||
|
row.logChange(COL_ONLINE_SIGN_UP, isOnlineSignUpForPasspointAccessPoint)
|
||||||
|
row.logChange(COL_PASSPOINT_NAME, passpointProviderFriendlyName)
|
||||||
|
}
|
||||||
|
|
||||||
override fun toString(): String {
|
override fun toString(): String {
|
||||||
// Only include the passpoint-related values in the string if we have them. (Most
|
// Only include the passpoint-related values in the string if we have them. (Most
|
||||||
// networks won't have them so they'll be mostly clutter.)
|
// networks won't have them so they'll be mostly clutter.)
|
||||||
@@ -188,22 +296,14 @@ sealed class WifiNetworkModel : Diffable<WifiNetworkModel> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
@VisibleForTesting
|
|
||||||
internal const val MIN_VALID_LEVEL = 0
|
|
||||||
@VisibleForTesting
|
@VisibleForTesting
|
||||||
internal const val MAX_VALID_LEVEL = 4
|
internal const val MAX_VALID_LEVEL = 4
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
internal fun logFullNonActiveNetwork(type: String, row: TableRowLogger) {
|
companion object {
|
||||||
row.logChange(COL_NETWORK_TYPE, type)
|
@VisibleForTesting
|
||||||
row.logChange(COL_NETWORK_ID, NETWORK_ID_DEFAULT)
|
internal const val MIN_VALID_LEVEL = 0
|
||||||
row.logChange(COL_VALIDATED, false)
|
|
||||||
row.logChange(COL_LEVEL, LEVEL_DEFAULT)
|
|
||||||
row.logChange(COL_SSID, null)
|
|
||||||
row.logChange(COL_PASSPOINT_ACCESS_POINT, false)
|
|
||||||
row.logChange(COL_ONLINE_SIGN_UP, false)
|
|
||||||
row.logChange(COL_PASSPOINT_NAME, null)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -214,12 +314,16 @@ const val TYPE_ACTIVE = "Active"
|
|||||||
|
|
||||||
const val COL_NETWORK_TYPE = "type"
|
const val COL_NETWORK_TYPE = "type"
|
||||||
const val COL_NETWORK_ID = "networkId"
|
const val COL_NETWORK_ID = "networkId"
|
||||||
|
const val COL_SUB_ID = "subscriptionId"
|
||||||
const val COL_VALIDATED = "isValidated"
|
const val COL_VALIDATED = "isValidated"
|
||||||
const val COL_LEVEL = "level"
|
const val COL_LEVEL = "level"
|
||||||
|
const val COL_NUM_LEVELS = "maxLevel"
|
||||||
const val COL_SSID = "ssid"
|
const val COL_SSID = "ssid"
|
||||||
const val COL_PASSPOINT_ACCESS_POINT = "isPasspointAccessPoint"
|
const val COL_PASSPOINT_ACCESS_POINT = "isPasspointAccessPoint"
|
||||||
const val COL_ONLINE_SIGN_UP = "isOnlineSignUpForPasspointAccessPoint"
|
const val COL_ONLINE_SIGN_UP = "isOnlineSignUpForPasspointAccessPoint"
|
||||||
const val COL_PASSPOINT_NAME = "passpointProviderFriendlyName"
|
const val COL_PASSPOINT_NAME = "passpointProviderFriendlyName"
|
||||||
|
|
||||||
val LEVEL_DEFAULT: String? = null
|
val LEVEL_DEFAULT: String? = null
|
||||||
|
val NUM_LEVELS_DEFAULT: String? = null
|
||||||
val NETWORK_ID_DEFAULT: String? = null
|
val NETWORK_ID_DEFAULT: String? = null
|
||||||
|
val SUB_ID_DEFAULT: String? = null
|
||||||
|
|||||||
@@ -22,6 +22,7 @@ import com.android.systemui.dagger.SysUISingleton
|
|||||||
import com.android.systemui.dagger.qualifiers.Application
|
import com.android.systemui.dagger.qualifiers.Application
|
||||||
import com.android.systemui.demomode.DemoMode.COMMAND_NETWORK
|
import com.android.systemui.demomode.DemoMode.COMMAND_NETWORK
|
||||||
import com.android.systemui.demomode.DemoModeController
|
import com.android.systemui.demomode.DemoModeController
|
||||||
|
import com.android.systemui.statusbar.pipeline.mobile.data.repository.MobileConnectionRepository.Companion.DEFAULT_NUM_LEVELS
|
||||||
import com.android.systemui.statusbar.pipeline.wifi.data.repository.demo.model.FakeWifiEventModel
|
import com.android.systemui.statusbar.pipeline.wifi.data.repository.demo.model.FakeWifiEventModel
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
import kotlinx.coroutines.CoroutineScope
|
import kotlinx.coroutines.CoroutineScope
|
||||||
@@ -43,10 +44,10 @@ constructor(
|
|||||||
|
|
||||||
private fun Bundle.toWifiEvent(): FakeWifiEventModel? {
|
private fun Bundle.toWifiEvent(): FakeWifiEventModel? {
|
||||||
val wifi = getString("wifi") ?: return null
|
val wifi = getString("wifi") ?: return null
|
||||||
return if (wifi == "show") {
|
return when (wifi) {
|
||||||
activeWifiEvent()
|
"show" -> activeWifiEvent()
|
||||||
} else {
|
"carriermerged" -> carrierMergedWifiEvent()
|
||||||
FakeWifiEventModel.WifiDisabled
|
else -> FakeWifiEventModel.WifiDisabled
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -64,6 +65,14 @@ constructor(
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun Bundle.carrierMergedWifiEvent(): FakeWifiEventModel.CarrierMerged {
|
||||||
|
val subId = getString("slot")?.toInt() ?: DEFAULT_CARRIER_MERGED_SUB_ID
|
||||||
|
val level = getString("level")?.toInt() ?: 0
|
||||||
|
val numberOfLevels = getString("numlevels")?.toInt() ?: DEFAULT_NUM_LEVELS
|
||||||
|
|
||||||
|
return FakeWifiEventModel.CarrierMerged(subId, level, numberOfLevels)
|
||||||
|
}
|
||||||
|
|
||||||
private fun String.toActivity(): Int =
|
private fun String.toActivity(): Int =
|
||||||
when (this) {
|
when (this) {
|
||||||
"inout" -> WifiManager.TrafficStateCallback.DATA_ACTIVITY_INOUT
|
"inout" -> WifiManager.TrafficStateCallback.DATA_ACTIVITY_INOUT
|
||||||
@@ -71,4 +80,8 @@ constructor(
|
|||||||
"out" -> WifiManager.TrafficStateCallback.DATA_ACTIVITY_OUT
|
"out" -> WifiManager.TrafficStateCallback.DATA_ACTIVITY_OUT
|
||||||
else -> WifiManager.TrafficStateCallback.DATA_ACTIVITY_NONE
|
else -> WifiManager.TrafficStateCallback.DATA_ACTIVITY_NONE
|
||||||
}
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
const val DEFAULT_CARRIER_MERGED_SUB_ID = 10
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -66,6 +66,7 @@ constructor(
|
|||||||
private fun processEvent(event: FakeWifiEventModel) =
|
private fun processEvent(event: FakeWifiEventModel) =
|
||||||
when (event) {
|
when (event) {
|
||||||
is FakeWifiEventModel.Wifi -> processEnabledWifiState(event)
|
is FakeWifiEventModel.Wifi -> processEnabledWifiState(event)
|
||||||
|
is FakeWifiEventModel.CarrierMerged -> processCarrierMergedWifiState(event)
|
||||||
is FakeWifiEventModel.WifiDisabled -> processDisabledWifiState()
|
is FakeWifiEventModel.WifiDisabled -> processDisabledWifiState()
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -85,6 +86,14 @@ constructor(
|
|||||||
_wifiNetwork.value = event.toWifiNetworkModel()
|
_wifiNetwork.value = event.toWifiNetworkModel()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun processCarrierMergedWifiState(event: FakeWifiEventModel.CarrierMerged) {
|
||||||
|
_isWifiEnabled.value = true
|
||||||
|
_isWifiDefault.value = true
|
||||||
|
// TODO(b/238425913): Support activity in demo mode.
|
||||||
|
_wifiActivity.value = DataActivityModel(hasActivityIn = false, hasActivityOut = false)
|
||||||
|
_wifiNetwork.value = event.toCarrierMergedModel()
|
||||||
|
}
|
||||||
|
|
||||||
private fun FakeWifiEventModel.Wifi.toWifiNetworkModel(): WifiNetworkModel =
|
private fun FakeWifiEventModel.Wifi.toWifiNetworkModel(): WifiNetworkModel =
|
||||||
WifiNetworkModel.Active(
|
WifiNetworkModel.Active(
|
||||||
networkId = DEMO_NET_ID,
|
networkId = DEMO_NET_ID,
|
||||||
@@ -99,6 +108,14 @@ constructor(
|
|||||||
passpointProviderFriendlyName = null,
|
passpointProviderFriendlyName = null,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
private fun FakeWifiEventModel.CarrierMerged.toCarrierMergedModel(): WifiNetworkModel =
|
||||||
|
WifiNetworkModel.CarrierMerged(
|
||||||
|
networkId = DEMO_NET_ID,
|
||||||
|
subscriptionId = subscriptionId,
|
||||||
|
level = level,
|
||||||
|
numberOfLevels = numberOfLevels,
|
||||||
|
)
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
private const val DEMO_NET_ID = 1234
|
private const val DEMO_NET_ID = 1234
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -29,5 +29,11 @@ sealed interface FakeWifiEventModel {
|
|||||||
val validated: Boolean?,
|
val validated: Boolean?,
|
||||||
) : FakeWifiEventModel
|
) : FakeWifiEventModel
|
||||||
|
|
||||||
|
data class CarrierMerged(
|
||||||
|
val subscriptionId: Int,
|
||||||
|
val level: Int,
|
||||||
|
val numberOfLevels: Int,
|
||||||
|
) : FakeWifiEventModel
|
||||||
|
|
||||||
object WifiDisabled : FakeWifiEventModel
|
object WifiDisabled : FakeWifiEventModel
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -29,6 +29,7 @@ import android.net.NetworkRequest
|
|||||||
import android.net.wifi.WifiInfo
|
import android.net.wifi.WifiInfo
|
||||||
import android.net.wifi.WifiManager
|
import android.net.wifi.WifiManager
|
||||||
import android.net.wifi.WifiManager.TrafficStateCallback
|
import android.net.wifi.WifiManager.TrafficStateCallback
|
||||||
|
import android.telephony.SubscriptionManager.INVALID_SUBSCRIPTION_ID
|
||||||
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.common.coroutine.ConflatedCallbackFlow.conflatedCallbackFlow
|
||||||
@@ -269,7 +270,19 @@ constructor(
|
|||||||
wifiManager: WifiManager,
|
wifiManager: WifiManager,
|
||||||
): WifiNetworkModel {
|
): WifiNetworkModel {
|
||||||
return if (wifiInfo.isCarrierMerged) {
|
return if (wifiInfo.isCarrierMerged) {
|
||||||
WifiNetworkModel.CarrierMerged
|
if (wifiInfo.subscriptionId == INVALID_SUBSCRIPTION_ID) {
|
||||||
|
WifiNetworkModel.Invalid(CARRIER_MERGED_INVALID_SUB_ID_REASON)
|
||||||
|
} else {
|
||||||
|
WifiNetworkModel.CarrierMerged(
|
||||||
|
networkId = network.getNetId(),
|
||||||
|
subscriptionId = wifiInfo.subscriptionId,
|
||||||
|
level = wifiManager.calculateSignalLevel(wifiInfo.rssi),
|
||||||
|
// The WiFi signal level returned by WifiManager#calculateSignalLevel start
|
||||||
|
// from 0, so WifiManager#getMaxSignalLevel + 1 represents the total level
|
||||||
|
// buckets count.
|
||||||
|
numberOfLevels = wifiManager.maxSignalLevel + 1,
|
||||||
|
)
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
WifiNetworkModel.Active(
|
WifiNetworkModel.Active(
|
||||||
network.getNetId(),
|
network.getNetId(),
|
||||||
@@ -302,6 +315,9 @@ constructor(
|
|||||||
.build()
|
.build()
|
||||||
|
|
||||||
private const val WIFI_NETWORK_CALLBACK_NAME = "wifiNetworkModel"
|
private const val WIFI_NETWORK_CALLBACK_NAME = "wifiNetworkModel"
|
||||||
|
|
||||||
|
private const val CARRIER_MERGED_INVALID_SUB_ID_REASON =
|
||||||
|
"Wifi network was carrier merged but had invalid sub ID"
|
||||||
}
|
}
|
||||||
|
|
||||||
@SysUISingleton
|
@SysUISingleton
|
||||||
|
|||||||
@@ -66,6 +66,7 @@ class WifiInteractorImpl @Inject constructor(
|
|||||||
override val ssid: Flow<String?> = wifiRepository.wifiNetwork.map { info ->
|
override val ssid: Flow<String?> = wifiRepository.wifiNetwork.map { info ->
|
||||||
when (info) {
|
when (info) {
|
||||||
is WifiNetworkModel.Unavailable -> null
|
is WifiNetworkModel.Unavailable -> null
|
||||||
|
is WifiNetworkModel.Invalid -> null
|
||||||
is WifiNetworkModel.Inactive -> null
|
is WifiNetworkModel.Inactive -> null
|
||||||
is WifiNetworkModel.CarrierMerged -> null
|
is WifiNetworkModel.CarrierMerged -> null
|
||||||
is WifiNetworkModel.Active -> when {
|
is WifiNetworkModel.Active -> when {
|
||||||
|
|||||||
@@ -83,6 +83,7 @@ constructor(
|
|||||||
private fun WifiNetworkModel.icon(): WifiIcon {
|
private fun WifiNetworkModel.icon(): WifiIcon {
|
||||||
return when (this) {
|
return when (this) {
|
||||||
is WifiNetworkModel.Unavailable -> WifiIcon.Hidden
|
is WifiNetworkModel.Unavailable -> WifiIcon.Hidden
|
||||||
|
is WifiNetworkModel.Invalid -> WifiIcon.Hidden
|
||||||
is WifiNetworkModel.CarrierMerged -> WifiIcon.Hidden
|
is WifiNetworkModel.CarrierMerged -> WifiIcon.Hidden
|
||||||
is WifiNetworkModel.Inactive -> WifiIcon.Visible(
|
is WifiNetworkModel.Inactive -> WifiIcon.Visible(
|
||||||
res = WIFI_NO_NETWORK,
|
res = WIFI_NO_NETWORK,
|
||||||
|
|||||||
@@ -34,6 +34,8 @@ import com.android.systemui.statusbar.pipeline.mobile.data.repository.demo.valid
|
|||||||
import com.android.systemui.statusbar.pipeline.mobile.data.repository.prod.MobileConnectionsRepositoryImpl
|
import com.android.systemui.statusbar.pipeline.mobile.data.repository.prod.MobileConnectionsRepositoryImpl
|
||||||
import com.android.systemui.statusbar.pipeline.mobile.util.FakeMobileMappingsProxy
|
import com.android.systemui.statusbar.pipeline.mobile.util.FakeMobileMappingsProxy
|
||||||
import com.android.systemui.statusbar.pipeline.shared.ConnectivityPipelineLogger
|
import com.android.systemui.statusbar.pipeline.shared.ConnectivityPipelineLogger
|
||||||
|
import com.android.systemui.statusbar.pipeline.wifi.data.repository.FakeWifiRepository
|
||||||
|
import com.android.systemui.statusbar.pipeline.wifi.data.repository.demo.DemoModeWifiDataSource
|
||||||
import com.android.systemui.util.mockito.any
|
import com.android.systemui.util.mockito.any
|
||||||
import com.android.systemui.util.mockito.kotlinArgumentCaptor
|
import com.android.systemui.util.mockito.kotlinArgumentCaptor
|
||||||
import com.android.systemui.util.mockito.mock
|
import com.android.systemui.util.mockito.mock
|
||||||
@@ -71,8 +73,10 @@ class MobileRepositorySwitcherTest : SysuiTestCase() {
|
|||||||
private lateinit var underTest: MobileRepositorySwitcher
|
private lateinit var underTest: MobileRepositorySwitcher
|
||||||
private lateinit var realRepo: MobileConnectionsRepositoryImpl
|
private lateinit var realRepo: MobileConnectionsRepositoryImpl
|
||||||
private lateinit var demoRepo: DemoMobileConnectionsRepository
|
private lateinit var demoRepo: DemoMobileConnectionsRepository
|
||||||
private lateinit var mockDataSource: DemoModeMobileConnectionDataSource
|
private lateinit var mobileDataSource: DemoModeMobileConnectionDataSource
|
||||||
|
private lateinit var wifiDataSource: DemoModeWifiDataSource
|
||||||
private lateinit var logFactory: TableLogBufferFactory
|
private lateinit var logFactory: TableLogBufferFactory
|
||||||
|
private lateinit var wifiRepository: FakeWifiRepository
|
||||||
|
|
||||||
@Mock private lateinit var connectivityManager: ConnectivityManager
|
@Mock private lateinit var connectivityManager: ConnectivityManager
|
||||||
@Mock private lateinit var subscriptionManager: SubscriptionManager
|
@Mock private lateinit var subscriptionManager: SubscriptionManager
|
||||||
@@ -96,10 +100,15 @@ class MobileRepositorySwitcherTest : SysuiTestCase() {
|
|||||||
// Never start in demo mode
|
// Never start in demo mode
|
||||||
whenever(demoModeController.isInDemoMode).thenReturn(false)
|
whenever(demoModeController.isInDemoMode).thenReturn(false)
|
||||||
|
|
||||||
mockDataSource =
|
mobileDataSource =
|
||||||
mock<DemoModeMobileConnectionDataSource>().also {
|
mock<DemoModeMobileConnectionDataSource>().also {
|
||||||
whenever(it.mobileEvents).thenReturn(fakeNetworkEventsFlow)
|
whenever(it.mobileEvents).thenReturn(fakeNetworkEventsFlow)
|
||||||
}
|
}
|
||||||
|
wifiDataSource =
|
||||||
|
mock<DemoModeWifiDataSource>().also {
|
||||||
|
whenever(it.wifiEvents).thenReturn(MutableStateFlow(null))
|
||||||
|
}
|
||||||
|
wifiRepository = FakeWifiRepository()
|
||||||
|
|
||||||
realRepo =
|
realRepo =
|
||||||
MobileConnectionsRepositoryImpl(
|
MobileConnectionsRepositoryImpl(
|
||||||
@@ -113,12 +122,14 @@ class MobileRepositorySwitcherTest : SysuiTestCase() {
|
|||||||
context,
|
context,
|
||||||
IMMEDIATE,
|
IMMEDIATE,
|
||||||
scope,
|
scope,
|
||||||
|
wifiRepository,
|
||||||
mock(),
|
mock(),
|
||||||
)
|
)
|
||||||
|
|
||||||
demoRepo =
|
demoRepo =
|
||||||
DemoMobileConnectionsRepository(
|
DemoMobileConnectionsRepository(
|
||||||
dataSource = mockDataSource,
|
mobileDataSource = mobileDataSource,
|
||||||
|
wifiDataSource = wifiDataSource,
|
||||||
scope = scope,
|
scope = scope,
|
||||||
context = context,
|
context = context,
|
||||||
logFactory = logFactory,
|
logFactory = logFactory,
|
||||||
|
|||||||
@@ -29,6 +29,8 @@ import com.android.systemui.statusbar.pipeline.mobile.data.model.MobileConnectio
|
|||||||
import com.android.systemui.statusbar.pipeline.mobile.data.model.NetworkNameModel
|
import com.android.systemui.statusbar.pipeline.mobile.data.model.NetworkNameModel
|
||||||
import com.android.systemui.statusbar.pipeline.mobile.data.repository.demo.model.FakeNetworkEventModel
|
import com.android.systemui.statusbar.pipeline.mobile.data.repository.demo.model.FakeNetworkEventModel
|
||||||
import com.android.systemui.statusbar.pipeline.shared.data.model.toMobileDataActivityModel
|
import com.android.systemui.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 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.android.systemui.util.time.FakeSystemClock
|
import com.android.systemui.util.time.FakeSystemClock
|
||||||
@@ -63,10 +65,12 @@ internal class DemoMobileConnectionParameterizedTest(private val testCase: TestC
|
|||||||
private val testScope = TestScope(testDispatcher)
|
private val testScope = TestScope(testDispatcher)
|
||||||
|
|
||||||
private val fakeNetworkEventFlow = MutableStateFlow<FakeNetworkEventModel?>(null)
|
private val fakeNetworkEventFlow = MutableStateFlow<FakeNetworkEventModel?>(null)
|
||||||
|
private val fakeWifiEventFlow = MutableStateFlow<FakeWifiEventModel?>(null)
|
||||||
|
|
||||||
private lateinit var connectionsRepo: DemoMobileConnectionsRepository
|
private lateinit var connectionsRepo: DemoMobileConnectionsRepository
|
||||||
private lateinit var underTest: DemoMobileConnectionRepository
|
private lateinit var underTest: DemoMobileConnectionRepository
|
||||||
private lateinit var mockDataSource: DemoModeMobileConnectionDataSource
|
private lateinit var mockDataSource: DemoModeMobileConnectionDataSource
|
||||||
|
private lateinit var mockWifiDataSource: DemoModeWifiDataSource
|
||||||
|
|
||||||
@Before
|
@Before
|
||||||
fun setUp() {
|
fun setUp() {
|
||||||
@@ -75,10 +79,15 @@ internal class DemoMobileConnectionParameterizedTest(private val testCase: TestC
|
|||||||
mock<DemoModeMobileConnectionDataSource>().also {
|
mock<DemoModeMobileConnectionDataSource>().also {
|
||||||
whenever(it.mobileEvents).thenReturn(fakeNetworkEventFlow)
|
whenever(it.mobileEvents).thenReturn(fakeNetworkEventFlow)
|
||||||
}
|
}
|
||||||
|
mockWifiDataSource =
|
||||||
|
mock<DemoModeWifiDataSource>().also {
|
||||||
|
whenever(it.wifiEvents).thenReturn(fakeWifiEventFlow)
|
||||||
|
}
|
||||||
|
|
||||||
connectionsRepo =
|
connectionsRepo =
|
||||||
DemoMobileConnectionsRepository(
|
DemoMobileConnectionsRepository(
|
||||||
dataSource = mockDataSource,
|
mobileDataSource = mockDataSource,
|
||||||
|
wifiDataSource = mockWifiDataSource,
|
||||||
scope = testScope.backgroundScope,
|
scope = testScope.backgroundScope,
|
||||||
context = context,
|
context = context,
|
||||||
logFactory = logFactory,
|
logFactory = logFactory,
|
||||||
|
|||||||
@@ -32,6 +32,8 @@ import com.android.systemui.statusbar.pipeline.mobile.data.model.SubscriptionMod
|
|||||||
import com.android.systemui.statusbar.pipeline.mobile.data.repository.demo.model.FakeNetworkEventModel
|
import com.android.systemui.statusbar.pipeline.mobile.data.repository.demo.model.FakeNetworkEventModel
|
||||||
import com.android.systemui.statusbar.pipeline.mobile.data.repository.demo.model.FakeNetworkEventModel.MobileDisabled
|
import com.android.systemui.statusbar.pipeline.mobile.data.repository.demo.model.FakeNetworkEventModel.MobileDisabled
|
||||||
import com.android.systemui.statusbar.pipeline.shared.data.model.toMobileDataActivityModel
|
import com.android.systemui.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 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.android.systemui.util.time.FakeSystemClock
|
import com.android.systemui.util.time.FakeSystemClock
|
||||||
@@ -57,21 +59,28 @@ class DemoMobileConnectionsRepositoryTest : SysuiTestCase() {
|
|||||||
private val testScope = TestScope(testDispatcher)
|
private val testScope = TestScope(testDispatcher)
|
||||||
|
|
||||||
private val fakeNetworkEventFlow = MutableStateFlow<FakeNetworkEventModel?>(null)
|
private val fakeNetworkEventFlow = MutableStateFlow<FakeNetworkEventModel?>(null)
|
||||||
|
private val fakeWifiEventFlow = MutableStateFlow<FakeWifiEventModel?>(null)
|
||||||
|
|
||||||
private lateinit var underTest: DemoMobileConnectionsRepository
|
private lateinit var underTest: DemoMobileConnectionsRepository
|
||||||
private lateinit var mockDataSource: DemoModeMobileConnectionDataSource
|
private lateinit var mobileDataSource: DemoModeMobileConnectionDataSource
|
||||||
|
private lateinit var wifiDataSource: DemoModeWifiDataSource
|
||||||
|
|
||||||
@Before
|
@Before
|
||||||
fun setUp() {
|
fun setUp() {
|
||||||
// The data source only provides one API, so we can mock it with a flow here for convenience
|
// The data source only provides one API, so we can mock it with a flow here for convenience
|
||||||
mockDataSource =
|
mobileDataSource =
|
||||||
mock<DemoModeMobileConnectionDataSource>().also {
|
mock<DemoModeMobileConnectionDataSource>().also {
|
||||||
whenever(it.mobileEvents).thenReturn(fakeNetworkEventFlow)
|
whenever(it.mobileEvents).thenReturn(fakeNetworkEventFlow)
|
||||||
}
|
}
|
||||||
|
wifiDataSource =
|
||||||
|
mock<DemoModeWifiDataSource>().also {
|
||||||
|
whenever(it.wifiEvents).thenReturn(fakeWifiEventFlow)
|
||||||
|
}
|
||||||
|
|
||||||
underTest =
|
underTest =
|
||||||
DemoMobileConnectionsRepository(
|
DemoMobileConnectionsRepository(
|
||||||
dataSource = mockDataSource,
|
mobileDataSource = mobileDataSource,
|
||||||
|
wifiDataSource = wifiDataSource,
|
||||||
scope = testScope.backgroundScope,
|
scope = testScope.backgroundScope,
|
||||||
context = context,
|
context = context,
|
||||||
logFactory = logFactory,
|
logFactory = logFactory,
|
||||||
@@ -96,6 +105,22 @@ class DemoMobileConnectionsRepositoryTest : SysuiTestCase() {
|
|||||||
job.cancel()
|
job.cancel()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `wifi carrier merged event - create new subscription`() =
|
||||||
|
testScope.runTest {
|
||||||
|
var latest: List<SubscriptionModel>? = null
|
||||||
|
val job = underTest.subscriptions.onEach { latest = it }.launchIn(this)
|
||||||
|
|
||||||
|
assertThat(latest).isEmpty()
|
||||||
|
|
||||||
|
fakeWifiEventFlow.value = validCarrierMergedEvent(subId = 5)
|
||||||
|
|
||||||
|
assertThat(latest).hasSize(1)
|
||||||
|
assertThat(latest!![0].subscriptionId).isEqualTo(5)
|
||||||
|
|
||||||
|
job.cancel()
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `network event - reuses subscription when same Id`() =
|
fun `network event - reuses subscription when same Id`() =
|
||||||
testScope.runTest {
|
testScope.runTest {
|
||||||
@@ -118,6 +143,28 @@ class DemoMobileConnectionsRepositoryTest : SysuiTestCase() {
|
|||||||
job.cancel()
|
job.cancel()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `wifi carrier merged event - reuses subscription when same Id`() =
|
||||||
|
testScope.runTest {
|
||||||
|
var latest: List<SubscriptionModel>? = null
|
||||||
|
val job = underTest.subscriptions.onEach { latest = it }.launchIn(this)
|
||||||
|
|
||||||
|
assertThat(latest).isEmpty()
|
||||||
|
|
||||||
|
fakeWifiEventFlow.value = validCarrierMergedEvent(subId = 5, level = 1)
|
||||||
|
|
||||||
|
assertThat(latest).hasSize(1)
|
||||||
|
assertThat(latest!![0].subscriptionId).isEqualTo(5)
|
||||||
|
|
||||||
|
// Second network event comes in with the same subId, does not create a new subscription
|
||||||
|
fakeWifiEventFlow.value = validCarrierMergedEvent(subId = 5, level = 2)
|
||||||
|
|
||||||
|
assertThat(latest).hasSize(1)
|
||||||
|
assertThat(latest!![0].subscriptionId).isEqualTo(5)
|
||||||
|
|
||||||
|
job.cancel()
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `multiple subscriptions`() =
|
fun `multiple subscriptions`() =
|
||||||
testScope.runTest {
|
testScope.runTest {
|
||||||
@@ -132,6 +179,35 @@ class DemoMobileConnectionsRepositoryTest : SysuiTestCase() {
|
|||||||
job.cancel()
|
job.cancel()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `mobile subscription and carrier merged subscription`() =
|
||||||
|
testScope.runTest {
|
||||||
|
var latest: List<SubscriptionModel>? = null
|
||||||
|
val job = underTest.subscriptions.onEach { latest = it }.launchIn(this)
|
||||||
|
|
||||||
|
fakeNetworkEventFlow.value = validMobileEvent(subId = 1)
|
||||||
|
fakeWifiEventFlow.value = validCarrierMergedEvent(subId = 5)
|
||||||
|
|
||||||
|
assertThat(latest).hasSize(2)
|
||||||
|
|
||||||
|
job.cancel()
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `multiple mobile subscriptions and carrier merged subscription`() =
|
||||||
|
testScope.runTest {
|
||||||
|
var latest: List<SubscriptionModel>? = null
|
||||||
|
val job = underTest.subscriptions.onEach { latest = it }.launchIn(this)
|
||||||
|
|
||||||
|
fakeNetworkEventFlow.value = validMobileEvent(subId = 1)
|
||||||
|
fakeNetworkEventFlow.value = validMobileEvent(subId = 2)
|
||||||
|
fakeWifiEventFlow.value = validCarrierMergedEvent(subId = 3)
|
||||||
|
|
||||||
|
assertThat(latest).hasSize(3)
|
||||||
|
|
||||||
|
job.cancel()
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `mobile disabled event - disables connection - subId specified - single conn`() =
|
fun `mobile disabled event - disables connection - subId specified - single conn`() =
|
||||||
testScope.runTest {
|
testScope.runTest {
|
||||||
@@ -194,6 +270,112 @@ class DemoMobileConnectionsRepositoryTest : SysuiTestCase() {
|
|||||||
job.cancel()
|
job.cancel()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `wifi network updates to disabled - carrier merged connection removed`() =
|
||||||
|
testScope.runTest {
|
||||||
|
var latest: List<SubscriptionModel>? = null
|
||||||
|
val job = underTest.subscriptions.onEach { latest = it }.launchIn(this)
|
||||||
|
|
||||||
|
fakeWifiEventFlow.value = validCarrierMergedEvent(subId = 1)
|
||||||
|
|
||||||
|
assertThat(latest).hasSize(1)
|
||||||
|
|
||||||
|
fakeWifiEventFlow.value = FakeWifiEventModel.WifiDisabled
|
||||||
|
|
||||||
|
assertThat(latest).isEmpty()
|
||||||
|
|
||||||
|
job.cancel()
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `wifi network updates to active - carrier merged connection removed`() =
|
||||||
|
testScope.runTest {
|
||||||
|
var latest: List<SubscriptionModel>? = null
|
||||||
|
val job = underTest.subscriptions.onEach { latest = it }.launchIn(this)
|
||||||
|
|
||||||
|
fakeWifiEventFlow.value = validCarrierMergedEvent(subId = 1)
|
||||||
|
|
||||||
|
assertThat(latest).hasSize(1)
|
||||||
|
|
||||||
|
fakeWifiEventFlow.value =
|
||||||
|
FakeWifiEventModel.Wifi(
|
||||||
|
level = 1,
|
||||||
|
activity = 0,
|
||||||
|
ssid = null,
|
||||||
|
validated = true,
|
||||||
|
)
|
||||||
|
|
||||||
|
assertThat(latest).isEmpty()
|
||||||
|
|
||||||
|
job.cancel()
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `mobile sub updates to carrier merged - only one connection`() =
|
||||||
|
testScope.runTest {
|
||||||
|
var latestSubsList: List<SubscriptionModel>? = null
|
||||||
|
var connections: List<DemoMobileConnectionRepository>? = null
|
||||||
|
val job =
|
||||||
|
underTest.subscriptions
|
||||||
|
.onEach { latestSubsList = it }
|
||||||
|
.onEach { infos ->
|
||||||
|
connections =
|
||||||
|
infos.map { info -> underTest.getRepoForSubId(info.subscriptionId) }
|
||||||
|
}
|
||||||
|
.launchIn(this)
|
||||||
|
|
||||||
|
fakeNetworkEventFlow.value = validMobileEvent(subId = 3, level = 2)
|
||||||
|
assertThat(latestSubsList).hasSize(1)
|
||||||
|
|
||||||
|
val carrierMergedEvent = validCarrierMergedEvent(subId = 3, level = 1)
|
||||||
|
fakeWifiEventFlow.value = carrierMergedEvent
|
||||||
|
assertThat(latestSubsList).hasSize(1)
|
||||||
|
val connection = connections!!.find { it.subId == 3 }!!
|
||||||
|
assertCarrierMergedConnection(connection, carrierMergedEvent)
|
||||||
|
|
||||||
|
job.cancel()
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `mobile sub updates to carrier merged then back - has old mobile data`() =
|
||||||
|
testScope.runTest {
|
||||||
|
var latestSubsList: List<SubscriptionModel>? = null
|
||||||
|
var connections: List<DemoMobileConnectionRepository>? = null
|
||||||
|
val job =
|
||||||
|
underTest.subscriptions
|
||||||
|
.onEach { latestSubsList = it }
|
||||||
|
.onEach { infos ->
|
||||||
|
connections =
|
||||||
|
infos.map { info -> underTest.getRepoForSubId(info.subscriptionId) }
|
||||||
|
}
|
||||||
|
.launchIn(this)
|
||||||
|
|
||||||
|
val mobileEvent = validMobileEvent(subId = 3, level = 2)
|
||||||
|
fakeNetworkEventFlow.value = mobileEvent
|
||||||
|
assertThat(latestSubsList).hasSize(1)
|
||||||
|
|
||||||
|
val carrierMergedEvent = validCarrierMergedEvent(subId = 3, level = 1)
|
||||||
|
fakeWifiEventFlow.value = carrierMergedEvent
|
||||||
|
assertThat(latestSubsList).hasSize(1)
|
||||||
|
var connection = connections!!.find { it.subId == 3 }!!
|
||||||
|
assertCarrierMergedConnection(connection, carrierMergedEvent)
|
||||||
|
|
||||||
|
// WHEN the carrier merged is removed
|
||||||
|
fakeWifiEventFlow.value =
|
||||||
|
FakeWifiEventModel.Wifi(
|
||||||
|
level = 4,
|
||||||
|
activity = 0,
|
||||||
|
ssid = null,
|
||||||
|
validated = true,
|
||||||
|
)
|
||||||
|
|
||||||
|
// THEN the subId=3 connection goes back to the mobile information
|
||||||
|
connection = connections!!.find { it.subId == 3 }!!
|
||||||
|
assertConnection(connection, mobileEvent)
|
||||||
|
|
||||||
|
job.cancel()
|
||||||
|
}
|
||||||
|
|
||||||
/** Regression test for b/261706421 */
|
/** Regression test for b/261706421 */
|
||||||
@Test
|
@Test
|
||||||
fun `multiple connections - remove all - does not throw`() =
|
fun `multiple connections - remove all - does not throw`() =
|
||||||
@@ -289,6 +471,51 @@ class DemoMobileConnectionsRepositoryTest : SysuiTestCase() {
|
|||||||
job.cancel()
|
job.cancel()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `demo connection - two connections - update carrier merged - no affect on first`() =
|
||||||
|
testScope.runTest {
|
||||||
|
var currentEvent1 = validMobileEvent(subId = 1)
|
||||||
|
var connection1: DemoMobileConnectionRepository? = null
|
||||||
|
var currentEvent2 = validCarrierMergedEvent(subId = 2)
|
||||||
|
var connection2: DemoMobileConnectionRepository? = null
|
||||||
|
var connections: List<DemoMobileConnectionRepository>? = null
|
||||||
|
val job =
|
||||||
|
underTest.subscriptions
|
||||||
|
.onEach { infos ->
|
||||||
|
connections =
|
||||||
|
infos.map { info -> underTest.getRepoForSubId(info.subscriptionId) }
|
||||||
|
}
|
||||||
|
.launchIn(this)
|
||||||
|
|
||||||
|
fakeNetworkEventFlow.value = currentEvent1
|
||||||
|
fakeWifiEventFlow.value = currentEvent2
|
||||||
|
assertThat(connections).hasSize(2)
|
||||||
|
connections!!.forEach {
|
||||||
|
when (it.subId) {
|
||||||
|
1 -> connection1 = it
|
||||||
|
2 -> connection2 = it
|
||||||
|
else -> Assert.fail("Unexpected subscription")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
assertConnection(connection1!!, currentEvent1)
|
||||||
|
assertCarrierMergedConnection(connection2!!, currentEvent2)
|
||||||
|
|
||||||
|
// WHEN the event changes for connection 2, it updates, and connection 1 stays the same
|
||||||
|
currentEvent2 = validCarrierMergedEvent(subId = 2, level = 4)
|
||||||
|
fakeWifiEventFlow.value = currentEvent2
|
||||||
|
assertConnection(connection1!!, currentEvent1)
|
||||||
|
assertCarrierMergedConnection(connection2!!, currentEvent2)
|
||||||
|
|
||||||
|
// and vice versa
|
||||||
|
currentEvent1 = validMobileEvent(subId = 1, inflateStrength = true)
|
||||||
|
fakeNetworkEventFlow.value = currentEvent1
|
||||||
|
assertConnection(connection1!!, currentEvent1)
|
||||||
|
assertCarrierMergedConnection(connection2!!, currentEvent2)
|
||||||
|
|
||||||
|
job.cancel()
|
||||||
|
}
|
||||||
|
|
||||||
private fun assertConnection(
|
private fun assertConnection(
|
||||||
conn: DemoMobileConnectionRepository,
|
conn: DemoMobileConnectionRepository,
|
||||||
model: FakeNetworkEventModel
|
model: FakeNetworkEventModel
|
||||||
@@ -315,6 +542,21 @@ class DemoMobileConnectionsRepositoryTest : SysuiTestCase() {
|
|||||||
else -> {}
|
else -> {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun assertCarrierMergedConnection(
|
||||||
|
conn: DemoMobileConnectionRepository,
|
||||||
|
model: FakeWifiEventModel.CarrierMerged,
|
||||||
|
) {
|
||||||
|
val connectionInfo: MobileConnectionModel = conn.connectionInfo.value
|
||||||
|
assertThat(conn.subId).isEqualTo(model.subscriptionId)
|
||||||
|
assertThat(connectionInfo.cdmaLevel).isEqualTo(model.level)
|
||||||
|
assertThat(connectionInfo.primaryLevel).isEqualTo(model.level)
|
||||||
|
assertThat(connectionInfo.carrierNetworkChangeActive).isEqualTo(false)
|
||||||
|
assertThat(connectionInfo.isRoaming).isEqualTo(false)
|
||||||
|
assertThat(connectionInfo.isEmergencyOnly).isFalse()
|
||||||
|
assertThat(connectionInfo.isGsm).isFalse()
|
||||||
|
assertThat(connectionInfo.dataConnectionState).isEqualTo(DataConnectionState.Connected)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Convenience to create a valid fake network event with minimal params */
|
/** Convenience to create a valid fake network event with minimal params */
|
||||||
@@ -339,3 +581,14 @@ fun validMobileEvent(
|
|||||||
roaming = roaming,
|
roaming = roaming,
|
||||||
name = "demo name",
|
name = "demo name",
|
||||||
)
|
)
|
||||||
|
|
||||||
|
fun validCarrierMergedEvent(
|
||||||
|
subId: Int = 1,
|
||||||
|
level: Int = 1,
|
||||||
|
numberOfLevels: Int = 4,
|
||||||
|
): FakeWifiEventModel.CarrierMerged =
|
||||||
|
FakeWifiEventModel.CarrierMerged(
|
||||||
|
subscriptionId = subId,
|
||||||
|
level = level,
|
||||||
|
numberOfLevels = numberOfLevels,
|
||||||
|
)
|
||||||
|
|||||||
@@ -0,0 +1,251 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2022 The Android Open Source Project
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.android.systemui.statusbar.pipeline.mobile.data.repository.prod
|
||||||
|
|
||||||
|
import android.testing.AndroidTestingRunner
|
||||||
|
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.model.DataConnectionState
|
||||||
|
import com.android.systemui.statusbar.pipeline.mobile.data.model.MobileConnectionModel
|
||||||
|
import com.android.systemui.statusbar.pipeline.mobile.data.model.NetworkNameModel
|
||||||
|
import com.android.systemui.statusbar.pipeline.mobile.data.model.ResolvedNetworkType
|
||||||
|
import com.android.systemui.statusbar.pipeline.shared.data.model.DataActivityModel
|
||||||
|
import com.android.systemui.statusbar.pipeline.wifi.data.model.WifiNetworkModel
|
||||||
|
import com.android.systemui.statusbar.pipeline.wifi.data.repository.FakeWifiRepository
|
||||||
|
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.junit.runner.RunWith
|
||||||
|
import org.mockito.Mock
|
||||||
|
import org.mockito.MockitoAnnotations
|
||||||
|
|
||||||
|
@SmallTest
|
||||||
|
@OptIn(ExperimentalCoroutinesApi::class)
|
||||||
|
@RunWith(AndroidTestingRunner::class)
|
||||||
|
class CarrierMergedConnectionRepositoryTest : SysuiTestCase() {
|
||||||
|
|
||||||
|
private lateinit var underTest: CarrierMergedConnectionRepository
|
||||||
|
|
||||||
|
private lateinit var wifiRepository: FakeWifiRepository
|
||||||
|
@Mock private lateinit var logger: TableLogBuffer
|
||||||
|
|
||||||
|
private val testDispatcher = UnconfinedTestDispatcher()
|
||||||
|
private val testScope = TestScope(testDispatcher)
|
||||||
|
|
||||||
|
@Before
|
||||||
|
fun setUp() {
|
||||||
|
MockitoAnnotations.initMocks(this)
|
||||||
|
wifiRepository = FakeWifiRepository()
|
||||||
|
|
||||||
|
underTest =
|
||||||
|
CarrierMergedConnectionRepository(
|
||||||
|
SUB_ID,
|
||||||
|
logger,
|
||||||
|
NetworkNameModel.Default("name"),
|
||||||
|
testScope.backgroundScope,
|
||||||
|
wifiRepository,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun connectionInfo_inactiveWifi_isDefault() =
|
||||||
|
testScope.runTest {
|
||||||
|
var latest: MobileConnectionModel? = null
|
||||||
|
val job = underTest.connectionInfo.onEach { latest = it }.launchIn(this)
|
||||||
|
|
||||||
|
wifiRepository.setWifiNetwork(WifiNetworkModel.Inactive)
|
||||||
|
|
||||||
|
assertThat(latest).isEqualTo(MobileConnectionModel())
|
||||||
|
|
||||||
|
job.cancel()
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun connectionInfo_activeWifi_isDefault() =
|
||||||
|
testScope.runTest {
|
||||||
|
var latest: MobileConnectionModel? = null
|
||||||
|
val job = underTest.connectionInfo.onEach { latest = it }.launchIn(this)
|
||||||
|
|
||||||
|
wifiRepository.setWifiNetwork(WifiNetworkModel.Active(networkId = NET_ID, level = 1))
|
||||||
|
|
||||||
|
assertThat(latest).isEqualTo(MobileConnectionModel())
|
||||||
|
|
||||||
|
job.cancel()
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun connectionInfo_carrierMergedWifi_isValidAndFieldsComeFromWifiNetwork() =
|
||||||
|
testScope.runTest {
|
||||||
|
var latest: MobileConnectionModel? = null
|
||||||
|
val job = underTest.connectionInfo.onEach { latest = it }.launchIn(this)
|
||||||
|
|
||||||
|
wifiRepository.setIsWifiEnabled(true)
|
||||||
|
wifiRepository.setIsWifiDefault(true)
|
||||||
|
|
||||||
|
wifiRepository.setWifiNetwork(
|
||||||
|
WifiNetworkModel.CarrierMerged(
|
||||||
|
networkId = NET_ID,
|
||||||
|
subscriptionId = SUB_ID,
|
||||||
|
level = 3,
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
val expected =
|
||||||
|
MobileConnectionModel(
|
||||||
|
primaryLevel = 3,
|
||||||
|
cdmaLevel = 3,
|
||||||
|
dataConnectionState = DataConnectionState.Connected,
|
||||||
|
dataActivityDirection =
|
||||||
|
DataActivityModel(
|
||||||
|
hasActivityIn = false,
|
||||||
|
hasActivityOut = false,
|
||||||
|
),
|
||||||
|
resolvedNetworkType = ResolvedNetworkType.CarrierMergedNetworkType,
|
||||||
|
isRoaming = false,
|
||||||
|
isEmergencyOnly = false,
|
||||||
|
operatorAlphaShort = null,
|
||||||
|
isInService = true,
|
||||||
|
isGsm = false,
|
||||||
|
carrierNetworkChangeActive = false,
|
||||||
|
)
|
||||||
|
assertThat(latest).isEqualTo(expected)
|
||||||
|
|
||||||
|
job.cancel()
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun connectionInfo_carrierMergedWifi_wrongSubId_isDefault() =
|
||||||
|
testScope.runTest {
|
||||||
|
var latest: MobileConnectionModel? = null
|
||||||
|
val job = underTest.connectionInfo.onEach { latest = it }.launchIn(this)
|
||||||
|
|
||||||
|
wifiRepository.setWifiNetwork(
|
||||||
|
WifiNetworkModel.CarrierMerged(
|
||||||
|
networkId = NET_ID,
|
||||||
|
subscriptionId = SUB_ID + 10,
|
||||||
|
level = 3,
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
assertThat(latest).isEqualTo(MobileConnectionModel())
|
||||||
|
assertThat(latest!!.primaryLevel).isNotEqualTo(3)
|
||||||
|
assertThat(latest!!.resolvedNetworkType)
|
||||||
|
.isNotEqualTo(ResolvedNetworkType.CarrierMergedNetworkType)
|
||||||
|
|
||||||
|
job.cancel()
|
||||||
|
}
|
||||||
|
|
||||||
|
// This scenario likely isn't possible, but write a test for it anyway
|
||||||
|
@Test
|
||||||
|
fun connectionInfo_carrierMergedButNotEnabled_isDefault() =
|
||||||
|
testScope.runTest {
|
||||||
|
var latest: MobileConnectionModel? = null
|
||||||
|
val job = underTest.connectionInfo.onEach { latest = it }.launchIn(this)
|
||||||
|
|
||||||
|
wifiRepository.setWifiNetwork(
|
||||||
|
WifiNetworkModel.CarrierMerged(
|
||||||
|
networkId = NET_ID,
|
||||||
|
subscriptionId = SUB_ID,
|
||||||
|
level = 3,
|
||||||
|
)
|
||||||
|
)
|
||||||
|
wifiRepository.setIsWifiEnabled(false)
|
||||||
|
|
||||||
|
assertThat(latest).isEqualTo(MobileConnectionModel())
|
||||||
|
|
||||||
|
job.cancel()
|
||||||
|
}
|
||||||
|
|
||||||
|
// This scenario likely isn't possible, but write a test for it anyway
|
||||||
|
@Test
|
||||||
|
fun connectionInfo_carrierMergedButWifiNotDefault_isDefault() =
|
||||||
|
testScope.runTest {
|
||||||
|
var latest: MobileConnectionModel? = null
|
||||||
|
val job = underTest.connectionInfo.onEach { latest = it }.launchIn(this)
|
||||||
|
|
||||||
|
wifiRepository.setWifiNetwork(
|
||||||
|
WifiNetworkModel.CarrierMerged(
|
||||||
|
networkId = NET_ID,
|
||||||
|
subscriptionId = SUB_ID,
|
||||||
|
level = 3,
|
||||||
|
)
|
||||||
|
)
|
||||||
|
wifiRepository.setIsWifiDefault(false)
|
||||||
|
|
||||||
|
assertThat(latest).isEqualTo(MobileConnectionModel())
|
||||||
|
|
||||||
|
job.cancel()
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun numberOfLevels_comesFromCarrierMerged() =
|
||||||
|
testScope.runTest {
|
||||||
|
var latest: Int? = null
|
||||||
|
val job = underTest.numberOfLevels.onEach { latest = it }.launchIn(this)
|
||||||
|
|
||||||
|
wifiRepository.setWifiNetwork(
|
||||||
|
WifiNetworkModel.CarrierMerged(
|
||||||
|
networkId = NET_ID,
|
||||||
|
subscriptionId = SUB_ID,
|
||||||
|
level = 1,
|
||||||
|
numberOfLevels = 6,
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
assertThat(latest).isEqualTo(6)
|
||||||
|
|
||||||
|
job.cancel()
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun dataEnabled_matchesWifiEnabled() =
|
||||||
|
testScope.runTest {
|
||||||
|
var latest: Boolean? = null
|
||||||
|
val job = underTest.dataEnabled.onEach { latest = it }.launchIn(this)
|
||||||
|
|
||||||
|
wifiRepository.setIsWifiEnabled(true)
|
||||||
|
assertThat(latest).isTrue()
|
||||||
|
|
||||||
|
wifiRepository.setIsWifiEnabled(false)
|
||||||
|
assertThat(latest).isFalse()
|
||||||
|
|
||||||
|
job.cancel()
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun cdmaRoaming_alwaysFalse() =
|
||||||
|
testScope.runTest {
|
||||||
|
var latest: Boolean? = null
|
||||||
|
val job = underTest.cdmaRoaming.onEach { latest = it }.launchIn(this)
|
||||||
|
|
||||||
|
assertThat(latest).isFalse()
|
||||||
|
|
||||||
|
job.cancel()
|
||||||
|
}
|
||||||
|
|
||||||
|
private companion object {
|
||||||
|
const val SUB_ID = 123
|
||||||
|
const val NET_ID = 456
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,389 @@
|
|||||||
|
/*
|
||||||
|
* 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 androidx.test.filters.SmallTest
|
||||||
|
import com.android.systemui.SysuiTestCase
|
||||||
|
import com.android.systemui.log.table.TableLogBuffer
|
||||||
|
import com.android.systemui.log.table.TableLogBufferFactory
|
||||||
|
import com.android.systemui.statusbar.pipeline.mobile.data.model.MobileConnectionModel
|
||||||
|
import com.android.systemui.statusbar.pipeline.mobile.data.model.NetworkNameModel
|
||||||
|
import com.android.systemui.statusbar.pipeline.mobile.data.repository.FakeMobileConnectionRepository
|
||||||
|
import com.android.systemui.statusbar.pipeline.mobile.data.repository.FakeMobileConnectionsRepository
|
||||||
|
import com.android.systemui.statusbar.pipeline.mobile.data.repository.MobileConnectionRepository
|
||||||
|
import com.android.systemui.statusbar.pipeline.mobile.util.FakeMobileMappingsProxy
|
||||||
|
import com.android.systemui.util.mockito.any
|
||||||
|
import com.android.systemui.util.mockito.eq
|
||||||
|
import com.android.systemui.util.mockito.mock
|
||||||
|
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.flow.Flow
|
||||||
|
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.Mockito.never
|
||||||
|
import org.mockito.Mockito.verify
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This repo acts as a dispatcher to either the `typical` or `carrier merged` versions of the
|
||||||
|
* repository interface it's switching on. These tests just need to verify that the entire interface
|
||||||
|
* properly switches over when the value of `isCarrierMerged` changes.
|
||||||
|
*/
|
||||||
|
@Suppress("EXPERIMENTAL_IS_NOT_ENABLED")
|
||||||
|
@OptIn(ExperimentalCoroutinesApi::class)
|
||||||
|
@SmallTest
|
||||||
|
class FullMobileConnectionRepositoryTest : SysuiTestCase() {
|
||||||
|
private lateinit var underTest: FullMobileConnectionRepository
|
||||||
|
|
||||||
|
private val testDispatcher = UnconfinedTestDispatcher()
|
||||||
|
private val testScope = TestScope(testDispatcher)
|
||||||
|
private val mobileMappings = FakeMobileMappingsProxy()
|
||||||
|
private val tableLogBuffer = mock<TableLogBuffer>()
|
||||||
|
private val mobileFactory = mock<MobileConnectionRepositoryImpl.Factory>()
|
||||||
|
private val carrierMergedFactory = mock<CarrierMergedConnectionRepository.Factory>()
|
||||||
|
|
||||||
|
private lateinit var connectionsRepo: FakeMobileConnectionsRepository
|
||||||
|
private val globalMobileDataSettingChangedEvent: Flow<Unit>
|
||||||
|
get() = connectionsRepo.globalMobileDataSettingChangedEvent
|
||||||
|
|
||||||
|
private lateinit var mobileRepo: FakeMobileConnectionRepository
|
||||||
|
private lateinit var carrierMergedRepo: FakeMobileConnectionRepository
|
||||||
|
|
||||||
|
@Before
|
||||||
|
fun setUp() {
|
||||||
|
connectionsRepo = FakeMobileConnectionsRepository(mobileMappings, tableLogBuffer)
|
||||||
|
|
||||||
|
mobileRepo = FakeMobileConnectionRepository(SUB_ID, tableLogBuffer)
|
||||||
|
carrierMergedRepo = FakeMobileConnectionRepository(SUB_ID, tableLogBuffer)
|
||||||
|
|
||||||
|
whenever(
|
||||||
|
mobileFactory.build(
|
||||||
|
eq(SUB_ID),
|
||||||
|
any(),
|
||||||
|
eq(DEFAULT_NAME),
|
||||||
|
eq(SEP),
|
||||||
|
eq(globalMobileDataSettingChangedEvent),
|
||||||
|
)
|
||||||
|
)
|
||||||
|
.thenReturn(mobileRepo)
|
||||||
|
whenever(carrierMergedFactory.build(eq(SUB_ID), any(), eq(DEFAULT_NAME)))
|
||||||
|
.thenReturn(carrierMergedRepo)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun startingIsCarrierMerged_usesCarrierMergedInitially() =
|
||||||
|
testScope.runTest {
|
||||||
|
val carrierMergedConnectionInfo =
|
||||||
|
MobileConnectionModel(
|
||||||
|
operatorAlphaShort = "Carrier Merged Operator",
|
||||||
|
)
|
||||||
|
carrierMergedRepo.setConnectionInfo(carrierMergedConnectionInfo)
|
||||||
|
|
||||||
|
initializeRepo(startingIsCarrierMerged = true)
|
||||||
|
|
||||||
|
assertThat(underTest.activeRepo.value).isEqualTo(carrierMergedRepo)
|
||||||
|
assertThat(underTest.connectionInfo.value).isEqualTo(carrierMergedConnectionInfo)
|
||||||
|
verify(mobileFactory, never())
|
||||||
|
.build(
|
||||||
|
SUB_ID,
|
||||||
|
tableLogBuffer,
|
||||||
|
DEFAULT_NAME,
|
||||||
|
SEP,
|
||||||
|
globalMobileDataSettingChangedEvent
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun startingNotCarrierMerged_usesTypicalInitially() =
|
||||||
|
testScope.runTest {
|
||||||
|
val mobileConnectionInfo =
|
||||||
|
MobileConnectionModel(
|
||||||
|
operatorAlphaShort = "Typical Operator",
|
||||||
|
)
|
||||||
|
mobileRepo.setConnectionInfo(mobileConnectionInfo)
|
||||||
|
|
||||||
|
initializeRepo(startingIsCarrierMerged = false)
|
||||||
|
|
||||||
|
assertThat(underTest.activeRepo.value).isEqualTo(mobileRepo)
|
||||||
|
assertThat(underTest.connectionInfo.value).isEqualTo(mobileConnectionInfo)
|
||||||
|
verify(carrierMergedFactory, never()).build(SUB_ID, tableLogBuffer, DEFAULT_NAME)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun activeRepo_matchesIsCarrierMerged() =
|
||||||
|
testScope.runTest {
|
||||||
|
initializeRepo(startingIsCarrierMerged = false)
|
||||||
|
var latest: MobileConnectionRepository? = null
|
||||||
|
val job = underTest.activeRepo.onEach { latest = it }.launchIn(this)
|
||||||
|
|
||||||
|
underTest.setIsCarrierMerged(true)
|
||||||
|
|
||||||
|
assertThat(latest).isEqualTo(carrierMergedRepo)
|
||||||
|
|
||||||
|
underTest.setIsCarrierMerged(false)
|
||||||
|
|
||||||
|
assertThat(latest).isEqualTo(mobileRepo)
|
||||||
|
|
||||||
|
underTest.setIsCarrierMerged(true)
|
||||||
|
|
||||||
|
assertThat(latest).isEqualTo(carrierMergedRepo)
|
||||||
|
|
||||||
|
job.cancel()
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun connectionInfo_getsUpdatesFromRepo_carrierMerged() =
|
||||||
|
testScope.runTest {
|
||||||
|
initializeRepo(startingIsCarrierMerged = false)
|
||||||
|
|
||||||
|
var latest: MobileConnectionModel? = null
|
||||||
|
val job = underTest.connectionInfo.onEach { latest = it }.launchIn(this)
|
||||||
|
|
||||||
|
underTest.setIsCarrierMerged(true)
|
||||||
|
|
||||||
|
val info1 =
|
||||||
|
MobileConnectionModel(
|
||||||
|
operatorAlphaShort = "Carrier Merged Operator",
|
||||||
|
primaryLevel = 1,
|
||||||
|
)
|
||||||
|
carrierMergedRepo.setConnectionInfo(info1)
|
||||||
|
|
||||||
|
assertThat(latest).isEqualTo(info1)
|
||||||
|
|
||||||
|
val info2 =
|
||||||
|
MobileConnectionModel(
|
||||||
|
operatorAlphaShort = "Carrier Merged Operator #2",
|
||||||
|
primaryLevel = 2,
|
||||||
|
)
|
||||||
|
carrierMergedRepo.setConnectionInfo(info2)
|
||||||
|
|
||||||
|
assertThat(latest).isEqualTo(info2)
|
||||||
|
|
||||||
|
val info3 =
|
||||||
|
MobileConnectionModel(
|
||||||
|
operatorAlphaShort = "Carrier Merged Operator #3",
|
||||||
|
primaryLevel = 3,
|
||||||
|
)
|
||||||
|
carrierMergedRepo.setConnectionInfo(info3)
|
||||||
|
|
||||||
|
assertThat(latest).isEqualTo(info3)
|
||||||
|
|
||||||
|
job.cancel()
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun connectionInfo_getsUpdatesFromRepo_mobile() =
|
||||||
|
testScope.runTest {
|
||||||
|
initializeRepo(startingIsCarrierMerged = false)
|
||||||
|
|
||||||
|
var latest: MobileConnectionModel? = null
|
||||||
|
val job = underTest.connectionInfo.onEach { latest = it }.launchIn(this)
|
||||||
|
|
||||||
|
underTest.setIsCarrierMerged(false)
|
||||||
|
|
||||||
|
val info1 =
|
||||||
|
MobileConnectionModel(
|
||||||
|
operatorAlphaShort = "Typical Merged Operator",
|
||||||
|
primaryLevel = 1,
|
||||||
|
)
|
||||||
|
mobileRepo.setConnectionInfo(info1)
|
||||||
|
|
||||||
|
assertThat(latest).isEqualTo(info1)
|
||||||
|
|
||||||
|
val info2 =
|
||||||
|
MobileConnectionModel(
|
||||||
|
operatorAlphaShort = "Typical Merged Operator #2",
|
||||||
|
primaryLevel = 2,
|
||||||
|
)
|
||||||
|
mobileRepo.setConnectionInfo(info2)
|
||||||
|
|
||||||
|
assertThat(latest).isEqualTo(info2)
|
||||||
|
|
||||||
|
val info3 =
|
||||||
|
MobileConnectionModel(
|
||||||
|
operatorAlphaShort = "Typical Merged Operator #3",
|
||||||
|
primaryLevel = 3,
|
||||||
|
)
|
||||||
|
mobileRepo.setConnectionInfo(info3)
|
||||||
|
|
||||||
|
assertThat(latest).isEqualTo(info3)
|
||||||
|
|
||||||
|
job.cancel()
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun connectionInfo_updatesWhenCarrierMergedUpdates() =
|
||||||
|
testScope.runTest {
|
||||||
|
initializeRepo(startingIsCarrierMerged = false)
|
||||||
|
|
||||||
|
var latest: MobileConnectionModel? = null
|
||||||
|
val job = underTest.connectionInfo.onEach { latest = it }.launchIn(this)
|
||||||
|
|
||||||
|
val carrierMergedInfo =
|
||||||
|
MobileConnectionModel(
|
||||||
|
operatorAlphaShort = "Carrier Merged Operator",
|
||||||
|
primaryLevel = 4,
|
||||||
|
)
|
||||||
|
carrierMergedRepo.setConnectionInfo(carrierMergedInfo)
|
||||||
|
|
||||||
|
val mobileInfo =
|
||||||
|
MobileConnectionModel(
|
||||||
|
operatorAlphaShort = "Typical Operator",
|
||||||
|
primaryLevel = 2,
|
||||||
|
)
|
||||||
|
mobileRepo.setConnectionInfo(mobileInfo)
|
||||||
|
|
||||||
|
// Start with the mobile info
|
||||||
|
assertThat(latest).isEqualTo(mobileInfo)
|
||||||
|
|
||||||
|
// WHEN isCarrierMerged is set to true
|
||||||
|
underTest.setIsCarrierMerged(true)
|
||||||
|
|
||||||
|
// THEN the carrier merged info is used
|
||||||
|
assertThat(latest).isEqualTo(carrierMergedInfo)
|
||||||
|
|
||||||
|
val newCarrierMergedInfo =
|
||||||
|
MobileConnectionModel(
|
||||||
|
operatorAlphaShort = "New CM Operator",
|
||||||
|
primaryLevel = 0,
|
||||||
|
)
|
||||||
|
carrierMergedRepo.setConnectionInfo(newCarrierMergedInfo)
|
||||||
|
|
||||||
|
assertThat(latest).isEqualTo(newCarrierMergedInfo)
|
||||||
|
|
||||||
|
// WHEN isCarrierMerged is set to false
|
||||||
|
underTest.setIsCarrierMerged(false)
|
||||||
|
|
||||||
|
// THEN the typical info is used
|
||||||
|
assertThat(latest).isEqualTo(mobileInfo)
|
||||||
|
|
||||||
|
val newMobileInfo =
|
||||||
|
MobileConnectionModel(
|
||||||
|
operatorAlphaShort = "New Mobile Operator",
|
||||||
|
primaryLevel = 3,
|
||||||
|
)
|
||||||
|
mobileRepo.setConnectionInfo(newMobileInfo)
|
||||||
|
|
||||||
|
assertThat(latest).isEqualTo(newMobileInfo)
|
||||||
|
|
||||||
|
job.cancel()
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `factory - reuses log buffers for same connection`() =
|
||||||
|
testScope.runTest {
|
||||||
|
val realLoggerFactory = TableLogBufferFactory(mock(), FakeSystemClock())
|
||||||
|
|
||||||
|
val factory =
|
||||||
|
FullMobileConnectionRepository.Factory(
|
||||||
|
scope = testScope.backgroundScope,
|
||||||
|
realLoggerFactory,
|
||||||
|
mobileFactory,
|
||||||
|
carrierMergedFactory,
|
||||||
|
)
|
||||||
|
|
||||||
|
// Create two connections for the same subId. Similar to if the connection appeared
|
||||||
|
// and disappeared from the connectionFactory's perspective
|
||||||
|
val connection1 =
|
||||||
|
factory.build(
|
||||||
|
SUB_ID,
|
||||||
|
startingIsCarrierMerged = false,
|
||||||
|
DEFAULT_NAME,
|
||||||
|
SEP,
|
||||||
|
globalMobileDataSettingChangedEvent,
|
||||||
|
)
|
||||||
|
|
||||||
|
val connection1Repeat =
|
||||||
|
factory.build(
|
||||||
|
SUB_ID,
|
||||||
|
startingIsCarrierMerged = false,
|
||||||
|
DEFAULT_NAME,
|
||||||
|
SEP,
|
||||||
|
globalMobileDataSettingChangedEvent,
|
||||||
|
)
|
||||||
|
|
||||||
|
assertThat(connection1.tableLogBuffer)
|
||||||
|
.isSameInstanceAs(connection1Repeat.tableLogBuffer)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `factory - reuses log buffers for same sub ID even if carrier merged`() =
|
||||||
|
testScope.runTest {
|
||||||
|
val realLoggerFactory = TableLogBufferFactory(mock(), FakeSystemClock())
|
||||||
|
|
||||||
|
val factory =
|
||||||
|
FullMobileConnectionRepository.Factory(
|
||||||
|
scope = testScope.backgroundScope,
|
||||||
|
realLoggerFactory,
|
||||||
|
mobileFactory,
|
||||||
|
carrierMergedFactory,
|
||||||
|
)
|
||||||
|
|
||||||
|
val connection1 =
|
||||||
|
factory.build(
|
||||||
|
SUB_ID,
|
||||||
|
startingIsCarrierMerged = false,
|
||||||
|
DEFAULT_NAME,
|
||||||
|
SEP,
|
||||||
|
globalMobileDataSettingChangedEvent,
|
||||||
|
)
|
||||||
|
|
||||||
|
// WHEN a connection with the same sub ID but carrierMerged = true is created
|
||||||
|
val connection1Repeat =
|
||||||
|
factory.build(
|
||||||
|
SUB_ID,
|
||||||
|
startingIsCarrierMerged = true,
|
||||||
|
DEFAULT_NAME,
|
||||||
|
SEP,
|
||||||
|
globalMobileDataSettingChangedEvent,
|
||||||
|
)
|
||||||
|
|
||||||
|
// THEN the same table is re-used
|
||||||
|
assertThat(connection1.tableLogBuffer)
|
||||||
|
.isSameInstanceAs(connection1Repeat.tableLogBuffer)
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO(b/238425913): Verify that the logging switches correctly (once the carrier merged repo
|
||||||
|
// implements logging).
|
||||||
|
|
||||||
|
private fun initializeRepo(startingIsCarrierMerged: Boolean) {
|
||||||
|
underTest =
|
||||||
|
FullMobileConnectionRepository(
|
||||||
|
SUB_ID,
|
||||||
|
startingIsCarrierMerged,
|
||||||
|
tableLogBuffer,
|
||||||
|
DEFAULT_NAME,
|
||||||
|
SEP,
|
||||||
|
globalMobileDataSettingChangedEvent,
|
||||||
|
testScope.backgroundScope,
|
||||||
|
mobileFactory,
|
||||||
|
carrierMergedFactory,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
private companion object {
|
||||||
|
const val SUB_ID = 42
|
||||||
|
private val DEFAULT_NAME = NetworkNameModel.Default("default name")
|
||||||
|
private const val SEP = "-"
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -37,17 +37,18 @@ import com.android.systemui.SysuiTestCase
|
|||||||
import com.android.systemui.log.table.TableLogBuffer
|
import com.android.systemui.log.table.TableLogBuffer
|
||||||
import com.android.systemui.log.table.TableLogBufferFactory
|
import com.android.systemui.log.table.TableLogBufferFactory
|
||||||
import com.android.systemui.statusbar.pipeline.mobile.data.model.MobileConnectivityModel
|
import com.android.systemui.statusbar.pipeline.mobile.data.model.MobileConnectivityModel
|
||||||
import com.android.systemui.statusbar.pipeline.mobile.data.model.NetworkNameModel
|
|
||||||
import com.android.systemui.statusbar.pipeline.mobile.data.model.SubscriptionModel
|
import com.android.systemui.statusbar.pipeline.mobile.data.model.SubscriptionModel
|
||||||
|
import com.android.systemui.statusbar.pipeline.mobile.data.repository.prod.FullMobileConnectionRepository.Factory.Companion.tableBufferLogName
|
||||||
import com.android.systemui.statusbar.pipeline.mobile.util.FakeMobileMappingsProxy
|
import com.android.systemui.statusbar.pipeline.mobile.util.FakeMobileMappingsProxy
|
||||||
import com.android.systemui.statusbar.pipeline.shared.ConnectivityPipelineLogger
|
import com.android.systemui.statusbar.pipeline.shared.ConnectivityPipelineLogger
|
||||||
|
import com.android.systemui.statusbar.pipeline.wifi.data.model.WifiNetworkModel
|
||||||
|
import com.android.systemui.statusbar.pipeline.wifi.data.repository.FakeWifiRepository
|
||||||
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.eq
|
import com.android.systemui.util.mockito.eq
|
||||||
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.android.systemui.util.settings.FakeSettings
|
import com.android.systemui.util.settings.FakeSettings
|
||||||
import com.android.systemui.util.time.FakeSystemClock
|
|
||||||
import com.google.common.truth.Truth.assertThat
|
import com.google.common.truth.Truth.assertThat
|
||||||
import kotlinx.coroutines.CoroutineScope
|
import kotlinx.coroutines.CoroutineScope
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
@@ -74,6 +75,9 @@ class MobileConnectionsRepositoryTest : SysuiTestCase() {
|
|||||||
private lateinit var underTest: MobileConnectionsRepositoryImpl
|
private lateinit var underTest: MobileConnectionsRepositoryImpl
|
||||||
|
|
||||||
private lateinit var connectionFactory: MobileConnectionRepositoryImpl.Factory
|
private lateinit var connectionFactory: MobileConnectionRepositoryImpl.Factory
|
||||||
|
private lateinit var carrierMergedFactory: CarrierMergedConnectionRepository.Factory
|
||||||
|
private lateinit var fullConnectionFactory: FullMobileConnectionRepository.Factory
|
||||||
|
private lateinit var wifiRepository: FakeWifiRepository
|
||||||
@Mock private lateinit var connectivityManager: ConnectivityManager
|
@Mock private lateinit var connectivityManager: ConnectivityManager
|
||||||
@Mock private lateinit var subscriptionManager: SubscriptionManager
|
@Mock private lateinit var subscriptionManager: SubscriptionManager
|
||||||
@Mock private lateinit var telephonyManager: TelephonyManager
|
@Mock private lateinit var telephonyManager: TelephonyManager
|
||||||
@@ -100,6 +104,8 @@ class MobileConnectionsRepositoryTest : SysuiTestCase() {
|
|||||||
mock<TableLogBuffer>()
|
mock<TableLogBuffer>()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
wifiRepository = FakeWifiRepository()
|
||||||
|
|
||||||
connectionFactory =
|
connectionFactory =
|
||||||
MobileConnectionRepositoryImpl.Factory(
|
MobileConnectionRepositoryImpl.Factory(
|
||||||
fakeBroadcastDispatcher,
|
fakeBroadcastDispatcher,
|
||||||
@@ -110,7 +116,18 @@ class MobileConnectionsRepositoryTest : SysuiTestCase() {
|
|||||||
logger = logger,
|
logger = logger,
|
||||||
mobileMappingsProxy = mobileMappings,
|
mobileMappingsProxy = mobileMappings,
|
||||||
scope = scope,
|
scope = scope,
|
||||||
|
)
|
||||||
|
carrierMergedFactory =
|
||||||
|
CarrierMergedConnectionRepository.Factory(
|
||||||
|
scope,
|
||||||
|
wifiRepository,
|
||||||
|
)
|
||||||
|
fullConnectionFactory =
|
||||||
|
FullMobileConnectionRepository.Factory(
|
||||||
|
scope = scope,
|
||||||
logFactory = logBufferFactory,
|
logFactory = logBufferFactory,
|
||||||
|
mobileRepoFactory = connectionFactory,
|
||||||
|
carrierMergedRepoFactory = carrierMergedFactory,
|
||||||
)
|
)
|
||||||
|
|
||||||
underTest =
|
underTest =
|
||||||
@@ -125,7 +142,8 @@ class MobileConnectionsRepositoryTest : SysuiTestCase() {
|
|||||||
context,
|
context,
|
||||||
IMMEDIATE,
|
IMMEDIATE,
|
||||||
scope,
|
scope,
|
||||||
connectionFactory,
|
wifiRepository,
|
||||||
|
fullConnectionFactory,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -179,6 +197,40 @@ class MobileConnectionsRepositoryTest : SysuiTestCase() {
|
|||||||
job.cancel()
|
job.cancel()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun testSubscriptions_carrierMergedOnly_listHasCarrierMerged() =
|
||||||
|
runBlocking(IMMEDIATE) {
|
||||||
|
var latest: List<SubscriptionModel>? = null
|
||||||
|
|
||||||
|
val job = underTest.subscriptions.onEach { latest = it }.launchIn(this)
|
||||||
|
|
||||||
|
wifiRepository.setWifiNetwork(WIFI_NETWORK_CM)
|
||||||
|
whenever(subscriptionManager.completeActiveSubscriptionInfoList)
|
||||||
|
.thenReturn(listOf(SUB_CM))
|
||||||
|
getSubscriptionCallback().onSubscriptionsChanged()
|
||||||
|
|
||||||
|
assertThat(latest).isEqualTo(listOf(MODEL_CM))
|
||||||
|
|
||||||
|
job.cancel()
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun testSubscriptions_carrierMergedAndOther_listHasBothWithCarrierMergedLast() =
|
||||||
|
runBlocking(IMMEDIATE) {
|
||||||
|
var latest: List<SubscriptionModel>? = null
|
||||||
|
|
||||||
|
val job = underTest.subscriptions.onEach { latest = it }.launchIn(this)
|
||||||
|
|
||||||
|
wifiRepository.setWifiNetwork(WIFI_NETWORK_CM)
|
||||||
|
whenever(subscriptionManager.completeActiveSubscriptionInfoList)
|
||||||
|
.thenReturn(listOf(SUB_1, SUB_2, SUB_CM))
|
||||||
|
getSubscriptionCallback().onSubscriptionsChanged()
|
||||||
|
|
||||||
|
assertThat(latest).isEqualTo(listOf(MODEL_1, MODEL_2, MODEL_CM))
|
||||||
|
|
||||||
|
job.cancel()
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun testActiveDataSubscriptionId_initialValueIsInvalidId() =
|
fun testActiveDataSubscriptionId_initialValueIsInvalidId() =
|
||||||
runBlocking(IMMEDIATE) {
|
runBlocking(IMMEDIATE) {
|
||||||
@@ -218,6 +270,96 @@ class MobileConnectionsRepositoryTest : SysuiTestCase() {
|
|||||||
job.cancel()
|
job.cancel()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun testConnectionRepository_carrierMergedSubId_isCached() =
|
||||||
|
runBlocking(IMMEDIATE) {
|
||||||
|
val job = underTest.subscriptions.launchIn(this)
|
||||||
|
|
||||||
|
wifiRepository.setWifiNetwork(WIFI_NETWORK_CM)
|
||||||
|
whenever(subscriptionManager.completeActiveSubscriptionInfoList)
|
||||||
|
.thenReturn(listOf(SUB_CM))
|
||||||
|
getSubscriptionCallback().onSubscriptionsChanged()
|
||||||
|
|
||||||
|
val repo1 = underTest.getRepoForSubId(SUB_CM_ID)
|
||||||
|
val repo2 = underTest.getRepoForSubId(SUB_CM_ID)
|
||||||
|
|
||||||
|
assertThat(repo1).isSameInstanceAs(repo2)
|
||||||
|
|
||||||
|
job.cancel()
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun testConnectionRepository_carrierMergedAndMobileSubs_usesCorrectRepos() =
|
||||||
|
runBlocking(IMMEDIATE) {
|
||||||
|
val job = underTest.subscriptions.launchIn(this)
|
||||||
|
|
||||||
|
wifiRepository.setWifiNetwork(WIFI_NETWORK_CM)
|
||||||
|
whenever(subscriptionManager.completeActiveSubscriptionInfoList)
|
||||||
|
.thenReturn(listOf(SUB_1, SUB_CM))
|
||||||
|
getSubscriptionCallback().onSubscriptionsChanged()
|
||||||
|
|
||||||
|
val carrierMergedRepo = underTest.getRepoForSubId(SUB_CM_ID)
|
||||||
|
val mobileRepo = underTest.getRepoForSubId(SUB_1_ID)
|
||||||
|
assertThat(carrierMergedRepo.getIsCarrierMerged()).isTrue()
|
||||||
|
assertThat(mobileRepo.getIsCarrierMerged()).isFalse()
|
||||||
|
|
||||||
|
job.cancel()
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun testSubscriptions_subNoLongerCarrierMerged_repoUpdates() =
|
||||||
|
runBlocking(IMMEDIATE) {
|
||||||
|
val job = underTest.subscriptions.launchIn(this)
|
||||||
|
|
||||||
|
wifiRepository.setWifiNetwork(WIFI_NETWORK_CM)
|
||||||
|
whenever(subscriptionManager.completeActiveSubscriptionInfoList)
|
||||||
|
.thenReturn(listOf(SUB_1, SUB_CM))
|
||||||
|
getSubscriptionCallback().onSubscriptionsChanged()
|
||||||
|
|
||||||
|
val carrierMergedRepo = underTest.getRepoForSubId(SUB_CM_ID)
|
||||||
|
var mobileRepo = underTest.getRepoForSubId(SUB_1_ID)
|
||||||
|
assertThat(carrierMergedRepo.getIsCarrierMerged()).isTrue()
|
||||||
|
assertThat(mobileRepo.getIsCarrierMerged()).isFalse()
|
||||||
|
|
||||||
|
// WHEN the wifi network updates to be not carrier merged
|
||||||
|
wifiRepository.setWifiNetwork(WifiNetworkModel.Active(networkId = 4, level = 1))
|
||||||
|
|
||||||
|
// THEN the repos update
|
||||||
|
val noLongerCarrierMergedRepo = underTest.getRepoForSubId(SUB_CM_ID)
|
||||||
|
mobileRepo = underTest.getRepoForSubId(SUB_1_ID)
|
||||||
|
assertThat(noLongerCarrierMergedRepo.getIsCarrierMerged()).isFalse()
|
||||||
|
assertThat(mobileRepo.getIsCarrierMerged()).isFalse()
|
||||||
|
|
||||||
|
job.cancel()
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun testSubscriptions_subBecomesCarrierMerged_repoUpdates() =
|
||||||
|
runBlocking(IMMEDIATE) {
|
||||||
|
val job = underTest.subscriptions.launchIn(this)
|
||||||
|
|
||||||
|
wifiRepository.setWifiNetwork(WifiNetworkModel.Inactive)
|
||||||
|
whenever(subscriptionManager.completeActiveSubscriptionInfoList)
|
||||||
|
.thenReturn(listOf(SUB_1, SUB_CM))
|
||||||
|
getSubscriptionCallback().onSubscriptionsChanged()
|
||||||
|
|
||||||
|
val notYetCarrierMergedRepo = underTest.getRepoForSubId(SUB_CM_ID)
|
||||||
|
var mobileRepo = underTest.getRepoForSubId(SUB_1_ID)
|
||||||
|
assertThat(notYetCarrierMergedRepo.getIsCarrierMerged()).isFalse()
|
||||||
|
assertThat(mobileRepo.getIsCarrierMerged()).isFalse()
|
||||||
|
|
||||||
|
// WHEN the wifi network updates to be carrier merged
|
||||||
|
wifiRepository.setWifiNetwork(WIFI_NETWORK_CM)
|
||||||
|
|
||||||
|
// THEN the repos update
|
||||||
|
val carrierMergedRepo = underTest.getRepoForSubId(SUB_CM_ID)
|
||||||
|
mobileRepo = underTest.getRepoForSubId(SUB_1_ID)
|
||||||
|
assertThat(carrierMergedRepo.getIsCarrierMerged()).isTrue()
|
||||||
|
assertThat(mobileRepo.getIsCarrierMerged()).isFalse()
|
||||||
|
|
||||||
|
job.cancel()
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun testConnectionCache_clearsInvalidSubscriptions() =
|
fun testConnectionCache_clearsInvalidSubscriptions() =
|
||||||
runBlocking(IMMEDIATE) {
|
runBlocking(IMMEDIATE) {
|
||||||
@@ -244,6 +386,34 @@ class MobileConnectionsRepositoryTest : SysuiTestCase() {
|
|||||||
job.cancel()
|
job.cancel()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun testConnectionCache_clearsInvalidSubscriptions_includingCarrierMerged() =
|
||||||
|
runBlocking(IMMEDIATE) {
|
||||||
|
val job = underTest.subscriptions.launchIn(this)
|
||||||
|
|
||||||
|
wifiRepository.setWifiNetwork(WIFI_NETWORK_CM)
|
||||||
|
whenever(subscriptionManager.completeActiveSubscriptionInfoList)
|
||||||
|
.thenReturn(listOf(SUB_1, SUB_2, SUB_CM))
|
||||||
|
getSubscriptionCallback().onSubscriptionsChanged()
|
||||||
|
|
||||||
|
// Get repos to trigger caching
|
||||||
|
val repo1 = underTest.getRepoForSubId(SUB_1_ID)
|
||||||
|
val repo2 = underTest.getRepoForSubId(SUB_2_ID)
|
||||||
|
val repoCarrierMerged = underTest.getRepoForSubId(SUB_CM_ID)
|
||||||
|
|
||||||
|
assertThat(underTest.getSubIdRepoCache())
|
||||||
|
.containsExactly(SUB_1_ID, repo1, SUB_2_ID, repo2, SUB_CM_ID, repoCarrierMerged)
|
||||||
|
|
||||||
|
// SUB_2 and SUB_CM disappear
|
||||||
|
whenever(subscriptionManager.completeActiveSubscriptionInfoList)
|
||||||
|
.thenReturn(listOf(SUB_1))
|
||||||
|
getSubscriptionCallback().onSubscriptionsChanged()
|
||||||
|
|
||||||
|
assertThat(underTest.getSubIdRepoCache()).containsExactly(SUB_1_ID, repo1)
|
||||||
|
|
||||||
|
job.cancel()
|
||||||
|
}
|
||||||
|
|
||||||
/** Regression test for b/261706421 */
|
/** Regression test for b/261706421 */
|
||||||
@Test
|
@Test
|
||||||
fun testConnectionsCache_clearMultipleSubscriptionsAtOnce_doesNotThrow() =
|
fun testConnectionsCache_clearMultipleSubscriptionsAtOnce_doesNotThrow() =
|
||||||
@@ -295,59 +465,19 @@ class MobileConnectionsRepositoryTest : SysuiTestCase() {
|
|||||||
underTest.getRepoForSubId(SUB_1_ID)
|
underTest.getRepoForSubId(SUB_1_ID)
|
||||||
verify(logBufferFactory)
|
verify(logBufferFactory)
|
||||||
.getOrCreate(
|
.getOrCreate(
|
||||||
eq(MobileConnectionRepositoryImpl.tableBufferLogName(SUB_1_ID)),
|
eq(tableBufferLogName(SUB_1_ID)),
|
||||||
anyInt(),
|
anyInt(),
|
||||||
)
|
)
|
||||||
underTest.getRepoForSubId(SUB_2_ID)
|
underTest.getRepoForSubId(SUB_2_ID)
|
||||||
verify(logBufferFactory)
|
verify(logBufferFactory)
|
||||||
.getOrCreate(
|
.getOrCreate(
|
||||||
eq(MobileConnectionRepositoryImpl.tableBufferLogName(SUB_2_ID)),
|
eq(tableBufferLogName(SUB_2_ID)),
|
||||||
anyInt(),
|
anyInt(),
|
||||||
)
|
)
|
||||||
|
|
||||||
job.cancel()
|
job.cancel()
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
|
||||||
fun `connection repository factory - reuses log buffers for same connection`() =
|
|
||||||
runBlocking(IMMEDIATE) {
|
|
||||||
val realLoggerFactory = TableLogBufferFactory(mock(), FakeSystemClock())
|
|
||||||
|
|
||||||
connectionFactory =
|
|
||||||
MobileConnectionRepositoryImpl.Factory(
|
|
||||||
fakeBroadcastDispatcher,
|
|
||||||
context = context,
|
|
||||||
telephonyManager = telephonyManager,
|
|
||||||
bgDispatcher = IMMEDIATE,
|
|
||||||
globalSettings = globalSettings,
|
|
||||||
logger = logger,
|
|
||||||
mobileMappingsProxy = mobileMappings,
|
|
||||||
scope = scope,
|
|
||||||
logFactory = realLoggerFactory,
|
|
||||||
)
|
|
||||||
|
|
||||||
// Create two connections for the same subId. Similar to if the connection appeared
|
|
||||||
// and disappeared from the connectionFactory's perspective
|
|
||||||
val connection1 =
|
|
||||||
connectionFactory.build(
|
|
||||||
1,
|
|
||||||
NetworkNameModel.Default("default_name"),
|
|
||||||
"-",
|
|
||||||
underTest.globalMobileDataSettingChangedEvent,
|
|
||||||
)
|
|
||||||
|
|
||||||
val connection1_repeat =
|
|
||||||
connectionFactory.build(
|
|
||||||
1,
|
|
||||||
NetworkNameModel.Default("default_name"),
|
|
||||||
"-",
|
|
||||||
underTest.globalMobileDataSettingChangedEvent,
|
|
||||||
)
|
|
||||||
|
|
||||||
assertThat(connection1.tableLogBuffer)
|
|
||||||
.isSameInstanceAs(connection1_repeat.tableLogBuffer)
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun mobileConnectivity_default() {
|
fun mobileConnectivity_default() {
|
||||||
assertThat(underTest.defaultMobileNetworkConnectivity.value)
|
assertThat(underTest.defaultMobileNetworkConnectivity.value)
|
||||||
@@ -461,7 +591,8 @@ class MobileConnectionsRepositoryTest : SysuiTestCase() {
|
|||||||
context,
|
context,
|
||||||
IMMEDIATE,
|
IMMEDIATE,
|
||||||
scope,
|
scope,
|
||||||
connectionFactory,
|
wifiRepository,
|
||||||
|
fullConnectionFactory,
|
||||||
)
|
)
|
||||||
|
|
||||||
var latest: MobileMappings.Config? = null
|
var latest: MobileMappings.Config? = null
|
||||||
@@ -571,5 +702,16 @@ class MobileConnectionsRepositoryTest : SysuiTestCase() {
|
|||||||
|
|
||||||
private const val NET_ID = 123
|
private const val NET_ID = 123
|
||||||
private val NETWORK = mock<Network>().apply { whenever(getNetId()).thenReturn(NET_ID) }
|
private val NETWORK = mock<Network>().apply { whenever(getNetId()).thenReturn(NET_ID) }
|
||||||
|
|
||||||
|
private const val SUB_CM_ID = 5
|
||||||
|
private val SUB_CM =
|
||||||
|
mock<SubscriptionInfo>().also { whenever(it.subscriptionId).thenReturn(SUB_CM_ID) }
|
||||||
|
private val MODEL_CM = SubscriptionModel(subscriptionId = SUB_CM_ID)
|
||||||
|
private val WIFI_NETWORK_CM =
|
||||||
|
WifiNetworkModel.CarrierMerged(
|
||||||
|
networkId = 3,
|
||||||
|
subscriptionId = SUB_CM_ID,
|
||||||
|
level = 1,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -25,6 +25,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.DataConnectionState
|
||||||
import com.android.systemui.statusbar.pipeline.mobile.data.model.MobileConnectionModel
|
import com.android.systemui.statusbar.pipeline.mobile.data.model.MobileConnectionModel
|
||||||
import com.android.systemui.statusbar.pipeline.mobile.data.model.NetworkNameModel
|
import com.android.systemui.statusbar.pipeline.mobile.data.model.NetworkNameModel
|
||||||
|
import com.android.systemui.statusbar.pipeline.mobile.data.model.ResolvedNetworkType.CarrierMergedNetworkType
|
||||||
import com.android.systemui.statusbar.pipeline.mobile.data.model.ResolvedNetworkType.DefaultNetworkType
|
import com.android.systemui.statusbar.pipeline.mobile.data.model.ResolvedNetworkType.DefaultNetworkType
|
||||||
import com.android.systemui.statusbar.pipeline.mobile.data.model.ResolvedNetworkType.OverrideNetworkType
|
import com.android.systemui.statusbar.pipeline.mobile.data.model.ResolvedNetworkType.OverrideNetworkType
|
||||||
import com.android.systemui.statusbar.pipeline.mobile.data.repository.FakeMobileConnectionRepository
|
import com.android.systemui.statusbar.pipeline.mobile.data.repository.FakeMobileConnectionRepository
|
||||||
@@ -270,6 +271,23 @@ class MobileIconInteractorTest : SysuiTestCase() {
|
|||||||
job.cancel()
|
job.cancel()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun iconGroup_carrierMerged_usesOverride() =
|
||||||
|
runBlocking(IMMEDIATE) {
|
||||||
|
connectionRepository.setConnectionInfo(
|
||||||
|
MobileConnectionModel(
|
||||||
|
resolvedNetworkType = CarrierMergedNetworkType,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
|
||||||
|
var latest: MobileIconGroup? = null
|
||||||
|
val job = underTest.networkTypeIconGroup.onEach { latest = it }.launchIn(this)
|
||||||
|
|
||||||
|
assertThat(latest).isEqualTo(CarrierMergedNetworkType.iconGroupOverride)
|
||||||
|
|
||||||
|
job.cancel()
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun alwaysShowDataRatIcon_matchesParent() =
|
fun alwaysShowDataRatIcon_matchesParent() =
|
||||||
runBlocking(IMMEDIATE) {
|
runBlocking(IMMEDIATE) {
|
||||||
|
|||||||
@@ -16,11 +16,12 @@
|
|||||||
|
|
||||||
package com.android.systemui.statusbar.pipeline.wifi.data.model
|
package com.android.systemui.statusbar.pipeline.wifi.data.model
|
||||||
|
|
||||||
|
import android.telephony.SubscriptionManager.INVALID_SUBSCRIPTION_ID
|
||||||
import androidx.test.filters.SmallTest
|
import androidx.test.filters.SmallTest
|
||||||
import com.android.systemui.SysuiTestCase
|
import com.android.systemui.SysuiTestCase
|
||||||
import com.android.systemui.log.table.TableRowLogger
|
import com.android.systemui.log.table.TableRowLogger
|
||||||
import com.android.systemui.statusbar.pipeline.wifi.data.model.WifiNetworkModel.Active.Companion.MAX_VALID_LEVEL
|
import com.android.systemui.statusbar.pipeline.wifi.data.model.WifiNetworkModel.Active.Companion.MAX_VALID_LEVEL
|
||||||
import com.android.systemui.statusbar.pipeline.wifi.data.model.WifiNetworkModel.Active.Companion.MIN_VALID_LEVEL
|
import com.android.systemui.statusbar.pipeline.wifi.data.model.WifiNetworkModel.Companion.MIN_VALID_LEVEL
|
||||||
import com.google.common.truth.Truth.assertThat
|
import com.google.common.truth.Truth.assertThat
|
||||||
import org.junit.Test
|
import org.junit.Test
|
||||||
|
|
||||||
@@ -44,8 +45,52 @@ class WifiNetworkModelTest : SysuiTestCase() {
|
|||||||
WifiNetworkModel.Active(NETWORK_ID, level = MAX_VALID_LEVEL + 1)
|
WifiNetworkModel.Active(NETWORK_ID, level = MAX_VALID_LEVEL + 1)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test(expected = IllegalArgumentException::class)
|
||||||
|
fun carrierMerged_invalidSubId_exceptionThrown() {
|
||||||
|
WifiNetworkModel.CarrierMerged(NETWORK_ID, INVALID_SUBSCRIPTION_ID, 1)
|
||||||
|
}
|
||||||
|
|
||||||
// Non-exhaustive logDiffs test -- just want to make sure the logging logic isn't totally broken
|
// Non-exhaustive logDiffs test -- just want to make sure the logging logic isn't totally broken
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun logDiffs_carrierMergedToInactive_resetsAllFields() {
|
||||||
|
val logger = TestLogger()
|
||||||
|
val prevVal =
|
||||||
|
WifiNetworkModel.CarrierMerged(
|
||||||
|
networkId = 5,
|
||||||
|
subscriptionId = 3,
|
||||||
|
level = 1,
|
||||||
|
)
|
||||||
|
|
||||||
|
WifiNetworkModel.Inactive.logDiffs(prevVal, logger)
|
||||||
|
|
||||||
|
assertThat(logger.changes).contains(Pair(COL_NETWORK_TYPE, TYPE_INACTIVE))
|
||||||
|
assertThat(logger.changes).contains(Pair(COL_NETWORK_ID, NETWORK_ID_DEFAULT.toString()))
|
||||||
|
assertThat(logger.changes).contains(Pair(COL_VALIDATED, "false"))
|
||||||
|
assertThat(logger.changes).contains(Pair(COL_LEVEL, LEVEL_DEFAULT.toString()))
|
||||||
|
assertThat(logger.changes).contains(Pair(COL_SSID, "null"))
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun logDiffs_inactiveToCarrierMerged_logsAllFields() {
|
||||||
|
val logger = TestLogger()
|
||||||
|
val carrierMerged =
|
||||||
|
WifiNetworkModel.CarrierMerged(
|
||||||
|
networkId = 6,
|
||||||
|
subscriptionId = 3,
|
||||||
|
level = 2,
|
||||||
|
)
|
||||||
|
|
||||||
|
carrierMerged.logDiffs(prevVal = WifiNetworkModel.Inactive, logger)
|
||||||
|
|
||||||
|
assertThat(logger.changes).contains(Pair(COL_NETWORK_TYPE, TYPE_CARRIER_MERGED))
|
||||||
|
assertThat(logger.changes).contains(Pair(COL_NETWORK_ID, "6"))
|
||||||
|
assertThat(logger.changes).contains(Pair(COL_SUB_ID, "3"))
|
||||||
|
assertThat(logger.changes).contains(Pair(COL_VALIDATED, "true"))
|
||||||
|
assertThat(logger.changes).contains(Pair(COL_LEVEL, "2"))
|
||||||
|
assertThat(logger.changes).contains(Pair(COL_SSID, "null"))
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun logDiffs_inactiveToActive_logsAllActiveFields() {
|
fun logDiffs_inactiveToActive_logsAllActiveFields() {
|
||||||
val logger = TestLogger()
|
val logger = TestLogger()
|
||||||
@@ -95,8 +140,14 @@ class WifiNetworkModelTest : SysuiTestCase() {
|
|||||||
level = 3,
|
level = 3,
|
||||||
ssid = "Test SSID"
|
ssid = "Test SSID"
|
||||||
)
|
)
|
||||||
|
val prevVal =
|
||||||
|
WifiNetworkModel.CarrierMerged(
|
||||||
|
networkId = 5,
|
||||||
|
subscriptionId = 3,
|
||||||
|
level = 1,
|
||||||
|
)
|
||||||
|
|
||||||
activeNetwork.logDiffs(prevVal = WifiNetworkModel.CarrierMerged, logger)
|
activeNetwork.logDiffs(prevVal, logger)
|
||||||
|
|
||||||
assertThat(logger.changes).contains(Pair(COL_NETWORK_TYPE, TYPE_ACTIVE))
|
assertThat(logger.changes).contains(Pair(COL_NETWORK_TYPE, TYPE_ACTIVE))
|
||||||
assertThat(logger.changes).contains(Pair(COL_NETWORK_ID, "5"))
|
assertThat(logger.changes).contains(Pair(COL_NETWORK_ID, "5"))
|
||||||
@@ -105,7 +156,7 @@ class WifiNetworkModelTest : SysuiTestCase() {
|
|||||||
assertThat(logger.changes).contains(Pair(COL_SSID, "Test SSID"))
|
assertThat(logger.changes).contains(Pair(COL_SSID, "Test SSID"))
|
||||||
}
|
}
|
||||||
@Test
|
@Test
|
||||||
fun logDiffs_activeToCarrierMerged_resetsAllActiveFields() {
|
fun logDiffs_activeToCarrierMerged_logsAllFields() {
|
||||||
val logger = TestLogger()
|
val logger = TestLogger()
|
||||||
val activeNetwork =
|
val activeNetwork =
|
||||||
WifiNetworkModel.Active(
|
WifiNetworkModel.Active(
|
||||||
@@ -114,13 +165,20 @@ class WifiNetworkModelTest : SysuiTestCase() {
|
|||||||
level = 3,
|
level = 3,
|
||||||
ssid = "Test SSID"
|
ssid = "Test SSID"
|
||||||
)
|
)
|
||||||
|
val carrierMerged =
|
||||||
|
WifiNetworkModel.CarrierMerged(
|
||||||
|
networkId = 6,
|
||||||
|
subscriptionId = 3,
|
||||||
|
level = 2,
|
||||||
|
)
|
||||||
|
|
||||||
WifiNetworkModel.CarrierMerged.logDiffs(prevVal = activeNetwork, logger)
|
carrierMerged.logDiffs(prevVal = activeNetwork, logger)
|
||||||
|
|
||||||
assertThat(logger.changes).contains(Pair(COL_NETWORK_TYPE, TYPE_CARRIER_MERGED))
|
assertThat(logger.changes).contains(Pair(COL_NETWORK_TYPE, TYPE_CARRIER_MERGED))
|
||||||
assertThat(logger.changes).contains(Pair(COL_NETWORK_ID, NETWORK_ID_DEFAULT.toString()))
|
assertThat(logger.changes).contains(Pair(COL_NETWORK_ID, "6"))
|
||||||
assertThat(logger.changes).contains(Pair(COL_VALIDATED, "false"))
|
assertThat(logger.changes).contains(Pair(COL_SUB_ID, "3"))
|
||||||
assertThat(logger.changes).contains(Pair(COL_LEVEL, LEVEL_DEFAULT.toString()))
|
assertThat(logger.changes).contains(Pair(COL_VALIDATED, "true"))
|
||||||
|
assertThat(logger.changes).contains(Pair(COL_LEVEL, "2"))
|
||||||
assertThat(logger.changes).contains(Pair(COL_SSID, "null"))
|
assertThat(logger.changes).contains(Pair(COL_SSID, "null"))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -26,6 +26,7 @@ import android.net.vcn.VcnTransportInfo
|
|||||||
import android.net.wifi.WifiInfo
|
import android.net.wifi.WifiInfo
|
||||||
import android.net.wifi.WifiManager
|
import android.net.wifi.WifiManager
|
||||||
import android.net.wifi.WifiManager.TrafficStateCallback
|
import android.net.wifi.WifiManager.TrafficStateCallback
|
||||||
|
import android.telephony.SubscriptionManager.INVALID_SUBSCRIPTION_ID
|
||||||
import androidx.test.filters.SmallTest
|
import androidx.test.filters.SmallTest
|
||||||
import com.android.systemui.SysuiTestCase
|
import com.android.systemui.SysuiTestCase
|
||||||
import com.android.systemui.broadcast.BroadcastDispatcher
|
import com.android.systemui.broadcast.BroadcastDispatcher
|
||||||
@@ -340,7 +341,6 @@ class WifiRepositoryImplTest : SysuiTestCase() {
|
|||||||
.launchIn(this)
|
.launchIn(this)
|
||||||
|
|
||||||
val wifiInfo = mock<WifiInfo>().apply {
|
val wifiInfo = mock<WifiInfo>().apply {
|
||||||
whenever(this.ssid).thenReturn(SSID)
|
|
||||||
whenever(this.isPrimary).thenReturn(true)
|
whenever(this.isPrimary).thenReturn(true)
|
||||||
whenever(this.isCarrierMerged).thenReturn(true)
|
whenever(this.isCarrierMerged).thenReturn(true)
|
||||||
}
|
}
|
||||||
@@ -352,6 +352,67 @@ class WifiRepositoryImplTest : SysuiTestCase() {
|
|||||||
job.cancel()
|
job.cancel()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun wifiNetwork_carrierMergedButInvalidSubId_flowHasInvalid() =
|
||||||
|
runBlocking(IMMEDIATE) {
|
||||||
|
var latest: WifiNetworkModel? = null
|
||||||
|
val job = underTest
|
||||||
|
.wifiNetwork
|
||||||
|
.onEach { latest = it }
|
||||||
|
.launchIn(this)
|
||||||
|
|
||||||
|
val wifiInfo = mock<WifiInfo>().apply {
|
||||||
|
whenever(this.isPrimary).thenReturn(true)
|
||||||
|
whenever(this.isCarrierMerged).thenReturn(true)
|
||||||
|
whenever(this.subscriptionId).thenReturn(INVALID_SUBSCRIPTION_ID)
|
||||||
|
}
|
||||||
|
|
||||||
|
getNetworkCallback().onCapabilitiesChanged(
|
||||||
|
NETWORK,
|
||||||
|
createWifiNetworkCapabilities(wifiInfo),
|
||||||
|
)
|
||||||
|
|
||||||
|
assertThat(latest).isInstanceOf(WifiNetworkModel.Invalid::class.java)
|
||||||
|
|
||||||
|
job.cancel()
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun wifiNetwork_isCarrierMerged_getsCorrectValues() =
|
||||||
|
runBlocking(IMMEDIATE) {
|
||||||
|
var latest: WifiNetworkModel? = null
|
||||||
|
val job = underTest
|
||||||
|
.wifiNetwork
|
||||||
|
.onEach { latest = it }
|
||||||
|
.launchIn(this)
|
||||||
|
|
||||||
|
val rssi = -57
|
||||||
|
val wifiInfo = mock<WifiInfo>().apply {
|
||||||
|
whenever(this.isPrimary).thenReturn(true)
|
||||||
|
whenever(this.isCarrierMerged).thenReturn(true)
|
||||||
|
whenever(this.rssi).thenReturn(rssi)
|
||||||
|
whenever(this.subscriptionId).thenReturn(567)
|
||||||
|
}
|
||||||
|
|
||||||
|
whenever(wifiManager.calculateSignalLevel(rssi)).thenReturn(2)
|
||||||
|
whenever(wifiManager.maxSignalLevel).thenReturn(5)
|
||||||
|
|
||||||
|
getNetworkCallback().onCapabilitiesChanged(
|
||||||
|
NETWORK,
|
||||||
|
createWifiNetworkCapabilities(wifiInfo),
|
||||||
|
)
|
||||||
|
|
||||||
|
assertThat(latest is WifiNetworkModel.CarrierMerged).isTrue()
|
||||||
|
val latestCarrierMerged = latest as WifiNetworkModel.CarrierMerged
|
||||||
|
assertThat(latestCarrierMerged.networkId).isEqualTo(NETWORK_ID)
|
||||||
|
assertThat(latestCarrierMerged.subscriptionId).isEqualTo(567)
|
||||||
|
assertThat(latestCarrierMerged.level).isEqualTo(2)
|
||||||
|
// numberOfLevels = maxSignalLevel + 1
|
||||||
|
assertThat(latestCarrierMerged.numberOfLevels).isEqualTo(6)
|
||||||
|
|
||||||
|
job.cancel()
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun wifiNetwork_notValidated_networkNotValidated() = runBlocking(IMMEDIATE) {
|
fun wifiNetwork_notValidated_networkNotValidated() = runBlocking(IMMEDIATE) {
|
||||||
var latest: WifiNetworkModel? = null
|
var latest: WifiNetworkModel? = null
|
||||||
|
|||||||
@@ -84,7 +84,9 @@ class WifiInteractorImplTest : SysuiTestCase() {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun ssid_carrierMergedNetwork_outputsNull() = runBlocking(IMMEDIATE) {
|
fun ssid_carrierMergedNetwork_outputsNull() = runBlocking(IMMEDIATE) {
|
||||||
wifiRepository.setWifiNetwork(WifiNetworkModel.CarrierMerged)
|
wifiRepository.setWifiNetwork(
|
||||||
|
WifiNetworkModel.CarrierMerged(networkId = 1, subscriptionId = 2, level = 1)
|
||||||
|
)
|
||||||
|
|
||||||
var latest: String? = "default"
|
var latest: String? = "default"
|
||||||
val job = underTest
|
val job = underTest
|
||||||
|
|||||||
@@ -206,7 +206,8 @@ internal class WifiViewModelIconParameterizedTest(private val testCase: TestCase
|
|||||||
// Enabled = false => no networks shown
|
// Enabled = false => no networks shown
|
||||||
TestCase(
|
TestCase(
|
||||||
enabled = false,
|
enabled = false,
|
||||||
network = WifiNetworkModel.CarrierMerged,
|
network =
|
||||||
|
WifiNetworkModel.CarrierMerged(NETWORK_ID, subscriptionId = 1, level = 1),
|
||||||
expected = null,
|
expected = null,
|
||||||
),
|
),
|
||||||
TestCase(
|
TestCase(
|
||||||
@@ -228,7 +229,8 @@ internal class WifiViewModelIconParameterizedTest(private val testCase: TestCase
|
|||||||
// forceHidden = true => no networks shown
|
// forceHidden = true => no networks shown
|
||||||
TestCase(
|
TestCase(
|
||||||
forceHidden = true,
|
forceHidden = true,
|
||||||
network = WifiNetworkModel.CarrierMerged,
|
network =
|
||||||
|
WifiNetworkModel.CarrierMerged(NETWORK_ID, subscriptionId = 1, level = 1),
|
||||||
expected = null,
|
expected = null,
|
||||||
),
|
),
|
||||||
TestCase(
|
TestCase(
|
||||||
@@ -369,7 +371,8 @@ internal class WifiViewModelIconParameterizedTest(private val testCase: TestCase
|
|||||||
|
|
||||||
// network = CarrierMerged => not shown
|
// network = CarrierMerged => not shown
|
||||||
TestCase(
|
TestCase(
|
||||||
network = WifiNetworkModel.CarrierMerged,
|
network =
|
||||||
|
WifiNetworkModel.CarrierMerged(NETWORK_ID, subscriptionId = 1, level = 1),
|
||||||
expected = null,
|
expected = null,
|
||||||
),
|
),
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user