Merge changes I6843e949,Ied9eea84,Id3ae744f into tm-qpr-dev
* changes: [Sb refactor] Rework TelephonyCallback flows [Sb refactor] Implement DataEnabledChangedListener [Sb refactor] CarrierConfigRepository
This commit is contained in:
@@ -49,6 +49,7 @@
|
|||||||
<permission name="android.permission.READ_FRAME_BUFFER"/>
|
<permission name="android.permission.READ_FRAME_BUFFER"/>
|
||||||
<permission name="android.permission.READ_NETWORK_USAGE_HISTORY"/>
|
<permission name="android.permission.READ_NETWORK_USAGE_HISTORY"/>
|
||||||
<permission name="android.permission.READ_PRIVILEGED_PHONE_STATE"/>
|
<permission name="android.permission.READ_PRIVILEGED_PHONE_STATE"/>
|
||||||
|
<permission name="android.permission.READ_PRECISE_PHONE_STATE"/>
|
||||||
<permission name="android.permission.REAL_GET_TASKS"/>
|
<permission name="android.permission.REAL_GET_TASKS"/>
|
||||||
<permission name="android.permission.REQUEST_NETWORK_SCORES"/>
|
<permission name="android.permission.REQUEST_NETWORK_SCORES"/>
|
||||||
<permission name="android.permission.RECEIVE_MEDIA_RESOURCE_USAGE"/>
|
<permission name="android.permission.RECEIVE_MEDIA_RESOURCE_USAGE"/>
|
||||||
|
|||||||
@@ -68,6 +68,7 @@
|
|||||||
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
|
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
|
||||||
<uses-permission android:name="android.permission.CHANGE_NETWORK_STATE" />
|
<uses-permission android:name="android.permission.CHANGE_NETWORK_STATE" />
|
||||||
<uses-permission android:name="android.permission.READ_PRIVILEGED_PHONE_STATE" />
|
<uses-permission android:name="android.permission.READ_PRIVILEGED_PHONE_STATE" />
|
||||||
|
<uses-permission android:name="android.permission.READ_PRECISE_PHONE_STATE" />
|
||||||
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
|
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
|
||||||
<uses-permission android:name="android.permission.CHANGE_WIFI_STATE" />
|
<uses-permission android:name="android.permission.CHANGE_WIFI_STATE" />
|
||||||
<uses-permission android:name="android.permission.OVERRIDE_WIFI_CONFIG" />
|
<uses-permission android:name="android.permission.OVERRIDE_WIFI_CONFIG" />
|
||||||
|
|||||||
@@ -25,6 +25,7 @@ import com.android.systemui.statusbar.pipeline.airplane.data.repository.Airplane
|
|||||||
import com.android.systemui.statusbar.pipeline.airplane.data.repository.AirplaneModeRepositoryImpl
|
import com.android.systemui.statusbar.pipeline.airplane.data.repository.AirplaneModeRepositoryImpl
|
||||||
import com.android.systemui.statusbar.pipeline.airplane.ui.viewmodel.AirplaneModeViewModel
|
import com.android.systemui.statusbar.pipeline.airplane.ui.viewmodel.AirplaneModeViewModel
|
||||||
import com.android.systemui.statusbar.pipeline.airplane.ui.viewmodel.AirplaneModeViewModelImpl
|
import com.android.systemui.statusbar.pipeline.airplane.ui.viewmodel.AirplaneModeViewModelImpl
|
||||||
|
import com.android.systemui.statusbar.pipeline.mobile.data.repository.CarrierConfigCoreStartable
|
||||||
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.data.repository.MobileRepositorySwitcher
|
import com.android.systemui.statusbar.pipeline.mobile.data.repository.MobileRepositorySwitcher
|
||||||
import com.android.systemui.statusbar.pipeline.mobile.data.repository.UserSetupRepository
|
import com.android.systemui.statusbar.pipeline.mobile.data.repository.UserSetupRepository
|
||||||
@@ -82,6 +83,11 @@ abstract class StatusBarPipelineModule {
|
|||||||
@ClassKey(MobileUiAdapter::class)
|
@ClassKey(MobileUiAdapter::class)
|
||||||
abstract fun bindFeature(impl: MobileUiAdapter): CoreStartable
|
abstract fun bindFeature(impl: MobileUiAdapter): CoreStartable
|
||||||
|
|
||||||
|
@Binds
|
||||||
|
@IntoMap
|
||||||
|
@ClassKey(CarrierConfigCoreStartable::class)
|
||||||
|
abstract fun bindCarrierConfigStartable(impl: CarrierConfigCoreStartable): CoreStartable
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
@Provides
|
@Provides
|
||||||
@SysUISingleton
|
@SysUISingleton
|
||||||
|
|||||||
@@ -0,0 +1,108 @@
|
|||||||
|
/*
|
||||||
|
* 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.model
|
||||||
|
|
||||||
|
import android.os.PersistableBundle
|
||||||
|
import android.telephony.CarrierConfigManager.KEY_INFLATE_SIGNAL_STRENGTH_BOOL
|
||||||
|
import android.telephony.CarrierConfigManager.KEY_SHOW_OPERATOR_NAME_IN_STATUSBAR_BOOL
|
||||||
|
import androidx.annotation.VisibleForTesting
|
||||||
|
import kotlinx.coroutines.flow.MutableStateFlow
|
||||||
|
import kotlinx.coroutines.flow.StateFlow
|
||||||
|
import kotlinx.coroutines.flow.asStateFlow
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Represents, for a given subscription ID, the set of keys about which SystemUI cares.
|
||||||
|
*
|
||||||
|
* Upon first creation, this config represents only the default configuration (see
|
||||||
|
* [android.telephony.CarrierConfigManager.getDefaultConfig]).
|
||||||
|
*
|
||||||
|
* Upon request (see
|
||||||
|
* [com.android.systemui.statusbar.pipeline.mobile.data.repository.CarrierConfigRepository]), an
|
||||||
|
* instance of this class may be created for a given subscription Id, and will default to
|
||||||
|
* representing the default carrier configuration. However, once a carrier config is received for
|
||||||
|
* this [subId], all fields will reflect those in the received config, using [PersistableBundle]'s
|
||||||
|
* default of false for any config that is not present in the override.
|
||||||
|
*
|
||||||
|
* To keep things relatively simple, this class defines a wrapper around each config key which
|
||||||
|
* exposes a StateFlow<Boolean> for each config we care about. It also tracks whether or not it is
|
||||||
|
* using the default config for logging purposes.
|
||||||
|
*
|
||||||
|
* NOTE to add new keys to be tracked:
|
||||||
|
* 1. Define a new `private val` wrapping the key using [BooleanCarrierConfig]
|
||||||
|
* 2. Define a public `val` exposing the wrapped flow using [BooleanCarrierConfig.config]
|
||||||
|
* 3. Add the new [BooleanCarrierConfig] to the list of tracked configs, so they are properly
|
||||||
|
* updated when a new carrier config comes down
|
||||||
|
*/
|
||||||
|
class SystemUiCarrierConfig
|
||||||
|
internal constructor(
|
||||||
|
val subId: Int,
|
||||||
|
defaultConfig: PersistableBundle,
|
||||||
|
) {
|
||||||
|
@VisibleForTesting
|
||||||
|
var isUsingDefault = true
|
||||||
|
private set
|
||||||
|
|
||||||
|
private val inflateSignalStrength =
|
||||||
|
BooleanCarrierConfig(KEY_INFLATE_SIGNAL_STRENGTH_BOOL, defaultConfig)
|
||||||
|
/** Flow tracking the [KEY_INFLATE_SIGNAL_STRENGTH_BOOL] carrier config */
|
||||||
|
val shouldInflateSignalStrength: StateFlow<Boolean> = inflateSignalStrength.config
|
||||||
|
|
||||||
|
private val showOperatorName =
|
||||||
|
BooleanCarrierConfig(KEY_SHOW_OPERATOR_NAME_IN_STATUSBAR_BOOL, defaultConfig)
|
||||||
|
/** Flow tracking the [KEY_SHOW_OPERATOR_NAME_IN_STATUSBAR_BOOL] config */
|
||||||
|
val showOperatorNameInStatusBar: StateFlow<Boolean> = showOperatorName.config
|
||||||
|
|
||||||
|
private val trackedConfigs =
|
||||||
|
listOf(
|
||||||
|
inflateSignalStrength,
|
||||||
|
showOperatorName,
|
||||||
|
)
|
||||||
|
|
||||||
|
/** Ingest a new carrier config, and switch all of the tracked keys over to the new values */
|
||||||
|
fun processNewCarrierConfig(config: PersistableBundle) {
|
||||||
|
isUsingDefault = false
|
||||||
|
trackedConfigs.forEach { it.update(config) }
|
||||||
|
}
|
||||||
|
|
||||||
|
/** For dumpsys, shortcut if we haven't overridden any keys */
|
||||||
|
fun toStringConsideringDefaults(): String {
|
||||||
|
return if (isUsingDefault) {
|
||||||
|
"using defaults"
|
||||||
|
} else {
|
||||||
|
trackedConfigs.joinToString { it.toString() }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun toString(): String = trackedConfigs.joinToString { it.toString() }
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Extracts [key] from the carrier config, and stores it in a flow */
|
||||||
|
private class BooleanCarrierConfig(
|
||||||
|
val key: String,
|
||||||
|
defaultConfig: PersistableBundle,
|
||||||
|
) {
|
||||||
|
private val _configValue = MutableStateFlow(defaultConfig.getBoolean(key))
|
||||||
|
val config = _configValue.asStateFlow()
|
||||||
|
|
||||||
|
fun update(config: PersistableBundle) {
|
||||||
|
_configValue.value = config.getBoolean(key)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun toString(): String {
|
||||||
|
return "$key=${config.value}"
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,39 @@
|
|||||||
|
/*
|
||||||
|
* 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
|
||||||
|
|
||||||
|
import com.android.systemui.CoreStartable
|
||||||
|
import com.android.systemui.dagger.qualifiers.Application
|
||||||
|
import javax.inject.Inject
|
||||||
|
import kotlinx.coroutines.CoroutineScope
|
||||||
|
import kotlinx.coroutines.launch
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Core startable which configures the [CarrierConfigRepository] to listen for updates for the
|
||||||
|
* lifetime of the process
|
||||||
|
*/
|
||||||
|
class CarrierConfigCoreStartable
|
||||||
|
@Inject
|
||||||
|
constructor(
|
||||||
|
private val carrierConfigRepository: CarrierConfigRepository,
|
||||||
|
@Application private val scope: CoroutineScope,
|
||||||
|
) : CoreStartable {
|
||||||
|
|
||||||
|
override fun start() {
|
||||||
|
scope.launch { carrierConfigRepository.startObservingCarrierConfigUpdates() }
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,136 @@
|
|||||||
|
/*
|
||||||
|
* 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
|
||||||
|
|
||||||
|
import android.content.IntentFilter
|
||||||
|
import android.os.PersistableBundle
|
||||||
|
import android.telephony.CarrierConfigManager
|
||||||
|
import android.telephony.SubscriptionManager
|
||||||
|
import android.util.SparseArray
|
||||||
|
import androidx.annotation.VisibleForTesting
|
||||||
|
import androidx.core.util.getOrElse
|
||||||
|
import androidx.core.util.isEmpty
|
||||||
|
import androidx.core.util.keyIterator
|
||||||
|
import com.android.systemui.Dumpable
|
||||||
|
import com.android.systemui.broadcast.BroadcastDispatcher
|
||||||
|
import com.android.systemui.dagger.SysUISingleton
|
||||||
|
import com.android.systemui.dagger.qualifiers.Application
|
||||||
|
import com.android.systemui.dump.DumpManager
|
||||||
|
import com.android.systemui.statusbar.pipeline.mobile.data.model.SystemUiCarrierConfig
|
||||||
|
import com.android.systemui.statusbar.pipeline.shared.ConnectivityPipelineLogger
|
||||||
|
import java.io.PrintWriter
|
||||||
|
import javax.inject.Inject
|
||||||
|
import kotlinx.coroutines.CoroutineScope
|
||||||
|
import kotlinx.coroutines.flow.SharedFlow
|
||||||
|
import kotlinx.coroutines.flow.SharingStarted
|
||||||
|
import kotlinx.coroutines.flow.filter
|
||||||
|
import kotlinx.coroutines.flow.mapNotNull
|
||||||
|
import kotlinx.coroutines.flow.onEach
|
||||||
|
import kotlinx.coroutines.flow.shareIn
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Meant to be the source of truth regarding CarrierConfigs. These are configuration objects defined
|
||||||
|
* on a per-subscriptionId basis, and do not trigger a device configuration event.
|
||||||
|
*
|
||||||
|
* Designed to supplant [com.android.systemui.util.CarrierConfigTracker].
|
||||||
|
*
|
||||||
|
* See [SystemUiCarrierConfig] for details on how to add carrier config keys to be tracked
|
||||||
|
*/
|
||||||
|
@SysUISingleton
|
||||||
|
class CarrierConfigRepository
|
||||||
|
@Inject
|
||||||
|
constructor(
|
||||||
|
broadcastDispatcher: BroadcastDispatcher,
|
||||||
|
private val carrierConfigManager: CarrierConfigManager,
|
||||||
|
dumpManager: DumpManager,
|
||||||
|
logger: ConnectivityPipelineLogger,
|
||||||
|
@Application scope: CoroutineScope,
|
||||||
|
) : Dumpable {
|
||||||
|
private var isListening = false
|
||||||
|
private val defaultConfig: PersistableBundle by lazy { CarrierConfigManager.getDefaultConfig() }
|
||||||
|
// Used for logging the default config in the dumpsys
|
||||||
|
private val defaultConfigForLogs: SystemUiCarrierConfig by lazy {
|
||||||
|
SystemUiCarrierConfig(-1, defaultConfig)
|
||||||
|
}
|
||||||
|
|
||||||
|
private val configs = SparseArray<SystemUiCarrierConfig>()
|
||||||
|
|
||||||
|
init {
|
||||||
|
dumpManager.registerNormalDumpable(this)
|
||||||
|
}
|
||||||
|
|
||||||
|
@VisibleForTesting
|
||||||
|
val carrierConfigStream: SharedFlow<Pair<Int, PersistableBundle>> =
|
||||||
|
broadcastDispatcher
|
||||||
|
.broadcastFlow(IntentFilter(CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED)) {
|
||||||
|
intent,
|
||||||
|
_ ->
|
||||||
|
intent.getIntExtra(
|
||||||
|
CarrierConfigManager.EXTRA_SUBSCRIPTION_INDEX,
|
||||||
|
SubscriptionManager.INVALID_SUBSCRIPTION_ID
|
||||||
|
)
|
||||||
|
}
|
||||||
|
.onEach { logger.logCarrierConfigChanged(it) }
|
||||||
|
.filter { SubscriptionManager.isValidSubscriptionId(it) }
|
||||||
|
.mapNotNull { subId ->
|
||||||
|
val config = carrierConfigManager.getConfigForSubId(subId)
|
||||||
|
config?.let { subId to it }
|
||||||
|
}
|
||||||
|
.shareIn(scope, SharingStarted.WhileSubscribed())
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Start this repository observing broadcasts for **all** carrier configuration updates. Must be
|
||||||
|
* called in order to keep SystemUI in sync with [CarrierConfigManager].
|
||||||
|
*/
|
||||||
|
suspend fun startObservingCarrierConfigUpdates() {
|
||||||
|
isListening = true
|
||||||
|
carrierConfigStream.collect { updateCarrierConfig(it.first, it.second) }
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Update or create the [SystemUiCarrierConfig] for subId with the override */
|
||||||
|
private fun updateCarrierConfig(subId: Int, config: PersistableBundle) {
|
||||||
|
val configToUpdate = getOrCreateConfigForSubId(subId)
|
||||||
|
configToUpdate.processNewCarrierConfig(config)
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Gets a cached [SystemUiCarrierConfig], or creates a new one which will track the defaults */
|
||||||
|
fun getOrCreateConfigForSubId(subId: Int): SystemUiCarrierConfig {
|
||||||
|
return configs.getOrElse(subId) {
|
||||||
|
val config = SystemUiCarrierConfig(subId, defaultConfig)
|
||||||
|
val carrierConfig = carrierConfigManager.getConfigForSubId(subId)
|
||||||
|
if (carrierConfig != null) config.processNewCarrierConfig(carrierConfig)
|
||||||
|
configs.put(subId, config)
|
||||||
|
config
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun dump(pw: PrintWriter, args: Array<out String>) {
|
||||||
|
pw.println("isListening: $isListening")
|
||||||
|
if (configs.isEmpty()) {
|
||||||
|
pw.println("no carrier configs loaded")
|
||||||
|
} else {
|
||||||
|
pw.println("Carrier configs by subId")
|
||||||
|
configs.keyIterator().forEach {
|
||||||
|
pw.println(" subId=$it")
|
||||||
|
pw.println(" config=${configs.get(it).toStringConsideringDefaults()}")
|
||||||
|
}
|
||||||
|
// Finally, print the default config
|
||||||
|
pw.println("Default config:")
|
||||||
|
pw.println(" $defaultConfigForLogs")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -16,7 +16,6 @@
|
|||||||
|
|
||||||
package com.android.systemui.statusbar.pipeline.mobile.data.repository
|
package com.android.systemui.statusbar.pipeline.mobile.data.repository
|
||||||
|
|
||||||
import android.provider.Settings
|
|
||||||
import android.telephony.CarrierConfigManager
|
import android.telephony.CarrierConfigManager
|
||||||
import android.telephony.SubscriptionManager
|
import android.telephony.SubscriptionManager
|
||||||
import com.android.settingslib.SignalIcon.MobileIconGroup
|
import com.android.settingslib.SignalIcon.MobileIconGroup
|
||||||
@@ -53,9 +52,6 @@ interface MobileConnectionsRepository {
|
|||||||
/** Get or create a repository for the line of service for the given subscription ID */
|
/** Get or create a repository for the line of service for the given subscription ID */
|
||||||
fun getRepoForSubId(subId: Int): MobileConnectionRepository
|
fun getRepoForSubId(subId: Int): MobileConnectionRepository
|
||||||
|
|
||||||
/** Observe changes to the [Settings.Global.MOBILE_DATA] setting */
|
|
||||||
val globalMobileDataSettingChangedEvent: Flow<Unit>
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* [Config] is an object that tracks relevant configuration flags for a given subscription ID.
|
* [Config] is an object that tracks relevant configuration flags for a given subscription ID.
|
||||||
* In the case of [MobileMappings], it's hard-coded to check the default data subscription's
|
* In the case of [MobileMappings], it's hard-coded to check the default data subscription's
|
||||||
|
|||||||
@@ -156,9 +156,6 @@ constructor(
|
|||||||
realRepository.defaultMobileNetworkConnectivity.value
|
realRepository.defaultMobileNetworkConnectivity.value
|
||||||
)
|
)
|
||||||
|
|
||||||
override val globalMobileDataSettingChangedEvent: Flow<Unit> =
|
|
||||||
activeRepo.flatMapLatest { it.globalMobileDataSettingChangedEvent }
|
|
||||||
|
|
||||||
override fun getRepoForSubId(subId: Int): MobileConnectionRepository {
|
override fun getRepoForSubId(subId: Int): MobileConnectionRepository {
|
||||||
if (isDemoMode.value) {
|
if (isDemoMode.value) {
|
||||||
return demoMobileConnectionsRepository.getRepoForSubId(subId)
|
return demoMobileConnectionsRepository.getRepoForSubId(subId)
|
||||||
|
|||||||
@@ -185,8 +185,6 @@ constructor(
|
|||||||
return CacheContainer(repo, lastMobileState = null)
|
return CacheContainer(repo, lastMobileState = null)
|
||||||
}
|
}
|
||||||
|
|
||||||
override val globalMobileDataSettingChangedEvent = MutableStateFlow(Unit)
|
|
||||||
|
|
||||||
fun startProcessingCommands() {
|
fun startProcessingCommands() {
|
||||||
mobileDemoCommandJob =
|
mobileDemoCommandJob =
|
||||||
scope.launch {
|
scope.launch {
|
||||||
|
|||||||
@@ -26,7 +26,6 @@ import com.android.systemui.statusbar.pipeline.mobile.data.repository.MobileConn
|
|||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
import kotlinx.coroutines.CoroutineScope
|
import kotlinx.coroutines.CoroutineScope
|
||||||
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
||||||
import kotlinx.coroutines.flow.Flow
|
|
||||||
import kotlinx.coroutines.flow.MutableStateFlow
|
import kotlinx.coroutines.flow.MutableStateFlow
|
||||||
import kotlinx.coroutines.flow.SharingStarted
|
import kotlinx.coroutines.flow.SharingStarted
|
||||||
import kotlinx.coroutines.flow.StateFlow
|
import kotlinx.coroutines.flow.StateFlow
|
||||||
@@ -50,7 +49,6 @@ class FullMobileConnectionRepository(
|
|||||||
override val tableLogBuffer: TableLogBuffer,
|
override val tableLogBuffer: TableLogBuffer,
|
||||||
private val defaultNetworkName: NetworkNameModel,
|
private val defaultNetworkName: NetworkNameModel,
|
||||||
private val networkNameSeparator: String,
|
private val networkNameSeparator: String,
|
||||||
private val globalMobileDataSettingChangedEvent: Flow<Unit>,
|
|
||||||
@Application scope: CoroutineScope,
|
@Application scope: CoroutineScope,
|
||||||
private val mobileRepoFactory: MobileConnectionRepositoryImpl.Factory,
|
private val mobileRepoFactory: MobileConnectionRepositoryImpl.Factory,
|
||||||
private val carrierMergedRepoFactory: CarrierMergedConnectionRepository.Factory,
|
private val carrierMergedRepoFactory: CarrierMergedConnectionRepository.Factory,
|
||||||
@@ -84,7 +82,6 @@ class FullMobileConnectionRepository(
|
|||||||
tableLogBuffer,
|
tableLogBuffer,
|
||||||
defaultNetworkName,
|
defaultNetworkName,
|
||||||
networkNameSeparator,
|
networkNameSeparator,
|
||||||
globalMobileDataSettingChangedEvent,
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -150,7 +147,6 @@ class FullMobileConnectionRepository(
|
|||||||
startingIsCarrierMerged: Boolean,
|
startingIsCarrierMerged: Boolean,
|
||||||
defaultNetworkName: NetworkNameModel,
|
defaultNetworkName: NetworkNameModel,
|
||||||
networkNameSeparator: String,
|
networkNameSeparator: String,
|
||||||
globalMobileDataSettingChangedEvent: Flow<Unit>,
|
|
||||||
): FullMobileConnectionRepository {
|
): FullMobileConnectionRepository {
|
||||||
val mobileLogger =
|
val mobileLogger =
|
||||||
logFactory.getOrCreate(tableBufferLogName(subId), MOBILE_CONNECTION_BUFFER_SIZE)
|
logFactory.getOrCreate(tableBufferLogName(subId), MOBILE_CONNECTION_BUFFER_SIZE)
|
||||||
@@ -161,7 +157,6 @@ class FullMobileConnectionRepository(
|
|||||||
mobileLogger,
|
mobileLogger,
|
||||||
defaultNetworkName,
|
defaultNetworkName,
|
||||||
networkNameSeparator,
|
networkNameSeparator,
|
||||||
globalMobileDataSettingChangedEvent,
|
|
||||||
scope,
|
scope,
|
||||||
mobileRepoFactory,
|
mobileRepoFactory,
|
||||||
carrierMergedRepoFactory,
|
carrierMergedRepoFactory,
|
||||||
|
|||||||
@@ -18,8 +18,6 @@ package com.android.systemui.statusbar.pipeline.mobile.data.repository.prod
|
|||||||
|
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.content.IntentFilter
|
import android.content.IntentFilter
|
||||||
import android.database.ContentObserver
|
|
||||||
import android.provider.Settings.Global
|
|
||||||
import android.telephony.CellSignalStrength
|
import android.telephony.CellSignalStrength
|
||||||
import android.telephony.CellSignalStrengthCdma
|
import android.telephony.CellSignalStrengthCdma
|
||||||
import android.telephony.ServiceState
|
import android.telephony.ServiceState
|
||||||
@@ -44,14 +42,15 @@ import com.android.systemui.statusbar.pipeline.mobile.data.model.NetworkNameMode
|
|||||||
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.model.ResolvedNetworkType.UnknownNetworkType
|
import com.android.systemui.statusbar.pipeline.mobile.data.model.ResolvedNetworkType.UnknownNetworkType
|
||||||
|
import com.android.systemui.statusbar.pipeline.mobile.data.model.SystemUiCarrierConfig
|
||||||
import com.android.systemui.statusbar.pipeline.mobile.data.model.toDataConnectionType
|
import com.android.systemui.statusbar.pipeline.mobile.data.model.toDataConnectionType
|
||||||
import com.android.systemui.statusbar.pipeline.mobile.data.model.toNetworkNameModel
|
import com.android.systemui.statusbar.pipeline.mobile.data.model.toNetworkNameModel
|
||||||
|
import com.android.systemui.statusbar.pipeline.mobile.data.repository.CarrierConfigRepository
|
||||||
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.mobile.data.repository.MobileConnectionRepository.Companion.DEFAULT_NUM_LEVELS
|
||||||
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.data.model.toMobileDataActivityModel
|
import com.android.systemui.statusbar.pipeline.shared.data.model.toMobileDataActivityModel
|
||||||
import com.android.systemui.util.settings.GlobalSettings
|
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
import kotlinx.coroutines.CoroutineDispatcher
|
import kotlinx.coroutines.CoroutineDispatcher
|
||||||
import kotlinx.coroutines.CoroutineScope
|
import kotlinx.coroutines.CoroutineScope
|
||||||
@@ -60,13 +59,15 @@ import kotlinx.coroutines.asExecutor
|
|||||||
import kotlinx.coroutines.channels.awaitClose
|
import kotlinx.coroutines.channels.awaitClose
|
||||||
import kotlinx.coroutines.flow.Flow
|
import kotlinx.coroutines.flow.Flow
|
||||||
import kotlinx.coroutines.flow.MutableSharedFlow
|
import kotlinx.coroutines.flow.MutableSharedFlow
|
||||||
|
import kotlinx.coroutines.flow.SharedFlow
|
||||||
import kotlinx.coroutines.flow.SharingStarted
|
import kotlinx.coroutines.flow.SharingStarted
|
||||||
import kotlinx.coroutines.flow.StateFlow
|
import kotlinx.coroutines.flow.StateFlow
|
||||||
import kotlinx.coroutines.flow.distinctUntilChanged
|
import kotlinx.coroutines.flow.distinctUntilChanged
|
||||||
import kotlinx.coroutines.flow.flowOf
|
import kotlinx.coroutines.flow.map
|
||||||
import kotlinx.coroutines.flow.mapLatest
|
import kotlinx.coroutines.flow.mapLatest
|
||||||
import kotlinx.coroutines.flow.merge
|
import kotlinx.coroutines.flow.mapNotNull
|
||||||
import kotlinx.coroutines.flow.onEach
|
import kotlinx.coroutines.flow.scan
|
||||||
|
import kotlinx.coroutines.flow.shareIn
|
||||||
import kotlinx.coroutines.flow.stateIn
|
import kotlinx.coroutines.flow.stateIn
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -81,10 +82,9 @@ class MobileConnectionRepositoryImpl(
|
|||||||
defaultNetworkName: NetworkNameModel,
|
defaultNetworkName: NetworkNameModel,
|
||||||
networkNameSeparator: String,
|
networkNameSeparator: String,
|
||||||
private val telephonyManager: TelephonyManager,
|
private val telephonyManager: TelephonyManager,
|
||||||
private val globalSettings: GlobalSettings,
|
systemUiCarrierConfig: SystemUiCarrierConfig,
|
||||||
broadcastDispatcher: BroadcastDispatcher,
|
broadcastDispatcher: BroadcastDispatcher,
|
||||||
globalMobileDataSettingChangedEvent: Flow<Unit>,
|
private val mobileMappingsProxy: MobileMappingsProxy,
|
||||||
mobileMappingsProxy: MobileMappingsProxy,
|
|
||||||
bgDispatcher: CoroutineDispatcher,
|
bgDispatcher: CoroutineDispatcher,
|
||||||
logger: ConnectivityPipelineLogger,
|
logger: ConnectivityPipelineLogger,
|
||||||
mobileLogger: TableLogBuffer,
|
mobileLogger: TableLogBuffer,
|
||||||
@@ -103,8 +103,15 @@ class MobileConnectionRepositoryImpl(
|
|||||||
|
|
||||||
override val tableLogBuffer: TableLogBuffer = mobileLogger
|
override val tableLogBuffer: TableLogBuffer = mobileLogger
|
||||||
|
|
||||||
override val connectionInfo: StateFlow<MobileConnectionModel> = run {
|
/**
|
||||||
var state = MobileConnectionModel()
|
* This flow defines the single shared connection to system_server via TelephonyCallback. Any
|
||||||
|
* new callback should be added to this listener and funneled through callbackEvents via a data
|
||||||
|
* class. See [CallbackEvent] for defining new callbacks.
|
||||||
|
*
|
||||||
|
* The reason we need to do this is because TelephonyManager limits the number of registered
|
||||||
|
* listeners per-process, so we don't want to create a new listener for every callback.
|
||||||
|
*/
|
||||||
|
private val callbackEvents: SharedFlow<CallbackEvent> =
|
||||||
conflatedCallbackFlow {
|
conflatedCallbackFlow {
|
||||||
val callback =
|
val callback =
|
||||||
object :
|
object :
|
||||||
@@ -114,41 +121,16 @@ class MobileConnectionRepositoryImpl(
|
|||||||
TelephonyCallback.DataConnectionStateListener,
|
TelephonyCallback.DataConnectionStateListener,
|
||||||
TelephonyCallback.DataActivityListener,
|
TelephonyCallback.DataActivityListener,
|
||||||
TelephonyCallback.CarrierNetworkListener,
|
TelephonyCallback.CarrierNetworkListener,
|
||||||
TelephonyCallback.DisplayInfoListener {
|
TelephonyCallback.DisplayInfoListener,
|
||||||
|
TelephonyCallback.DataEnabledListener {
|
||||||
override fun onServiceStateChanged(serviceState: ServiceState) {
|
override fun onServiceStateChanged(serviceState: ServiceState) {
|
||||||
logger.logOnServiceStateChanged(serviceState, subId)
|
logger.logOnServiceStateChanged(serviceState, subId)
|
||||||
state =
|
trySend(CallbackEvent.OnServiceStateChanged(serviceState))
|
||||||
state.copy(
|
|
||||||
isEmergencyOnly = serviceState.isEmergencyOnly,
|
|
||||||
isRoaming = serviceState.roaming,
|
|
||||||
operatorAlphaShort = serviceState.operatorAlphaShort,
|
|
||||||
isInService = Utils.isInService(serviceState),
|
|
||||||
)
|
|
||||||
trySend(state)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onSignalStrengthsChanged(signalStrength: SignalStrength) {
|
override fun onSignalStrengthsChanged(signalStrength: SignalStrength) {
|
||||||
logger.logOnSignalStrengthsChanged(signalStrength, subId)
|
logger.logOnSignalStrengthsChanged(signalStrength, subId)
|
||||||
val cdmaLevel =
|
trySend(CallbackEvent.OnSignalStrengthChanged(signalStrength))
|
||||||
signalStrength
|
|
||||||
.getCellSignalStrengths(CellSignalStrengthCdma::class.java)
|
|
||||||
.let { strengths ->
|
|
||||||
if (!strengths.isEmpty()) {
|
|
||||||
strengths[0].level
|
|
||||||
} else {
|
|
||||||
CellSignalStrength.SIGNAL_STRENGTH_NONE_OR_UNKNOWN
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
val primaryLevel = signalStrength.level
|
|
||||||
|
|
||||||
state =
|
|
||||||
state.copy(
|
|
||||||
cdmaLevel = cdmaLevel,
|
|
||||||
primaryLevel = primaryLevel,
|
|
||||||
isGsm = signalStrength.isGsm,
|
|
||||||
)
|
|
||||||
trySend(state)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onDataConnectionStateChanged(
|
override fun onDataConnectionStateChanged(
|
||||||
@@ -156,101 +138,136 @@ class MobileConnectionRepositoryImpl(
|
|||||||
networkType: Int
|
networkType: Int
|
||||||
) {
|
) {
|
||||||
logger.logOnDataConnectionStateChanged(dataState, networkType, subId)
|
logger.logOnDataConnectionStateChanged(dataState, networkType, subId)
|
||||||
state =
|
trySend(CallbackEvent.OnDataConnectionStateChanged(dataState))
|
||||||
state.copy(dataConnectionState = dataState.toDataConnectionType())
|
|
||||||
trySend(state)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onDataActivity(direction: Int) {
|
override fun onDataActivity(direction: Int) {
|
||||||
logger.logOnDataActivity(direction, subId)
|
logger.logOnDataActivity(direction, subId)
|
||||||
state =
|
trySend(CallbackEvent.OnDataActivity(direction))
|
||||||
state.copy(
|
|
||||||
dataActivityDirection = direction.toMobileDataActivityModel()
|
|
||||||
)
|
|
||||||
trySend(state)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onCarrierNetworkChange(active: Boolean) {
|
override fun onCarrierNetworkChange(active: Boolean) {
|
||||||
logger.logOnCarrierNetworkChange(active, subId)
|
logger.logOnCarrierNetworkChange(active, subId)
|
||||||
state = state.copy(carrierNetworkChangeActive = active)
|
trySend(CallbackEvent.OnCarrierNetworkChange(active))
|
||||||
trySend(state)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onDisplayInfoChanged(
|
override fun onDisplayInfoChanged(
|
||||||
telephonyDisplayInfo: TelephonyDisplayInfo
|
telephonyDisplayInfo: TelephonyDisplayInfo
|
||||||
) {
|
) {
|
||||||
logger.logOnDisplayInfoChanged(telephonyDisplayInfo, subId)
|
logger.logOnDisplayInfoChanged(telephonyDisplayInfo, subId)
|
||||||
|
trySend(CallbackEvent.OnDisplayInfoChanged(telephonyDisplayInfo))
|
||||||
|
}
|
||||||
|
|
||||||
val networkType =
|
override fun onDataEnabledChanged(enabled: Boolean, reason: Int) {
|
||||||
if (telephonyDisplayInfo.networkType == NETWORK_TYPE_UNKNOWN) {
|
logger.logOnDataEnabledChanged(enabled, subId)
|
||||||
UnknownNetworkType
|
trySend(CallbackEvent.OnDataEnabledChanged(enabled))
|
||||||
} else if (
|
|
||||||
telephonyDisplayInfo.overrideNetworkType ==
|
|
||||||
OVERRIDE_NETWORK_TYPE_NONE
|
|
||||||
) {
|
|
||||||
DefaultNetworkType(
|
|
||||||
mobileMappingsProxy.toIconKey(
|
|
||||||
telephonyDisplayInfo.networkType
|
|
||||||
)
|
|
||||||
)
|
|
||||||
} else {
|
|
||||||
OverrideNetworkType(
|
|
||||||
mobileMappingsProxy.toIconKeyOverride(
|
|
||||||
telephonyDisplayInfo.overrideNetworkType
|
|
||||||
)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
state = state.copy(resolvedNetworkType = networkType)
|
|
||||||
trySend(state)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
telephonyManager.registerTelephonyCallback(bgDispatcher.asExecutor(), callback)
|
telephonyManager.registerTelephonyCallback(bgDispatcher.asExecutor(), callback)
|
||||||
awaitClose { telephonyManager.unregisterTelephonyCallback(callback) }
|
awaitClose { telephonyManager.unregisterTelephonyCallback(callback) }
|
||||||
}
|
}
|
||||||
.onEach { telephonyCallbackEvent.tryEmit(Unit) }
|
.shareIn(scope, SharingStarted.WhileSubscribed())
|
||||||
|
|
||||||
|
private fun updateConnectionState(
|
||||||
|
prevState: MobileConnectionModel,
|
||||||
|
callbackEvent: CallbackEvent,
|
||||||
|
): MobileConnectionModel =
|
||||||
|
when (callbackEvent) {
|
||||||
|
is CallbackEvent.OnServiceStateChanged -> {
|
||||||
|
val serviceState = callbackEvent.serviceState
|
||||||
|
prevState.copy(
|
||||||
|
isEmergencyOnly = serviceState.isEmergencyOnly,
|
||||||
|
isRoaming = serviceState.roaming,
|
||||||
|
operatorAlphaShort = serviceState.operatorAlphaShort,
|
||||||
|
isInService = Utils.isInService(serviceState),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
is CallbackEvent.OnSignalStrengthChanged -> {
|
||||||
|
val signalStrength = callbackEvent.signalStrength
|
||||||
|
val cdmaLevel =
|
||||||
|
signalStrength.getCellSignalStrengths(CellSignalStrengthCdma::class.java).let {
|
||||||
|
strengths ->
|
||||||
|
if (!strengths.isEmpty()) {
|
||||||
|
strengths[0].level
|
||||||
|
} else {
|
||||||
|
CellSignalStrength.SIGNAL_STRENGTH_NONE_OR_UNKNOWN
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
val primaryLevel = signalStrength.level
|
||||||
|
|
||||||
|
prevState.copy(
|
||||||
|
cdmaLevel = cdmaLevel,
|
||||||
|
primaryLevel = primaryLevel,
|
||||||
|
isGsm = signalStrength.isGsm,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
is CallbackEvent.OnDataConnectionStateChanged -> {
|
||||||
|
prevState.copy(dataConnectionState = callbackEvent.dataState.toDataConnectionType())
|
||||||
|
}
|
||||||
|
is CallbackEvent.OnDataActivity -> {
|
||||||
|
prevState.copy(
|
||||||
|
dataActivityDirection = callbackEvent.direction.toMobileDataActivityModel()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
is CallbackEvent.OnCarrierNetworkChange -> {
|
||||||
|
prevState.copy(carrierNetworkChangeActive = callbackEvent.active)
|
||||||
|
}
|
||||||
|
is CallbackEvent.OnDisplayInfoChanged -> {
|
||||||
|
val telephonyDisplayInfo = callbackEvent.telephonyDisplayInfo
|
||||||
|
val networkType =
|
||||||
|
if (telephonyDisplayInfo.networkType == NETWORK_TYPE_UNKNOWN) {
|
||||||
|
UnknownNetworkType
|
||||||
|
} else if (
|
||||||
|
telephonyDisplayInfo.overrideNetworkType == OVERRIDE_NETWORK_TYPE_NONE
|
||||||
|
) {
|
||||||
|
DefaultNetworkType(
|
||||||
|
mobileMappingsProxy.toIconKey(telephonyDisplayInfo.networkType)
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
OverrideNetworkType(
|
||||||
|
mobileMappingsProxy.toIconKeyOverride(
|
||||||
|
telephonyDisplayInfo.overrideNetworkType
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
prevState.copy(resolvedNetworkType = networkType)
|
||||||
|
}
|
||||||
|
is CallbackEvent.OnDataEnabledChanged -> {
|
||||||
|
// Not part of this object, handled in a separate flow
|
||||||
|
prevState
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override val connectionInfo = run {
|
||||||
|
val initial = MobileConnectionModel()
|
||||||
|
callbackEvents
|
||||||
|
.scan(initial, ::updateConnectionState)
|
||||||
.logDiffsForTable(
|
.logDiffsForTable(
|
||||||
mobileLogger,
|
mobileLogger,
|
||||||
columnPrefix = "MobileConnection ($subId)",
|
columnPrefix = "MobileConnection ($subId)",
|
||||||
initialValue = state,
|
initialValue = initial,
|
||||||
)
|
)
|
||||||
.stateIn(scope, SharingStarted.WhileSubscribed(), state)
|
.stateIn(scope, SharingStarted.WhileSubscribed(), initial)
|
||||||
}
|
}
|
||||||
|
|
||||||
// This will become variable based on [CarrierConfigManager.KEY_INFLATE_SIGNAL_STRENGTH_BOOL]
|
override val numberOfLevels =
|
||||||
// once it's wired up inside of [CarrierConfigTracker].
|
systemUiCarrierConfig.shouldInflateSignalStrength
|
||||||
override val numberOfLevels: StateFlow<Int> =
|
.map { shouldInflate ->
|
||||||
flowOf(DEFAULT_NUM_LEVELS)
|
if (shouldInflate) {
|
||||||
.stateIn(scope, SharingStarted.WhileSubscribed(), DEFAULT_NUM_LEVELS)
|
DEFAULT_NUM_LEVELS + 1
|
||||||
|
} else {
|
||||||
/** Produces whenever the mobile data setting changes for this subId */
|
DEFAULT_NUM_LEVELS
|
||||||
private val localMobileDataSettingChangedEvent: Flow<Unit> = conflatedCallbackFlow {
|
|
||||||
val observer =
|
|
||||||
object : ContentObserver(null) {
|
|
||||||
override fun onChange(selfChange: Boolean) {
|
|
||||||
trySend(Unit)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
.stateIn(scope, SharingStarted.WhileSubscribed(), DEFAULT_NUM_LEVELS)
|
||||||
globalSettings.registerContentObserver(
|
|
||||||
globalSettings.getUriFor("${Global.MOBILE_DATA}$subId"),
|
|
||||||
/* notifyForDescendants */ true,
|
|
||||||
observer
|
|
||||||
)
|
|
||||||
|
|
||||||
awaitClose { context.contentResolver.unregisterContentObserver(observer) }
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* There are a few cases where we will need to poll [TelephonyManager] so we can update some
|
* There are a few cases where we will need to poll [TelephonyManager] so we can update some
|
||||||
* internal state where callbacks aren't provided. Any of those events should be merged into
|
* internal state where callbacks aren't provided. Any of those events should be merged into
|
||||||
* this flow, which can be used to trigger the polling.
|
* this flow, which can be used to trigger the polling.
|
||||||
*/
|
*/
|
||||||
private val telephonyPollingEvent: Flow<Unit> =
|
private val telephonyPollingEvent: Flow<Unit> = callbackEvents.map { Unit }
|
||||||
merge(
|
|
||||||
telephonyCallbackEvent,
|
|
||||||
localMobileDataSettingChangedEvent,
|
|
||||||
globalMobileDataSettingChangedEvent,
|
|
||||||
)
|
|
||||||
|
|
||||||
override val cdmaRoaming: StateFlow<Boolean> =
|
override val cdmaRoaming: StateFlow<Boolean> =
|
||||||
telephonyPollingEvent
|
telephonyPollingEvent
|
||||||
@@ -276,22 +293,19 @@ class MobileConnectionRepositoryImpl(
|
|||||||
)
|
)
|
||||||
.stateIn(scope, SharingStarted.WhileSubscribed(), defaultNetworkName)
|
.stateIn(scope, SharingStarted.WhileSubscribed(), defaultNetworkName)
|
||||||
|
|
||||||
override val dataEnabled: StateFlow<Boolean> = run {
|
override val dataEnabled = run {
|
||||||
val initial = dataConnectionAllowed()
|
val initial = telephonyManager.isDataConnectionAllowed
|
||||||
telephonyPollingEvent
|
callbackEvents
|
||||||
.mapLatest { dataConnectionAllowed() }
|
.mapNotNull { (it as? CallbackEvent.OnDataEnabledChanged)?.enabled }
|
||||||
.distinctUntilChanged()
|
|
||||||
.logDiffsForTable(
|
.logDiffsForTable(
|
||||||
mobileLogger,
|
mobileLogger,
|
||||||
columnPrefix = "",
|
columnPrefix = "",
|
||||||
columnName = "dataEnabled",
|
columnName = "dataEnabled",
|
||||||
initialValue = initial,
|
initialValue = initial
|
||||||
)
|
)
|
||||||
.stateIn(scope, SharingStarted.WhileSubscribed(), initial)
|
.stateIn(scope, SharingStarted.WhileSubscribed(), initial)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun dataConnectionAllowed(): Boolean = telephonyManager.isDataConnectionAllowed
|
|
||||||
|
|
||||||
class Factory
|
class Factory
|
||||||
@Inject
|
@Inject
|
||||||
constructor(
|
constructor(
|
||||||
@@ -299,7 +313,7 @@ class MobileConnectionRepositoryImpl(
|
|||||||
private val context: Context,
|
private val context: Context,
|
||||||
private val telephonyManager: TelephonyManager,
|
private val telephonyManager: TelephonyManager,
|
||||||
private val logger: ConnectivityPipelineLogger,
|
private val logger: ConnectivityPipelineLogger,
|
||||||
private val globalSettings: GlobalSettings,
|
private val carrierConfigRepository: CarrierConfigRepository,
|
||||||
private val mobileMappingsProxy: MobileMappingsProxy,
|
private val mobileMappingsProxy: MobileMappingsProxy,
|
||||||
@Background private val bgDispatcher: CoroutineDispatcher,
|
@Background private val bgDispatcher: CoroutineDispatcher,
|
||||||
@Application private val scope: CoroutineScope,
|
@Application private val scope: CoroutineScope,
|
||||||
@@ -309,7 +323,6 @@ class MobileConnectionRepositoryImpl(
|
|||||||
mobileLogger: TableLogBuffer,
|
mobileLogger: TableLogBuffer,
|
||||||
defaultNetworkName: NetworkNameModel,
|
defaultNetworkName: NetworkNameModel,
|
||||||
networkNameSeparator: String,
|
networkNameSeparator: String,
|
||||||
globalMobileDataSettingChangedEvent: Flow<Unit>,
|
|
||||||
): MobileConnectionRepository {
|
): MobileConnectionRepository {
|
||||||
return MobileConnectionRepositoryImpl(
|
return MobileConnectionRepositoryImpl(
|
||||||
context,
|
context,
|
||||||
@@ -317,9 +330,8 @@ class MobileConnectionRepositoryImpl(
|
|||||||
defaultNetworkName,
|
defaultNetworkName,
|
||||||
networkNameSeparator,
|
networkNameSeparator,
|
||||||
telephonyManager.createForSubscriptionId(subId),
|
telephonyManager.createForSubscriptionId(subId),
|
||||||
globalSettings,
|
carrierConfigRepository.getOrCreateConfigForSubId(subId),
|
||||||
broadcastDispatcher,
|
broadcastDispatcher,
|
||||||
globalMobileDataSettingChangedEvent,
|
|
||||||
mobileMappingsProxy,
|
mobileMappingsProxy,
|
||||||
bgDispatcher,
|
bgDispatcher,
|
||||||
logger,
|
logger,
|
||||||
@@ -329,3 +341,17 @@ class MobileConnectionRepositoryImpl(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Wrap every [TelephonyCallback] we care about in a data class so we can accept them in a single
|
||||||
|
* shared flow and then split them back out into other flows.
|
||||||
|
*/
|
||||||
|
private sealed interface CallbackEvent {
|
||||||
|
data class OnServiceStateChanged(val serviceState: ServiceState) : CallbackEvent
|
||||||
|
data class OnSignalStrengthChanged(val signalStrength: SignalStrength) : CallbackEvent
|
||||||
|
data class OnDataConnectionStateChanged(val dataState: Int) : CallbackEvent
|
||||||
|
data class OnDataActivity(val direction: Int) : CallbackEvent
|
||||||
|
data class OnCarrierNetworkChange(val active: Boolean) : CallbackEvent
|
||||||
|
data class OnDisplayInfoChanged(val telephonyDisplayInfo: TelephonyDisplayInfo) : CallbackEvent
|
||||||
|
data class OnDataEnabledChanged(val enabled: Boolean) : CallbackEvent
|
||||||
|
}
|
||||||
|
|||||||
@@ -19,14 +19,12 @@ package com.android.systemui.statusbar.pipeline.mobile.data.repository.prod
|
|||||||
import android.annotation.SuppressLint
|
import android.annotation.SuppressLint
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.content.IntentFilter
|
import android.content.IntentFilter
|
||||||
import android.database.ContentObserver
|
|
||||||
import android.net.ConnectivityManager
|
import android.net.ConnectivityManager
|
||||||
import android.net.ConnectivityManager.NetworkCallback
|
import android.net.ConnectivityManager.NetworkCallback
|
||||||
import android.net.Network
|
import android.net.Network
|
||||||
import android.net.NetworkCapabilities
|
import android.net.NetworkCapabilities
|
||||||
import android.net.NetworkCapabilities.NET_CAPABILITY_VALIDATED
|
import android.net.NetworkCapabilities.NET_CAPABILITY_VALIDATED
|
||||||
import android.net.NetworkCapabilities.TRANSPORT_CELLULAR
|
import android.net.NetworkCapabilities.TRANSPORT_CELLULAR
|
||||||
import android.provider.Settings.Global.MOBILE_DATA
|
|
||||||
import android.telephony.CarrierConfigManager
|
import android.telephony.CarrierConfigManager
|
||||||
import android.telephony.SubscriptionInfo
|
import android.telephony.SubscriptionInfo
|
||||||
import android.telephony.SubscriptionManager
|
import android.telephony.SubscriptionManager
|
||||||
@@ -54,7 +52,6 @@ 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.model.WifiNetworkModel
|
||||||
import com.android.systemui.statusbar.pipeline.wifi.data.repository.WifiRepository
|
import com.android.systemui.statusbar.pipeline.wifi.data.repository.WifiRepository
|
||||||
import com.android.systemui.util.kotlin.pairwise
|
import com.android.systemui.util.kotlin.pairwise
|
||||||
import com.android.systemui.util.settings.GlobalSettings
|
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
import kotlinx.coroutines.CoroutineDispatcher
|
import kotlinx.coroutines.CoroutineDispatcher
|
||||||
import kotlinx.coroutines.CoroutineScope
|
import kotlinx.coroutines.CoroutineScope
|
||||||
@@ -87,7 +84,6 @@ constructor(
|
|||||||
private val logger: ConnectivityPipelineLogger,
|
private val logger: ConnectivityPipelineLogger,
|
||||||
mobileMappingsProxy: MobileMappingsProxy,
|
mobileMappingsProxy: MobileMappingsProxy,
|
||||||
broadcastDispatcher: BroadcastDispatcher,
|
broadcastDispatcher: BroadcastDispatcher,
|
||||||
private val globalSettings: GlobalSettings,
|
|
||||||
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,
|
||||||
@@ -222,29 +218,6 @@ constructor(
|
|||||||
?: createRepositoryForSubId(subId).also { subIdRepositoryCache[subId] = it }
|
?: createRepositoryForSubId(subId).also { subIdRepositoryCache[subId] = it }
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* In single-SIM devices, the [MOBILE_DATA] setting is phone-wide. For multi-SIM, the individual
|
|
||||||
* connection repositories also observe the URI for [MOBILE_DATA] + subId.
|
|
||||||
*/
|
|
||||||
override val globalMobileDataSettingChangedEvent: Flow<Unit> =
|
|
||||||
conflatedCallbackFlow {
|
|
||||||
val observer =
|
|
||||||
object : ContentObserver(null) {
|
|
||||||
override fun onChange(selfChange: Boolean) {
|
|
||||||
trySend(Unit)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
globalSettings.registerContentObserver(
|
|
||||||
globalSettings.getUriFor(MOBILE_DATA),
|
|
||||||
true,
|
|
||||||
observer
|
|
||||||
)
|
|
||||||
|
|
||||||
awaitClose { context.contentResolver.unregisterContentObserver(observer) }
|
|
||||||
}
|
|
||||||
.logInputChange(logger, "globalMobileDataSettingChangedEvent")
|
|
||||||
|
|
||||||
@SuppressLint("MissingPermission")
|
@SuppressLint("MissingPermission")
|
||||||
override val defaultMobileNetworkConnectivity: StateFlow<MobileConnectivityModel> =
|
override val defaultMobileNetworkConnectivity: StateFlow<MobileConnectivityModel> =
|
||||||
conflatedCallbackFlow {
|
conflatedCallbackFlow {
|
||||||
@@ -315,7 +288,6 @@ constructor(
|
|||||||
isCarrierMerged(subId),
|
isCarrierMerged(subId),
|
||||||
defaultNetworkName,
|
defaultNetworkName,
|
||||||
networkNameSeparator,
|
networkNameSeparator,
|
||||||
globalMobileDataSettingChangedEvent,
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -231,6 +231,27 @@ constructor(
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun logCarrierConfigChanged(subId: Int) {
|
||||||
|
buffer.log(
|
||||||
|
SB_LOGGING_TAG,
|
||||||
|
LogLevel.INFO,
|
||||||
|
{ int1 = subId },
|
||||||
|
{ "onCarrierConfigChanged: subId=$int1" },
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun logOnDataEnabledChanged(enabled: Boolean, subId: Int) {
|
||||||
|
buffer.log(
|
||||||
|
SB_LOGGING_TAG,
|
||||||
|
LogLevel.INFO,
|
||||||
|
{
|
||||||
|
int1 = subId
|
||||||
|
bool1 = enabled
|
||||||
|
},
|
||||||
|
{ "onDataEnabledChanged: subId=$int1 enabled=$bool1" },
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
const val SB_LOGGING_TAG = "SbConnectivity"
|
const val SB_LOGGING_TAG = "SbConnectivity"
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,120 @@
|
|||||||
|
/*
|
||||||
|
* 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.model
|
||||||
|
|
||||||
|
import android.os.PersistableBundle
|
||||||
|
import android.telephony.CarrierConfigManager
|
||||||
|
import android.telephony.CarrierConfigManager.KEY_INFLATE_SIGNAL_STRENGTH_BOOL
|
||||||
|
import android.telephony.CarrierConfigManager.KEY_SHOW_OPERATOR_NAME_IN_STATUSBAR_BOOL
|
||||||
|
import androidx.test.filters.SmallTest
|
||||||
|
import com.android.systemui.SysuiTestCase
|
||||||
|
import com.google.common.truth.Truth.assertThat
|
||||||
|
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
||||||
|
import org.junit.Before
|
||||||
|
import org.junit.Test
|
||||||
|
|
||||||
|
@OptIn(ExperimentalCoroutinesApi::class)
|
||||||
|
@SmallTest
|
||||||
|
class SystemUiCarrierConfigTest : SysuiTestCase() {
|
||||||
|
|
||||||
|
lateinit var underTest: SystemUiCarrierConfig
|
||||||
|
|
||||||
|
@Before
|
||||||
|
fun setUp() {
|
||||||
|
underTest = SystemUiCarrierConfig(SUB_1_ID, createTestConfig())
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `process new config - reflected by isUsingDefault`() {
|
||||||
|
// Starts out using the defaults
|
||||||
|
assertThat(underTest.isUsingDefault).isTrue()
|
||||||
|
|
||||||
|
// ANY new config means we're no longer tracking defaults
|
||||||
|
underTest.processNewCarrierConfig(createTestConfig())
|
||||||
|
|
||||||
|
assertThat(underTest.isUsingDefault).isFalse()
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `process new config - updates all flows`() {
|
||||||
|
assertThat(underTest.shouldInflateSignalStrength.value).isFalse()
|
||||||
|
assertThat(underTest.showOperatorNameInStatusBar.value).isFalse()
|
||||||
|
|
||||||
|
underTest.processNewCarrierConfig(
|
||||||
|
configWithOverrides(
|
||||||
|
KEY_INFLATE_SIGNAL_STRENGTH_BOOL to true,
|
||||||
|
KEY_SHOW_OPERATOR_NAME_IN_STATUSBAR_BOOL to true,
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
assertThat(underTest.shouldInflateSignalStrength.value).isTrue()
|
||||||
|
assertThat(underTest.showOperatorNameInStatusBar.value).isTrue()
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `process new config - defaults to false for config overrides`() {
|
||||||
|
// This case is only apparent when:
|
||||||
|
// 1. The default is true
|
||||||
|
// 2. The override config has no value for a given key
|
||||||
|
// In this case (per the old code) we would use the default value of false, despite there
|
||||||
|
// being no override key present in the override config
|
||||||
|
|
||||||
|
underTest =
|
||||||
|
SystemUiCarrierConfig(
|
||||||
|
SUB_1_ID,
|
||||||
|
configWithOverrides(
|
||||||
|
KEY_INFLATE_SIGNAL_STRENGTH_BOOL to true,
|
||||||
|
KEY_SHOW_OPERATOR_NAME_IN_STATUSBAR_BOOL to true,
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
assertThat(underTest.isUsingDefault).isTrue()
|
||||||
|
assertThat(underTest.shouldInflateSignalStrength.value).isTrue()
|
||||||
|
assertThat(underTest.showOperatorNameInStatusBar.value).isTrue()
|
||||||
|
|
||||||
|
// Process a new config with no keys
|
||||||
|
underTest.processNewCarrierConfig(PersistableBundle())
|
||||||
|
|
||||||
|
assertThat(underTest.isUsingDefault).isFalse()
|
||||||
|
assertThat(underTest.shouldInflateSignalStrength.value).isFalse()
|
||||||
|
assertThat(underTest.showOperatorNameInStatusBar.value).isFalse()
|
||||||
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
private const val SUB_1_ID = 1
|
||||||
|
|
||||||
|
/**
|
||||||
|
* In order to keep us from having to update every place that might want to create a config,
|
||||||
|
* make sure to add new keys here
|
||||||
|
*/
|
||||||
|
fun createTestConfig() =
|
||||||
|
PersistableBundle().also {
|
||||||
|
it.putBoolean(CarrierConfigManager.KEY_INFLATE_SIGNAL_STRENGTH_BOOL, false)
|
||||||
|
it.putBoolean(CarrierConfigManager.KEY_SHOW_OPERATOR_NAME_IN_STATUSBAR_BOOL, false)
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Override the default config with the given (key, value) pair */
|
||||||
|
fun configWithOverride(key: String, override: Boolean): PersistableBundle =
|
||||||
|
createTestConfig().also { it.putBoolean(key, override) }
|
||||||
|
|
||||||
|
/** Override any number of configs from the default */
|
||||||
|
fun configWithOverrides(vararg overrides: Pair<String, Boolean>) =
|
||||||
|
createTestConfig().also { config ->
|
||||||
|
overrides.forEach { (key, value) -> config.putBoolean(key, value) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,172 @@
|
|||||||
|
/*
|
||||||
|
* 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
|
||||||
|
|
||||||
|
import android.content.Intent
|
||||||
|
import android.os.PersistableBundle
|
||||||
|
import android.telephony.CarrierConfigManager
|
||||||
|
import android.telephony.SubscriptionManager.INVALID_SUBSCRIPTION_ID
|
||||||
|
import androidx.test.filters.SmallTest
|
||||||
|
import com.android.dx.mockito.inline.extended.ExtendedMockito.mockitoSession
|
||||||
|
import com.android.systemui.SysuiTestCase
|
||||||
|
import com.android.systemui.dump.DumpManager
|
||||||
|
import com.android.systemui.statusbar.pipeline.mobile.data.model.SystemUiCarrierConfigTest.Companion.createTestConfig
|
||||||
|
import com.android.systemui.statusbar.pipeline.shared.ConnectivityPipelineLogger
|
||||||
|
import com.android.systemui.util.mockito.whenever
|
||||||
|
import com.google.common.truth.Truth.assertThat
|
||||||
|
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
||||||
|
import kotlinx.coroutines.flow.launchIn
|
||||||
|
import kotlinx.coroutines.flow.onEach
|
||||||
|
import kotlinx.coroutines.test.TestScope
|
||||||
|
import kotlinx.coroutines.test.UnconfinedTestDispatcher
|
||||||
|
import kotlinx.coroutines.test.runTest
|
||||||
|
import org.junit.After
|
||||||
|
import org.junit.Before
|
||||||
|
import org.junit.Test
|
||||||
|
import org.mockito.ArgumentMatchers.anyInt
|
||||||
|
import org.mockito.Mock
|
||||||
|
import org.mockito.MockitoAnnotations
|
||||||
|
import org.mockito.MockitoSession
|
||||||
|
import org.mockito.quality.Strictness
|
||||||
|
|
||||||
|
@OptIn(ExperimentalCoroutinesApi::class)
|
||||||
|
@SmallTest
|
||||||
|
class CarrierConfigRepositoryTest : SysuiTestCase() {
|
||||||
|
private val testDispatcher = UnconfinedTestDispatcher()
|
||||||
|
private val testScope = TestScope(testDispatcher)
|
||||||
|
|
||||||
|
private lateinit var underTest: CarrierConfigRepository
|
||||||
|
private lateinit var mockitoSession: MockitoSession
|
||||||
|
private lateinit var carrierConfigCoreStartable: CarrierConfigCoreStartable
|
||||||
|
|
||||||
|
@Mock private lateinit var logger: ConnectivityPipelineLogger
|
||||||
|
@Mock private lateinit var carrierConfigManager: CarrierConfigManager
|
||||||
|
@Mock private lateinit var dumpManager: DumpManager
|
||||||
|
|
||||||
|
@Before
|
||||||
|
fun setUp() {
|
||||||
|
MockitoAnnotations.initMocks(this)
|
||||||
|
mockitoSession =
|
||||||
|
mockitoSession()
|
||||||
|
.initMocks(this)
|
||||||
|
.mockStatic(CarrierConfigManager::class.java)
|
||||||
|
.strictness(Strictness.LENIENT)
|
||||||
|
.startMocking()
|
||||||
|
|
||||||
|
whenever(CarrierConfigManager.getDefaultConfig()).thenReturn(DEFAULT_CONFIG)
|
||||||
|
|
||||||
|
whenever(carrierConfigManager.getConfigForSubId(anyInt())).thenAnswer { invocation ->
|
||||||
|
when (invocation.getArgument(0) as Int) {
|
||||||
|
1 -> CONFIG_1
|
||||||
|
2 -> CONFIG_2
|
||||||
|
else -> null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
underTest =
|
||||||
|
CarrierConfigRepository(
|
||||||
|
fakeBroadcastDispatcher,
|
||||||
|
carrierConfigManager,
|
||||||
|
dumpManager,
|
||||||
|
logger,
|
||||||
|
testScope.backgroundScope,
|
||||||
|
)
|
||||||
|
|
||||||
|
carrierConfigCoreStartable =
|
||||||
|
CarrierConfigCoreStartable(underTest, testScope.backgroundScope)
|
||||||
|
}
|
||||||
|
|
||||||
|
@After
|
||||||
|
fun tearDown() {
|
||||||
|
mockitoSession.finishMocking()
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `carrier config stream produces int-bundle pairs`() =
|
||||||
|
testScope.runTest {
|
||||||
|
var latest: Pair<Int, PersistableBundle>? = null
|
||||||
|
val job = underTest.carrierConfigStream.onEach { latest = it }.launchIn(this)
|
||||||
|
|
||||||
|
sendConfig(SUB_ID_1)
|
||||||
|
assertThat(latest).isEqualTo(Pair(SUB_ID_1, CONFIG_1))
|
||||||
|
|
||||||
|
sendConfig(SUB_ID_2)
|
||||||
|
assertThat(latest).isEqualTo(Pair(SUB_ID_2, CONFIG_2))
|
||||||
|
|
||||||
|
job.cancel()
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `carrier config stream ignores invalid subscriptions`() =
|
||||||
|
testScope.runTest {
|
||||||
|
var latest: Pair<Int, PersistableBundle>? = null
|
||||||
|
val job = underTest.carrierConfigStream.onEach { latest = it }.launchIn(this)
|
||||||
|
|
||||||
|
sendConfig(INVALID_SUBSCRIPTION_ID)
|
||||||
|
|
||||||
|
assertThat(latest).isNull()
|
||||||
|
|
||||||
|
job.cancel()
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `getOrCreateConfig - uses default config if no override`() {
|
||||||
|
val config = underTest.getOrCreateConfigForSubId(123)
|
||||||
|
assertThat(config.isUsingDefault).isTrue()
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `getOrCreateConfig - uses override if exists`() {
|
||||||
|
val config = underTest.getOrCreateConfigForSubId(SUB_ID_1)
|
||||||
|
assertThat(config.isUsingDefault).isFalse()
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `config - updates while config stream is collected`() =
|
||||||
|
testScope.runTest {
|
||||||
|
CONFIG_1.putBoolean(CarrierConfigManager.KEY_INFLATE_SIGNAL_STRENGTH_BOOL, false)
|
||||||
|
|
||||||
|
carrierConfigCoreStartable.start()
|
||||||
|
|
||||||
|
val config = underTest.getOrCreateConfigForSubId(SUB_ID_1)
|
||||||
|
assertThat(config.shouldInflateSignalStrength.value).isFalse()
|
||||||
|
|
||||||
|
CONFIG_1.putBoolean(CarrierConfigManager.KEY_INFLATE_SIGNAL_STRENGTH_BOOL, true)
|
||||||
|
sendConfig(SUB_ID_1)
|
||||||
|
|
||||||
|
assertThat(config.shouldInflateSignalStrength.value).isTrue()
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun sendConfig(subId: Int) {
|
||||||
|
fakeBroadcastDispatcher.registeredReceivers.forEach { receiver ->
|
||||||
|
receiver.onReceive(
|
||||||
|
context,
|
||||||
|
Intent(CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED)
|
||||||
|
.putExtra(CarrierConfigManager.EXTRA_SUBSCRIPTION_INDEX, subId)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
private const val SUB_ID_1 = 1
|
||||||
|
private const val SUB_ID_2 = 2
|
||||||
|
|
||||||
|
private val DEFAULT_CONFIG = createTestConfig()
|
||||||
|
private val CONFIG_1 = createTestConfig()
|
||||||
|
private val CONFIG_2 = createTestConfig()
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -71,9 +71,6 @@ class FakeMobileConnectionsRepository(
|
|||||||
?: FakeMobileConnectionRepository(subId, tableLogBuffer).also { subIdRepos[subId] = it }
|
?: FakeMobileConnectionRepository(subId, tableLogBuffer).also { subIdRepos[subId] = it }
|
||||||
}
|
}
|
||||||
|
|
||||||
private val _globalMobileDataSettingChangedEvent = MutableStateFlow(Unit)
|
|
||||||
override val globalMobileDataSettingChangedEvent = _globalMobileDataSettingChangedEvent
|
|
||||||
|
|
||||||
override val defaultDataSubRatConfig = MutableStateFlow(MobileMappings.Config())
|
override val defaultDataSubRatConfig = MutableStateFlow(MobileMappings.Config())
|
||||||
|
|
||||||
private val _defaultMobileIconMapping = MutableStateFlow(TEST_MAPPING)
|
private val _defaultMobileIconMapping = MutableStateFlow(TEST_MAPPING)
|
||||||
@@ -94,10 +91,6 @@ class FakeMobileConnectionsRepository(
|
|||||||
_mobileConnectivity.value = model
|
_mobileConnectivity.value = model
|
||||||
}
|
}
|
||||||
|
|
||||||
suspend fun triggerGlobalMobileDataSettingChangedEvent() {
|
|
||||||
_globalMobileDataSettingChangedEvent.emit(Unit)
|
|
||||||
}
|
|
||||||
|
|
||||||
fun setActiveMobileDataSubscriptionId(subId: Int) {
|
fun setActiveMobileDataSubscriptionId(subId: Int) {
|
||||||
_activeMobileDataSubscriptionId.value = subId
|
_activeMobileDataSubscriptionId.value = subId
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -40,7 +40,6 @@ 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
|
||||||
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.time.FakeSystemClock
|
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
|
||||||
@@ -85,7 +84,6 @@ class MobileRepositorySwitcherTest : SysuiTestCase() {
|
|||||||
@Mock private lateinit var demoModeController: DemoModeController
|
@Mock private lateinit var demoModeController: DemoModeController
|
||||||
@Mock private lateinit var dumpManager: DumpManager
|
@Mock private lateinit var dumpManager: DumpManager
|
||||||
|
|
||||||
private val globalSettings = FakeSettings()
|
|
||||||
private val fakeNetworkEventsFlow = MutableStateFlow<FakeNetworkEventModel?>(null)
|
private val fakeNetworkEventsFlow = MutableStateFlow<FakeNetworkEventModel?>(null)
|
||||||
private val mobileMappings = FakeMobileMappingsProxy()
|
private val mobileMappings = FakeMobileMappingsProxy()
|
||||||
|
|
||||||
@@ -118,7 +116,6 @@ class MobileRepositorySwitcherTest : SysuiTestCase() {
|
|||||||
logger,
|
logger,
|
||||||
mobileMappings,
|
mobileMappings,
|
||||||
fakeBroadcastDispatcher,
|
fakeBroadcastDispatcher,
|
||||||
globalSettings,
|
|
||||||
context,
|
context,
|
||||||
IMMEDIATE,
|
IMMEDIATE,
|
||||||
scope,
|
scope,
|
||||||
|
|||||||
@@ -23,9 +23,7 @@ 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.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.repository.FakeMobileConnectionRepository
|
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.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.any
|
||||||
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
|
||||||
@@ -33,7 +31,6 @@ import com.android.systemui.util.mockito.whenever
|
|||||||
import com.android.systemui.util.time.FakeSystemClock
|
import com.android.systemui.util.time.FakeSystemClock
|
||||||
import com.google.common.truth.Truth.assertThat
|
import com.google.common.truth.Truth.assertThat
|
||||||
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
||||||
import kotlinx.coroutines.flow.Flow
|
|
||||||
import kotlinx.coroutines.flow.launchIn
|
import kotlinx.coroutines.flow.launchIn
|
||||||
import kotlinx.coroutines.flow.onEach
|
import kotlinx.coroutines.flow.onEach
|
||||||
import kotlinx.coroutines.test.TestScope
|
import kotlinx.coroutines.test.TestScope
|
||||||
@@ -57,22 +54,15 @@ class FullMobileConnectionRepositoryTest : SysuiTestCase() {
|
|||||||
|
|
||||||
private val testDispatcher = UnconfinedTestDispatcher()
|
private val testDispatcher = UnconfinedTestDispatcher()
|
||||||
private val testScope = TestScope(testDispatcher)
|
private val testScope = TestScope(testDispatcher)
|
||||||
private val mobileMappings = FakeMobileMappingsProxy()
|
|
||||||
private val tableLogBuffer = mock<TableLogBuffer>()
|
private val tableLogBuffer = mock<TableLogBuffer>()
|
||||||
private val mobileFactory = mock<MobileConnectionRepositoryImpl.Factory>()
|
private val mobileFactory = mock<MobileConnectionRepositoryImpl.Factory>()
|
||||||
private val carrierMergedFactory = mock<CarrierMergedConnectionRepository.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 mobileRepo: FakeMobileConnectionRepository
|
||||||
private lateinit var carrierMergedRepo: FakeMobileConnectionRepository
|
private lateinit var carrierMergedRepo: FakeMobileConnectionRepository
|
||||||
|
|
||||||
@Before
|
@Before
|
||||||
fun setUp() {
|
fun setUp() {
|
||||||
connectionsRepo = FakeMobileConnectionsRepository(mobileMappings, tableLogBuffer)
|
|
||||||
|
|
||||||
mobileRepo = FakeMobileConnectionRepository(SUB_ID, tableLogBuffer)
|
mobileRepo = FakeMobileConnectionRepository(SUB_ID, tableLogBuffer)
|
||||||
carrierMergedRepo = FakeMobileConnectionRepository(SUB_ID, tableLogBuffer)
|
carrierMergedRepo = FakeMobileConnectionRepository(SUB_ID, tableLogBuffer)
|
||||||
|
|
||||||
@@ -82,7 +72,6 @@ class FullMobileConnectionRepositoryTest : SysuiTestCase() {
|
|||||||
any(),
|
any(),
|
||||||
eq(DEFAULT_NAME),
|
eq(DEFAULT_NAME),
|
||||||
eq(SEP),
|
eq(SEP),
|
||||||
eq(globalMobileDataSettingChangedEvent),
|
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
.thenReturn(mobileRepo)
|
.thenReturn(mobileRepo)
|
||||||
@@ -109,7 +98,6 @@ class FullMobileConnectionRepositoryTest : SysuiTestCase() {
|
|||||||
tableLogBuffer,
|
tableLogBuffer,
|
||||||
DEFAULT_NAME,
|
DEFAULT_NAME,
|
||||||
SEP,
|
SEP,
|
||||||
globalMobileDataSettingChangedEvent
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -310,7 +298,6 @@ class FullMobileConnectionRepositoryTest : SysuiTestCase() {
|
|||||||
startingIsCarrierMerged = false,
|
startingIsCarrierMerged = false,
|
||||||
DEFAULT_NAME,
|
DEFAULT_NAME,
|
||||||
SEP,
|
SEP,
|
||||||
globalMobileDataSettingChangedEvent,
|
|
||||||
)
|
)
|
||||||
|
|
||||||
val connection1Repeat =
|
val connection1Repeat =
|
||||||
@@ -319,7 +306,6 @@ class FullMobileConnectionRepositoryTest : SysuiTestCase() {
|
|||||||
startingIsCarrierMerged = false,
|
startingIsCarrierMerged = false,
|
||||||
DEFAULT_NAME,
|
DEFAULT_NAME,
|
||||||
SEP,
|
SEP,
|
||||||
globalMobileDataSettingChangedEvent,
|
|
||||||
)
|
)
|
||||||
|
|
||||||
assertThat(connection1.tableLogBuffer)
|
assertThat(connection1.tableLogBuffer)
|
||||||
@@ -345,7 +331,6 @@ class FullMobileConnectionRepositoryTest : SysuiTestCase() {
|
|||||||
startingIsCarrierMerged = false,
|
startingIsCarrierMerged = false,
|
||||||
DEFAULT_NAME,
|
DEFAULT_NAME,
|
||||||
SEP,
|
SEP,
|
||||||
globalMobileDataSettingChangedEvent,
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// WHEN a connection with the same sub ID but carrierMerged = true is created
|
// WHEN a connection with the same sub ID but carrierMerged = true is created
|
||||||
@@ -355,7 +340,6 @@ class FullMobileConnectionRepositoryTest : SysuiTestCase() {
|
|||||||
startingIsCarrierMerged = true,
|
startingIsCarrierMerged = true,
|
||||||
DEFAULT_NAME,
|
DEFAULT_NAME,
|
||||||
SEP,
|
SEP,
|
||||||
globalMobileDataSettingChangedEvent,
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// THEN the same table is re-used
|
// THEN the same table is re-used
|
||||||
@@ -374,7 +358,6 @@ class FullMobileConnectionRepositoryTest : SysuiTestCase() {
|
|||||||
tableLogBuffer,
|
tableLogBuffer,
|
||||||
DEFAULT_NAME,
|
DEFAULT_NAME,
|
||||||
SEP,
|
SEP,
|
||||||
globalMobileDataSettingChangedEvent,
|
|
||||||
testScope.backgroundScope,
|
testScope.backgroundScope,
|
||||||
mobileFactory,
|
mobileFactory,
|
||||||
carrierMergedFactory,
|
carrierMergedFactory,
|
||||||
|
|||||||
@@ -17,8 +17,7 @@
|
|||||||
package com.android.systemui.statusbar.pipeline.mobile.data.repository.prod
|
package com.android.systemui.statusbar.pipeline.mobile.data.repository.prod
|
||||||
|
|
||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
import android.os.UserHandle
|
import android.telephony.CarrierConfigManager.KEY_INFLATE_SIGNAL_STRENGTH_BOOL
|
||||||
import android.provider.Settings
|
|
||||||
import android.telephony.CellSignalStrengthCdma
|
import android.telephony.CellSignalStrengthCdma
|
||||||
import android.telephony.NetworkRegistrationInfo
|
import android.telephony.NetworkRegistrationInfo
|
||||||
import android.telephony.ServiceState
|
import android.telephony.ServiceState
|
||||||
@@ -61,6 +60,9 @@ import com.android.systemui.statusbar.pipeline.mobile.data.model.NetworkNameMode
|
|||||||
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.model.ResolvedNetworkType.UnknownNetworkType
|
import com.android.systemui.statusbar.pipeline.mobile.data.model.ResolvedNetworkType.UnknownNetworkType
|
||||||
|
import com.android.systemui.statusbar.pipeline.mobile.data.model.SystemUiCarrierConfig
|
||||||
|
import com.android.systemui.statusbar.pipeline.mobile.data.model.SystemUiCarrierConfigTest.Companion.configWithOverride
|
||||||
|
import com.android.systemui.statusbar.pipeline.mobile.data.model.SystemUiCarrierConfigTest.Companion.createTestConfig
|
||||||
import com.android.systemui.statusbar.pipeline.mobile.data.model.toNetworkNameModel
|
import com.android.systemui.statusbar.pipeline.mobile.data.model.toNetworkNameModel
|
||||||
import com.android.systemui.statusbar.pipeline.mobile.data.repository.FakeMobileConnectionsRepository
|
import com.android.systemui.statusbar.pipeline.mobile.data.repository.FakeMobileConnectionsRepository
|
||||||
import com.android.systemui.statusbar.pipeline.mobile.data.repository.MobileConnectionRepository.Companion.DEFAULT_NUM_LEVELS
|
import com.android.systemui.statusbar.pipeline.mobile.data.repository.MobileConnectionRepository.Companion.DEFAULT_NUM_LEVELS
|
||||||
@@ -72,7 +74,6 @@ import com.android.systemui.util.mockito.any
|
|||||||
import com.android.systemui.util.mockito.argumentCaptor
|
import com.android.systemui.util.mockito.argumentCaptor
|
||||||
import com.android.systemui.util.mockito.mock
|
import com.android.systemui.util.mockito.mock
|
||||||
import com.android.systemui.util.mockito.whenever
|
import com.android.systemui.util.mockito.whenever
|
||||||
import com.android.systemui.util.settings.FakeSettings
|
|
||||||
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
|
||||||
@@ -101,12 +102,15 @@ class MobileConnectionRepositoryTest : SysuiTestCase() {
|
|||||||
|
|
||||||
private val scope = CoroutineScope(IMMEDIATE)
|
private val scope = CoroutineScope(IMMEDIATE)
|
||||||
private val mobileMappings = FakeMobileMappingsProxy()
|
private val mobileMappings = FakeMobileMappingsProxy()
|
||||||
private val globalSettings = FakeSettings()
|
private val systemUiCarrierConfig =
|
||||||
|
SystemUiCarrierConfig(
|
||||||
|
SUB_1_ID,
|
||||||
|
createTestConfig(),
|
||||||
|
)
|
||||||
|
|
||||||
@Before
|
@Before
|
||||||
fun setUp() {
|
fun setUp() {
|
||||||
MockitoAnnotations.initMocks(this)
|
MockitoAnnotations.initMocks(this)
|
||||||
globalSettings.userId = UserHandle.USER_ALL
|
|
||||||
whenever(telephonyManager.subscriptionId).thenReturn(SUB_1_ID)
|
whenever(telephonyManager.subscriptionId).thenReturn(SUB_1_ID)
|
||||||
|
|
||||||
connectionsRepo = FakeMobileConnectionsRepository(mobileMappings, tableLogger)
|
connectionsRepo = FakeMobileConnectionsRepository(mobileMappings, tableLogger)
|
||||||
@@ -118,9 +122,8 @@ class MobileConnectionRepositoryTest : SysuiTestCase() {
|
|||||||
DEFAULT_NAME,
|
DEFAULT_NAME,
|
||||||
SEP,
|
SEP,
|
||||||
telephonyManager,
|
telephonyManager,
|
||||||
globalSettings,
|
systemUiCarrierConfig,
|
||||||
fakeBroadcastDispatcher,
|
fakeBroadcastDispatcher,
|
||||||
connectionsRepo.globalMobileDataSettingChangedEvent,
|
|
||||||
mobileMappings,
|
mobileMappings,
|
||||||
IMMEDIATE,
|
IMMEDIATE,
|
||||||
logger,
|
logger,
|
||||||
@@ -399,53 +402,27 @@ class MobileConnectionRepositoryTest : SysuiTestCase() {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun dataEnabled_initial_false() =
|
fun dataEnabled_initial_false() =
|
||||||
runBlocking(IMMEDIATE) {
|
|
||||||
whenever(telephonyManager.isDataConnectionAllowed).thenReturn(true)
|
|
||||||
|
|
||||||
assertThat(underTest.dataEnabled.value).isFalse()
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
fun dataEnabled_isEnabled_true() =
|
|
||||||
runBlocking(IMMEDIATE) {
|
|
||||||
whenever(telephonyManager.isDataConnectionAllowed).thenReturn(true)
|
|
||||||
val job = underTest.dataEnabled.launchIn(this)
|
|
||||||
|
|
||||||
assertThat(underTest.dataEnabled.value).isTrue()
|
|
||||||
|
|
||||||
job.cancel()
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
fun dataEnabled_isDisabled() =
|
|
||||||
runBlocking(IMMEDIATE) {
|
runBlocking(IMMEDIATE) {
|
||||||
whenever(telephonyManager.isDataConnectionAllowed).thenReturn(false)
|
whenever(telephonyManager.isDataConnectionAllowed).thenReturn(false)
|
||||||
val job = underTest.dataEnabled.launchIn(this)
|
|
||||||
|
|
||||||
assertThat(underTest.dataEnabled.value).isFalse()
|
assertThat(underTest.dataEnabled.value).isFalse()
|
||||||
|
|
||||||
job.cancel()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun isDataConnectionAllowed_subIdSettingUpdate_valueUpdated() =
|
fun `is data enabled - tracks telephony callback`() =
|
||||||
runBlocking(IMMEDIATE) {
|
runBlocking(IMMEDIATE) {
|
||||||
val subIdSettingName = "${Settings.Global.MOBILE_DATA}$SUB_1_ID"
|
|
||||||
|
|
||||||
var latest: Boolean? = null
|
var latest: Boolean? = null
|
||||||
val job = underTest.dataEnabled.onEach { latest = it }.launchIn(this)
|
val job = underTest.dataEnabled.onEach { latest = it }.launchIn(this)
|
||||||
|
|
||||||
// We don't read the setting directly, we query telephony when changes happen
|
|
||||||
whenever(telephonyManager.isDataConnectionAllowed).thenReturn(false)
|
whenever(telephonyManager.isDataConnectionAllowed).thenReturn(false)
|
||||||
globalSettings.putInt(subIdSettingName, 0)
|
assertThat(underTest.dataEnabled.value).isFalse()
|
||||||
assertThat(latest).isFalse()
|
|
||||||
|
|
||||||
whenever(telephonyManager.isDataConnectionAllowed).thenReturn(true)
|
val callback = getTelephonyCallbackForType<TelephonyCallback.DataEnabledListener>()
|
||||||
globalSettings.putInt(subIdSettingName, 1)
|
|
||||||
|
callback.onDataEnabledChanged(true, 1)
|
||||||
assertThat(latest).isTrue()
|
assertThat(latest).isTrue()
|
||||||
|
|
||||||
whenever(telephonyManager.isDataConnectionAllowed).thenReturn(false)
|
callback.onDataEnabledChanged(false, 1)
|
||||||
globalSettings.putInt(subIdSettingName, 0)
|
|
||||||
assertThat(latest).isFalse()
|
assertThat(latest).isFalse()
|
||||||
|
|
||||||
job.cancel()
|
job.cancel()
|
||||||
@@ -466,8 +443,6 @@ class MobileConnectionRepositoryTest : SysuiTestCase() {
|
|||||||
fun `roaming - cdma - queries telephony manager`() =
|
fun `roaming - cdma - queries telephony manager`() =
|
||||||
runBlocking(IMMEDIATE) {
|
runBlocking(IMMEDIATE) {
|
||||||
var latest: Boolean? = null
|
var latest: Boolean? = null
|
||||||
// Start the telephony collection job so that cdmaRoaming starts updating
|
|
||||||
val telephonyJob = underTest.connectionInfo.launchIn(this)
|
|
||||||
val job = underTest.cdmaRoaming.onEach { latest = it }.launchIn(this)
|
val job = underTest.cdmaRoaming.onEach { latest = it }.launchIn(this)
|
||||||
|
|
||||||
val cb = getTelephonyCallbackForType<ServiceStateListener>()
|
val cb = getTelephonyCallbackForType<ServiceStateListener>()
|
||||||
@@ -487,7 +462,6 @@ class MobileConnectionRepositoryTest : SysuiTestCase() {
|
|||||||
|
|
||||||
assertThat(latest).isTrue()
|
assertThat(latest).isTrue()
|
||||||
|
|
||||||
telephonyJob.cancel()
|
|
||||||
job.cancel()
|
job.cancel()
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -673,6 +647,29 @@ class MobileConnectionRepositoryTest : SysuiTestCase() {
|
|||||||
job.cancel()
|
job.cancel()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `number of levels - uses carrier config`() =
|
||||||
|
runBlocking(IMMEDIATE) {
|
||||||
|
var latest: Int? = null
|
||||||
|
val job = underTest.numberOfLevels.onEach { latest = it }.launchIn(this)
|
||||||
|
|
||||||
|
assertThat(latest).isEqualTo(DEFAULT_NUM_LEVELS)
|
||||||
|
|
||||||
|
systemUiCarrierConfig.processNewCarrierConfig(
|
||||||
|
configWithOverride(KEY_INFLATE_SIGNAL_STRENGTH_BOOL, true)
|
||||||
|
)
|
||||||
|
|
||||||
|
assertThat(latest).isEqualTo(DEFAULT_NUM_LEVELS + 1)
|
||||||
|
|
||||||
|
systemUiCarrierConfig.processNewCarrierConfig(
|
||||||
|
configWithOverride(KEY_INFLATE_SIGNAL_STRENGTH_BOOL, false)
|
||||||
|
)
|
||||||
|
|
||||||
|
assertThat(latest).isEqualTo(DEFAULT_NUM_LEVELS)
|
||||||
|
|
||||||
|
job.cancel()
|
||||||
|
}
|
||||||
|
|
||||||
private fun getTelephonyCallbacks(): List<TelephonyCallback> {
|
private fun getTelephonyCallbacks(): List<TelephonyCallback> {
|
||||||
val callbackCaptor = argumentCaptor<TelephonyCallback>()
|
val callbackCaptor = argumentCaptor<TelephonyCallback>()
|
||||||
Mockito.verify(telephonyManager).registerTelephonyCallback(any(), callbackCaptor.capture())
|
Mockito.verify(telephonyManager).registerTelephonyCallback(any(), callbackCaptor.capture())
|
||||||
|
|||||||
@@ -23,7 +23,6 @@ import android.net.NetworkCapabilities
|
|||||||
import android.net.NetworkCapabilities.NET_CAPABILITY_VALIDATED
|
import android.net.NetworkCapabilities.NET_CAPABILITY_VALIDATED
|
||||||
import android.net.NetworkCapabilities.TRANSPORT_CELLULAR
|
import android.net.NetworkCapabilities.TRANSPORT_CELLULAR
|
||||||
import android.os.ParcelUuid
|
import android.os.ParcelUuid
|
||||||
import android.provider.Settings
|
|
||||||
import android.telephony.CarrierConfigManager
|
import android.telephony.CarrierConfigManager
|
||||||
import android.telephony.SubscriptionInfo
|
import android.telephony.SubscriptionInfo
|
||||||
import android.telephony.SubscriptionManager
|
import android.telephony.SubscriptionManager
|
||||||
@@ -39,6 +38,7 @@ 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.SubscriptionModel
|
import com.android.systemui.statusbar.pipeline.mobile.data.model.SubscriptionModel
|
||||||
|
import com.android.systemui.statusbar.pipeline.mobile.data.repository.CarrierConfigRepository
|
||||||
import com.android.systemui.statusbar.pipeline.mobile.data.repository.prod.FullMobileConnectionRepository.Factory.Companion.tableBufferLogName
|
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
|
||||||
@@ -49,7 +49,6 @@ 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.google.common.truth.Truth.assertThat
|
import com.google.common.truth.Truth.assertThat
|
||||||
import java.util.UUID
|
import java.util.UUID
|
||||||
import kotlinx.coroutines.CoroutineScope
|
import kotlinx.coroutines.CoroutineScope
|
||||||
@@ -80,6 +79,7 @@ class MobileConnectionsRepositoryTest : SysuiTestCase() {
|
|||||||
private lateinit var carrierMergedFactory: CarrierMergedConnectionRepository.Factory
|
private lateinit var carrierMergedFactory: CarrierMergedConnectionRepository.Factory
|
||||||
private lateinit var fullConnectionFactory: FullMobileConnectionRepository.Factory
|
private lateinit var fullConnectionFactory: FullMobileConnectionRepository.Factory
|
||||||
private lateinit var wifiRepository: FakeWifiRepository
|
private lateinit var wifiRepository: FakeWifiRepository
|
||||||
|
private lateinit var carrierConfigRepository: CarrierConfigRepository
|
||||||
@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
|
||||||
@@ -89,7 +89,6 @@ class MobileConnectionsRepositoryTest : SysuiTestCase() {
|
|||||||
private val mobileMappings = FakeMobileMappingsProxy()
|
private val mobileMappings = FakeMobileMappingsProxy()
|
||||||
|
|
||||||
private val scope = CoroutineScope(IMMEDIATE)
|
private val scope = CoroutineScope(IMMEDIATE)
|
||||||
private val globalSettings = FakeSettings()
|
|
||||||
|
|
||||||
@Before
|
@Before
|
||||||
fun setUp() {
|
fun setUp() {
|
||||||
@@ -119,16 +118,25 @@ class MobileConnectionsRepositoryTest : SysuiTestCase() {
|
|||||||
|
|
||||||
wifiRepository = FakeWifiRepository()
|
wifiRepository = FakeWifiRepository()
|
||||||
|
|
||||||
|
carrierConfigRepository =
|
||||||
|
CarrierConfigRepository(
|
||||||
|
fakeBroadcastDispatcher,
|
||||||
|
mock(),
|
||||||
|
mock(),
|
||||||
|
logger,
|
||||||
|
scope,
|
||||||
|
)
|
||||||
|
|
||||||
connectionFactory =
|
connectionFactory =
|
||||||
MobileConnectionRepositoryImpl.Factory(
|
MobileConnectionRepositoryImpl.Factory(
|
||||||
fakeBroadcastDispatcher,
|
fakeBroadcastDispatcher,
|
||||||
context = context,
|
context = context,
|
||||||
telephonyManager = telephonyManager,
|
telephonyManager = telephonyManager,
|
||||||
bgDispatcher = IMMEDIATE,
|
bgDispatcher = IMMEDIATE,
|
||||||
globalSettings = globalSettings,
|
|
||||||
logger = logger,
|
logger = logger,
|
||||||
mobileMappingsProxy = mobileMappings,
|
mobileMappingsProxy = mobileMappings,
|
||||||
scope = scope,
|
scope = scope,
|
||||||
|
carrierConfigRepository = carrierConfigRepository,
|
||||||
)
|
)
|
||||||
carrierMergedFactory =
|
carrierMergedFactory =
|
||||||
CarrierMergedConnectionRepository.Factory(
|
CarrierMergedConnectionRepository.Factory(
|
||||||
@@ -151,7 +159,6 @@ class MobileConnectionsRepositoryTest : SysuiTestCase() {
|
|||||||
logger,
|
logger,
|
||||||
mobileMappings,
|
mobileMappings,
|
||||||
fakeBroadcastDispatcher,
|
fakeBroadcastDispatcher,
|
||||||
globalSettings,
|
|
||||||
context,
|
context,
|
||||||
IMMEDIATE,
|
IMMEDIATE,
|
||||||
scope,
|
scope,
|
||||||
@@ -543,24 +550,6 @@ class MobileConnectionsRepositoryTest : SysuiTestCase() {
|
|||||||
job.cancel()
|
job.cancel()
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
|
||||||
fun globalMobileDataSettingsChangedEvent_producesOnSettingChange() =
|
|
||||||
runBlocking(IMMEDIATE) {
|
|
||||||
var produced = false
|
|
||||||
val job =
|
|
||||||
underTest.globalMobileDataSettingChangedEvent
|
|
||||||
.onEach { produced = true }
|
|
||||||
.launchIn(this)
|
|
||||||
|
|
||||||
assertThat(produced).isFalse()
|
|
||||||
|
|
||||||
globalSettings.putInt(Settings.Global.MOBILE_DATA, 0)
|
|
||||||
|
|
||||||
assertThat(produced).isTrue()
|
|
||||||
|
|
||||||
job.cancel()
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun mobileConnectivity_isConnected_isNotValidated() =
|
fun mobileConnectivity_isConnected_isNotValidated() =
|
||||||
runBlocking(IMMEDIATE) {
|
runBlocking(IMMEDIATE) {
|
||||||
@@ -629,7 +618,6 @@ class MobileConnectionsRepositoryTest : SysuiTestCase() {
|
|||||||
logger,
|
logger,
|
||||||
mobileMappings,
|
mobileMappings,
|
||||||
fakeBroadcastDispatcher,
|
fakeBroadcastDispatcher,
|
||||||
globalSettings,
|
|
||||||
context,
|
context,
|
||||||
IMMEDIATE,
|
IMMEDIATE,
|
||||||
scope,
|
scope,
|
||||||
|
|||||||
Reference in New Issue
Block a user