Merge "[SB Refactor] Implement the wifi network flow using the NetworkCallback." into tm-qpr-dev
This commit is contained in:
committed by
Android (Google) Code Review
commit
e805c9bf06
@@ -600,6 +600,9 @@ public class Utils {
|
|||||||
* Returns the WifiInfo for the underlying WiFi network of the VCN network, returns null if the
|
* Returns the WifiInfo for the underlying WiFi network of the VCN network, returns null if the
|
||||||
* input NetworkCapabilities is not for a VCN network with underlying WiFi network.
|
* input NetworkCapabilities is not for a VCN network with underlying WiFi network.
|
||||||
*
|
*
|
||||||
|
* TODO(b/238425913): Move this method to be inside systemui not settingslib once we've migrated
|
||||||
|
* off of {@link WifiStatusTracker} and {@link NetworkControllerImpl}.
|
||||||
|
*
|
||||||
* @param networkCapabilities NetworkCapabilities of the network.
|
* @param networkCapabilities NetworkCapabilities of the network.
|
||||||
*/
|
*/
|
||||||
@Nullable
|
@Nullable
|
||||||
|
|||||||
@@ -1,49 +0,0 @@
|
|||||||
/*
|
|
||||||
* 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
|
|
||||||
|
|
||||||
import com.android.systemui.statusbar.pipeline.wifi.data.repository.NetworkCapabilityInfo
|
|
||||||
import kotlinx.coroutines.flow.StateFlow
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Interface exposing a flow for raw connectivity information. Clients should collect on
|
|
||||||
* [rawConnectivityInfoFlow] to get updates on connectivity information.
|
|
||||||
*
|
|
||||||
* Note: [rawConnectivityInfoFlow] should be a *hot* flow, so that we only create one instance of it
|
|
||||||
* and all clients get references to the same flow.
|
|
||||||
*
|
|
||||||
* This will be used for the new status bar pipeline to compile information we need to display some
|
|
||||||
* of the icons in the RHS of the status bar.
|
|
||||||
*/
|
|
||||||
interface ConnectivityInfoCollector {
|
|
||||||
val rawConnectivityInfoFlow: StateFlow<RawConnectivityInfo>
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* An object containing all of the raw connectivity information.
|
|
||||||
*
|
|
||||||
* Importantly, all the information in this object should not be processed at all (i.e., the data
|
|
||||||
* that we receive from callbacks should be piped straight into this object and not be filtered,
|
|
||||||
* manipulated, or processed in any way). Instead, any listeners on
|
|
||||||
* [ConnectivityInfoCollector.rawConnectivityInfoFlow] can do the processing.
|
|
||||||
*
|
|
||||||
* This allows us to keep all the processing in one place which is beneficial for logging and
|
|
||||||
* debugging purposes.
|
|
||||||
*/
|
|
||||||
data class RawConnectivityInfo(
|
|
||||||
val networkCapabilityInfo: Map<Int, NetworkCapabilityInfo> = emptyMap(),
|
|
||||||
)
|
|
||||||
@@ -1,46 +0,0 @@
|
|||||||
/*
|
|
||||||
* 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
|
|
||||||
|
|
||||||
import com.android.systemui.dagger.SysUISingleton
|
|
||||||
import com.android.systemui.dagger.qualifiers.Application
|
|
||||||
import com.android.systemui.statusbar.pipeline.wifi.data.repository.NetworkCapabilitiesRepo
|
|
||||||
import javax.inject.Inject
|
|
||||||
import kotlinx.coroutines.CoroutineScope
|
|
||||||
import kotlinx.coroutines.flow.SharingStarted.Companion.Lazily
|
|
||||||
import kotlinx.coroutines.flow.StateFlow
|
|
||||||
import kotlinx.coroutines.flow.map
|
|
||||||
import kotlinx.coroutines.flow.stateIn
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The real implementation of [ConnectivityInfoCollector] that will collect information from all the
|
|
||||||
* relevant connectivity callbacks and compile it into [rawConnectivityInfoFlow].
|
|
||||||
*/
|
|
||||||
@SysUISingleton
|
|
||||||
class ConnectivityInfoCollectorImpl @Inject constructor(
|
|
||||||
networkCapabilitiesRepo: NetworkCapabilitiesRepo,
|
|
||||||
@Application scope: CoroutineScope,
|
|
||||||
) : ConnectivityInfoCollector {
|
|
||||||
override val rawConnectivityInfoFlow: StateFlow<RawConnectivityInfo> =
|
|
||||||
// TODO(b/238425913): Collect all the separate flows for individual raw information into
|
|
||||||
// this final flow.
|
|
||||||
networkCapabilitiesRepo.dataStream
|
|
||||||
.map {
|
|
||||||
RawConnectivityInfo(networkCapabilityInfo = it)
|
|
||||||
}
|
|
||||||
.stateIn(scope, started = Lazily, initialValue = RawConnectivityInfo())
|
|
||||||
}
|
|
||||||
@@ -20,31 +20,21 @@ import android.content.Context
|
|||||||
import com.android.systemui.CoreStartable
|
import com.android.systemui.CoreStartable
|
||||||
import com.android.systemui.dagger.SysUISingleton
|
import com.android.systemui.dagger.SysUISingleton
|
||||||
import com.android.systemui.dagger.qualifiers.Application
|
import com.android.systemui.dagger.qualifiers.Application
|
||||||
import com.android.systemui.statusbar.pipeline.wifi.data.repository.NetworkCapabilityInfo
|
|
||||||
import com.android.systemui.statusbar.pipeline.wifi.ui.viewmodel.WifiViewModel
|
import com.android.systemui.statusbar.pipeline.wifi.ui.viewmodel.WifiViewModel
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
import javax.inject.Provider
|
import javax.inject.Provider
|
||||||
import kotlinx.coroutines.CoroutineScope
|
import kotlinx.coroutines.CoroutineScope
|
||||||
import kotlinx.coroutines.flow.Flow
|
|
||||||
import kotlinx.coroutines.flow.SharingStarted.Companion.Lazily
|
|
||||||
import kotlinx.coroutines.flow.collect
|
import kotlinx.coroutines.flow.collect
|
||||||
import kotlinx.coroutines.flow.emptyFlow
|
|
||||||
import kotlinx.coroutines.flow.map
|
|
||||||
import kotlinx.coroutines.flow.stateIn
|
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A processor that transforms raw connectivity information that we get from callbacks and turns it
|
* A temporary object that collects on [WifiViewModel] flows for debugging purposes.
|
||||||
* into a list of displayable connectivity information.
|
|
||||||
*
|
*
|
||||||
* This will be used for the new status bar pipeline to calculate the list of icons that should be
|
* This will eventually get migrated to a view binder that will use the flow outputs to set state on
|
||||||
* displayed in the RHS of the status bar.
|
* views. For now, this just collects on flows so that the information gets logged.
|
||||||
*
|
|
||||||
* Anyone can listen to [processedInfoFlow] to get updates to the processed data.
|
|
||||||
*/
|
*/
|
||||||
@SysUISingleton
|
@SysUISingleton
|
||||||
class ConnectivityInfoProcessor @Inject constructor(
|
class ConnectivityInfoProcessor @Inject constructor(
|
||||||
connectivityInfoCollector: ConnectivityInfoCollector,
|
|
||||||
context: Context,
|
context: Context,
|
||||||
// TODO(b/238425913): Don't use the application scope; instead, use the status bar view's
|
// TODO(b/238425913): Don't use the application scope; instead, use the status bar view's
|
||||||
// scope so we only do work when there's UI that cares about it.
|
// scope so we only do work when there's UI that cares about it.
|
||||||
@@ -52,21 +42,6 @@ class ConnectivityInfoProcessor @Inject constructor(
|
|||||||
private val statusBarPipelineFlags: StatusBarPipelineFlags,
|
private val statusBarPipelineFlags: StatusBarPipelineFlags,
|
||||||
private val wifiViewModelProvider: Provider<WifiViewModel>,
|
private val wifiViewModelProvider: Provider<WifiViewModel>,
|
||||||
) : CoreStartable(context) {
|
) : CoreStartable(context) {
|
||||||
// Note: This flow will not start running until a client calls `collect` on it, which means that
|
|
||||||
// [connectivityInfoCollector]'s flow will also not start anything until that `collect` call
|
|
||||||
// happens.
|
|
||||||
// TODO(b/238425913): Delete this.
|
|
||||||
val processedInfoFlow: Flow<ProcessedConnectivityInfo> =
|
|
||||||
if (!statusBarPipelineFlags.isNewPipelineEnabled())
|
|
||||||
emptyFlow()
|
|
||||||
else connectivityInfoCollector.rawConnectivityInfoFlow
|
|
||||||
.map { it.process() }
|
|
||||||
.stateIn(
|
|
||||||
scope,
|
|
||||||
started = Lazily,
|
|
||||||
initialValue = ProcessedConnectivityInfo()
|
|
||||||
)
|
|
||||||
|
|
||||||
override fun start() {
|
override fun start() {
|
||||||
if (!statusBarPipelineFlags.isNewPipelineEnabled()) {
|
if (!statusBarPipelineFlags.isNewPipelineEnabled()) {
|
||||||
return
|
return
|
||||||
@@ -77,17 +52,4 @@ class ConnectivityInfoProcessor @Inject constructor(
|
|||||||
wifiViewModelProvider.get().isActivityInVisible.collect { }
|
wifiViewModelProvider.get().isActivityInVisible.collect { }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun RawConnectivityInfo.process(): ProcessedConnectivityInfo {
|
|
||||||
// TODO(b/238425913): Actually process the raw info into meaningful data.
|
|
||||||
return ProcessedConnectivityInfo(this.networkCapabilityInfo)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* An object containing connectivity info that has been processed into data that can be directly
|
|
||||||
* used by the status bar (and potentially other SysUI areas) to display icons.
|
|
||||||
*/
|
|
||||||
data class ProcessedConnectivityInfo(
|
|
||||||
val networkCapabilityInfo: Map<Int, NetworkCapabilityInfo> = emptyMap(),
|
|
||||||
)
|
|
||||||
|
|||||||
@@ -17,8 +17,6 @@
|
|||||||
package com.android.systemui.statusbar.pipeline.dagger
|
package com.android.systemui.statusbar.pipeline.dagger
|
||||||
|
|
||||||
import com.android.systemui.CoreStartable
|
import com.android.systemui.CoreStartable
|
||||||
import com.android.systemui.statusbar.pipeline.ConnectivityInfoCollector
|
|
||||||
import com.android.systemui.statusbar.pipeline.ConnectivityInfoCollectorImpl
|
|
||||||
import com.android.systemui.statusbar.pipeline.ConnectivityInfoProcessor
|
import com.android.systemui.statusbar.pipeline.ConnectivityInfoProcessor
|
||||||
import com.android.systemui.statusbar.pipeline.wifi.data.repository.WifiRepository
|
import com.android.systemui.statusbar.pipeline.wifi.data.repository.WifiRepository
|
||||||
import com.android.systemui.statusbar.pipeline.wifi.data.repository.WifiRepositoryImpl
|
import com.android.systemui.statusbar.pipeline.wifi.data.repository.WifiRepositoryImpl
|
||||||
@@ -35,11 +33,6 @@ abstract class StatusBarPipelineModule {
|
|||||||
@ClassKey(ConnectivityInfoProcessor::class)
|
@ClassKey(ConnectivityInfoProcessor::class)
|
||||||
abstract fun bindConnectivityInfoProcessor(cip: ConnectivityInfoProcessor): CoreStartable
|
abstract fun bindConnectivityInfoProcessor(cip: ConnectivityInfoProcessor): CoreStartable
|
||||||
|
|
||||||
@Binds
|
|
||||||
abstract fun provideConnectivityInfoCollector(
|
|
||||||
impl: ConnectivityInfoCollectorImpl
|
|
||||||
): ConnectivityInfoCollector
|
|
||||||
|
|
||||||
@Binds
|
@Binds
|
||||||
abstract fun wifiRepository(impl: WifiRepositoryImpl): WifiRepository
|
abstract fun wifiRepository(impl: WifiRepositoryImpl): WifiRepository
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -31,6 +31,9 @@ import kotlinx.coroutines.flow.onEach
|
|||||||
class ConnectivityPipelineLogger @Inject constructor(
|
class ConnectivityPipelineLogger @Inject constructor(
|
||||||
@StatusBarConnectivityLog private val buffer: LogBuffer,
|
@StatusBarConnectivityLog private val buffer: LogBuffer,
|
||||||
) {
|
) {
|
||||||
|
/**
|
||||||
|
* Logs a change in one of the **raw inputs** to the connectivity pipeline.
|
||||||
|
*/
|
||||||
fun logInputChange(callbackName: String, changeInfo: String) {
|
fun logInputChange(callbackName: String, changeInfo: String) {
|
||||||
buffer.log(
|
buffer.log(
|
||||||
SB_LOGGING_TAG,
|
SB_LOGGING_TAG,
|
||||||
@@ -45,6 +48,41 @@ class ConnectivityPipelineLogger @Inject constructor(
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Logs a **data transformation** that we performed within the connectivity pipeline.
|
||||||
|
*/
|
||||||
|
fun logTransformation(transformationName: String, oldValue: Any?, newValue: Any?) {
|
||||||
|
if (oldValue == newValue) {
|
||||||
|
buffer.log(
|
||||||
|
SB_LOGGING_TAG,
|
||||||
|
LogLevel.INFO,
|
||||||
|
{
|
||||||
|
str1 = transformationName
|
||||||
|
str2 = oldValue.toString()
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Transform: $str1: $str2 (transformation didn't change it)"
|
||||||
|
}
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
buffer.log(
|
||||||
|
SB_LOGGING_TAG,
|
||||||
|
LogLevel.INFO,
|
||||||
|
{
|
||||||
|
str1 = transformationName
|
||||||
|
str2 = oldValue.toString()
|
||||||
|
str3 = newValue.toString()
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Transform: $str1: $str2 -> $str3"
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Logs a change in one of the **outputs** to the connectivity pipeline.
|
||||||
|
*/
|
||||||
fun logOutputChange(outputParamName: String, changeInfo: String) {
|
fun logOutputChange(outputParamName: String, changeInfo: String) {
|
||||||
buffer.log(
|
buffer.log(
|
||||||
SB_LOGGING_TAG,
|
SB_LOGGING_TAG,
|
||||||
|
|||||||
@@ -1,29 +0,0 @@
|
|||||||
/*
|
|
||||||
* 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.model
|
|
||||||
|
|
||||||
/** Provides information about the current wifi state. */
|
|
||||||
data class WifiModel(
|
|
||||||
/** See [android.net.wifi.WifiInfo.ssid]. */
|
|
||||||
val ssid: String? = null,
|
|
||||||
/** See [android.net.wifi.WifiInfo.isPasspointAp]. */
|
|
||||||
val isPasspointAccessPoint: Boolean = false,
|
|
||||||
/** See [android.net.wifi.WifiInfo.isOsuAp]. */
|
|
||||||
val isOnlineSignUpForPasspointAccessPoint: Boolean = false,
|
|
||||||
/** See [android.net.wifi.WifiInfo.passpointProviderFriendlyName]. */
|
|
||||||
val passpointProviderFriendlyName: String? = null,
|
|
||||||
)
|
|
||||||
@@ -0,0 +1,46 @@
|
|||||||
|
/*
|
||||||
|
* 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.model
|
||||||
|
|
||||||
|
/** Provides information about the current wifi network. */
|
||||||
|
sealed class WifiNetworkModel {
|
||||||
|
/** A model representing that we have no active wifi network. */
|
||||||
|
object Inactive : WifiNetworkModel()
|
||||||
|
|
||||||
|
/** Provides information about an active wifi network. */
|
||||||
|
class Active(
|
||||||
|
/**
|
||||||
|
* The [android.net.Network.netId] we received from
|
||||||
|
* [android.net.ConnectivityManager.NetworkCallback] in association with this wifi network.
|
||||||
|
*
|
||||||
|
* Importantly, **not** [android.net.wifi.WifiInfo.getNetworkId].
|
||||||
|
*/
|
||||||
|
val networkId: Int,
|
||||||
|
|
||||||
|
/** See [android.net.wifi.WifiInfo.ssid]. */
|
||||||
|
val ssid: String? = null,
|
||||||
|
|
||||||
|
/** See [android.net.wifi.WifiInfo.isPasspointAp]. */
|
||||||
|
val isPasspointAccessPoint: Boolean = false,
|
||||||
|
|
||||||
|
/** See [android.net.wifi.WifiInfo.isOsuAp]. */
|
||||||
|
val isOnlineSignUpForPasspointAccessPoint: Boolean = false,
|
||||||
|
|
||||||
|
/** See [android.net.wifi.WifiInfo.passpointProviderFriendlyName]. */
|
||||||
|
val passpointProviderFriendlyName: String? = null,
|
||||||
|
) : WifiNetworkModel()
|
||||||
|
}
|
||||||
@@ -1,94 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (C) 2021 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.
|
|
||||||
*/
|
|
||||||
|
|
||||||
@file:OptIn(ExperimentalCoroutinesApi::class)
|
|
||||||
|
|
||||||
package com.android.systemui.statusbar.pipeline.wifi.data.repository
|
|
||||||
|
|
||||||
import android.annotation.SuppressLint
|
|
||||||
import android.net.ConnectivityManager
|
|
||||||
import android.net.Network
|
|
||||||
import android.net.NetworkCapabilities
|
|
||||||
import android.net.NetworkRequest
|
|
||||||
import com.android.systemui.dagger.SysUISingleton
|
|
||||||
import com.android.systemui.dagger.qualifiers.Application
|
|
||||||
import com.android.systemui.statusbar.pipeline.shared.ConnectivityPipelineLogger
|
|
||||||
import javax.inject.Inject
|
|
||||||
import kotlinx.coroutines.CoroutineScope
|
|
||||||
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
|
||||||
import kotlinx.coroutines.channels.awaitClose
|
|
||||||
import kotlinx.coroutines.flow.SharingStarted.Companion.Lazily
|
|
||||||
import kotlinx.coroutines.flow.StateFlow
|
|
||||||
import kotlinx.coroutines.flow.callbackFlow
|
|
||||||
import kotlinx.coroutines.flow.stateIn
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Repository that contains all relevant [NetworkCapabilities] for the current networks.
|
|
||||||
*
|
|
||||||
* TODO(b/238425913): Figure out how to merge this with [WifiRepository].
|
|
||||||
*/
|
|
||||||
@SysUISingleton
|
|
||||||
class NetworkCapabilitiesRepo @Inject constructor(
|
|
||||||
connectivityManager: ConnectivityManager,
|
|
||||||
@Application scope: CoroutineScope,
|
|
||||||
logger: ConnectivityPipelineLogger,
|
|
||||||
) {
|
|
||||||
@SuppressLint("MissingPermission")
|
|
||||||
val dataStream: StateFlow<Map<Int, NetworkCapabilityInfo>> = run {
|
|
||||||
var state = emptyMap<Int, NetworkCapabilityInfo>()
|
|
||||||
callbackFlow {
|
|
||||||
val networkRequest: NetworkRequest =
|
|
||||||
NetworkRequest.Builder()
|
|
||||||
.clearCapabilities()
|
|
||||||
.addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_VPN)
|
|
||||||
.addTransportType(NetworkCapabilities.TRANSPORT_WIFI)
|
|
||||||
.addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR)
|
|
||||||
.build()
|
|
||||||
val callback =
|
|
||||||
// TODO (b/240569788): log these using [LogBuffer]
|
|
||||||
object : ConnectivityManager.NetworkCallback(FLAG_INCLUDE_LOCATION_INFO) {
|
|
||||||
override fun onCapabilitiesChanged(
|
|
||||||
network: Network,
|
|
||||||
networkCapabilities: NetworkCapabilities
|
|
||||||
) {
|
|
||||||
logger.logOnCapabilitiesChanged(network, networkCapabilities)
|
|
||||||
state =
|
|
||||||
state.toMutableMap().also {
|
|
||||||
it[network.getNetId()] =
|
|
||||||
NetworkCapabilityInfo(network, networkCapabilities)
|
|
||||||
}
|
|
||||||
trySend(state)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onLost(network: Network) {
|
|
||||||
logger.logOnLost(network)
|
|
||||||
state = state.toMutableMap().also { it.remove(network.getNetId()) }
|
|
||||||
trySend(state)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
connectivityManager.registerNetworkCallback(networkRequest, callback)
|
|
||||||
|
|
||||||
awaitClose { connectivityManager.unregisterNetworkCallback(callback) }
|
|
||||||
}
|
|
||||||
.stateIn(scope, started = Lazily, initialValue = state)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/** contains info about network capabilities. */
|
|
||||||
data class NetworkCapabilityInfo(
|
|
||||||
val network: Network,
|
|
||||||
val capabilities: NetworkCapabilities,
|
|
||||||
)
|
|
||||||
@@ -16,16 +16,26 @@
|
|||||||
|
|
||||||
package com.android.systemui.statusbar.pipeline.wifi.data.repository
|
package com.android.systemui.statusbar.pipeline.wifi.data.repository
|
||||||
|
|
||||||
|
import android.annotation.SuppressLint
|
||||||
|
import android.net.ConnectivityManager
|
||||||
|
import android.net.Network
|
||||||
|
import android.net.NetworkCapabilities
|
||||||
|
import android.net.NetworkCapabilities.NET_CAPABILITY_NOT_VPN
|
||||||
|
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
|
||||||
import android.net.wifi.WifiManager.TrafficStateCallback
|
import android.net.wifi.WifiManager.TrafficStateCallback
|
||||||
import android.util.Log
|
import android.util.Log
|
||||||
|
import com.android.settingslib.Utils
|
||||||
import com.android.systemui.common.coroutine.ConflatedCallbackFlow.conflatedCallbackFlow
|
import com.android.systemui.common.coroutine.ConflatedCallbackFlow.conflatedCallbackFlow
|
||||||
import com.android.systemui.dagger.SysUISingleton
|
import com.android.systemui.dagger.SysUISingleton
|
||||||
import com.android.systemui.dagger.qualifiers.Main
|
import com.android.systemui.dagger.qualifiers.Main
|
||||||
import com.android.systemui.statusbar.pipeline.shared.ConnectivityPipelineLogger
|
import com.android.systemui.statusbar.pipeline.shared.ConnectivityPipelineLogger
|
||||||
import com.android.systemui.statusbar.pipeline.shared.ConnectivityPipelineLogger.Companion.SB_LOGGING_TAG
|
import com.android.systemui.statusbar.pipeline.shared.ConnectivityPipelineLogger.Companion.SB_LOGGING_TAG
|
||||||
import com.android.systemui.statusbar.pipeline.wifi.data.model.WifiActivityModel
|
import com.android.systemui.statusbar.pipeline.wifi.data.model.WifiActivityModel
|
||||||
import com.android.systemui.statusbar.pipeline.wifi.data.model.WifiModel
|
import com.android.systemui.statusbar.pipeline.wifi.data.model.WifiNetworkModel
|
||||||
import java.util.concurrent.Executor
|
import java.util.concurrent.Executor
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
||||||
@@ -38,9 +48,9 @@ import kotlinx.coroutines.flow.flowOf
|
|||||||
*/
|
*/
|
||||||
interface WifiRepository {
|
interface WifiRepository {
|
||||||
/**
|
/**
|
||||||
* Observable for the current state of wifi; `null` when there is no active wifi.
|
* Observable for the current wifi network.
|
||||||
*/
|
*/
|
||||||
val wifiModel: Flow<WifiModel?>
|
val wifiNetwork: Flow<WifiNetworkModel>
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Observable for the current wifi network activity.
|
* Observable for the current wifi network activity.
|
||||||
@@ -51,14 +61,57 @@ interface WifiRepository {
|
|||||||
/** Real implementation of [WifiRepository]. */
|
/** Real implementation of [WifiRepository]. */
|
||||||
@OptIn(ExperimentalCoroutinesApi::class)
|
@OptIn(ExperimentalCoroutinesApi::class)
|
||||||
@SysUISingleton
|
@SysUISingleton
|
||||||
|
@SuppressLint("MissingPermission")
|
||||||
class WifiRepositoryImpl @Inject constructor(
|
class WifiRepositoryImpl @Inject constructor(
|
||||||
|
connectivityManager: ConnectivityManager,
|
||||||
wifiManager: WifiManager?,
|
wifiManager: WifiManager?,
|
||||||
@Main mainExecutor: Executor,
|
@Main mainExecutor: Executor,
|
||||||
logger: ConnectivityPipelineLogger,
|
logger: ConnectivityPipelineLogger,
|
||||||
) : WifiRepository {
|
) : WifiRepository {
|
||||||
|
override val wifiNetwork: Flow<WifiNetworkModel> = conflatedCallbackFlow {
|
||||||
|
var currentWifi: WifiNetworkModel = WIFI_NETWORK_DEFAULT
|
||||||
|
|
||||||
// TODO(b/238425913): Actually implement the wifiModel flow.
|
val callback = object : ConnectivityManager.NetworkCallback(FLAG_INCLUDE_LOCATION_INFO) {
|
||||||
override val wifiModel: Flow<WifiModel?> = flowOf(WifiModel(ssid = "AB"))
|
override fun onCapabilitiesChanged(
|
||||||
|
network: Network,
|
||||||
|
networkCapabilities: NetworkCapabilities
|
||||||
|
) {
|
||||||
|
logger.logOnCapabilitiesChanged(network, networkCapabilities)
|
||||||
|
|
||||||
|
val wifiInfo = networkCapabilitiesToWifiInfo(networkCapabilities)
|
||||||
|
if (wifiInfo?.isPrimary == true) {
|
||||||
|
val wifiNetworkModel = wifiInfoToModel(wifiInfo, network.getNetId())
|
||||||
|
logger.logTransformation(
|
||||||
|
WIFI_NETWORK_CALLBACK_NAME,
|
||||||
|
oldValue = currentWifi,
|
||||||
|
newValue = wifiNetworkModel
|
||||||
|
)
|
||||||
|
currentWifi = wifiNetworkModel
|
||||||
|
trySend(wifiNetworkModel)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onLost(network: Network) {
|
||||||
|
logger.logOnLost(network)
|
||||||
|
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)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
trySend(WIFI_NETWORK_DEFAULT)
|
||||||
|
connectivityManager.registerNetworkCallback(WIFI_NETWORK_CALLBACK_REQUEST, callback)
|
||||||
|
|
||||||
|
awaitClose { connectivityManager.unregisterNetworkCallback(callback) }
|
||||||
|
}
|
||||||
|
|
||||||
override val wifiActivity: Flow<WifiActivityModel> =
|
override val wifiActivity: Flow<WifiActivityModel> =
|
||||||
if (wifiManager == null) {
|
if (wifiManager == null) {
|
||||||
@@ -71,8 +124,8 @@ class WifiRepositoryImpl @Inject constructor(
|
|||||||
trySend(trafficStateToWifiActivityModel(state))
|
trySend(trafficStateToWifiActivityModel(state))
|
||||||
}
|
}
|
||||||
|
|
||||||
wifiManager.registerTrafficStateCallback(mainExecutor, callback)
|
|
||||||
trySend(ACTIVITY_DEFAULT)
|
trySend(ACTIVITY_DEFAULT)
|
||||||
|
wifiManager.registerTrafficStateCallback(mainExecutor, callback)
|
||||||
|
|
||||||
awaitClose { wifiManager.unregisterTrafficStateCallback(callback) }
|
awaitClose { wifiManager.unregisterTrafficStateCallback(callback) }
|
||||||
}
|
}
|
||||||
@@ -80,6 +133,13 @@ class WifiRepositoryImpl @Inject constructor(
|
|||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
val ACTIVITY_DEFAULT = WifiActivityModel(hasActivityIn = false, hasActivityOut = false)
|
val ACTIVITY_DEFAULT = WifiActivityModel(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 trafficStateToWifiActivityModel(state: Int): WifiActivityModel {
|
private fun trafficStateToWifiActivityModel(state: Int): WifiActivityModel {
|
||||||
return WifiActivityModel(
|
return WifiActivityModel(
|
||||||
@@ -90,6 +150,30 @@ class WifiRepositoryImpl @Inject constructor(
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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 wifiInfoToModel(wifiInfo: WifiInfo, networkId: Int): WifiNetworkModel {
|
||||||
|
return WifiNetworkModel.Active(
|
||||||
|
networkId,
|
||||||
|
wifiInfo.ssid,
|
||||||
|
wifiInfo.isPasspointAp,
|
||||||
|
wifiInfo.isOsuAp,
|
||||||
|
wifiInfo.passpointProviderFriendlyName
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
private fun prettyPrintActivity(activity: Int): String {
|
private fun prettyPrintActivity(activity: Int): String {
|
||||||
return when (activity) {
|
return when (activity) {
|
||||||
TrafficStateCallback.DATA_ACTIVITY_NONE -> "NONE"
|
TrafficStateCallback.DATA_ACTIVITY_NONE -> "NONE"
|
||||||
@@ -99,5 +183,15 @@ class WifiRepositoryImpl @Inject constructor(
|
|||||||
else -> "INVALID"
|
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"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -18,6 +18,7 @@ package com.android.systemui.statusbar.pipeline.wifi.domain.interactor
|
|||||||
|
|
||||||
import android.net.wifi.WifiManager
|
import android.net.wifi.WifiManager
|
||||||
import com.android.systemui.dagger.SysUISingleton
|
import com.android.systemui.dagger.SysUISingleton
|
||||||
|
import com.android.systemui.statusbar.pipeline.wifi.data.model.WifiNetworkModel
|
||||||
import com.android.systemui.statusbar.pipeline.wifi.data.repository.WifiRepository
|
import com.android.systemui.statusbar.pipeline.wifi.data.repository.WifiRepository
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
import kotlinx.coroutines.flow.Flow
|
import kotlinx.coroutines.flow.Flow
|
||||||
@@ -34,15 +35,17 @@ import kotlinx.coroutines.flow.map
|
|||||||
class WifiInteractor @Inject constructor(
|
class WifiInteractor @Inject constructor(
|
||||||
repository: WifiRepository,
|
repository: WifiRepository,
|
||||||
) {
|
) {
|
||||||
private val ssid: Flow<String?> = repository.wifiModel.map { info ->
|
private val ssid: Flow<String?> = repository.wifiNetwork.map { info ->
|
||||||
when {
|
when (info) {
|
||||||
info == null -> null
|
is WifiNetworkModel.Inactive -> null
|
||||||
|
is WifiNetworkModel.Active -> when {
|
||||||
info.isPasspointAccessPoint || info.isOnlineSignUpForPasspointAccessPoint ->
|
info.isPasspointAccessPoint || info.isOnlineSignUpForPasspointAccessPoint ->
|
||||||
info.passpointProviderFriendlyName
|
info.passpointProviderFriendlyName
|
||||||
info.ssid != WifiManager.UNKNOWN_SSID -> info.ssid
|
info.ssid != WifiManager.UNKNOWN_SSID -> info.ssid
|
||||||
else -> null
|
else -> null
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
val hasActivityIn: Flow<Boolean> = combine(repository.wifiActivity, ssid) { activity, ssid ->
|
val hasActivityIn: Flow<Boolean> = combine(repository.wifiActivity, ssid) { activity, ssid ->
|
||||||
activity.hasActivityIn && ssid != null
|
activity.hasActivityIn && ssid != null
|
||||||
|
|||||||
@@ -1,88 +0,0 @@
|
|||||||
/*
|
|
||||||
* 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
|
|
||||||
|
|
||||||
import android.net.NetworkCapabilities
|
|
||||||
import android.testing.AndroidTestingRunner
|
|
||||||
import androidx.test.filters.SmallTest
|
|
||||||
import com.android.systemui.SysuiTestCase
|
|
||||||
import com.android.systemui.statusbar.pipeline.wifi.data.repository.NetworkCapabilityInfo
|
|
||||||
import com.android.systemui.util.mockito.mock
|
|
||||||
import com.google.common.truth.Truth.assertThat
|
|
||||||
import kotlinx.coroutines.CoroutineScope
|
|
||||||
import kotlinx.coroutines.CoroutineStart
|
|
||||||
import kotlinx.coroutines.Dispatchers
|
|
||||||
import kotlinx.coroutines.InternalCoroutinesApi
|
|
||||||
import kotlinx.coroutines.cancel
|
|
||||||
import kotlinx.coroutines.flow.collect
|
|
||||||
import kotlinx.coroutines.launch
|
|
||||||
import kotlinx.coroutines.runBlocking
|
|
||||||
import kotlinx.coroutines.yield
|
|
||||||
import org.junit.Before
|
|
||||||
import org.junit.Test
|
|
||||||
import org.junit.runner.RunWith
|
|
||||||
import org.mockito.Mockito.`when` as whenever
|
|
||||||
|
|
||||||
@OptIn(InternalCoroutinesApi::class)
|
|
||||||
@SmallTest
|
|
||||||
@RunWith(AndroidTestingRunner::class)
|
|
||||||
class ConnectivityInfoProcessorTest : SysuiTestCase() {
|
|
||||||
|
|
||||||
private val statusBarPipelineFlags = mock<StatusBarPipelineFlags>()
|
|
||||||
|
|
||||||
@Before
|
|
||||||
fun setUp() {
|
|
||||||
whenever(statusBarPipelineFlags.isNewPipelineEnabled()).thenReturn(true)
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
fun collectorInfoUpdated_processedInfoAlsoUpdated() = runBlocking {
|
|
||||||
// GIVEN a processor hooked up to a collector
|
|
||||||
val scope = CoroutineScope(Dispatchers.Unconfined)
|
|
||||||
val collector = FakeConnectivityInfoCollector()
|
|
||||||
val processor = ConnectivityInfoProcessor(
|
|
||||||
collector,
|
|
||||||
context,
|
|
||||||
scope,
|
|
||||||
statusBarPipelineFlags,
|
|
||||||
mock(),
|
|
||||||
)
|
|
||||||
|
|
||||||
var mostRecentValue: ProcessedConnectivityInfo? = null
|
|
||||||
val job = launch(start = CoroutineStart.UNDISPATCHED) {
|
|
||||||
processor.processedInfoFlow.collect {
|
|
||||||
mostRecentValue = it
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// WHEN the collector emits a value
|
|
||||||
val networkCapabilityInfo = mapOf(
|
|
||||||
10 to NetworkCapabilityInfo(mock(), NetworkCapabilities.Builder().build())
|
|
||||||
)
|
|
||||||
collector.emitValue(RawConnectivityInfo(networkCapabilityInfo))
|
|
||||||
// Because our job uses [CoroutineStart.UNDISPATCHED], it executes in the same thread as
|
|
||||||
// this test. So, our test needs to yield to let the job run.
|
|
||||||
// Note: Once we upgrade our Kotlin coroutines testing library, we won't need this.
|
|
||||||
yield()
|
|
||||||
|
|
||||||
// THEN the processor receives it
|
|
||||||
assertThat(mostRecentValue?.networkCapabilityInfo).isEqualTo(networkCapabilityInfo)
|
|
||||||
|
|
||||||
job.cancel()
|
|
||||||
scope.cancel()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,33 +0,0 @@
|
|||||||
/*
|
|
||||||
* 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
|
|
||||||
|
|
||||||
import kotlinx.coroutines.flow.MutableStateFlow
|
|
||||||
import kotlinx.coroutines.flow.asStateFlow
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A test-friendly implementation of [ConnectivityInfoCollector] that just emits whatever value it
|
|
||||||
* receives in [emitValue].
|
|
||||||
*/
|
|
||||||
class FakeConnectivityInfoCollector : ConnectivityInfoCollector {
|
|
||||||
private val _rawConnectivityInfoFlow = MutableStateFlow(RawConnectivityInfo())
|
|
||||||
override val rawConnectivityInfoFlow = _rawConnectivityInfoFlow.asStateFlow()
|
|
||||||
|
|
||||||
suspend fun emitValue(value: RawConnectivityInfo) {
|
|
||||||
_rawConnectivityInfoFlow.emit(value)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -17,21 +17,22 @@
|
|||||||
package com.android.systemui.statusbar.pipeline.wifi.data.repository
|
package com.android.systemui.statusbar.pipeline.wifi.data.repository
|
||||||
|
|
||||||
import com.android.systemui.statusbar.pipeline.wifi.data.model.WifiActivityModel
|
import com.android.systemui.statusbar.pipeline.wifi.data.model.WifiActivityModel
|
||||||
import com.android.systemui.statusbar.pipeline.wifi.data.model.WifiModel
|
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.ACTIVITY_DEFAULT
|
||||||
import kotlinx.coroutines.flow.Flow
|
import kotlinx.coroutines.flow.Flow
|
||||||
import kotlinx.coroutines.flow.MutableStateFlow
|
import kotlinx.coroutines.flow.MutableStateFlow
|
||||||
|
|
||||||
/** Fake implementation of [WifiRepository] exposing set methods for all the flows. */
|
/** Fake implementation of [WifiRepository] exposing set methods for all the flows. */
|
||||||
class FakeWifiRepository : WifiRepository {
|
class FakeWifiRepository : WifiRepository {
|
||||||
private val _wifiModel: MutableStateFlow<WifiModel?> = MutableStateFlow(null)
|
private val _wifiNetwork: MutableStateFlow<WifiNetworkModel> =
|
||||||
override val wifiModel: Flow<WifiModel?> = _wifiModel
|
MutableStateFlow(WifiNetworkModel.Inactive)
|
||||||
|
override val wifiNetwork: Flow<WifiNetworkModel> = _wifiNetwork
|
||||||
|
|
||||||
private val _wifiActivity = MutableStateFlow(ACTIVITY_DEFAULT)
|
private val _wifiActivity = MutableStateFlow(ACTIVITY_DEFAULT)
|
||||||
override val wifiActivity: Flow<WifiActivityModel> = _wifiActivity
|
override val wifiActivity: Flow<WifiActivityModel> = _wifiActivity
|
||||||
|
|
||||||
fun setWifiModel(wifiModel: WifiModel?) {
|
fun setWifiNetwork(wifiNetworkModel: WifiNetworkModel) {
|
||||||
_wifiModel.value = wifiModel
|
_wifiNetwork.value = wifiNetworkModel
|
||||||
}
|
}
|
||||||
|
|
||||||
fun setWifiActivity(activity: WifiActivityModel) {
|
fun setWifiActivity(activity: WifiActivityModel) {
|
||||||
|
|||||||
@@ -1,252 +0,0 @@
|
|||||||
/*
|
|
||||||
* 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
|
|
||||||
|
|
||||||
import android.net.ConnectivityManager
|
|
||||||
import android.net.ConnectivityManager.NetworkCallback
|
|
||||||
import android.net.Network
|
|
||||||
import android.net.NetworkCapabilities
|
|
||||||
import android.net.NetworkCapabilities.NET_CAPABILITY_NOT_METERED
|
|
||||||
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.test.suitebuilder.annotation.SmallTest
|
|
||||||
import android.testing.AndroidTestingRunner
|
|
||||||
import com.android.systemui.SysuiTestCase
|
|
||||||
import com.android.systemui.statusbar.pipeline.shared.ConnectivityPipelineLogger
|
|
||||||
import com.android.systemui.util.mockito.mock
|
|
||||||
import com.android.systemui.util.mockito.withArgCaptor
|
|
||||||
import com.google.common.truth.Truth.assertThat
|
|
||||||
import kotlinx.coroutines.CoroutineScope
|
|
||||||
import kotlinx.coroutines.CoroutineStart
|
|
||||||
import kotlinx.coroutines.Dispatchers
|
|
||||||
import kotlinx.coroutines.cancel
|
|
||||||
import kotlinx.coroutines.flow.collect
|
|
||||||
import kotlinx.coroutines.launch
|
|
||||||
import kotlinx.coroutines.runBlocking
|
|
||||||
import org.junit.Before
|
|
||||||
import org.junit.Test
|
|
||||||
import org.junit.runner.RunWith
|
|
||||||
import org.mockito.ArgumentMatchers.any
|
|
||||||
import org.mockito.Mock
|
|
||||||
import org.mockito.Mockito.verify
|
|
||||||
import org.mockito.Mockito.`when` as whenever
|
|
||||||
import org.mockito.MockitoAnnotations
|
|
||||||
|
|
||||||
// TODO(b/240619365): Update this test to use `runTest` when we update the testing library
|
|
||||||
@SmallTest
|
|
||||||
@RunWith(AndroidTestingRunner::class)
|
|
||||||
class NetworkCapabilitiesRepoTest : SysuiTestCase() {
|
|
||||||
@Mock private lateinit var connectivityManager: ConnectivityManager
|
|
||||||
@Mock private lateinit var logger: ConnectivityPipelineLogger
|
|
||||||
|
|
||||||
@Before
|
|
||||||
fun setup() {
|
|
||||||
MockitoAnnotations.initMocks(this)
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
fun testOnCapabilitiesChanged_oneNewNetwork_networkStored() = runBlocking {
|
|
||||||
// GIVEN a repo hooked up to [ConnectivityManager]
|
|
||||||
val scope = CoroutineScope(Dispatchers.Unconfined)
|
|
||||||
val repo = NetworkCapabilitiesRepo(
|
|
||||||
connectivityManager = connectivityManager,
|
|
||||||
scope = scope,
|
|
||||||
logger = logger,
|
|
||||||
)
|
|
||||||
|
|
||||||
val job = launch(start = CoroutineStart.UNDISPATCHED) {
|
|
||||||
repo.dataStream.collect {
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
val callback: NetworkCallback = withArgCaptor {
|
|
||||||
verify(connectivityManager)
|
|
||||||
.registerNetworkCallback(any(NetworkRequest::class.java), capture())
|
|
||||||
}
|
|
||||||
|
|
||||||
// WHEN a new network is added
|
|
||||||
callback.onCapabilitiesChanged(NET_1, NET_1_CAPS)
|
|
||||||
|
|
||||||
val currentMap = repo.dataStream.value
|
|
||||||
|
|
||||||
// THEN it is emitted from the flow
|
|
||||||
assertThat(currentMap[NET_1_ID]?.network).isEqualTo(NET_1)
|
|
||||||
assertThat(currentMap[NET_1_ID]?.capabilities).isEqualTo(NET_1_CAPS)
|
|
||||||
|
|
||||||
job.cancel()
|
|
||||||
scope.cancel()
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
fun testOnCapabilitiesChanged_twoNewNetworks_bothStored() = runBlocking {
|
|
||||||
// GIVEN a repo hooked up to [ConnectivityManager]
|
|
||||||
val scope = CoroutineScope(Dispatchers.Unconfined)
|
|
||||||
val repo = NetworkCapabilitiesRepo(
|
|
||||||
connectivityManager = connectivityManager,
|
|
||||||
scope = scope,
|
|
||||||
logger = logger,
|
|
||||||
)
|
|
||||||
|
|
||||||
val job = launch(start = CoroutineStart.UNDISPATCHED) {
|
|
||||||
repo.dataStream.collect {
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
val callback: NetworkCallback = withArgCaptor {
|
|
||||||
verify(connectivityManager)
|
|
||||||
.registerNetworkCallback(any(NetworkRequest::class.java), capture())
|
|
||||||
}
|
|
||||||
|
|
||||||
// WHEN two new networks are added
|
|
||||||
callback.onCapabilitiesChanged(NET_1, NET_1_CAPS)
|
|
||||||
callback.onCapabilitiesChanged(NET_2, NET_2_CAPS)
|
|
||||||
|
|
||||||
val currentMap = repo.dataStream.value
|
|
||||||
|
|
||||||
// THEN the current state of the flow reflects 2 networks
|
|
||||||
assertThat(currentMap[NET_1_ID]?.network).isEqualTo(NET_1)
|
|
||||||
assertThat(currentMap[NET_1_ID]?.capabilities).isEqualTo(NET_1_CAPS)
|
|
||||||
assertThat(currentMap[NET_2_ID]?.network).isEqualTo(NET_2)
|
|
||||||
assertThat(currentMap[NET_2_ID]?.capabilities).isEqualTo(NET_2_CAPS)
|
|
||||||
|
|
||||||
job.cancel()
|
|
||||||
scope.cancel()
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
fun testOnCapabilitesChanged_newCapabilitiesForExistingNetwork_areCaptured() = runBlocking {
|
|
||||||
// GIVEN a repo hooked up to [ConnectivityManager]
|
|
||||||
val scope = CoroutineScope(Dispatchers.Unconfined)
|
|
||||||
val repo = NetworkCapabilitiesRepo(
|
|
||||||
connectivityManager = connectivityManager,
|
|
||||||
scope = scope,
|
|
||||||
logger = logger,
|
|
||||||
)
|
|
||||||
|
|
||||||
val job = launch(start = CoroutineStart.UNDISPATCHED) {
|
|
||||||
repo.dataStream.collect {
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
val callback: NetworkCallback = withArgCaptor {
|
|
||||||
verify(connectivityManager)
|
|
||||||
.registerNetworkCallback(any(NetworkRequest::class.java), capture())
|
|
||||||
}
|
|
||||||
|
|
||||||
// WHEN a network is added, and then its capabilities are changed
|
|
||||||
callback.onCapabilitiesChanged(NET_1, NET_1_CAPS)
|
|
||||||
callback.onCapabilitiesChanged(NET_1, NET_2_CAPS)
|
|
||||||
|
|
||||||
val currentMap = repo.dataStream.value
|
|
||||||
|
|
||||||
// THEN the current state of the flow reflects the new capabilities
|
|
||||||
assertThat(currentMap[NET_1_ID]?.capabilities).isEqualTo(NET_2_CAPS)
|
|
||||||
|
|
||||||
job.cancel()
|
|
||||||
scope.cancel()
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
fun testOnLost_networkIsRemoved() = runBlocking {
|
|
||||||
// GIVEN a repo hooked up to [ConnectivityManager]
|
|
||||||
val scope = CoroutineScope(Dispatchers.Unconfined)
|
|
||||||
val repo = NetworkCapabilitiesRepo(
|
|
||||||
connectivityManager = connectivityManager,
|
|
||||||
scope = scope,
|
|
||||||
logger = logger,
|
|
||||||
)
|
|
||||||
|
|
||||||
val job = launch(start = CoroutineStart.UNDISPATCHED) {
|
|
||||||
repo.dataStream.collect {
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
val callback: NetworkCallback = withArgCaptor {
|
|
||||||
verify(connectivityManager)
|
|
||||||
.registerNetworkCallback(any(NetworkRequest::class.java), capture())
|
|
||||||
}
|
|
||||||
|
|
||||||
// WHEN two new networks are added, and one is removed
|
|
||||||
callback.onCapabilitiesChanged(NET_1, NET_1_CAPS)
|
|
||||||
callback.onCapabilitiesChanged(NET_2, NET_2_CAPS)
|
|
||||||
callback.onLost(NET_1)
|
|
||||||
|
|
||||||
val currentMap = repo.dataStream.value
|
|
||||||
|
|
||||||
// THEN the current state of the flow reflects only the remaining network
|
|
||||||
assertThat(currentMap[NET_1_ID]).isNull()
|
|
||||||
assertThat(currentMap[NET_2_ID]?.network).isEqualTo(NET_2)
|
|
||||||
assertThat(currentMap[NET_2_ID]?.capabilities).isEqualTo(NET_2_CAPS)
|
|
||||||
|
|
||||||
job.cancel()
|
|
||||||
scope.cancel()
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
fun testOnLost_noNetworks_doesNotCrash() = runBlocking {
|
|
||||||
// GIVEN a repo hooked up to [ConnectivityManager]
|
|
||||||
val scope = CoroutineScope(Dispatchers.Unconfined)
|
|
||||||
val repo = NetworkCapabilitiesRepo(
|
|
||||||
connectivityManager = connectivityManager,
|
|
||||||
scope = scope,
|
|
||||||
logger = logger,
|
|
||||||
)
|
|
||||||
|
|
||||||
val job = launch(start = CoroutineStart.UNDISPATCHED) {
|
|
||||||
repo.dataStream.collect {
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
val callback: NetworkCallback = withArgCaptor {
|
|
||||||
verify(connectivityManager)
|
|
||||||
.registerNetworkCallback(any(NetworkRequest::class.java), capture())
|
|
||||||
}
|
|
||||||
|
|
||||||
// WHEN no networks are added, and one is removed
|
|
||||||
callback.onLost(NET_1)
|
|
||||||
|
|
||||||
val currentMap = repo.dataStream.value
|
|
||||||
|
|
||||||
// THEN the current state of the flow shows no networks
|
|
||||||
assertThat(currentMap).isEmpty()
|
|
||||||
|
|
||||||
job.cancel()
|
|
||||||
scope.cancel()
|
|
||||||
}
|
|
||||||
|
|
||||||
private val NET_1_ID = 100
|
|
||||||
private val NET_1 = mock<Network>().also {
|
|
||||||
whenever(it.getNetId()).thenReturn(NET_1_ID)
|
|
||||||
}
|
|
||||||
private val NET_2_ID = 200
|
|
||||||
private val NET_2 = mock<Network>().also {
|
|
||||||
whenever(it.getNetId()).thenReturn(NET_2_ID)
|
|
||||||
}
|
|
||||||
|
|
||||||
private val NET_1_CAPS = NetworkCapabilities.Builder()
|
|
||||||
.addTransportType(TRANSPORT_CELLULAR)
|
|
||||||
.addCapability(NET_CAPABILITY_VALIDATED)
|
|
||||||
.build()
|
|
||||||
|
|
||||||
private val NET_2_CAPS = NetworkCapabilities.Builder()
|
|
||||||
.addTransportType(TRANSPORT_WIFI)
|
|
||||||
.addCapability(NET_CAPABILITY_NOT_METERED)
|
|
||||||
.addCapability(NET_CAPABILITY_VALIDATED)
|
|
||||||
.build()
|
|
||||||
}
|
|
||||||
@@ -16,16 +16,26 @@
|
|||||||
|
|
||||||
package com.android.systemui.statusbar.pipeline.wifi.data.repository
|
package com.android.systemui.statusbar.pipeline.wifi.data.repository
|
||||||
|
|
||||||
|
import android.net.ConnectivityManager
|
||||||
|
import android.net.Network
|
||||||
|
import android.net.NetworkCapabilities
|
||||||
|
import android.net.NetworkCapabilities.TRANSPORT_CELLULAR
|
||||||
|
import android.net.NetworkCapabilities.TRANSPORT_WIFI
|
||||||
|
import android.net.vcn.VcnTransportInfo
|
||||||
|
import android.net.wifi.WifiInfo
|
||||||
import android.net.wifi.WifiManager
|
import android.net.wifi.WifiManager
|
||||||
import android.net.wifi.WifiManager.TrafficStateCallback
|
import android.net.wifi.WifiManager.TrafficStateCallback
|
||||||
import androidx.test.filters.SmallTest
|
import androidx.test.filters.SmallTest
|
||||||
import com.android.systemui.SysuiTestCase
|
import com.android.systemui.SysuiTestCase
|
||||||
import com.android.systemui.statusbar.pipeline.shared.ConnectivityPipelineLogger
|
import com.android.systemui.statusbar.pipeline.shared.ConnectivityPipelineLogger
|
||||||
import com.android.systemui.statusbar.pipeline.wifi.data.model.WifiActivityModel
|
import com.android.systemui.statusbar.pipeline.wifi.data.model.WifiActivityModel
|
||||||
|
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.ACTIVITY_DEFAULT
|
||||||
|
import com.android.systemui.statusbar.pipeline.wifi.data.repository.WifiRepositoryImpl.Companion.WIFI_NETWORK_DEFAULT
|
||||||
import com.android.systemui.util.concurrency.FakeExecutor
|
import com.android.systemui.util.concurrency.FakeExecutor
|
||||||
import com.android.systemui.util.mockito.any
|
import com.android.systemui.util.mockito.any
|
||||||
import com.android.systemui.util.mockito.argumentCaptor
|
import com.android.systemui.util.mockito.argumentCaptor
|
||||||
|
import com.android.systemui.util.mockito.mock
|
||||||
import com.android.systemui.util.time.FakeSystemClock
|
import com.android.systemui.util.time.FakeSystemClock
|
||||||
import com.google.common.truth.Truth.assertThat
|
import com.google.common.truth.Truth.assertThat
|
||||||
import java.util.concurrent.Executor
|
import java.util.concurrent.Executor
|
||||||
@@ -38,6 +48,7 @@ import org.junit.Before
|
|||||||
import org.junit.Test
|
import org.junit.Test
|
||||||
import org.mockito.Mock
|
import org.mockito.Mock
|
||||||
import org.mockito.Mockito.verify
|
import org.mockito.Mockito.verify
|
||||||
|
import org.mockito.Mockito.`when` as whenever
|
||||||
import org.mockito.MockitoAnnotations
|
import org.mockito.MockitoAnnotations
|
||||||
|
|
||||||
@OptIn(ExperimentalCoroutinesApi::class)
|
@OptIn(ExperimentalCoroutinesApi::class)
|
||||||
@@ -47,6 +58,7 @@ class WifiRepositoryImplTest : SysuiTestCase() {
|
|||||||
private lateinit var underTest: WifiRepositoryImpl
|
private lateinit var underTest: WifiRepositoryImpl
|
||||||
|
|
||||||
@Mock private lateinit var logger: ConnectivityPipelineLogger
|
@Mock private lateinit var logger: ConnectivityPipelineLogger
|
||||||
|
@Mock private lateinit var connectivityManager: ConnectivityManager
|
||||||
@Mock private lateinit var wifiManager: WifiManager
|
@Mock private lateinit var wifiManager: WifiManager
|
||||||
private lateinit var executor: Executor
|
private lateinit var executor: Executor
|
||||||
|
|
||||||
@@ -54,11 +66,347 @@ class WifiRepositoryImplTest : SysuiTestCase() {
|
|||||||
fun setUp() {
|
fun setUp() {
|
||||||
MockitoAnnotations.initMocks(this)
|
MockitoAnnotations.initMocks(this)
|
||||||
executor = FakeExecutor(FakeSystemClock())
|
executor = FakeExecutor(FakeSystemClock())
|
||||||
|
|
||||||
|
underTest = WifiRepositoryImpl(
|
||||||
|
connectivityManager,
|
||||||
|
wifiManager,
|
||||||
|
executor,
|
||||||
|
logger,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun wifiNetwork_initiallyGetsDefault() = runBlocking(IMMEDIATE) {
|
||||||
|
var latest: WifiNetworkModel? = null
|
||||||
|
val job = underTest
|
||||||
|
.wifiNetwork
|
||||||
|
.onEach { latest = it }
|
||||||
|
.launchIn(this)
|
||||||
|
|
||||||
|
assertThat(latest).isEqualTo(WIFI_NETWORK_DEFAULT)
|
||||||
|
|
||||||
|
job.cancel()
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun wifiNetwork_primaryWifiNetworkAdded_flowHasNetwork() = runBlocking(IMMEDIATE) {
|
||||||
|
var latest: WifiNetworkModel? = null
|
||||||
|
val job = underTest
|
||||||
|
.wifiNetwork
|
||||||
|
.onEach { latest = it }
|
||||||
|
.launchIn(this)
|
||||||
|
|
||||||
|
val wifiInfo = mock<WifiInfo>().apply {
|
||||||
|
whenever(this.ssid).thenReturn(SSID)
|
||||||
|
whenever(this.isPrimary).thenReturn(true)
|
||||||
|
}
|
||||||
|
val network = mock<Network>().apply {
|
||||||
|
whenever(this.getNetId()).thenReturn(NETWORK_ID)
|
||||||
|
}
|
||||||
|
|
||||||
|
getNetworkCallback().onCapabilitiesChanged(network, createWifiNetworkCapabilities(wifiInfo))
|
||||||
|
|
||||||
|
assertThat(latest is WifiNetworkModel.Active).isTrue()
|
||||||
|
val latestActive = latest as WifiNetworkModel.Active
|
||||||
|
assertThat(latestActive.networkId).isEqualTo(NETWORK_ID)
|
||||||
|
assertThat(latestActive.ssid).isEqualTo(SSID)
|
||||||
|
|
||||||
|
job.cancel()
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun wifiNetwork_nonPrimaryWifiNetworkAdded_flowHasNoNetwork() = runBlocking(IMMEDIATE) {
|
||||||
|
var latest: WifiNetworkModel? = null
|
||||||
|
val job = underTest
|
||||||
|
.wifiNetwork
|
||||||
|
.onEach { latest = it }
|
||||||
|
.launchIn(this)
|
||||||
|
|
||||||
|
val wifiInfo = mock<WifiInfo>().apply {
|
||||||
|
whenever(this.ssid).thenReturn(SSID)
|
||||||
|
whenever(this.isPrimary).thenReturn(false)
|
||||||
|
}
|
||||||
|
|
||||||
|
getNetworkCallback().onCapabilitiesChanged(NETWORK, createWifiNetworkCapabilities(wifiInfo))
|
||||||
|
|
||||||
|
assertThat(latest is WifiNetworkModel.Inactive).isTrue()
|
||||||
|
|
||||||
|
job.cancel()
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun wifiNetwork_cellularVcnNetworkAdded_flowHasNetwork() = runBlocking(IMMEDIATE) {
|
||||||
|
var latest: WifiNetworkModel? = null
|
||||||
|
val job = underTest
|
||||||
|
.wifiNetwork
|
||||||
|
.onEach { latest = it }
|
||||||
|
.launchIn(this)
|
||||||
|
|
||||||
|
val capabilities = mock<NetworkCapabilities>().apply {
|
||||||
|
whenever(this.hasTransport(TRANSPORT_CELLULAR)).thenReturn(true)
|
||||||
|
whenever(this.transportInfo).thenReturn(VcnTransportInfo(PRIMARY_WIFI_INFO))
|
||||||
|
}
|
||||||
|
|
||||||
|
getNetworkCallback().onCapabilitiesChanged(NETWORK, capabilities)
|
||||||
|
|
||||||
|
assertThat(latest is WifiNetworkModel.Active).isTrue()
|
||||||
|
val latestActive = latest as WifiNetworkModel.Active
|
||||||
|
assertThat(latestActive.networkId).isEqualTo(NETWORK_ID)
|
||||||
|
assertThat(latestActive.ssid).isEqualTo(SSID)
|
||||||
|
|
||||||
|
job.cancel()
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun wifiNetwork_nonPrimaryCellularVcnNetworkAdded_flowHasNoNetwork() = runBlocking(IMMEDIATE) {
|
||||||
|
var latest: WifiNetworkModel? = null
|
||||||
|
val job = underTest
|
||||||
|
.wifiNetwork
|
||||||
|
.onEach { latest = it }
|
||||||
|
.launchIn(this)
|
||||||
|
|
||||||
|
val wifiInfo = mock<WifiInfo>().apply {
|
||||||
|
whenever(this.ssid).thenReturn(SSID)
|
||||||
|
whenever(this.isPrimary).thenReturn(false)
|
||||||
|
}
|
||||||
|
val capabilities = mock<NetworkCapabilities>().apply {
|
||||||
|
whenever(this.hasTransport(TRANSPORT_CELLULAR)).thenReturn(true)
|
||||||
|
whenever(this.transportInfo).thenReturn(VcnTransportInfo(wifiInfo))
|
||||||
|
}
|
||||||
|
|
||||||
|
getNetworkCallback().onCapabilitiesChanged(NETWORK, capabilities)
|
||||||
|
|
||||||
|
assertThat(latest is WifiNetworkModel.Inactive).isTrue()
|
||||||
|
|
||||||
|
job.cancel()
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun wifiNetwork_cellularNotVcnNetworkAdded_flowHasNoNetwork() = runBlocking(IMMEDIATE) {
|
||||||
|
var latest: WifiNetworkModel? = null
|
||||||
|
val job = underTest
|
||||||
|
.wifiNetwork
|
||||||
|
.onEach { latest = it }
|
||||||
|
.launchIn(this)
|
||||||
|
|
||||||
|
val capabilities = mock<NetworkCapabilities>().apply {
|
||||||
|
whenever(this.hasTransport(TRANSPORT_CELLULAR)).thenReturn(true)
|
||||||
|
whenever(this.transportInfo).thenReturn(mock())
|
||||||
|
}
|
||||||
|
|
||||||
|
getNetworkCallback().onCapabilitiesChanged(NETWORK, capabilities)
|
||||||
|
|
||||||
|
assertThat(latest is WifiNetworkModel.Inactive).isTrue()
|
||||||
|
|
||||||
|
job.cancel()
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun wifiNetwork_newPrimaryWifiNetwork_flowHasNewNetwork() = runBlocking(IMMEDIATE) {
|
||||||
|
var latest: WifiNetworkModel? = null
|
||||||
|
val job = underTest
|
||||||
|
.wifiNetwork
|
||||||
|
.onEach { latest = it }
|
||||||
|
.launchIn(this)
|
||||||
|
|
||||||
|
// Start with the original network
|
||||||
|
getNetworkCallback()
|
||||||
|
.onCapabilitiesChanged(NETWORK, createWifiNetworkCapabilities(PRIMARY_WIFI_INFO))
|
||||||
|
|
||||||
|
// WHEN we update to a new primary network
|
||||||
|
val newNetworkId = 456
|
||||||
|
val newNetwork = mock<Network>().apply {
|
||||||
|
whenever(this.getNetId()).thenReturn(newNetworkId)
|
||||||
|
}
|
||||||
|
val newSsid = "CD"
|
||||||
|
val newWifiInfo = mock<WifiInfo>().apply {
|
||||||
|
whenever(this.ssid).thenReturn(newSsid)
|
||||||
|
whenever(this.isPrimary).thenReturn(true)
|
||||||
|
}
|
||||||
|
|
||||||
|
getNetworkCallback().onCapabilitiesChanged(
|
||||||
|
newNetwork, createWifiNetworkCapabilities(newWifiInfo)
|
||||||
|
)
|
||||||
|
|
||||||
|
// THEN we use the new network
|
||||||
|
assertThat(latest is WifiNetworkModel.Active).isTrue()
|
||||||
|
val latestActive = latest as WifiNetworkModel.Active
|
||||||
|
assertThat(latestActive.networkId).isEqualTo(newNetworkId)
|
||||||
|
assertThat(latestActive.ssid).isEqualTo(newSsid)
|
||||||
|
|
||||||
|
job.cancel()
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun wifiNetwork_newNonPrimaryWifiNetwork_flowHasOldNetwork() = runBlocking(IMMEDIATE) {
|
||||||
|
var latest: WifiNetworkModel? = null
|
||||||
|
val job = underTest
|
||||||
|
.wifiNetwork
|
||||||
|
.onEach { latest = it }
|
||||||
|
.launchIn(this)
|
||||||
|
|
||||||
|
// Start with the original network
|
||||||
|
getNetworkCallback()
|
||||||
|
.onCapabilitiesChanged(NETWORK, createWifiNetworkCapabilities(PRIMARY_WIFI_INFO))
|
||||||
|
|
||||||
|
// WHEN we notify of a new but non-primary network
|
||||||
|
val newNetworkId = 456
|
||||||
|
val newNetwork = mock<Network>().apply {
|
||||||
|
whenever(this.getNetId()).thenReturn(newNetworkId)
|
||||||
|
}
|
||||||
|
val newSsid = "EF"
|
||||||
|
val newWifiInfo = mock<WifiInfo>().apply {
|
||||||
|
whenever(this.ssid).thenReturn(newSsid)
|
||||||
|
whenever(this.isPrimary).thenReturn(false)
|
||||||
|
}
|
||||||
|
|
||||||
|
getNetworkCallback().onCapabilitiesChanged(
|
||||||
|
newNetwork, createWifiNetworkCapabilities(newWifiInfo)
|
||||||
|
)
|
||||||
|
|
||||||
|
// THEN we still use the original network
|
||||||
|
assertThat(latest is WifiNetworkModel.Active).isTrue()
|
||||||
|
val latestActive = latest as WifiNetworkModel.Active
|
||||||
|
assertThat(latestActive.networkId).isEqualTo(NETWORK_ID)
|
||||||
|
assertThat(latestActive.ssid).isEqualTo(SSID)
|
||||||
|
|
||||||
|
job.cancel()
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun wifiNetwork_newNetworkCapabilities_flowHasNewData() = runBlocking(IMMEDIATE) {
|
||||||
|
var latest: WifiNetworkModel? = null
|
||||||
|
val job = underTest
|
||||||
|
.wifiNetwork
|
||||||
|
.onEach { latest = it }
|
||||||
|
.launchIn(this)
|
||||||
|
|
||||||
|
val wifiInfo = mock<WifiInfo>().apply {
|
||||||
|
whenever(this.ssid).thenReturn(SSID)
|
||||||
|
whenever(this.isPrimary).thenReturn(true)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Start with the original network
|
||||||
|
getNetworkCallback()
|
||||||
|
.onCapabilitiesChanged(NETWORK, createWifiNetworkCapabilities(wifiInfo))
|
||||||
|
|
||||||
|
// WHEN we keep the same network ID but change the SSID
|
||||||
|
val newSsid = "CD"
|
||||||
|
val newWifiInfo = mock<WifiInfo>().apply {
|
||||||
|
whenever(this.ssid).thenReturn(newSsid)
|
||||||
|
whenever(this.isPrimary).thenReturn(true)
|
||||||
|
}
|
||||||
|
|
||||||
|
getNetworkCallback()
|
||||||
|
.onCapabilitiesChanged(NETWORK, createWifiNetworkCapabilities(newWifiInfo))
|
||||||
|
|
||||||
|
// THEN we've updated to the new SSID
|
||||||
|
assertThat(latest is WifiNetworkModel.Active).isTrue()
|
||||||
|
val latestActive = latest as WifiNetworkModel.Active
|
||||||
|
assertThat(latestActive.networkId).isEqualTo(NETWORK_ID)
|
||||||
|
assertThat(latestActive.ssid).isEqualTo(newSsid)
|
||||||
|
|
||||||
|
job.cancel()
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun wifiNetwork_noCurrentNetwork_networkLost_flowHasNoNetwork() = runBlocking(IMMEDIATE) {
|
||||||
|
var latest: WifiNetworkModel? = null
|
||||||
|
val job = underTest
|
||||||
|
.wifiNetwork
|
||||||
|
.onEach { latest = it }
|
||||||
|
.launchIn(this)
|
||||||
|
|
||||||
|
// WHEN we receive #onLost without any #onCapabilitiesChanged beforehand
|
||||||
|
getNetworkCallback().onLost(NETWORK)
|
||||||
|
|
||||||
|
// THEN there's no crash and we still have no network
|
||||||
|
assertThat(latest is WifiNetworkModel.Inactive).isTrue()
|
||||||
|
|
||||||
|
job.cancel()
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun wifiNetwork_currentNetworkLost_flowHasNoNetwork() = runBlocking(IMMEDIATE) {
|
||||||
|
var latest: WifiNetworkModel? = null
|
||||||
|
val job = underTest
|
||||||
|
.wifiNetwork
|
||||||
|
.onEach { latest = it }
|
||||||
|
.launchIn(this)
|
||||||
|
|
||||||
|
getNetworkCallback()
|
||||||
|
.onCapabilitiesChanged(NETWORK, createWifiNetworkCapabilities(PRIMARY_WIFI_INFO))
|
||||||
|
assertThat((latest as WifiNetworkModel.Active).networkId).isEqualTo(NETWORK_ID)
|
||||||
|
|
||||||
|
// WHEN we lose our current network
|
||||||
|
getNetworkCallback().onLost(NETWORK)
|
||||||
|
|
||||||
|
// THEN we update to no network
|
||||||
|
assertThat(latest is WifiNetworkModel.Inactive).isTrue()
|
||||||
|
|
||||||
|
job.cancel()
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun wifiNetwork_unknownNetworkLost_flowHasPreviousNetwork() = runBlocking(IMMEDIATE) {
|
||||||
|
var latest: WifiNetworkModel? = null
|
||||||
|
val job = underTest
|
||||||
|
.wifiNetwork
|
||||||
|
.onEach { latest = it }
|
||||||
|
.launchIn(this)
|
||||||
|
|
||||||
|
getNetworkCallback()
|
||||||
|
.onCapabilitiesChanged(NETWORK, createWifiNetworkCapabilities(PRIMARY_WIFI_INFO))
|
||||||
|
assertThat((latest as WifiNetworkModel.Active).networkId).isEqualTo(NETWORK_ID)
|
||||||
|
|
||||||
|
// WHEN we lose an unknown network
|
||||||
|
val unknownNetwork = mock<Network>().apply {
|
||||||
|
whenever(this.getNetId()).thenReturn(543)
|
||||||
|
}
|
||||||
|
getNetworkCallback().onLost(unknownNetwork)
|
||||||
|
|
||||||
|
// THEN we still have our previous network
|
||||||
|
assertThat(latest is WifiNetworkModel.Active).isTrue()
|
||||||
|
val latestActive = latest as WifiNetworkModel.Active
|
||||||
|
assertThat(latestActive.networkId).isEqualTo(NETWORK_ID)
|
||||||
|
assertThat(latestActive.ssid).isEqualTo(SSID)
|
||||||
|
|
||||||
|
job.cancel()
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun wifiNetwork_notCurrentNetworkLost_flowHasCurrentNetwork() = runBlocking(IMMEDIATE) {
|
||||||
|
var latest: WifiNetworkModel? = null
|
||||||
|
val job = underTest
|
||||||
|
.wifiNetwork
|
||||||
|
.onEach { latest = it }
|
||||||
|
.launchIn(this)
|
||||||
|
|
||||||
|
getNetworkCallback()
|
||||||
|
.onCapabilitiesChanged(NETWORK, createWifiNetworkCapabilities(PRIMARY_WIFI_INFO))
|
||||||
|
assertThat((latest as WifiNetworkModel.Active).networkId).isEqualTo(NETWORK_ID)
|
||||||
|
|
||||||
|
// WHEN we update to a new network...
|
||||||
|
val newNetworkId = 89
|
||||||
|
val newNetwork = mock<Network>().apply {
|
||||||
|
whenever(this.getNetId()).thenReturn(newNetworkId)
|
||||||
|
}
|
||||||
|
getNetworkCallback().onCapabilitiesChanged(
|
||||||
|
newNetwork, createWifiNetworkCapabilities(PRIMARY_WIFI_INFO)
|
||||||
|
)
|
||||||
|
// ...and lose the old network
|
||||||
|
getNetworkCallback().onLost(NETWORK)
|
||||||
|
|
||||||
|
// THEN we still have the new network
|
||||||
|
assertThat((latest as WifiNetworkModel.Active).networkId).isEqualTo(newNetworkId)
|
||||||
|
|
||||||
|
job.cancel()
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun wifiActivity_nullWifiManager_receivesDefault() = runBlocking(IMMEDIATE) {
|
fun wifiActivity_nullWifiManager_receivesDefault() = runBlocking(IMMEDIATE) {
|
||||||
underTest = WifiRepositoryImpl(
|
underTest = WifiRepositoryImpl(
|
||||||
|
connectivityManager,
|
||||||
wifiManager = null,
|
wifiManager = null,
|
||||||
executor,
|
executor,
|
||||||
logger,
|
logger,
|
||||||
@@ -77,12 +425,6 @@ class WifiRepositoryImplTest : SysuiTestCase() {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun wifiActivity_callbackGivesNone_activityFlowHasNone() = runBlocking(IMMEDIATE) {
|
fun wifiActivity_callbackGivesNone_activityFlowHasNone() = runBlocking(IMMEDIATE) {
|
||||||
underTest = WifiRepositoryImpl(
|
|
||||||
wifiManager,
|
|
||||||
executor,
|
|
||||||
logger,
|
|
||||||
)
|
|
||||||
|
|
||||||
var latest: WifiActivityModel? = null
|
var latest: WifiActivityModel? = null
|
||||||
val job = underTest
|
val job = underTest
|
||||||
.wifiActivity
|
.wifiActivity
|
||||||
@@ -100,12 +442,6 @@ class WifiRepositoryImplTest : SysuiTestCase() {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun wifiActivity_callbackGivesIn_activityFlowHasIn() = runBlocking(IMMEDIATE) {
|
fun wifiActivity_callbackGivesIn_activityFlowHasIn() = runBlocking(IMMEDIATE) {
|
||||||
underTest = WifiRepositoryImpl(
|
|
||||||
wifiManager,
|
|
||||||
executor,
|
|
||||||
logger,
|
|
||||||
)
|
|
||||||
|
|
||||||
var latest: WifiActivityModel? = null
|
var latest: WifiActivityModel? = null
|
||||||
val job = underTest
|
val job = underTest
|
||||||
.wifiActivity
|
.wifiActivity
|
||||||
@@ -123,12 +459,6 @@ class WifiRepositoryImplTest : SysuiTestCase() {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun wifiActivity_callbackGivesOut_activityFlowHasOut() = runBlocking(IMMEDIATE) {
|
fun wifiActivity_callbackGivesOut_activityFlowHasOut() = runBlocking(IMMEDIATE) {
|
||||||
underTest = WifiRepositoryImpl(
|
|
||||||
wifiManager,
|
|
||||||
executor,
|
|
||||||
logger,
|
|
||||||
)
|
|
||||||
|
|
||||||
var latest: WifiActivityModel? = null
|
var latest: WifiActivityModel? = null
|
||||||
val job = underTest
|
val job = underTest
|
||||||
.wifiActivity
|
.wifiActivity
|
||||||
@@ -146,12 +476,6 @@ class WifiRepositoryImplTest : SysuiTestCase() {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun wifiActivity_callbackGivesInout_activityFlowHasInAndOut() = runBlocking(IMMEDIATE) {
|
fun wifiActivity_callbackGivesInout_activityFlowHasInAndOut() = runBlocking(IMMEDIATE) {
|
||||||
underTest = WifiRepositoryImpl(
|
|
||||||
wifiManager,
|
|
||||||
executor,
|
|
||||||
logger,
|
|
||||||
)
|
|
||||||
|
|
||||||
var latest: WifiActivityModel? = null
|
var latest: WifiActivityModel? = null
|
||||||
val job = underTest
|
val job = underTest
|
||||||
.wifiActivity
|
.wifiActivity
|
||||||
@@ -170,6 +494,30 @@ class WifiRepositoryImplTest : SysuiTestCase() {
|
|||||||
verify(wifiManager).registerTrafficStateCallback(any(), callbackCaptor.capture())
|
verify(wifiManager).registerTrafficStateCallback(any(), callbackCaptor.capture())
|
||||||
return callbackCaptor.value!!
|
return callbackCaptor.value!!
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun getNetworkCallback(): ConnectivityManager.NetworkCallback {
|
||||||
|
val callbackCaptor = argumentCaptor<ConnectivityManager.NetworkCallback>()
|
||||||
|
verify(connectivityManager).registerNetworkCallback(any(), callbackCaptor.capture())
|
||||||
|
return callbackCaptor.value!!
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun createWifiNetworkCapabilities(wifiInfo: WifiInfo) =
|
||||||
|
mock<NetworkCapabilities>().apply {
|
||||||
|
whenever(this.hasTransport(TRANSPORT_WIFI)).thenReturn(true)
|
||||||
|
whenever(this.transportInfo).thenReturn(wifiInfo)
|
||||||
|
}
|
||||||
|
|
||||||
|
private companion object {
|
||||||
|
const val NETWORK_ID = 45
|
||||||
|
val NETWORK = mock<Network>().apply {
|
||||||
|
whenever(this.getNetId()).thenReturn(NETWORK_ID)
|
||||||
|
}
|
||||||
|
const val SSID = "AB"
|
||||||
|
val PRIMARY_WIFI_INFO: WifiInfo = mock<WifiInfo>().apply {
|
||||||
|
whenever(this.ssid).thenReturn(SSID)
|
||||||
|
whenever(this.isPrimary).thenReturn(true)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private val IMMEDIATE = Dispatchers.Main.immediate
|
private val IMMEDIATE = Dispatchers.Main.immediate
|
||||||
|
|||||||
@@ -19,7 +19,7 @@ package com.android.systemui.statusbar.pipeline.wifi.domain.interactor
|
|||||||
import androidx.test.filters.SmallTest
|
import androidx.test.filters.SmallTest
|
||||||
import com.android.systemui.SysuiTestCase
|
import com.android.systemui.SysuiTestCase
|
||||||
import com.android.systemui.statusbar.pipeline.wifi.data.model.WifiActivityModel
|
import com.android.systemui.statusbar.pipeline.wifi.data.model.WifiActivityModel
|
||||||
import com.android.systemui.statusbar.pipeline.wifi.data.model.WifiModel
|
import com.android.systemui.statusbar.pipeline.wifi.data.model.WifiNetworkModel
|
||||||
import com.android.systemui.statusbar.pipeline.wifi.data.repository.FakeWifiRepository
|
import com.android.systemui.statusbar.pipeline.wifi.data.repository.FakeWifiRepository
|
||||||
import com.google.common.truth.Truth.assertThat
|
import com.google.common.truth.Truth.assertThat
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
@@ -47,7 +47,7 @@ class WifiInteractorTest : SysuiTestCase() {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun hasActivityIn_noInOrOut_outputsFalse() = runBlocking(IMMEDIATE) {
|
fun hasActivityIn_noInOrOut_outputsFalse() = runBlocking(IMMEDIATE) {
|
||||||
repository.setWifiModel(WifiModel(ssid = "AB"))
|
repository.setWifiNetwork(VALID_WIFI_NETWORK_MODEL)
|
||||||
repository.setWifiActivity(WifiActivityModel(hasActivityIn = false, hasActivityOut = false))
|
repository.setWifiActivity(WifiActivityModel(hasActivityIn = false, hasActivityOut = false))
|
||||||
|
|
||||||
var latest: Boolean? = null
|
var latest: Boolean? = null
|
||||||
@@ -63,7 +63,7 @@ class WifiInteractorTest : SysuiTestCase() {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun hasActivityIn_onlyOut_outputsFalse() = runBlocking(IMMEDIATE) {
|
fun hasActivityIn_onlyOut_outputsFalse() = runBlocking(IMMEDIATE) {
|
||||||
repository.setWifiModel(WifiModel(ssid = "AB"))
|
repository.setWifiNetwork(VALID_WIFI_NETWORK_MODEL)
|
||||||
repository.setWifiActivity(WifiActivityModel(hasActivityIn = false, hasActivityOut = true))
|
repository.setWifiActivity(WifiActivityModel(hasActivityIn = false, hasActivityOut = true))
|
||||||
|
|
||||||
var latest: Boolean? = null
|
var latest: Boolean? = null
|
||||||
@@ -79,7 +79,7 @@ class WifiInteractorTest : SysuiTestCase() {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun hasActivityIn_onlyIn_outputsTrue() = runBlocking(IMMEDIATE) {
|
fun hasActivityIn_onlyIn_outputsTrue() = runBlocking(IMMEDIATE) {
|
||||||
repository.setWifiModel(WifiModel(ssid = "AB"))
|
repository.setWifiNetwork(VALID_WIFI_NETWORK_MODEL)
|
||||||
repository.setWifiActivity(WifiActivityModel(hasActivityIn = true, hasActivityOut = false))
|
repository.setWifiActivity(WifiActivityModel(hasActivityIn = true, hasActivityOut = false))
|
||||||
|
|
||||||
var latest: Boolean? = null
|
var latest: Boolean? = null
|
||||||
@@ -95,7 +95,7 @@ class WifiInteractorTest : SysuiTestCase() {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun hasActivityIn_inAndOut_outputsTrue() = runBlocking(IMMEDIATE) {
|
fun hasActivityIn_inAndOut_outputsTrue() = runBlocking(IMMEDIATE) {
|
||||||
repository.setWifiModel(WifiModel(ssid = "AB"))
|
repository.setWifiNetwork(VALID_WIFI_NETWORK_MODEL)
|
||||||
repository.setWifiActivity(WifiActivityModel(hasActivityIn = true, hasActivityOut = true))
|
repository.setWifiActivity(WifiActivityModel(hasActivityIn = true, hasActivityOut = true))
|
||||||
|
|
||||||
var latest: Boolean? = null
|
var latest: Boolean? = null
|
||||||
@@ -111,7 +111,7 @@ class WifiInteractorTest : SysuiTestCase() {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun hasActivityIn_ssidNull_outputsFalse() = runBlocking(IMMEDIATE) {
|
fun hasActivityIn_ssidNull_outputsFalse() = runBlocking(IMMEDIATE) {
|
||||||
repository.setWifiModel(WifiModel(ssid = null))
|
repository.setWifiNetwork(WifiNetworkModel.Active(networkId = 1, ssid = null))
|
||||||
repository.setWifiActivity(WifiActivityModel(hasActivityIn = true, hasActivityOut = true))
|
repository.setWifiActivity(WifiActivityModel(hasActivityIn = true, hasActivityOut = true))
|
||||||
|
|
||||||
var latest: Boolean? = null
|
var latest: Boolean? = null
|
||||||
@@ -127,7 +127,7 @@ class WifiInteractorTest : SysuiTestCase() {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun hasActivityIn_multipleChanges_multipleOutputChanges() = runBlocking(IMMEDIATE) {
|
fun hasActivityIn_multipleChanges_multipleOutputChanges() = runBlocking(IMMEDIATE) {
|
||||||
repository.setWifiModel(WifiModel(ssid = "AB"))
|
repository.setWifiNetwork(VALID_WIFI_NETWORK_MODEL)
|
||||||
|
|
||||||
var latest: Boolean? = null
|
var latest: Boolean? = null
|
||||||
val job = underTest
|
val job = underTest
|
||||||
@@ -158,6 +158,10 @@ class WifiInteractorTest : SysuiTestCase() {
|
|||||||
|
|
||||||
job.cancel()
|
job.cancel()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
val VALID_WIFI_NETWORK_MODEL = WifiNetworkModel.Active(networkId = 1, ssid = "AB")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private val IMMEDIATE = Dispatchers.Main.immediate
|
private val IMMEDIATE = Dispatchers.Main.immediate
|
||||||
|
|||||||
@@ -20,7 +20,7 @@ import androidx.test.filters.SmallTest
|
|||||||
import com.android.systemui.SysuiTestCase
|
import com.android.systemui.SysuiTestCase
|
||||||
import com.android.systemui.statusbar.pipeline.shared.ConnectivityPipelineLogger
|
import com.android.systemui.statusbar.pipeline.shared.ConnectivityPipelineLogger
|
||||||
import com.android.systemui.statusbar.pipeline.wifi.data.model.WifiActivityModel
|
import com.android.systemui.statusbar.pipeline.wifi.data.model.WifiActivityModel
|
||||||
import com.android.systemui.statusbar.pipeline.wifi.data.model.WifiModel
|
import com.android.systemui.statusbar.pipeline.wifi.data.model.WifiNetworkModel
|
||||||
import com.android.systemui.statusbar.pipeline.wifi.data.repository.FakeWifiRepository
|
import com.android.systemui.statusbar.pipeline.wifi.data.repository.FakeWifiRepository
|
||||||
import com.android.systemui.statusbar.pipeline.wifi.domain.interactor.WifiInteractor
|
import com.android.systemui.statusbar.pipeline.wifi.domain.interactor.WifiInteractor
|
||||||
import com.android.systemui.statusbar.pipeline.wifi.shared.WifiConstants
|
import com.android.systemui.statusbar.pipeline.wifi.shared.WifiConstants
|
||||||
@@ -61,7 +61,7 @@ class WifiViewModelTest : SysuiTestCase() {
|
|||||||
)
|
)
|
||||||
|
|
||||||
// Set up with a valid SSID
|
// Set up with a valid SSID
|
||||||
repository.setWifiModel(WifiModel(ssid = "AB"))
|
repository.setWifiNetwork(WifiNetworkModel.Active(networkId = 1, ssid = "AB"))
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
|||||||
Reference in New Issue
Block a user