Merge changes Ie0da0143,I9541a914,I21f3259e,I40a6d5aa,I9c6b9ba3 into tm-qpr-dev
* changes: [Sb refactor] Consume isInService in mobile view model [Sb refactor] Add Utils.isInService to mobile pipeline [Sb refactor] Pull the WifiRepository interface out of the impl file (2/2) [Sb refactor] Pull the WifiRepository interface out of the impl file (1/2) [Sb refactor] Move WifiRepositoryImpl to prod/ package
This commit is contained in:
committed by
Android (Google) Code Review
commit
933c12efa1
@@ -460,7 +460,7 @@
|
||||
-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/WifiRepository.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
|
||||
@@ -752,7 +752,7 @@
|
||||
-packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/panelstate/ShadeExpansionStateManagerTest.kt
|
||||
-packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/userswitcher/StatusBarUserSwitcherControllerOldImplTest.kt
|
||||
-packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/shared/ConnectivityPipelineLoggerTest.kt
|
||||
-packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/WifiRepositoryImplTest.kt
|
||||
-packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/prod/WifiRepositoryImplTest.kt
|
||||
-packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/wifi/domain/interactor/WifiInteractorImplTest.kt
|
||||
-packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/wifi/ui/view/ModernStatusBarWifiViewTest.kt
|
||||
-packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/wifi/ui/viewmodel/WifiViewModelTest.kt
|
||||
|
||||
@@ -51,6 +51,16 @@ data class MobileConnectionModel(
|
||||
*/
|
||||
val operatorAlphaShort: String? = null,
|
||||
|
||||
/**
|
||||
* TODO (b/263167683): Clarify this field
|
||||
*
|
||||
* This check comes from [com.android.settingslib.Utils.isInService]. It is intended to be a
|
||||
* mapping from a ServiceState to a notion of connectivity. Notably, it will consider a
|
||||
* connection to be in-service if either the voice registration state is IN_SERVICE or the data
|
||||
* registration state is IN_SERVICE and NOT IWLAN.
|
||||
*/
|
||||
val isInService: Boolean = false,
|
||||
|
||||
/** Fields below from [SignalStrengthsListener.onSignalStrengthsChanged] */
|
||||
val isGsm: Boolean = false,
|
||||
@IntRange(from = 0, to = 4)
|
||||
@@ -99,6 +109,10 @@ data class MobileConnectionModel(
|
||||
row.logChange(COL_OPERATOR, operatorAlphaShort)
|
||||
}
|
||||
|
||||
if (prevVal.isInService != isInService) {
|
||||
row.logChange(COL_IS_IN_SERVICE, isInService)
|
||||
}
|
||||
|
||||
if (prevVal.isGsm != isGsm) {
|
||||
row.logChange(COL_IS_GSM, isGsm)
|
||||
}
|
||||
@@ -129,6 +143,7 @@ data class MobileConnectionModel(
|
||||
row.logChange(COL_EMERGENCY, isEmergencyOnly)
|
||||
row.logChange(COL_ROAMING, isRoaming)
|
||||
row.logChange(COL_OPERATOR, operatorAlphaShort)
|
||||
row.logChange(COL_IS_IN_SERVICE, isInService)
|
||||
row.logChange(COL_IS_GSM, isGsm)
|
||||
row.logChange(COL_CDMA_LEVEL, cdmaLevel)
|
||||
row.logChange(COL_PRIMARY_LEVEL, primaryLevel)
|
||||
@@ -141,6 +156,7 @@ data class MobileConnectionModel(
|
||||
const val COL_EMERGENCY = "EmergencyOnly"
|
||||
const val COL_ROAMING = "Roaming"
|
||||
const val COL_OPERATOR = "OperatorName"
|
||||
const val COL_IS_IN_SERVICE = "IsInService"
|
||||
const val COL_IS_GSM = "IsGsm"
|
||||
const val COL_CDMA_LEVEL = "CdmaLevel"
|
||||
const val COL_PRIMARY_LEVEL = "PrimaryLevel"
|
||||
|
||||
@@ -247,6 +247,7 @@ constructor(
|
||||
return MobileConnectionModel(
|
||||
isEmergencyOnly = false, // TODO(b/261029387): not yet supported
|
||||
isRoaming = roaming,
|
||||
isInService = (level ?: 0) > 0,
|
||||
isGsm = false, // TODO(b/261029387): not yet supported
|
||||
cdmaLevel = level ?: 0,
|
||||
primaryLevel = level ?: 0,
|
||||
|
||||
@@ -32,6 +32,7 @@ import android.telephony.TelephonyManager
|
||||
import android.telephony.TelephonyManager.ERI_OFF
|
||||
import android.telephony.TelephonyManager.EXTRA_SUBSCRIPTION_ID
|
||||
import android.telephony.TelephonyManager.NETWORK_TYPE_UNKNOWN
|
||||
import com.android.settingslib.Utils
|
||||
import com.android.systemui.broadcast.BroadcastDispatcher
|
||||
import com.android.systemui.common.coroutine.ConflatedCallbackFlow.conflatedCallbackFlow
|
||||
import com.android.systemui.dagger.qualifiers.Application
|
||||
@@ -117,6 +118,7 @@ class MobileConnectionRepositoryImpl(
|
||||
isEmergencyOnly = serviceState.isEmergencyOnly,
|
||||
isRoaming = serviceState.roaming,
|
||||
operatorAlphaShort = serviceState.operatorAlphaShort,
|
||||
isInService = Utils.isInService(serviceState),
|
||||
)
|
||||
trySend(state)
|
||||
}
|
||||
|
||||
@@ -48,6 +48,9 @@ interface MobileIconInteractor {
|
||||
/** True when telephony tells us that the data state is CONNECTED */
|
||||
val isDataConnected: StateFlow<Boolean>
|
||||
|
||||
/** True if we consider this connection to be in service, i.e. can make calls */
|
||||
val isInService: StateFlow<Boolean>
|
||||
|
||||
// TODO(b/256839546): clarify naming of default vs active
|
||||
/** True if we want to consider the data connection enabled */
|
||||
val isDefaultDataEnabled: StateFlow<Boolean>
|
||||
@@ -175,4 +178,9 @@ class MobileIconInteractorImpl(
|
||||
connectionInfo
|
||||
.mapLatest { connection -> connection.dataConnectionState == Connected }
|
||||
.stateIn(scope, SharingStarted.WhileSubscribed(), false)
|
||||
|
||||
override val isInService =
|
||||
connectionRepository.connectionInfo
|
||||
.mapLatest { it.isInService }
|
||||
.stateIn(scope, SharingStarted.WhileSubscribed(), false)
|
||||
}
|
||||
|
||||
@@ -80,11 +80,17 @@ constructor(
|
||||
|
||||
override val iconId: Flow<Int> = run {
|
||||
val initial = SignalDrawable.getEmptyState(iconInteractor.numberOfLevels.value)
|
||||
combine(iconInteractor.level, iconInteractor.numberOfLevels, showExclamationMark) {
|
||||
level,
|
||||
numberOfLevels,
|
||||
showExclamationMark ->
|
||||
SignalDrawable.getState(level, numberOfLevels, showExclamationMark)
|
||||
combine(
|
||||
iconInteractor.level,
|
||||
iconInteractor.numberOfLevels,
|
||||
showExclamationMark,
|
||||
iconInteractor.isInService,
|
||||
) { level, numberOfLevels, showExclamationMark, isInService ->
|
||||
if (!isInService) {
|
||||
SignalDrawable.getEmptyState(numberOfLevels)
|
||||
} else {
|
||||
SignalDrawable.getState(level, numberOfLevels, showExclamationMark)
|
||||
}
|
||||
}
|
||||
.distinctUntilChanged()
|
||||
.logDiffsForTable(
|
||||
|
||||
@@ -16,51 +16,9 @@
|
||||
|
||||
package com.android.systemui.statusbar.pipeline.wifi.data.repository
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import android.content.IntentFilter
|
||||
import android.net.ConnectivityManager
|
||||
import android.net.Network
|
||||
import android.net.NetworkCapabilities
|
||||
import android.net.NetworkCapabilities.NET_CAPABILITY_NOT_VPN
|
||||
import android.net.NetworkCapabilities.NET_CAPABILITY_VALIDATED
|
||||
import android.net.NetworkCapabilities.TRANSPORT_CELLULAR
|
||||
import android.net.NetworkCapabilities.TRANSPORT_WIFI
|
||||
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
|
||||
import com.android.systemui.dagger.SysUISingleton
|
||||
import com.android.systemui.dagger.qualifiers.Application
|
||||
import com.android.systemui.dagger.qualifiers.Main
|
||||
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 java.util.concurrent.Executor
|
||||
import javax.inject.Inject
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
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
|
||||
|
||||
/** Provides data related to the wifi state. */
|
||||
interface WifiRepository {
|
||||
@@ -76,250 +34,3 @@ interface WifiRepository {
|
||||
/** Observable for the current wifi network activity. */
|
||||
val wifiActivity: StateFlow<DataActivityModel>
|
||||
}
|
||||
|
||||
/** Real implementation of [WifiRepository]. */
|
||||
@Suppress("EXPERIMENTAL_IS_NOT_ENABLED")
|
||||
@OptIn(ExperimentalCoroutinesApi::class)
|
||||
@SysUISingleton
|
||||
@SuppressLint("MissingPermission")
|
||||
class WifiRepositoryImpl @Inject constructor(
|
||||
broadcastDispatcher: BroadcastDispatcher,
|
||||
connectivityManager: ConnectivityManager,
|
||||
logger: ConnectivityPipelineLogger,
|
||||
@WifiTableLog wifiTableLogBuffer: TableLogBuffer,
|
||||
@Main mainExecutor: Executor,
|
||||
@Application scope: CoroutineScope,
|
||||
wifiManager: WifiManager?,
|
||||
) : WifiRepository {
|
||||
|
||||
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)
|
||||
|
||||
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
|
||||
)
|
||||
}
|
||||
|
||||
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 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
|
||||
)
|
||||
|
||||
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) }
|
||||
}
|
||||
}
|
||||
.logDiffsForTable(
|
||||
wifiTableLogBuffer,
|
||||
columnPrefix = ACTIVITY_PREFIX,
|
||||
initialValue = ACTIVITY_DEFAULT,
|
||||
)
|
||||
.stateIn(
|
||||
scope,
|
||||
started = SharingStarted.WhileSubscribed(),
|
||||
initialValue = ACTIVITY_DEFAULT
|
||||
)
|
||||
|
||||
companion object {
|
||||
private const val ACTIVITY_PREFIX = "wifiActivity"
|
||||
|
||||
val ACTIVITY_DEFAULT = DataActivityModel(hasActivityIn = false, hasActivityOut = false)
|
||||
// Start out with no known wifi network.
|
||||
// Note: [WifiStatusTracker] (the old implementation of connectivity logic) does do an
|
||||
// initial fetch to get a starting wifi network. But, it uses a deprecated API
|
||||
// [WifiManager.getConnectionInfo()], and the deprecation doc indicates to just use
|
||||
// [ConnectivityManager.NetworkCallback] results instead. So, for now we'll just rely on the
|
||||
// NetworkCallback inside [wifiNetwork] for our wifi network information.
|
||||
val WIFI_NETWORK_DEFAULT = WifiNetworkModel.Inactive
|
||||
|
||||
private fun networkCapabilitiesToWifiInfo(
|
||||
networkCapabilities: NetworkCapabilities
|
||||
): WifiInfo? {
|
||||
return when {
|
||||
networkCapabilities.hasTransport(TRANSPORT_WIFI) ->
|
||||
networkCapabilities.transportInfo as WifiInfo?
|
||||
networkCapabilities.hasTransport(TRANSPORT_CELLULAR) ->
|
||||
// Sometimes, cellular networks can act as wifi networks (known as VCN --
|
||||
// virtual carrier network). So, see if this cellular network has wifi info.
|
||||
Utils.tryGetWifiInfoForVcn(networkCapabilities)
|
||||
else -> null
|
||||
}
|
||||
}
|
||||
|
||||
private fun createWifiNetworkModel(
|
||||
wifiInfo: WifiInfo,
|
||||
network: Network,
|
||||
networkCapabilities: NetworkCapabilities,
|
||||
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
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private fun prettyPrintActivity(activity: Int): String {
|
||||
return when (activity) {
|
||||
TrafficStateCallback.DATA_ACTIVITY_NONE -> "NONE"
|
||||
TrafficStateCallback.DATA_ACTIVITY_IN -> "IN"
|
||||
TrafficStateCallback.DATA_ACTIVITY_OUT -> "OUT"
|
||||
TrafficStateCallback.DATA_ACTIVITY_INOUT -> "INOUT"
|
||||
else -> "INVALID"
|
||||
}
|
||||
}
|
||||
|
||||
private val WIFI_NETWORK_CALLBACK_REQUEST: NetworkRequest =
|
||||
NetworkRequest.Builder()
|
||||
.clearCapabilities()
|
||||
.addCapability(NET_CAPABILITY_NOT_VPN)
|
||||
.addTransportType(TRANSPORT_WIFI)
|
||||
.addTransportType(TRANSPORT_CELLULAR)
|
||||
.build()
|
||||
|
||||
private const val WIFI_NETWORK_CALLBACK_NAME = "wifiNetworkModel"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -25,6 +25,7 @@ import com.android.systemui.demomode.DemoModeController
|
||||
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.demo.DemoWifiRepository
|
||||
import com.android.systemui.statusbar.pipeline.wifi.data.repository.prod.WifiRepositoryImpl
|
||||
import javax.inject.Inject
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
||||
|
||||
@@ -0,0 +1,311 @@
|
||||
/*
|
||||
* 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 android.annotation.SuppressLint
|
||||
import android.content.IntentFilter
|
||||
import android.net.ConnectivityManager
|
||||
import android.net.Network
|
||||
import android.net.NetworkCapabilities
|
||||
import android.net.NetworkCapabilities.NET_CAPABILITY_NOT_VPN
|
||||
import android.net.NetworkCapabilities.NET_CAPABILITY_VALIDATED
|
||||
import android.net.NetworkCapabilities.TRANSPORT_CELLULAR
|
||||
import android.net.NetworkCapabilities.TRANSPORT_WIFI
|
||||
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
|
||||
import com.android.systemui.dagger.SysUISingleton
|
||||
import com.android.systemui.dagger.qualifiers.Application
|
||||
import com.android.systemui.dagger.qualifiers.Main
|
||||
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.WifiRepository
|
||||
import java.util.concurrent.Executor
|
||||
import javax.inject.Inject
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
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
|
||||
|
||||
/** Real implementation of [WifiRepository]. */
|
||||
@Suppress("EXPERIMENTAL_IS_NOT_ENABLED")
|
||||
@OptIn(ExperimentalCoroutinesApi::class)
|
||||
@SysUISingleton
|
||||
@SuppressLint("MissingPermission")
|
||||
class WifiRepositoryImpl @Inject constructor(
|
||||
broadcastDispatcher: BroadcastDispatcher,
|
||||
connectivityManager: ConnectivityManager,
|
||||
logger: ConnectivityPipelineLogger,
|
||||
@WifiTableLog wifiTableLogBuffer: TableLogBuffer,
|
||||
@Main mainExecutor: Executor,
|
||||
@Application scope: CoroutineScope,
|
||||
wifiManager: WifiManager?,
|
||||
) : WifiRepository {
|
||||
|
||||
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)
|
||||
|
||||
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
|
||||
)
|
||||
}
|
||||
|
||||
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 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
|
||||
)
|
||||
|
||||
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) }
|
||||
}
|
||||
}
|
||||
.logDiffsForTable(
|
||||
wifiTableLogBuffer,
|
||||
columnPrefix = ACTIVITY_PREFIX,
|
||||
initialValue = ACTIVITY_DEFAULT,
|
||||
)
|
||||
.stateIn(
|
||||
scope,
|
||||
started = SharingStarted.WhileSubscribed(),
|
||||
initialValue = ACTIVITY_DEFAULT
|
||||
)
|
||||
|
||||
companion object {
|
||||
private const val ACTIVITY_PREFIX = "wifiActivity"
|
||||
|
||||
val ACTIVITY_DEFAULT = DataActivityModel(hasActivityIn = false, hasActivityOut = false)
|
||||
// Start out with no known wifi network.
|
||||
// Note: [WifiStatusTracker] (the old implementation of connectivity logic) does do an
|
||||
// initial fetch to get a starting wifi network. But, it uses a deprecated API
|
||||
// [WifiManager.getConnectionInfo()], and the deprecation doc indicates to just use
|
||||
// [ConnectivityManager.NetworkCallback] results instead. So, for now we'll just rely on the
|
||||
// NetworkCallback inside [wifiNetwork] for our wifi network information.
|
||||
val WIFI_NETWORK_DEFAULT = WifiNetworkModel.Inactive
|
||||
|
||||
private fun networkCapabilitiesToWifiInfo(
|
||||
networkCapabilities: NetworkCapabilities
|
||||
): WifiInfo? {
|
||||
return when {
|
||||
networkCapabilities.hasTransport(TRANSPORT_WIFI) ->
|
||||
networkCapabilities.transportInfo as WifiInfo?
|
||||
networkCapabilities.hasTransport(TRANSPORT_CELLULAR) ->
|
||||
// Sometimes, cellular networks can act as wifi networks (known as VCN --
|
||||
// virtual carrier network). So, see if this cellular network has wifi info.
|
||||
Utils.tryGetWifiInfoForVcn(networkCapabilities)
|
||||
else -> null
|
||||
}
|
||||
}
|
||||
|
||||
private fun createWifiNetworkModel(
|
||||
wifiInfo: WifiInfo,
|
||||
network: Network,
|
||||
networkCapabilities: NetworkCapabilities,
|
||||
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
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private fun prettyPrintActivity(activity: Int): String {
|
||||
return when (activity) {
|
||||
TrafficStateCallback.DATA_ACTIVITY_NONE -> "NONE"
|
||||
TrafficStateCallback.DATA_ACTIVITY_IN -> "IN"
|
||||
TrafficStateCallback.DATA_ACTIVITY_OUT -> "OUT"
|
||||
TrafficStateCallback.DATA_ACTIVITY_INOUT -> "INOUT"
|
||||
else -> "INVALID"
|
||||
}
|
||||
}
|
||||
|
||||
private val WIFI_NETWORK_CALLBACK_REQUEST: NetworkRequest =
|
||||
NetworkRequest.Builder()
|
||||
.clearCapabilities()
|
||||
.addCapability(NET_CAPABILITY_NOT_VPN)
|
||||
.addTransportType(TRANSPORT_WIFI)
|
||||
.addTransportType(TRANSPORT_CELLULAR)
|
||||
.build()
|
||||
|
||||
private const val WIFI_NETWORK_CALLBACK_NAME = "wifiNetworkModel"
|
||||
}
|
||||
}
|
||||
@@ -20,7 +20,10 @@ import android.content.Intent
|
||||
import android.os.UserHandle
|
||||
import android.provider.Settings
|
||||
import android.telephony.CellSignalStrengthCdma
|
||||
import android.telephony.NetworkRegistrationInfo
|
||||
import android.telephony.ServiceState
|
||||
import android.telephony.ServiceState.STATE_IN_SERVICE
|
||||
import android.telephony.ServiceState.STATE_OUT_OF_SERVICE
|
||||
import android.telephony.SignalStrength
|
||||
import android.telephony.SubscriptionInfo
|
||||
import android.telephony.TelephonyCallback
|
||||
@@ -47,7 +50,6 @@ import android.telephony.TelephonyManager.EXTRA_SHOW_SPN
|
||||
import android.telephony.TelephonyManager.EXTRA_SPN
|
||||
import android.telephony.TelephonyManager.EXTRA_SUBSCRIPTION_ID
|
||||
import android.telephony.TelephonyManager.NETWORK_TYPE_LTE
|
||||
import android.telephony.TelephonyManager.NETWORK_TYPE_UNKNOWN
|
||||
import androidx.test.filters.SmallTest
|
||||
import com.android.systemui.SysuiTestCase
|
||||
import com.android.systemui.log.table.TableLogBuffer
|
||||
@@ -302,7 +304,6 @@ class MobileConnectionRepositoryTest : SysuiTestCase() {
|
||||
var latest: MobileConnectionModel? = null
|
||||
val job = underTest.connectionInfo.onEach { latest = it }.launchIn(this)
|
||||
|
||||
val type = NETWORK_TYPE_UNKNOWN
|
||||
val expected = UnknownNetworkType
|
||||
|
||||
assertThat(latest?.resolvedNetworkType).isEqualTo(expected)
|
||||
@@ -590,6 +591,56 @@ class MobileConnectionRepositoryTest : SysuiTestCase() {
|
||||
job.cancel()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `connection model - isInService - not iwlan`() =
|
||||
runBlocking(IMMEDIATE) {
|
||||
var latest: Boolean? = null
|
||||
val job = underTest.connectionInfo.onEach { latest = it.isInService }.launchIn(this)
|
||||
|
||||
val serviceState = ServiceState()
|
||||
serviceState.voiceRegState = STATE_IN_SERVICE
|
||||
serviceState.dataRegState = STATE_IN_SERVICE
|
||||
|
||||
getTelephonyCallbackForType<ServiceStateListener>().onServiceStateChanged(serviceState)
|
||||
|
||||
assertThat(latest).isTrue()
|
||||
|
||||
serviceState.voiceRegState = STATE_OUT_OF_SERVICE
|
||||
getTelephonyCallbackForType<ServiceStateListener>().onServiceStateChanged(serviceState)
|
||||
assertThat(latest).isTrue()
|
||||
|
||||
serviceState.dataRegState = STATE_OUT_OF_SERVICE
|
||||
getTelephonyCallbackForType<ServiceStateListener>().onServiceStateChanged(serviceState)
|
||||
assertThat(latest).isFalse()
|
||||
|
||||
job.cancel()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `connection model - isInService - is iwlan - voice out of service - data in service`() =
|
||||
runBlocking(IMMEDIATE) {
|
||||
var latest: Boolean? = null
|
||||
val job = underTest.connectionInfo.onEach { latest = it.isInService }.launchIn(this)
|
||||
|
||||
// Mock the service state here so we can make it specifically IWLAN
|
||||
val serviceState: ServiceState = mock()
|
||||
whenever(serviceState.state).thenReturn(STATE_OUT_OF_SERVICE)
|
||||
whenever(serviceState.dataRegistrationState).thenReturn(STATE_IN_SERVICE)
|
||||
|
||||
// See [com.android.settingslib.Utils.isInService] for more info. This is one way to
|
||||
// make the network look like IWLAN
|
||||
val networkRegWlan: NetworkRegistrationInfo = mock()
|
||||
whenever(serviceState.getNetworkRegistrationInfo(any(), any()))
|
||||
.thenReturn(networkRegWlan)
|
||||
whenever(networkRegWlan.registrationState)
|
||||
.thenReturn(NetworkRegistrationInfo.REGISTRATION_STATE_HOME)
|
||||
|
||||
getTelephonyCallbackForType<ServiceStateListener>().onServiceStateChanged(serviceState)
|
||||
assertThat(latest).isFalse()
|
||||
|
||||
job.cancel()
|
||||
}
|
||||
|
||||
private fun getTelephonyCallbacks(): List<TelephonyCallback> {
|
||||
val callbackCaptor = argumentCaptor<TelephonyCallback>()
|
||||
Mockito.verify(telephonyManager).registerTelephonyCallback(any(), callbackCaptor.capture())
|
||||
|
||||
@@ -52,6 +52,8 @@ class FakeMobileIconInteractor(
|
||||
|
||||
override val isDataConnected = MutableStateFlow(true)
|
||||
|
||||
override val isInService = MutableStateFlow(true)
|
||||
|
||||
private val _isDataEnabled = MutableStateFlow(true)
|
||||
override val isDataEnabled = _isDataEnabled
|
||||
|
||||
|
||||
@@ -299,6 +299,23 @@ class MobileIconInteractorTest : SysuiTestCase() {
|
||||
job.cancel()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `isInService - uses repository value`() =
|
||||
runBlocking(IMMEDIATE) {
|
||||
var latest: Boolean? = null
|
||||
val job = underTest.isInService.onEach { latest = it }.launchIn(this)
|
||||
|
||||
connectionRepository.setConnectionInfo(MobileConnectionModel(isInService = true))
|
||||
|
||||
assertThat(latest).isTrue()
|
||||
|
||||
connectionRepository.setConnectionInfo(MobileConnectionModel(isInService = false))
|
||||
|
||||
assertThat(latest).isFalse()
|
||||
|
||||
job.cancel()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `roaming - is gsm - uses connection model`() =
|
||||
runBlocking(IMMEDIATE) {
|
||||
|
||||
@@ -97,6 +97,30 @@ class MobileIconViewModelTest : SysuiTestCase() {
|
||||
job.cancel()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `icon - uses empty state - when not in service`() =
|
||||
testScope.runTest {
|
||||
var latest: Int? = null
|
||||
val job = underTest.iconId.onEach { latest = it }.launchIn(this)
|
||||
|
||||
interactor.isInService.value = false
|
||||
|
||||
var expected = emptySignal()
|
||||
|
||||
assertThat(latest).isEqualTo(expected)
|
||||
|
||||
// Changing the level doesn't overwrite the disabled state
|
||||
interactor.level.value = 2
|
||||
assertThat(latest).isEqualTo(expected)
|
||||
|
||||
// Once back in service, the regular icon appears
|
||||
interactor.isInService.value = true
|
||||
expected = defaultSignal(level = 2)
|
||||
assertThat(latest).isEqualTo(expected)
|
||||
|
||||
job.cancel()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun networkType_dataEnabled_groupIsRepresented() =
|
||||
testScope.runTest {
|
||||
@@ -375,5 +399,7 @@ class MobileIconViewModelTest : SysuiTestCase() {
|
||||
): Int {
|
||||
return SignalDrawable.getState(level, /* numLevels */ 4, !connected)
|
||||
}
|
||||
|
||||
fun emptySignal(): Int = SignalDrawable.getEmptyState(4)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,7 +18,7 @@ package com.android.systemui.statusbar.pipeline.wifi.data.repository
|
||||
|
||||
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.WifiRepositoryImpl.Companion.ACTIVITY_DEFAULT
|
||||
import com.android.systemui.statusbar.pipeline.wifi.data.repository.prod.WifiRepositoryImpl.Companion.ACTIVITY_DEFAULT
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.flow.StateFlow
|
||||
|
||||
|
||||
@@ -27,6 +27,7 @@ import com.android.systemui.statusbar.pipeline.shared.ConnectivityPipelineLogger
|
||||
import com.android.systemui.statusbar.pipeline.wifi.data.repository.demo.DemoModeWifiDataSource
|
||||
import com.android.systemui.statusbar.pipeline.wifi.data.repository.demo.DemoWifiRepository
|
||||
import com.android.systemui.statusbar.pipeline.wifi.data.repository.demo.model.FakeWifiEventModel
|
||||
import com.android.systemui.statusbar.pipeline.wifi.data.repository.prod.WifiRepositoryImpl
|
||||
import com.android.systemui.util.concurrency.FakeExecutor
|
||||
import com.android.systemui.util.mockito.kotlinArgumentCaptor
|
||||
import com.android.systemui.util.mockito.whenever
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.systemui.statusbar.pipeline.wifi.data.repository
|
||||
package com.android.systemui.statusbar.pipeline.wifi.data.repository.prod
|
||||
|
||||
import android.net.ConnectivityManager
|
||||
import android.net.Network
|
||||
@@ -33,8 +33,8 @@ 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.WifiRepositoryImpl.Companion.ACTIVITY_DEFAULT
|
||||
import com.android.systemui.statusbar.pipeline.wifi.data.repository.WifiRepositoryImpl.Companion.WIFI_NETWORK_DEFAULT
|
||||
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
|
||||
import com.android.systemui.util.mockito.argumentCaptor
|
||||
Reference in New Issue
Block a user