diff options
| author | 2022-12-28 17:31:07 +0000 | |
|---|---|---|
| committer | 2022-12-28 17:31:07 +0000 | |
| commit | b425997d1ffda0dda270c1c46e0a85bbf31d5372 (patch) | |
| tree | f065e07ffc4cca4f6cb64aa0822486875a2c1540 | |
| parent | 67546c8fe14496ec35356a0217a8f9120b33bf14 (diff) | |
| parent | 937ab161491c6a76c43003b814adc4ccd7e2dc96 (diff) | |
Merge changes Ie0da0143,I9541a914,I21f3259e,I40a6d5aa,I9c6b9ba3 into tm-qpr-dev am: 933c12efa1 am: 937ab16149
Original change: https://googleplex-android-review.googlesource.com/c/platform/frameworks/base/+/20803315
Change-Id: Ia39308a0a690799a94be581317dbc3234bdbaced
Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
16 files changed, 455 insertions, 302 deletions
diff --git a/packages/SystemUI/ktfmt_includes.txt b/packages/SystemUI/ktfmt_includes.txt index 7290e7ed5394..7243ca4cece0 100644 --- a/packages/SystemUI/ktfmt_includes.txt +++ b/packages/SystemUI/ktfmt_includes.txt @@ -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 diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/model/MobileConnectionModel.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/model/MobileConnectionModel.kt index 1aa954ff48cf..012b9ec09e7a 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/model/MobileConnectionModel.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/model/MobileConnectionModel.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" diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/demo/DemoMobileConnectionsRepository.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/demo/DemoMobileConnectionsRepository.kt index b252de8dd389..0b5f9d5ae59e 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/demo/DemoMobileConnectionsRepository.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/demo/DemoMobileConnectionsRepository.kt @@ -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, diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionRepositoryImpl.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionRepositoryImpl.kt index 0b9e1583898e..5cfff82253c5 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionRepositoryImpl.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionRepositoryImpl.kt @@ -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) } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconInteractor.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconInteractor.kt index e6686dce7bbc..675760533d97 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconInteractor.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconInteractor.kt @@ -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) } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/ui/viewmodel/MobileIconViewModel.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/ui/viewmodel/MobileIconViewModel.kt index 2d6ac4efd512..a2117c7df188 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/ui/viewmodel/MobileIconViewModel.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/ui/viewmodel/MobileIconViewModel.kt @@ -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( diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/WifiRepository.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/WifiRepository.kt index 5ccd6f45770d..53525f254e1d 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/WifiRepository.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/WifiRepository.kt @@ -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" - } -} diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/WifiRepositorySwitcher.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/WifiRepositorySwitcher.kt index 73bcdfd2b78e..be86620e01f3 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/WifiRepositorySwitcher.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/WifiRepositorySwitcher.kt @@ -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 diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/prod/WifiRepositoryImpl.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/prod/WifiRepositoryImpl.kt new file mode 100644 index 000000000000..c8c94e102999 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/prod/WifiRepositoryImpl.kt @@ -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" + } +} diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionRepositoryTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionRepositoryTest.kt index 7970443f69b1..c63dd2a2318c 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionRepositoryTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionRepositoryTest.kt @@ -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()) diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/FakeMobileIconInteractor.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/FakeMobileIconInteractor.kt index c49458909c78..5889ec885e1f 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/FakeMobileIconInteractor.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/FakeMobileIconInteractor.kt @@ -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 diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconInteractorTest.kt index 83c5055a6eda..cb2ee9940c38 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconInteractorTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconInteractorTest.kt @@ -300,6 +300,23 @@ class MobileIconInteractorTest : SysuiTestCase() { } @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) { var latest: Boolean? = null diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/ui/viewmodel/MobileIconViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/ui/viewmodel/MobileIconViewModelTest.kt index 50221bc97bad..2a8d42ff6997 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/ui/viewmodel/MobileIconViewModelTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/ui/viewmodel/MobileIconViewModelTest.kt @@ -98,6 +98,30 @@ class MobileIconViewModelTest : SysuiTestCase() { } @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 { val expected = @@ -375,5 +399,7 @@ class MobileIconViewModelTest : SysuiTestCase() { ): Int { return SignalDrawable.getState(level, /* numLevels */ 4, !connected) } + + fun emptySignal(): Int = SignalDrawable.getEmptyState(4) } } diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/FakeWifiRepository.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/FakeWifiRepository.kt index 4e15b4a503d7..f5837d698c51 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/FakeWifiRepository.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/FakeWifiRepository.kt @@ -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 diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/WifiRepositorySwitcherTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/WifiRepositorySwitcherTest.kt index b935442fd73a..1085c2b1a5d5 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/WifiRepositorySwitcherTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/WifiRepositorySwitcherTest.kt @@ -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 diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/WifiRepositoryImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/prod/WifiRepositoryImplTest.kt index 5d0d87b13d20..befb2901d4d5 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/WifiRepositoryImplTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/prod/WifiRepositoryImplTest.kt @@ -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 |