Merge changes Ieb73c357,I7f5bc07b,I01b33b24,I873e57bf,I8de76ad5 into tm-qpr-dev

* changes:
  [SB Refactor] Remove `type` from ResolvedNetworkType.
  [SB Refactor] Make `numberOfLevels` a flow at the repo level.
  [SB Refactor] Remove unused `isDefaultDataSubscription` flow.
  [SB Refactor] Run the linter on WifiRepositoryImpl.
  [SB Refactor] Provide a disabled wifi repo if there's no wifi manager.
This commit is contained in:
TreeHugger Robot
2023-01-05 01:59:24 +00:00
committed by Android (Google) Code Review
30 changed files with 471 additions and 413 deletions

View File

@@ -460,7 +460,6 @@
-packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/ConnectivityPipelineLogger.kt
-packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/data/model/WifiActivityModel.kt
-packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/data/model/WifiNetworkModel.kt
-packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/prod/WifiRepositoryImpl.kt
-packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/domain/interactor/WifiInteractor.kt
-packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/shared/WifiConstants.kt
-packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/ui/view/ModernStatusBarWifiView.kt

View File

@@ -16,6 +16,7 @@
package com.android.systemui.statusbar.pipeline.dagger
import android.net.wifi.WifiManager
import com.android.systemui.CoreStartable
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.log.table.TableLogBuffer
@@ -35,8 +36,11 @@ import com.android.systemui.statusbar.pipeline.mobile.util.MobileMappingsProxy
import com.android.systemui.statusbar.pipeline.mobile.util.MobileMappingsProxyImpl
import com.android.systemui.statusbar.pipeline.shared.data.repository.ConnectivityRepository
import com.android.systemui.statusbar.pipeline.shared.data.repository.ConnectivityRepositoryImpl
import com.android.systemui.statusbar.pipeline.wifi.data.repository.RealWifiRepository
import com.android.systemui.statusbar.pipeline.wifi.data.repository.WifiRepository
import com.android.systemui.statusbar.pipeline.wifi.data.repository.WifiRepositorySwitcher
import com.android.systemui.statusbar.pipeline.wifi.data.repository.prod.DisabledWifiRepository
import com.android.systemui.statusbar.pipeline.wifi.data.repository.prod.WifiRepositoryImpl
import com.android.systemui.statusbar.pipeline.wifi.domain.interactor.WifiInteractor
import com.android.systemui.statusbar.pipeline.wifi.domain.interactor.WifiInteractorImpl
import dagger.Binds
@@ -78,9 +82,23 @@ abstract class StatusBarPipelineModule {
@ClassKey(MobileUiAdapter::class)
abstract fun bindFeature(impl: MobileUiAdapter): CoreStartable
@Module
companion object {
@JvmStatic
@Provides
@SysUISingleton
fun provideRealWifiRepository(
wifiManager: WifiManager?,
disabledWifiRepository: DisabledWifiRepository,
wifiRepositoryImplFactory: WifiRepositoryImpl.Factory,
): RealWifiRepository {
// If we have a null [WifiManager], then the wifi repository should be permanently
// disabled.
return if (wifiManager == null) {
disabledWifiRepository
} else {
wifiRepositoryImplFactory.create(wifiManager)
}
}
@Provides
@SysUISingleton
@WifiTableLog
@@ -88,7 +106,6 @@ abstract class StatusBarPipelineModule {
return factory.create("WifiTableLog", 100)
}
@JvmStatic
@Provides
@SysUISingleton
@AirplaneTableLog

View File

@@ -17,7 +17,6 @@
package com.android.systemui.statusbar.pipeline.mobile.data.model
import android.telephony.Annotation.NetworkType
import android.telephony.TelephonyManager.NETWORK_TYPE_UNKNOWN
import com.android.systemui.statusbar.pipeline.mobile.util.MobileMappingsProxy
/**
@@ -26,21 +25,17 @@ import com.android.systemui.statusbar.pipeline.mobile.util.MobileMappingsProxy
* methods on [MobileMappingsProxy] to generate an icon lookup key.
*/
sealed interface ResolvedNetworkType {
@NetworkType val type: Int
val lookupKey: String
object UnknownNetworkType : ResolvedNetworkType {
override val type: Int = NETWORK_TYPE_UNKNOWN
override val lookupKey: String = "unknown"
}
data class DefaultNetworkType(
@NetworkType override val type: Int,
override val lookupKey: String,
) : ResolvedNetworkType
data class OverrideNetworkType(
@NetworkType override val type: Int,
override val lookupKey: String,
) : ResolvedNetworkType
}

View File

@@ -17,7 +17,6 @@
package com.android.systemui.statusbar.pipeline.mobile.data.repository
import android.telephony.SubscriptionInfo
import android.telephony.SubscriptionManager
import android.telephony.TelephonyCallback
import android.telephony.TelephonyManager
import com.android.systemui.log.table.TableLogBuffer
@@ -52,13 +51,12 @@ interface MobileConnectionRepository {
* listener + model.
*/
val connectionInfo: Flow<MobileConnectionModel>
/** The total number of levels. Used with [SignalDrawable]. */
val numberOfLevels: StateFlow<Int>
/** Observable tracking [TelephonyManager.isDataConnectionAllowed] */
val dataEnabled: StateFlow<Boolean>
/**
* True if this connection represents the default subscription per
* [SubscriptionManager.getDefaultDataSubscriptionId]
*/
val isDefaultDataSubscription: StateFlow<Boolean>
/**
* See [TelephonyManager.getCdmaEnhancedRoamingIndicatorDisplayNumber]. This bit only matters if
@@ -70,4 +68,9 @@ interface MobileConnectionRepository {
/** The service provider name for this network connection, or the default name */
val networkName: StateFlow<NetworkNameModel>
companion object {
/** The default number of levels to use for [numberOfLevels]. */
const val DEFAULT_NUM_LEVELS = 4
}
}

View File

@@ -18,7 +18,6 @@ package com.android.systemui.statusbar.pipeline.mobile.data.repository
import android.provider.Settings
import android.telephony.CarrierConfigManager
import android.telephony.SubscriptionManager
import com.android.settingslib.SignalIcon.MobileIconGroup
import com.android.settingslib.mobile.MobileMappings
import com.android.settingslib.mobile.MobileMappings.Config
@@ -38,9 +37,6 @@ interface MobileConnectionsRepository {
/** Observable for the subscriptionId of the current mobile data connection */
val activeMobileDataSubscriptionId: StateFlow<Int>
/** Tracks [SubscriptionManager.getDefaultDataSubscriptionId] */
val defaultDataSubId: StateFlow<Int>
/** The current connectivity status for the default mobile network connection */
val defaultMobileNetworkConnectivity: StateFlow<MobileConnectivityModel>

View File

@@ -139,11 +139,6 @@ constructor(
override val defaultMobileIconGroup: Flow<SignalIcon.MobileIconGroup> =
activeRepo.flatMapLatest { it.defaultMobileIconGroup }
override val defaultDataSubId: StateFlow<Int> =
activeRepo
.flatMapLatest { it.defaultDataSubId }
.stateIn(scope, SharingStarted.WhileSubscribed(), realRepository.defaultDataSubId.value)
override val defaultMobileNetworkConnectivity: StateFlow<MobileConnectivityModel> =
activeRepo
.flatMapLatest { it.defaultMobileNetworkConnectivity }

View File

@@ -34,6 +34,7 @@ import com.android.systemui.statusbar.pipeline.mobile.data.model.ResolvedNetwork
import com.android.systemui.statusbar.pipeline.mobile.data.model.ResolvedNetworkType.DefaultNetworkType
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.MobileConnectionRepository.Companion.DEFAULT_NUM_LEVELS
import com.android.systemui.statusbar.pipeline.mobile.data.repository.MobileConnectionsRepository
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
@@ -139,14 +140,6 @@ constructor(
private fun <K, V> Map<K, V>.reverse() = entries.associateBy({ it.value }) { it.key }
// TODO(b/261029387): add a command for this value
override val defaultDataSubId =
activeMobileDataSubscriptionId.stateIn(
scope,
SharingStarted.WhileSubscribed(),
INVALID_SUBSCRIPTION_ID
)
// TODO(b/261029387): not yet supported
override val defaultMobileNetworkConnectivity = MutableStateFlow(MobileConnectivityModel())
@@ -199,7 +192,6 @@ constructor(
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.isDefaultDataSubscription.value = state.dataType != null
connection.networkName.value = NetworkNameModel.Derived(state.name)
connection.cdmaRoaming.value = state.roaming
@@ -261,15 +253,13 @@ constructor(
private fun SignalIcon.MobileIconGroup?.toResolvedNetworkType(): ResolvedNetworkType {
val key = mobileMappingsReverseLookup.value[this] ?: "dis"
return DefaultNetworkType(DEMO_NET_TYPE, key)
return DefaultNetworkType(key)
}
companion object {
private const val TAG = "DemoMobileConnectionsRepo"
private const val DEFAULT_SUB_ID = 1
private const val DEMO_NET_TYPE = 1234
}
}
@@ -279,9 +269,9 @@ class DemoMobileConnectionRepository(
) : MobileConnectionRepository {
override val connectionInfo = MutableStateFlow(MobileConnectionModel())
override val dataEnabled = MutableStateFlow(true)
override val numberOfLevels = MutableStateFlow(DEFAULT_NUM_LEVELS)
override val isDefaultDataSubscription = MutableStateFlow(true)
override val dataEnabled = MutableStateFlow(true)
override val cdmaRoaming = MutableStateFlow(false)

View File

@@ -48,6 +48,7 @@ import com.android.systemui.statusbar.pipeline.mobile.data.model.ResolvedNetwork
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.repository.MobileConnectionRepository
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.shared.ConnectivityPipelineLogger
import com.android.systemui.statusbar.pipeline.shared.data.model.toMobileDataActivityModel
@@ -63,6 +64,7 @@ import kotlinx.coroutines.flow.MutableSharedFlow
import kotlinx.coroutines.flow.SharingStarted
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.distinctUntilChanged
import kotlinx.coroutines.flow.flowOf
import kotlinx.coroutines.flow.mapLatest
import kotlinx.coroutines.flow.merge
import kotlinx.coroutines.flow.onEach
@@ -78,7 +80,6 @@ class MobileConnectionRepositoryImpl(
private val telephonyManager: TelephonyManager,
private val globalSettings: GlobalSettings,
broadcastDispatcher: BroadcastDispatcher,
defaultDataSubId: StateFlow<Int>,
globalMobileDataSettingChangedEvent: Flow<Unit>,
mobileMappingsProxy: MobileMappingsProxy,
bgDispatcher: CoroutineDispatcher,
@@ -185,14 +186,12 @@ class MobileConnectionRepositoryImpl(
OVERRIDE_NETWORK_TYPE_NONE
) {
DefaultNetworkType(
telephonyDisplayInfo.networkType,
mobileMappingsProxy.toIconKey(
telephonyDisplayInfo.networkType
)
)
} else {
OverrideNetworkType(
telephonyDisplayInfo.overrideNetworkType,
mobileMappingsProxy.toIconKeyOverride(
telephonyDisplayInfo.overrideNetworkType
)
@@ -214,6 +213,12 @@ class MobileConnectionRepositoryImpl(
.stateIn(scope, SharingStarted.WhileSubscribed(), state)
}
// This will become variable based on [CarrierConfigManager.KEY_INFLATE_SIGNAL_STRENGTH_BOOL]
// once it's wired up inside of [CarrierConfigTracker].
override val numberOfLevels: StateFlow<Int> =
flowOf(DEFAULT_NUM_LEVELS)
.stateIn(scope, SharingStarted.WhileSubscribed(), DEFAULT_NUM_LEVELS)
/** Produces whenever the mobile data setting changes for this subId */
private val localMobileDataSettingChangedEvent: Flow<Unit> = conflatedCallbackFlow {
val observer =
@@ -284,20 +289,6 @@ class MobileConnectionRepositoryImpl(
private fun dataConnectionAllowed(): Boolean = telephonyManager.isDataConnectionAllowed
override val isDefaultDataSubscription: StateFlow<Boolean> = run {
val initialValue = defaultDataSubId.value == subId
defaultDataSubId
.mapLatest { it == subId }
.distinctUntilChanged()
.logDiffsForTable(
mobileLogger,
columnPrefix = "",
columnName = "isDefaultDataSub",
initialValue = initialValue,
)
.stateIn(scope, SharingStarted.WhileSubscribed(), initialValue)
}
class Factory
@Inject
constructor(
@@ -315,7 +306,6 @@ class MobileConnectionRepositoryImpl(
subId: Int,
defaultNetworkName: NetworkNameModel,
networkNameSeparator: String,
defaultDataSubId: StateFlow<Int>,
globalMobileDataSettingChangedEvent: Flow<Unit>,
): MobileConnectionRepository {
val mobileLogger = logFactory.create(tableBufferLogName(subId), 100)
@@ -328,7 +318,6 @@ class MobileConnectionRepositoryImpl(
telephonyManager.createForSubscriptionId(subId),
globalSettings,
broadcastDispatcher,
defaultDataSubId,
globalMobileDataSettingChangedEvent,
mobileMappingsProxy,
bgDispatcher,

View File

@@ -35,7 +35,6 @@ import android.telephony.TelephonyCallback
import android.telephony.TelephonyCallback.ActiveDataSubscriptionIdListener
import android.telephony.TelephonyManager
import androidx.annotation.VisibleForTesting
import com.android.internal.telephony.PhoneConstants
import com.android.settingslib.SignalIcon.MobileIconGroup
import com.android.settingslib.mobile.MobileMappings.Config
import com.android.systemui.R
@@ -60,7 +59,6 @@ import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.asExecutor
import kotlinx.coroutines.channels.awaitClose
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.MutableSharedFlow
import kotlinx.coroutines.flow.SharingStarted
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.distinctUntilChanged
@@ -142,24 +140,10 @@ constructor(
.logInputChange(logger, "onActiveDataSubscriptionIdChanged")
.stateIn(scope, started = SharingStarted.WhileSubscribed(), INVALID_SUBSCRIPTION_ID)
private val defaultDataSubIdChangeEvent: MutableSharedFlow<Unit> =
MutableSharedFlow(extraBufferCapacity = 1)
override val defaultDataSubId: StateFlow<Int> =
private val defaultDataSubIdChangedEvent =
broadcastDispatcher
.broadcastFlow(
IntentFilter(TelephonyManager.ACTION_DEFAULT_DATA_SUBSCRIPTION_CHANGED)
) { intent, _ ->
intent.getIntExtra(PhoneConstants.SUBSCRIPTION_KEY, INVALID_SUBSCRIPTION_ID)
}
.distinctUntilChanged()
.broadcastFlow(IntentFilter(TelephonyManager.ACTION_DEFAULT_DATA_SUBSCRIPTION_CHANGED))
.logInputChange(logger, "ACTION_DEFAULT_DATA_SUBSCRIPTION_CHANGED")
.onEach { defaultDataSubIdChangeEvent.tryEmit(Unit) }
.stateIn(
scope,
SharingStarted.WhileSubscribed(),
SubscriptionManager.getDefaultDataSubscriptionId()
)
private val carrierConfigChangedEvent =
broadcastDispatcher
@@ -167,7 +151,7 @@ constructor(
.logInputChange(logger, "ACTION_CARRIER_CONFIG_CHANGED")
override val defaultDataSubRatConfig: StateFlow<Config> =
merge(defaultDataSubIdChangeEvent, carrierConfigChangedEvent)
merge(defaultDataSubIdChangedEvent, carrierConfigChangedEvent)
.mapLatest { Config.readConfig(context) }
.distinctUntilChanged()
.logInputChange(logger, "defaultDataSubRatConfig")
@@ -272,7 +256,6 @@ constructor(
subId,
defaultNetworkName,
networkNameSeparator,
defaultDataSubId,
globalMobileDataSettingChangedEvent,
)
}

View File

@@ -23,12 +23,11 @@ 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.NetworkNameModel
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.util.CarrierConfigTracker
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.SharingStarted
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.combine
@@ -171,11 +170,12 @@ class MobileIconInteractorImpl(
}
.stateIn(scope, SharingStarted.WhileSubscribed(), 0)
/**
* This will become variable based on [CarrierConfigManager.KEY_INFLATE_SIGNAL_STRENGTH_BOOL]
* once it's wired up inside of [CarrierConfigTracker]
*/
override val numberOfLevels: StateFlow<Int> = MutableStateFlow(4)
override val numberOfLevels: StateFlow<Int> =
connectionRepository.numberOfLevels.stateIn(
scope,
SharingStarted.WhileSubscribed(),
connectionRepository.numberOfLevels.value,
)
override val isDataConnected: StateFlow<Boolean> =
connectionInfo

View File

@@ -23,6 +23,33 @@ import com.android.systemui.log.table.Diffable
/** Provides information about the current wifi network. */
sealed class WifiNetworkModel : Diffable<WifiNetworkModel> {
/**
* A model representing that we couldn't fetch any wifi information.
*
* This is only used with [DisabledWifiRepository], where [WifiManager] is null.
*/
object Unavailable : WifiNetworkModel() {
override fun toString() = "WifiNetwork.Unavailable"
override fun logDiffs(prevVal: WifiNetworkModel, row: TableRowLogger) {
if (prevVal is Unavailable) {
return
}
logFull(row)
}
override fun logFull(row: TableRowLogger) {
row.logChange(COL_NETWORK_TYPE, TYPE_UNAVAILABLE)
row.logChange(COL_NETWORK_ID, NETWORK_ID_DEFAULT)
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)
}
}
/** A model representing that we have no active wifi network. */
object Inactive : WifiNetworkModel() {
override fun toString() = "WifiNetwork.Inactive"
@@ -87,13 +114,8 @@ sealed class WifiNetworkModel : Diffable<WifiNetworkModel> {
/**
* The wifi signal level, guaranteed to be 0 <= level <= 4.
*
* Null if we couldn't fetch the level for some reason.
*
* TODO(b/238425913): The level will only be null if we have a null WifiManager. Is there a
* way we can guarantee a non-null WifiManager?
*/
val level: Int? = null,
val level: Int,
/** See [android.net.wifi.WifiInfo.ssid]. */
val ssid: String? = null,
@@ -108,7 +130,7 @@ sealed class WifiNetworkModel : Diffable<WifiNetworkModel> {
val passpointProviderFriendlyName: String? = null,
) : WifiNetworkModel() {
init {
require(level == null || level in MIN_VALID_LEVEL..MAX_VALID_LEVEL) {
require(level in MIN_VALID_LEVEL..MAX_VALID_LEVEL) {
"0 <= wifi level <= 4 required; level was $level"
}
}
@@ -125,11 +147,7 @@ sealed class WifiNetworkModel : Diffable<WifiNetworkModel> {
row.logChange(COL_VALIDATED, isValidated)
}
if (prevVal !is Active || prevVal.level != level) {
if (level != null) {
row.logChange(COL_LEVEL, level)
} else {
row.logChange(COL_LEVEL, LEVEL_DEFAULT)
}
row.logChange(COL_LEVEL, level)
}
if (prevVal !is Active || prevVal.ssid != ssid) {
row.logChange(COL_SSID, ssid)
@@ -190,6 +208,7 @@ sealed class WifiNetworkModel : Diffable<WifiNetworkModel> {
}
const val TYPE_CARRIER_MERGED = "CarrierMerged"
const val TYPE_UNAVAILABLE = "Unavailable"
const val TYPE_INACTIVE = "Inactive"
const val TYPE_ACTIVE = "Active"

View File

@@ -34,3 +34,13 @@ interface WifiRepository {
/** Observable for the current wifi network activity. */
val wifiActivity: StateFlow<DataActivityModel>
}
/**
* A no-op interface used for Dagger bindings.
*
* [WifiRepositorySwitcher] needs to inject the "real" wifi repository, which could either be the
* full [WifiRepositoryImpl] or just [DisabledWifiRepository]. Having this interface lets us bind
* [RealWifiRepository], and then [WifiRepositorySwitcher] will automatically get the correct real
* repository.
*/
interface RealWifiRepository : WifiRepository

View File

@@ -58,7 +58,7 @@ import kotlinx.coroutines.flow.stateIn
class WifiRepositorySwitcher
@Inject
constructor(
private val realImpl: WifiRepositoryImpl,
private val realImpl: RealWifiRepository,
private val demoImpl: DemoWifiRepository,
private val demoModeController: DemoModeController,
@Application scope: CoroutineScope,

View File

@@ -89,7 +89,7 @@ constructor(
WifiNetworkModel.Active(
networkId = DEMO_NET_ID,
isValidated = validated ?: true,
level = level,
level = level ?: 0,
ssid = ssid,
// These fields below aren't supported in demo mode, since they aren't needed to satisfy

View File

@@ -0,0 +1,49 @@
/*
* 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.wifi.data.repository.prod
import com.android.systemui.dagger.SysUISingleton
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.RealWifiRepository
import javax.inject.Inject
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.asStateFlow
/**
* Implementation of wifi repository used when wifi is permanently disabled on the device.
*
* This repo should only exist when [WifiManager] is null, which means that we can never fetch any
* wifi information.
*/
@SysUISingleton
class DisabledWifiRepository @Inject constructor() : RealWifiRepository {
override val isWifiEnabled: StateFlow<Boolean> = MutableStateFlow(false).asStateFlow()
override val isWifiDefault: StateFlow<Boolean> = MutableStateFlow(false).asStateFlow()
override val wifiNetwork: StateFlow<WifiNetworkModel> = MutableStateFlow(NETWORK).asStateFlow()
override val wifiActivity: StateFlow<DataActivityModel> =
MutableStateFlow(ACTIVITY).asStateFlow()
companion object {
private val NETWORK = WifiNetworkModel.Unavailable
private val ACTIVITY = DataActivityModel(hasActivityIn = false, hasActivityOut = false)
}
}

View File

@@ -29,7 +29,6 @@ import android.net.NetworkRequest
import android.net.wifi.WifiInfo
import android.net.wifi.WifiManager
import android.net.wifi.WifiManager.TrafficStateCallback
import android.util.Log
import com.android.settingslib.Utils
import com.android.systemui.broadcast.BroadcastDispatcher
import com.android.systemui.common.coroutine.ConflatedCallbackFlow.conflatedCallbackFlow
@@ -40,11 +39,11 @@ import com.android.systemui.log.table.TableLogBuffer
import com.android.systemui.log.table.logDiffsForTable
import com.android.systemui.statusbar.pipeline.dagger.WifiTableLog
import com.android.systemui.statusbar.pipeline.shared.ConnectivityPipelineLogger
import com.android.systemui.statusbar.pipeline.shared.ConnectivityPipelineLogger.Companion.SB_LOGGING_TAG
import com.android.systemui.statusbar.pipeline.shared.ConnectivityPipelineLogger.Companion.logInputChange
import com.android.systemui.statusbar.pipeline.shared.data.model.DataActivityModel
import com.android.systemui.statusbar.pipeline.shared.data.model.toWifiDataActivityModel
import com.android.systemui.statusbar.pipeline.wifi.data.model.WifiNetworkModel
import com.android.systemui.statusbar.pipeline.wifi.data.repository.RealWifiRepository
import com.android.systemui.statusbar.pipeline.wifi.data.repository.WifiRepository
import java.util.concurrent.Executor
import javax.inject.Inject
@@ -53,12 +52,9 @@ import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.channels.awaitClose
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.MutableSharedFlow
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.SharingStarted
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.asStateFlow
import kotlinx.coroutines.flow.distinctUntilChanged
import kotlinx.coroutines.flow.flowOf
import kotlinx.coroutines.flow.mapLatest
import kotlinx.coroutines.flow.merge
import kotlinx.coroutines.flow.stateIn
@@ -68,178 +64,177 @@ import kotlinx.coroutines.flow.stateIn
@OptIn(ExperimentalCoroutinesApi::class)
@SysUISingleton
@SuppressLint("MissingPermission")
class WifiRepositoryImpl @Inject constructor(
class WifiRepositoryImpl
@Inject
constructor(
broadcastDispatcher: BroadcastDispatcher,
connectivityManager: ConnectivityManager,
logger: ConnectivityPipelineLogger,
@WifiTableLog wifiTableLogBuffer: TableLogBuffer,
@Main mainExecutor: Executor,
@Application scope: CoroutineScope,
wifiManager: WifiManager?,
) : WifiRepository {
wifiManager: WifiManager,
) : RealWifiRepository {
private val wifiStateChangeEvents: Flow<Unit> = broadcastDispatcher.broadcastFlow(
IntentFilter(WifiManager.WIFI_STATE_CHANGED_ACTION)
)
.logInputChange(logger, "WIFI_STATE_CHANGED_ACTION intent")
private val wifiStateChangeEvents: Flow<Unit> =
broadcastDispatcher
.broadcastFlow(IntentFilter(WifiManager.WIFI_STATE_CHANGED_ACTION))
.logInputChange(logger, "WIFI_STATE_CHANGED_ACTION intent")
private val wifiNetworkChangeEvents: MutableSharedFlow<Unit> =
MutableSharedFlow(extraBufferCapacity = 1)
// Because [WifiManager] doesn't expose a wifi enabled change listener, we do it
// internally by fetching [WifiManager.isWifiEnabled] whenever we think the state may
// have changed.
override val isWifiEnabled: StateFlow<Boolean> =
if (wifiManager == null) {
MutableStateFlow(false).asStateFlow()
} else {
// Because [WifiManager] doesn't expose a wifi enabled change listener, we do it
// internally by fetching [WifiManager.isWifiEnabled] whenever we think the state may
// have changed.
merge(wifiNetworkChangeEvents, wifiStateChangeEvents)
.mapLatest { wifiManager.isWifiEnabled }
.distinctUntilChanged()
.logDiffsForTable(
wifiTableLogBuffer,
columnPrefix = "",
columnName = "isWifiEnabled",
initialValue = wifiManager.isWifiEnabled,
)
.stateIn(
scope = scope,
started = SharingStarted.WhileSubscribed(),
initialValue = wifiManager.isWifiEnabled
)
}
merge(wifiNetworkChangeEvents, wifiStateChangeEvents)
.mapLatest { wifiManager.isWifiEnabled }
.distinctUntilChanged()
.logDiffsForTable(
wifiTableLogBuffer,
columnPrefix = "",
columnName = "isWifiEnabled",
initialValue = wifiManager.isWifiEnabled,
)
.stateIn(
scope = scope,
started = SharingStarted.WhileSubscribed(),
initialValue = wifiManager.isWifiEnabled,
)
override val isWifiDefault: StateFlow<Boolean> = conflatedCallbackFlow {
// Note: This callback doesn't do any logging because we already log every network change
// in the [wifiNetwork] callback.
val callback = object : ConnectivityManager.NetworkCallback(FLAG_INCLUDE_LOCATION_INFO) {
override fun onCapabilitiesChanged(
network: Network,
networkCapabilities: NetworkCapabilities
) {
// This method will always be called immediately after the network becomes the
// default, in addition to any time the capabilities change while the network is
// the default.
// If this network contains valid wifi info, then wifi is the default network.
val wifiInfo = networkCapabilitiesToWifiInfo(networkCapabilities)
trySend(wifiInfo != null)
override val isWifiDefault: StateFlow<Boolean> =
conflatedCallbackFlow {
// Note: This callback doesn't do any logging because we already log every network
// change in the [wifiNetwork] callback.
val callback =
object : ConnectivityManager.NetworkCallback(FLAG_INCLUDE_LOCATION_INFO) {
override fun onCapabilitiesChanged(
network: Network,
networkCapabilities: NetworkCapabilities
) {
// This method will always be called immediately after the network
// becomes the default, in addition to any time the capabilities change
// while the network is the default.
// If this network contains valid wifi info, then wifi is the default
// network.
val wifiInfo = networkCapabilitiesToWifiInfo(networkCapabilities)
trySend(wifiInfo != null)
}
override fun onLost(network: Network) {
// The system no longer has a default network, so wifi is definitely not
// default.
trySend(false)
}
}
connectivityManager.registerDefaultNetworkCallback(callback)
awaitClose { connectivityManager.unregisterNetworkCallback(callback) }
}
.distinctUntilChanged()
.logDiffsForTable(
wifiTableLogBuffer,
columnPrefix = "",
columnName = "isWifiDefault",
initialValue = false,
)
.stateIn(scope, started = SharingStarted.WhileSubscribed(), initialValue = false)
override fun onLost(network: Network) {
// The system no longer has a default network, so wifi is definitely not default.
trySend(false)
override val wifiNetwork: StateFlow<WifiNetworkModel> =
conflatedCallbackFlow {
var currentWifi: WifiNetworkModel = WIFI_NETWORK_DEFAULT
val callback =
object : ConnectivityManager.NetworkCallback(FLAG_INCLUDE_LOCATION_INFO) {
override fun onCapabilitiesChanged(
network: Network,
networkCapabilities: NetworkCapabilities
) {
logger.logOnCapabilitiesChanged(network, networkCapabilities)
wifiNetworkChangeEvents.tryEmit(Unit)
val wifiInfo = networkCapabilitiesToWifiInfo(networkCapabilities)
if (wifiInfo?.isPrimary == true) {
val wifiNetworkModel =
createWifiNetworkModel(
wifiInfo,
network,
networkCapabilities,
wifiManager,
)
logger.logTransformation(
WIFI_NETWORK_CALLBACK_NAME,
oldValue = currentWifi,
newValue = wifiNetworkModel,
)
currentWifi = wifiNetworkModel
trySend(wifiNetworkModel)
}
}
override fun onLost(network: Network) {
logger.logOnLost(network)
wifiNetworkChangeEvents.tryEmit(Unit)
val wifi = currentWifi
if (
wifi is WifiNetworkModel.Active &&
wifi.networkId == network.getNetId()
) {
val newNetworkModel = WifiNetworkModel.Inactive
logger.logTransformation(
WIFI_NETWORK_CALLBACK_NAME,
oldValue = wifi,
newValue = newNetworkModel,
)
currentWifi = newNetworkModel
trySend(newNetworkModel)
}
}
}
connectivityManager.registerNetworkCallback(WIFI_NETWORK_CALLBACK_REQUEST, callback)
awaitClose { connectivityManager.unregisterNetworkCallback(callback) }
}
}
connectivityManager.registerDefaultNetworkCallback(callback)
awaitClose { connectivityManager.unregisterNetworkCallback(callback) }
}
.distinctUntilChanged()
.logDiffsForTable(
wifiTableLogBuffer,
columnPrefix = "",
columnName = "isWifiDefault",
initialValue = false,
)
.stateIn(
scope,
started = SharingStarted.WhileSubscribed(),
initialValue = false
)
override val wifiNetwork: StateFlow<WifiNetworkModel> = conflatedCallbackFlow {
var currentWifi: WifiNetworkModel = WIFI_NETWORK_DEFAULT
val callback = object : ConnectivityManager.NetworkCallback(FLAG_INCLUDE_LOCATION_INFO) {
override fun onCapabilitiesChanged(
network: Network,
networkCapabilities: NetworkCapabilities
) {
logger.logOnCapabilitiesChanged(network, networkCapabilities)
wifiNetworkChangeEvents.tryEmit(Unit)
val wifiInfo = networkCapabilitiesToWifiInfo(networkCapabilities)
if (wifiInfo?.isPrimary == true) {
val wifiNetworkModel = createWifiNetworkModel(
wifiInfo,
network,
networkCapabilities,
wifiManager,
)
logger.logTransformation(
WIFI_NETWORK_CALLBACK_NAME,
oldValue = currentWifi,
newValue = wifiNetworkModel
)
currentWifi = wifiNetworkModel
trySend(wifiNetworkModel)
}
}
override fun onLost(network: Network) {
logger.logOnLost(network)
wifiNetworkChangeEvents.tryEmit(Unit)
val wifi = currentWifi
if (wifi is WifiNetworkModel.Active && wifi.networkId == network.getNetId()) {
val newNetworkModel = WifiNetworkModel.Inactive
logger.logTransformation(
WIFI_NETWORK_CALLBACK_NAME,
oldValue = wifi,
newValue = newNetworkModel
)
currentWifi = newNetworkModel
trySend(newNetworkModel)
}
}
}
connectivityManager.registerNetworkCallback(WIFI_NETWORK_CALLBACK_REQUEST, callback)
awaitClose { connectivityManager.unregisterNetworkCallback(callback) }
}
.distinctUntilChanged()
.logDiffsForTable(
wifiTableLogBuffer,
columnPrefix = "wifiNetwork",
initialValue = WIFI_NETWORK_DEFAULT,
)
// There will be multiple wifi icons in different places that will frequently
// subscribe/unsubscribe to flows as the views attach/detach. Using [stateIn] ensures that
// new subscribes will get the latest value immediately upon subscription. Otherwise, the
// views could show stale data. See b/244173280.
.stateIn(
scope,
started = SharingStarted.WhileSubscribed(),
initialValue = WIFI_NETWORK_DEFAULT
)
.distinctUntilChanged()
.logDiffsForTable(
wifiTableLogBuffer,
columnPrefix = "wifiNetwork",
initialValue = WIFI_NETWORK_DEFAULT,
)
// There will be multiple wifi icons in different places that will frequently
// subscribe/unsubscribe to flows as the views attach/detach. Using [stateIn] ensures
// that new subscribes will get the latest value immediately upon subscription.
// Otherwise, the views could show stale data. See b/244173280.
.stateIn(
scope,
started = SharingStarted.WhileSubscribed(),
initialValue = WIFI_NETWORK_DEFAULT,
)
override val wifiActivity: StateFlow<DataActivityModel> =
if (wifiManager == null) {
Log.w(SB_LOGGING_TAG, "Null WifiManager; skipping activity callback")
flowOf(ACTIVITY_DEFAULT)
} else {
conflatedCallbackFlow {
val callback = TrafficStateCallback { state ->
logger.logInputChange("onTrafficStateChange", prettyPrintActivity(state))
trySend(state.toWifiDataActivityModel())
}
wifiManager.registerTrafficStateCallback(mainExecutor, callback)
awaitClose { wifiManager.unregisterTrafficStateCallback(callback) }
conflatedCallbackFlow {
val callback = TrafficStateCallback { state ->
logger.logInputChange("onTrafficStateChange", prettyPrintActivity(state))
trySend(state.toWifiDataActivityModel())
}
wifiManager.registerTrafficStateCallback(mainExecutor, callback)
awaitClose { wifiManager.unregisterTrafficStateCallback(callback) }
}
.logDiffsForTable(
wifiTableLogBuffer,
columnPrefix = ACTIVITY_PREFIX,
initialValue = ACTIVITY_DEFAULT,
)
.stateIn(
scope,
started = SharingStarted.WhileSubscribed(),
initialValue = ACTIVITY_DEFAULT
)
.logDiffsForTable(
wifiTableLogBuffer,
columnPrefix = ACTIVITY_PREFIX,
initialValue = ACTIVITY_DEFAULT,
)
.stateIn(
scope,
started = SharingStarted.WhileSubscribed(),
initialValue = ACTIVITY_DEFAULT,
)
companion object {
private const val ACTIVITY_PREFIX = "wifiActivity"
@@ -271,19 +266,19 @@ class WifiRepositoryImpl @Inject constructor(
wifiInfo: WifiInfo,
network: Network,
networkCapabilities: NetworkCapabilities,
wifiManager: WifiManager?,
wifiManager: WifiManager,
): WifiNetworkModel {
return if (wifiInfo.isCarrierMerged) {
WifiNetworkModel.CarrierMerged
} else {
WifiNetworkModel.Active(
network.getNetId(),
isValidated = networkCapabilities.hasCapability(NET_CAPABILITY_VALIDATED),
level = wifiManager?.calculateSignalLevel(wifiInfo.rssi),
wifiInfo.ssid,
wifiInfo.isPasspointAp,
wifiInfo.isOsuAp,
wifiInfo.passpointProviderFriendlyName
network.getNetId(),
isValidated = networkCapabilities.hasCapability(NET_CAPABILITY_VALIDATED),
level = wifiManager.calculateSignalLevel(wifiInfo.rssi),
wifiInfo.ssid,
wifiInfo.isPasspointAp,
wifiInfo.isOsuAp,
wifiInfo.passpointProviderFriendlyName
)
}
}
@@ -308,4 +303,28 @@ class WifiRepositoryImpl @Inject constructor(
private const val WIFI_NETWORK_CALLBACK_NAME = "wifiNetworkModel"
}
@SysUISingleton
class Factory
@Inject
constructor(
private val broadcastDispatcher: BroadcastDispatcher,
private val connectivityManager: ConnectivityManager,
private val logger: ConnectivityPipelineLogger,
@WifiTableLog private val wifiTableLogBuffer: TableLogBuffer,
@Main private val mainExecutor: Executor,
@Application private val scope: CoroutineScope,
) {
fun create(wifiManager: WifiManager): WifiRepositoryImpl {
return WifiRepositoryImpl(
broadcastDispatcher,
connectivityManager,
logger,
wifiTableLogBuffer,
mainExecutor,
scope,
wifiManager,
)
}
}
}

View File

@@ -65,6 +65,7 @@ class WifiInteractorImpl @Inject constructor(
override val ssid: Flow<String?> = wifiRepository.wifiNetwork.map { info ->
when (info) {
is WifiNetworkModel.Unavailable -> null
is WifiNetworkModel.Inactive -> null
is WifiNetworkModel.CarrierMerged -> null
is WifiNetworkModel.Active -> when {

View File

@@ -82,6 +82,7 @@ constructor(
/** Returns the icon to use based on the given network. */
private fun WifiNetworkModel.icon(): WifiIcon {
return when (this) {
is WifiNetworkModel.Unavailable -> WifiIcon.Hidden
is WifiNetworkModel.CarrierMerged -> WifiIcon.Hidden
is WifiNetworkModel.Inactive -> WifiIcon.Visible(
res = WIFI_NO_NETWORK,
@@ -89,27 +90,23 @@ constructor(
"${context.getString(WIFI_NO_CONNECTION)},${context.getString(NO_INTERNET)}"
)
)
is WifiNetworkModel.Active ->
when (this.level) {
null -> WifiIcon.Hidden
else -> {
val levelDesc = context.getString(WIFI_CONNECTION_STRENGTH[this.level])
when {
this.isValidated ->
WifiIcon.Visible(
WIFI_FULL_ICONS[this.level],
ContentDescription.Loaded(levelDesc)
)
else ->
WifiIcon.Visible(
WIFI_NO_INTERNET_ICONS[this.level],
ContentDescription.Loaded(
"$levelDesc,${context.getString(NO_INTERNET)}"
)
)
}
}
is WifiNetworkModel.Active -> {
val levelDesc = context.getString(WIFI_CONNECTION_STRENGTH[this.level])
when {
this.isValidated ->
WifiIcon.Visible(
WIFI_FULL_ICONS[this.level],
ContentDescription.Loaded(levelDesc),
)
else ->
WifiIcon.Visible(
WIFI_NO_INTERNET_ICONS[this.level],
ContentDescription.Loaded(
"$levelDesc,${context.getString(NO_INTERNET)}"
),
)
}
}
}
}

View File

@@ -19,6 +19,7 @@ package com.android.systemui.statusbar.pipeline.mobile.data.repository
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.NetworkNameModel
import com.android.systemui.statusbar.pipeline.mobile.data.repository.MobileConnectionRepository.Companion.DEFAULT_NUM_LEVELS
import kotlinx.coroutines.flow.MutableStateFlow
// TODO(b/261632894): remove this in favor of the real impl or DemoMobileConnectionRepository
@@ -29,12 +30,11 @@ class FakeMobileConnectionRepository(
private val _connectionInfo = MutableStateFlow(MobileConnectionModel())
override val connectionInfo = _connectionInfo
override val numberOfLevels = MutableStateFlow(DEFAULT_NUM_LEVELS)
private val _dataEnabled = MutableStateFlow(true)
override val dataEnabled = _dataEnabled
private val _isDefaultDataSubscription = MutableStateFlow(true)
override val isDefaultDataSubscription = _isDefaultDataSubscription
override val cdmaRoaming = MutableStateFlow(false)
override val networkName =
@@ -47,8 +47,4 @@ class FakeMobileConnectionRepository(
fun setDataEnabled(enabled: Boolean) {
_dataEnabled.value = enabled
}
fun setIsDefaultDataSubscription(isDefault: Boolean) {
_isDefaultDataSubscription.value = isDefault
}
}

View File

@@ -57,9 +57,6 @@ class FakeMobileConnectionsRepository(
private val _activeMobileDataSubscriptionId = MutableStateFlow(INVALID_SUBSCRIPTION_ID)
override val activeMobileDataSubscriptionId = _activeMobileDataSubscriptionId
private val _defaultDataSubId = MutableStateFlow(INVALID_SUBSCRIPTION_ID)
override val defaultDataSubId = _defaultDataSubId
private val _mobileConnectivity = MutableStateFlow(MobileConnectivityModel())
override val defaultMobileNetworkConnectivity = _mobileConnectivity
@@ -84,10 +81,6 @@ class FakeMobileConnectionsRepository(
_subscriptions.value = subs
}
fun setDefaultDataSubId(id: Int) {
_defaultDataSubId.value = id
}
fun setMobileConnectivity(model: MobileConnectivityModel) {
_mobileConnectivity.value = model
}

View File

@@ -61,6 +61,7 @@ import com.android.systemui.statusbar.pipeline.mobile.data.model.ResolvedNetwork
import com.android.systemui.statusbar.pipeline.mobile.data.model.ResolvedNetworkType.UnknownNetworkType
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.MobileConnectionRepository.Companion.DEFAULT_NUM_LEVELS
import com.android.systemui.statusbar.pipeline.mobile.util.FakeMobileMappingsProxy
import com.android.systemui.statusbar.pipeline.shared.ConnectivityPipelineLogger
import com.android.systemui.statusbar.pipeline.shared.data.model.DataActivityModel
@@ -117,7 +118,6 @@ class MobileConnectionRepositoryTest : SysuiTestCase() {
telephonyManager,
globalSettings,
fakeBroadcastDispatcher,
connectionsRepo.defaultDataSubId,
connectionsRepo.globalMobileDataSettingChangedEvent,
mobileMappings,
IMMEDIATE,
@@ -319,7 +319,7 @@ class MobileConnectionRepositoryTest : SysuiTestCase() {
val callback = getTelephonyCallbackForType<TelephonyCallback.DisplayInfoListener>()
val type = NETWORK_TYPE_LTE
val expected = DefaultNetworkType(type, mobileMappings.toIconKey(type))
val expected = DefaultNetworkType(mobileMappings.toIconKey(type))
val ti = mock<TelephonyDisplayInfo>().also { whenever(it.networkType).thenReturn(type) }
callback.onDisplayInfoChanged(ti)
@@ -336,7 +336,7 @@ class MobileConnectionRepositoryTest : SysuiTestCase() {
val callback = getTelephonyCallbackForType<TelephonyCallback.DisplayInfoListener>()
val type = OVERRIDE_NETWORK_TYPE_LTE_CA
val expected = OverrideNetworkType(type, mobileMappings.toIconKeyOverride(type))
val expected = OverrideNetworkType(mobileMappings.toIconKeyOverride(type))
val ti =
mock<TelephonyDisplayInfo>().also {
whenever(it.networkType).thenReturn(type)
@@ -379,33 +379,6 @@ class MobileConnectionRepositoryTest : SysuiTestCase() {
job.cancel()
}
@Test
fun isDefaultDataSubscription_isDefault() =
runBlocking(IMMEDIATE) {
connectionsRepo.setDefaultDataSubId(SUB_1_ID)
var latest: Boolean? = null
val job = underTest.isDefaultDataSubscription.onEach { latest = it }.launchIn(this)
assertThat(latest).isTrue()
job.cancel()
}
@Test
fun isDefaultDataSubscription_isNotDefault() =
runBlocking(IMMEDIATE) {
// Our subId is SUB_1_ID
connectionsRepo.setDefaultDataSubId(123)
var latest: Boolean? = null
val job = underTest.isDefaultDataSubscription.onEach { latest = it }.launchIn(this)
assertThat(latest).isFalse()
job.cancel()
}
@Test
fun isDataConnectionAllowed_subIdSettingUpdate_valueUpdated() =
runBlocking(IMMEDIATE) {
@@ -430,6 +403,17 @@ class MobileConnectionRepositoryTest : SysuiTestCase() {
job.cancel()
}
@Test
fun numberOfLevels_isDefault() =
runBlocking(IMMEDIATE) {
var latest: Int? = null
val job = underTest.numberOfLevels.onEach { latest = it }.launchIn(this)
assertThat(latest).isEqualTo(DEFAULT_NUM_LEVELS)
job.cancel()
}
@Test
fun `roaming - cdma - queries telephony manager`() =
runBlocking(IMMEDIATE) {

View File

@@ -306,35 +306,6 @@ class MobileConnectionsRepositoryTest : SysuiTestCase() {
job.cancel()
}
@Test
fun testDefaultDataSubId_updatesOnBroadcast() =
runBlocking(IMMEDIATE) {
var latest: Int? = null
val job = underTest.defaultDataSubId.onEach { latest = it }.launchIn(this)
fakeBroadcastDispatcher.registeredReceivers.forEach { receiver ->
receiver.onReceive(
context,
Intent(TelephonyManager.ACTION_DEFAULT_DATA_SUBSCRIPTION_CHANGED)
.putExtra(PhoneConstants.SUBSCRIPTION_KEY, SUB_2_ID)
)
}
assertThat(latest).isEqualTo(SUB_2_ID)
fakeBroadcastDispatcher.registeredReceivers.forEach { receiver ->
receiver.onReceive(
context,
Intent(TelephonyManager.ACTION_DEFAULT_DATA_SUBSCRIPTION_CHANGED)
.putExtra(PhoneConstants.SUBSCRIPTION_KEY, SUB_1_ID)
)
}
assertThat(latest).isEqualTo(SUB_1_ID)
job.cancel()
}
@Test
fun mobileConnectivity_default() {
assertThat(underTest.defaultMobileNetworkConnectivity.value)

View File

@@ -21,6 +21,7 @@ import com.android.settingslib.SignalIcon
import com.android.settingslib.mobile.TelephonyIcons
import com.android.systemui.log.table.TableLogBuffer
import com.android.systemui.statusbar.pipeline.mobile.data.model.NetworkNameModel
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 kotlinx.coroutines.flow.MutableStateFlow
@@ -65,7 +66,7 @@ class FakeMobileIconInteractor(
private val _level = MutableStateFlow(CellSignalStrength.SIGNAL_STRENGTH_NONE_OR_UNKNOWN)
override val level = _level
private val _numberOfLevels = MutableStateFlow(4)
private val _numberOfLevels = MutableStateFlow(DEFAULT_NUM_LEVELS)
override val numberOfLevels = _numberOfLevels
fun setIconGroup(group: SignalIcon.MobileIconGroup) {

View File

@@ -17,7 +17,6 @@
package com.android.systemui.statusbar.pipeline.mobile.domain.interactor
import android.telephony.CellSignalStrength
import android.telephony.SubscriptionInfo
import android.telephony.TelephonyManager.NETWORK_TYPE_UNKNOWN
import androidx.test.filters.SmallTest
import com.android.settingslib.SignalIcon.MobileIconGroup
@@ -34,7 +33,6 @@ import com.android.systemui.statusbar.pipeline.mobile.domain.interactor.FakeMobi
import com.android.systemui.statusbar.pipeline.mobile.domain.interactor.FakeMobileIconsInteractor.Companion.THREE_G
import com.android.systemui.statusbar.pipeline.mobile.util.FakeMobileMappingsProxy
import com.android.systemui.util.mockito.mock
import com.android.systemui.util.mockito.whenever
import com.google.common.truth.Truth.assertThat
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
@@ -177,13 +175,27 @@ class MobileIconInteractorTest : SysuiTestCase() {
job.cancel()
}
@Test
fun numberOfLevels_comesFromRepo() =
runBlocking(IMMEDIATE) {
var latest: Int? = null
val job = underTest.numberOfLevels.onEach { latest = it }.launchIn(this)
connectionRepository.numberOfLevels.value = 5
assertThat(latest).isEqualTo(5)
connectionRepository.numberOfLevels.value = 4
assertThat(latest).isEqualTo(4)
job.cancel()
}
@Test
fun iconGroup_three_g() =
runBlocking(IMMEDIATE) {
connectionRepository.setConnectionInfo(
MobileConnectionModel(
resolvedNetworkType =
DefaultNetworkType(THREE_G, mobileMappingsProxy.toIconKey(THREE_G))
resolvedNetworkType = DefaultNetworkType(mobileMappingsProxy.toIconKey(THREE_G))
),
)
@@ -200,8 +212,7 @@ class MobileIconInteractorTest : SysuiTestCase() {
runBlocking(IMMEDIATE) {
connectionRepository.setConnectionInfo(
MobileConnectionModel(
resolvedNetworkType =
DefaultNetworkType(THREE_G, mobileMappingsProxy.toIconKey(THREE_G))
resolvedNetworkType = DefaultNetworkType(mobileMappingsProxy.toIconKey(THREE_G))
),
)
@@ -212,7 +223,6 @@ class MobileIconInteractorTest : SysuiTestCase() {
MobileConnectionModel(
resolvedNetworkType =
DefaultNetworkType(
FOUR_G,
mobileMappingsProxy.toIconKey(FOUR_G),
),
),
@@ -230,10 +240,7 @@ class MobileIconInteractorTest : SysuiTestCase() {
connectionRepository.setConnectionInfo(
MobileConnectionModel(
resolvedNetworkType =
OverrideNetworkType(
FIVE_G_OVERRIDE,
mobileMappingsProxy.toIconKeyOverride(FIVE_G_OVERRIDE)
)
OverrideNetworkType(mobileMappingsProxy.toIconKeyOverride(FIVE_G_OVERRIDE))
),
)
@@ -251,10 +258,7 @@ class MobileIconInteractorTest : SysuiTestCase() {
connectionRepository.setConnectionInfo(
MobileConnectionModel(
resolvedNetworkType =
DefaultNetworkType(
NETWORK_TYPE_UNKNOWN,
mobileMappingsProxy.toIconKey(NETWORK_TYPE_UNKNOWN)
),
DefaultNetworkType(mobileMappingsProxy.toIconKey(NETWORK_TYPE_UNKNOWN)),
),
)
@@ -509,8 +513,6 @@ class MobileIconInteractorTest : SysuiTestCase() {
private const val CDMA_LEVEL = 2
private const val SUB_1_ID = 1
private val SUB_1 =
mock<SubscriptionInfo>().also { whenever(it.subscriptionId).thenReturn(SUB_1_ID) }
private val DEFAULT_NAME = NetworkNameModel.Default("test default name")
private val DERIVED_NAME = NetworkNameModel.Derived("test derived name")

View File

@@ -34,12 +34,6 @@ class WifiNetworkModelTest : SysuiTestCase() {
}
}
@Test
fun active_levelNull_noException() {
WifiNetworkModel.Active(NETWORK_ID, level = null)
// No assert, just need no crash
}
@Test(expected = IllegalArgumentException::class)
fun active_levelNegative_exceptionThrown() {
WifiNetworkModel.Active(NETWORK_ID, level = MIN_VALID_LEVEL - 1)

View File

@@ -0,0 +1,57 @@
/*
* 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.wifi.data.repository.prod
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.statusbar.pipeline.shared.data.model.DataActivityModel
import com.android.systemui.statusbar.pipeline.wifi.data.model.WifiNetworkModel
import com.google.common.truth.Truth.assertThat
import org.junit.Before
import org.junit.Test
@SmallTest
class DisabledWifiRepositoryTest : SysuiTestCase() {
private lateinit var underTest: DisabledWifiRepository
@Before
fun setUp() {
underTest = DisabledWifiRepository()
}
@Test
fun enabled_alwaysFalse() {
assertThat(underTest.isWifiEnabled.value).isEqualTo(false)
}
@Test
fun default_alwaysFalse() {
assertThat(underTest.isWifiDefault.value).isEqualTo(false)
}
@Test
fun network_alwaysUnavailable() {
assertThat(underTest.wifiNetwork.value).isEqualTo(WifiNetworkModel.Unavailable)
}
@Test
fun activity_alwaysFalse() {
assertThat(underTest.wifiActivity.value)
.isEqualTo(DataActivityModel(hasActivityIn = false, hasActivityOut = false))
}
}

View File

@@ -33,7 +33,6 @@ import com.android.systemui.log.table.TableLogBuffer
import com.android.systemui.statusbar.pipeline.shared.ConnectivityPipelineLogger
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.prod.WifiRepositoryImpl.Companion.ACTIVITY_DEFAULT
import com.android.systemui.statusbar.pipeline.wifi.data.repository.prod.WifiRepositoryImpl.Companion.WIFI_NETWORK_DEFAULT
import com.android.systemui.util.concurrency.FakeExecutor
import com.android.systemui.util.mockito.any
@@ -97,13 +96,6 @@ class WifiRepositoryImplTest : SysuiTestCase() {
scope.cancel()
}
@Test
fun isWifiEnabled_nullWifiManager_getsFalse() = runBlocking(IMMEDIATE) {
underTest = createRepo(wifiManagerToUse = null)
assertThat(underTest.isWifiEnabled.value).isFalse()
}
@Test
fun isWifiEnabled_initiallyGetsWifiManagerValue() = runBlocking(IMMEDIATE) {
whenever(wifiManager.isWifiEnabled).thenReturn(true)
@@ -720,21 +712,6 @@ class WifiRepositoryImplTest : SysuiTestCase() {
job2.cancel()
}
@Test
fun wifiActivity_nullWifiManager_receivesDefault() = runBlocking(IMMEDIATE) {
underTest = createRepo(wifiManagerToUse = null)
var latest: DataActivityModel? = null
val job = underTest
.wifiActivity
.onEach { latest = it }
.launchIn(this)
assertThat(latest).isEqualTo(ACTIVITY_DEFAULT)
job.cancel()
}
@Test
fun wifiActivity_callbackGivesNone_activityFlowHasNone() = runBlocking(IMMEDIATE) {
var latest: DataActivityModel? = null
@@ -801,7 +778,7 @@ class WifiRepositoryImplTest : SysuiTestCase() {
job.cancel()
}
private fun createRepo(wifiManagerToUse: WifiManager? = wifiManager): WifiRepositoryImpl {
private fun createRepo(): WifiRepositoryImpl {
return WifiRepositoryImpl(
broadcastDispatcher,
connectivityManager,
@@ -809,7 +786,7 @@ class WifiRepositoryImplTest : SysuiTestCase() {
tableLogger,
executor,
scope,
wifiManagerToUse,
wifiManager,
)
}

View File

@@ -51,6 +51,22 @@ class WifiInteractorImplTest : SysuiTestCase() {
underTest = WifiInteractorImpl(connectivityRepository, wifiRepository)
}
@Test
fun ssid_unavailableNetwork_outputsNull() =
runBlocking(IMMEDIATE) {
wifiRepository.setWifiNetwork(WifiNetworkModel.Unavailable)
var latest: String? = "default"
val job = underTest
.ssid
.onEach { latest = it }
.launchIn(this)
assertThat(latest).isNull()
job.cancel()
}
@Test
fun ssid_inactiveNetwork_outputsNull() = runBlocking(IMMEDIATE) {
wifiRepository.setWifiNetwork(WifiNetworkModel.Inactive)
@@ -85,6 +101,7 @@ class WifiInteractorImplTest : SysuiTestCase() {
fun ssid_isPasspointAccessPoint_outputsPasspointName() = runBlocking(IMMEDIATE) {
wifiRepository.setWifiNetwork(WifiNetworkModel.Active(
networkId = 1,
level = 1,
isPasspointAccessPoint = true,
passpointProviderFriendlyName = "friendly",
))
@@ -104,6 +121,7 @@ class WifiInteractorImplTest : SysuiTestCase() {
fun ssid_isOnlineSignUpForPasspoint_outputsPasspointName() = runBlocking(IMMEDIATE) {
wifiRepository.setWifiNetwork(WifiNetworkModel.Active(
networkId = 1,
level = 1,
isOnlineSignUpForPasspointAccessPoint = true,
passpointProviderFriendlyName = "friendly",
))
@@ -123,6 +141,7 @@ class WifiInteractorImplTest : SysuiTestCase() {
fun ssid_unknownSsid_outputsNull() = runBlocking(IMMEDIATE) {
wifiRepository.setWifiNetwork(WifiNetworkModel.Active(
networkId = 1,
level = 1,
ssid = WifiManager.UNKNOWN_SSID,
))
@@ -141,6 +160,7 @@ class WifiInteractorImplTest : SysuiTestCase() {
fun ssid_validSsid_outputsSsid() = runBlocking(IMMEDIATE) {
wifiRepository.setWifiNetwork(WifiNetworkModel.Active(
networkId = 1,
level = 1,
ssid = "MyAwesomeWifiNetwork",
))

View File

@@ -379,6 +379,12 @@ internal class WifiViewModelIconParameterizedTest(private val testCase: TestCase
expected = null,
),
// network = Unavailable => not shown
TestCase(
network = WifiNetworkModel.Unavailable,
expected = null,
),
// network = Active & validated = false => not shown
TestCase(
network = WifiNetworkModel.Active(NETWORK_ID, isValidated = false, level = 3),
@@ -397,12 +403,6 @@ internal class WifiViewModelIconParameterizedTest(private val testCase: TestCase
description = "Full internet level 4 icon",
),
),
// network has null level => not shown
TestCase(
network = WifiNetworkModel.Active(NETWORK_ID, isValidated = true, level = null),
expected = null,
),
)
}
}

View File

@@ -228,7 +228,7 @@ class WifiViewModelTest : SysuiTestCase() {
whenever(connectivityConstants.shouldShowActivityConfig).thenReturn(true)
createAndSetViewModel()
wifiRepository.setWifiNetwork(WifiNetworkModel.Active(NETWORK_ID, ssid = null))
wifiRepository.setWifiNetwork(WifiNetworkModel.Active(NETWORK_ID, ssid = null, level = 1))
var activityIn: Boolean? = null
val activityInJob = underTest
@@ -553,7 +553,8 @@ class WifiViewModelTest : SysuiTestCase() {
companion object {
private const val NETWORK_ID = 2
private val ACTIVE_VALID_WIFI_NETWORK = WifiNetworkModel.Active(NETWORK_ID, ssid = "AB")
private val ACTIVE_VALID_WIFI_NETWORK =
WifiNetworkModel.Active(NETWORK_ID, ssid = "AB", level = 1)
}
}