Merge "[Sb Refactor] Define an initial data/domain/ui layer for the status bar connectivity architecture for wifi." into tm-qpr-dev am: 9dce321437
Original change: https://googleplex-android-review.googlesource.com/c/platform/frameworks/base/+/19558692 Change-Id: If9479d126a49ad7432e0aa5ef7c1b6732593b77c Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
This commit is contained in:
@@ -270,7 +270,7 @@ public class LogModule {
|
||||
@SysUISingleton
|
||||
@StatusBarConnectivityLog
|
||||
public static LogBuffer provideStatusBarConnectivityBuffer(LogBufferFactory factory) {
|
||||
return factory.create("StatusBarConnectivityLog", 64);
|
||||
return factory.create("SbConnectivity", 64);
|
||||
}
|
||||
|
||||
/** Allows logging buffers to be tweaked via adb on debug builds but not on prod builds. */
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
|
||||
package com.android.systemui.statusbar.pipeline
|
||||
|
||||
import com.android.systemui.statusbar.pipeline.repository.NetworkCapabilityInfo
|
||||
import com.android.systemui.statusbar.pipeline.wifi.data.repository.NetworkCapabilityInfo
|
||||
import kotlinx.coroutines.flow.StateFlow
|
||||
|
||||
/**
|
||||
|
||||
@@ -18,9 +18,9 @@ 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.repository.NetworkCapabilitiesRepo
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
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
|
||||
|
||||
@@ -20,14 +20,18 @@ import android.content.Context
|
||||
import com.android.systemui.CoreStartable
|
||||
import com.android.systemui.dagger.SysUISingleton
|
||||
import com.android.systemui.dagger.qualifiers.Application
|
||||
import com.android.systemui.statusbar.pipeline.repository.NetworkCapabilityInfo
|
||||
import com.android.systemui.statusbar.pipeline.wifi.data.repository.NetworkCapabilityInfo
|
||||
import com.android.systemui.statusbar.pipeline.wifi.ui.viewmodel.WifiViewModel
|
||||
import javax.inject.Inject
|
||||
import javax.inject.Provider
|
||||
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.emptyFlow
|
||||
import kotlinx.coroutines.flow.map
|
||||
import kotlinx.coroutines.flow.stateIn
|
||||
import kotlinx.coroutines.launch
|
||||
|
||||
/**
|
||||
* A processor that transforms raw connectivity information that we get from callbacks and turns it
|
||||
@@ -42,12 +46,16 @@ import kotlinx.coroutines.flow.stateIn
|
||||
class ConnectivityInfoProcessor @Inject constructor(
|
||||
connectivityInfoCollector: ConnectivityInfoCollector,
|
||||
context: Context,
|
||||
// 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.
|
||||
@Application private val scope: CoroutineScope,
|
||||
statusBarPipelineFlags: StatusBarPipelineFlags,
|
||||
private val statusBarPipelineFlags: StatusBarPipelineFlags,
|
||||
private val wifiViewModelProvider: Provider<WifiViewModel>,
|
||||
) : 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()
|
||||
@@ -60,6 +68,14 @@ class ConnectivityInfoProcessor @Inject constructor(
|
||||
)
|
||||
|
||||
override fun start() {
|
||||
if (!statusBarPipelineFlags.isNewPipelineEnabled()) {
|
||||
return
|
||||
}
|
||||
// TODO(b/238425913): The view binder should do this instead. For now, do it here so we can
|
||||
// see the logs.
|
||||
scope.launch {
|
||||
wifiViewModelProvider.get().isActivityInVisible.collect { }
|
||||
}
|
||||
}
|
||||
|
||||
private fun RawConnectivityInfo.process(): ProcessedConnectivityInfo {
|
||||
|
||||
@@ -1,59 +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.Network
|
||||
import android.net.NetworkCapabilities
|
||||
import com.android.systemui.dagger.SysUISingleton
|
||||
import com.android.systemui.log.LogBuffer
|
||||
import com.android.systemui.log.LogLevel
|
||||
import com.android.systemui.log.dagger.StatusBarConnectivityLog
|
||||
import javax.inject.Inject
|
||||
|
||||
@SysUISingleton
|
||||
class ConnectivityPipelineLogger @Inject constructor(
|
||||
@StatusBarConnectivityLog private val buffer: LogBuffer,
|
||||
) {
|
||||
fun logOnCapabilitiesChanged(network: Network, networkCapabilities: NetworkCapabilities) {
|
||||
buffer.log(
|
||||
TAG,
|
||||
LogLevel.INFO,
|
||||
{
|
||||
int1 = network.getNetId()
|
||||
str1 = networkCapabilities.toString()
|
||||
},
|
||||
{
|
||||
"onCapabilitiesChanged: net=$int1 capabilities=$str1"
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
fun logOnLost(network: Network) {
|
||||
buffer.log(
|
||||
TAG,
|
||||
LogLevel.INFO,
|
||||
{
|
||||
int1 = network.getNetId()
|
||||
},
|
||||
{
|
||||
"onLost: net=$int1"
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private const val TAG = "SbConnectivityPipeline"
|
||||
@@ -20,6 +20,8 @@ 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.wifi.data.repository.WifiRepository
|
||||
import com.android.systemui.statusbar.pipeline.wifi.data.repository.WifiRepositoryImpl
|
||||
import dagger.Binds
|
||||
import dagger.Module
|
||||
import dagger.multibindings.ClassKey
|
||||
@@ -37,4 +39,7 @@ abstract class StatusBarPipelineModule {
|
||||
abstract fun provideConnectivityInfoCollector(
|
||||
impl: ConnectivityInfoCollectorImpl
|
||||
): ConnectivityInfoCollector
|
||||
|
||||
@Binds
|
||||
abstract fun wifiRepository(impl: WifiRepositoryImpl): WifiRepository
|
||||
}
|
||||
|
||||
@@ -0,0 +1,106 @@
|
||||
/*
|
||||
* 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.shared
|
||||
|
||||
import android.net.Network
|
||||
import android.net.NetworkCapabilities
|
||||
import com.android.systemui.dagger.SysUISingleton
|
||||
import com.android.systemui.log.LogBuffer
|
||||
import com.android.systemui.log.LogLevel
|
||||
import com.android.systemui.log.dagger.StatusBarConnectivityLog
|
||||
import com.android.systemui.statusbar.pipeline.shared.ConnectivityPipelineLogger.Companion.toString
|
||||
import javax.inject.Inject
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.onEach
|
||||
|
||||
@SysUISingleton
|
||||
class ConnectivityPipelineLogger @Inject constructor(
|
||||
@StatusBarConnectivityLog private val buffer: LogBuffer,
|
||||
) {
|
||||
fun logInputChange(callbackName: String, changeInfo: String) {
|
||||
buffer.log(
|
||||
SB_LOGGING_TAG,
|
||||
LogLevel.INFO,
|
||||
{
|
||||
str1 = callbackName
|
||||
str2 = changeInfo
|
||||
},
|
||||
{
|
||||
"Input: $str1: $str2"
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
fun logOutputChange(outputParamName: String, changeInfo: String) {
|
||||
buffer.log(
|
||||
SB_LOGGING_TAG,
|
||||
LogLevel.INFO,
|
||||
{
|
||||
str1 = outputParamName
|
||||
str2 = changeInfo
|
||||
},
|
||||
{
|
||||
"Output: $str1: $str2"
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
fun logOnCapabilitiesChanged(network: Network, networkCapabilities: NetworkCapabilities) {
|
||||
buffer.log(
|
||||
SB_LOGGING_TAG,
|
||||
LogLevel.INFO,
|
||||
{
|
||||
int1 = network.getNetId()
|
||||
str1 = networkCapabilities.toString()
|
||||
},
|
||||
{
|
||||
"onCapabilitiesChanged: net=$int1 capabilities=$str1"
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
fun logOnLost(network: Network) {
|
||||
buffer.log(
|
||||
SB_LOGGING_TAG,
|
||||
LogLevel.INFO,
|
||||
{
|
||||
int1 = network.getNetId()
|
||||
},
|
||||
{
|
||||
"onLost: net=$int1"
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
companion object {
|
||||
const val SB_LOGGING_TAG = "SbConnectivity"
|
||||
|
||||
/**
|
||||
* Log a change in one of the **outputs** to the connectivity pipeline.
|
||||
*
|
||||
* @param prettyPrint an optional function to transform the value into a readable string.
|
||||
* [toString] is used if no custom function is provided.
|
||||
*/
|
||||
fun <T : Any> Flow<T>.logOutputChange(
|
||||
logger: ConnectivityPipelineLogger,
|
||||
outputParamName: String,
|
||||
prettyPrint: (T) -> String = { it.toString() }
|
||||
): Flow<T> {
|
||||
return this.onEach { logger.logOutputChange(outputParamName, prettyPrint(it)) }
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
/*
|
||||
* 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 on the current wifi activity.
|
||||
*/
|
||||
data class WifiActivityModel(
|
||||
/** True if the wifi has activity in (download). */
|
||||
val hasActivityIn: Boolean,
|
||||
/** True if the wifi has activity out (upload). */
|
||||
val hasActivityOut: Boolean,
|
||||
)
|
||||
@@ -0,0 +1,29 @@
|
||||
/*
|
||||
* 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,
|
||||
)
|
||||
@@ -16,7 +16,7 @@
|
||||
|
||||
@file:OptIn(ExperimentalCoroutinesApi::class)
|
||||
|
||||
package com.android.systemui.statusbar.pipeline.repository
|
||||
package com.android.systemui.statusbar.pipeline.wifi.data.repository
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import android.net.ConnectivityManager
|
||||
@@ -25,7 +25,7 @@ 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.ConnectivityPipelineLogger
|
||||
import com.android.systemui.statusbar.pipeline.shared.ConnectivityPipelineLogger
|
||||
import javax.inject.Inject
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
||||
@@ -35,7 +35,11 @@ import kotlinx.coroutines.flow.StateFlow
|
||||
import kotlinx.coroutines.flow.callbackFlow
|
||||
import kotlinx.coroutines.flow.stateIn
|
||||
|
||||
/** Repository that contains all relevant [NetworkCapabilites] for the current networks */
|
||||
/**
|
||||
* 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,
|
||||
@@ -88,5 +92,3 @@ data class NetworkCapabilityInfo(
|
||||
val network: Network,
|
||||
val capabilities: NetworkCapabilities,
|
||||
)
|
||||
|
||||
private const val TAG = "ConnectivityRepository"
|
||||
@@ -0,0 +1,103 @@
|
||||
/*
|
||||
* 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.wifi.WifiManager
|
||||
import android.net.wifi.WifiManager.TrafficStateCallback
|
||||
import android.util.Log
|
||||
import com.android.systemui.common.coroutine.ConflatedCallbackFlow.conflatedCallbackFlow
|
||||
import com.android.systemui.dagger.SysUISingleton
|
||||
import com.android.systemui.dagger.qualifiers.Main
|
||||
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.wifi.data.model.WifiActivityModel
|
||||
import com.android.systemui.statusbar.pipeline.wifi.data.model.WifiModel
|
||||
import java.util.concurrent.Executor
|
||||
import javax.inject.Inject
|
||||
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
||||
import kotlinx.coroutines.channels.awaitClose
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.flowOf
|
||||
|
||||
/**
|
||||
* Provides data related to the wifi state.
|
||||
*/
|
||||
interface WifiRepository {
|
||||
/**
|
||||
* Observable for the current state of wifi; `null` when there is no active wifi.
|
||||
*/
|
||||
val wifiModel: Flow<WifiModel?>
|
||||
|
||||
/**
|
||||
* Observable for the current wifi network activity.
|
||||
*/
|
||||
val wifiActivity: Flow<WifiActivityModel>
|
||||
}
|
||||
|
||||
/** Real implementation of [WifiRepository]. */
|
||||
@OptIn(ExperimentalCoroutinesApi::class)
|
||||
@SysUISingleton
|
||||
class WifiRepositoryImpl @Inject constructor(
|
||||
wifiManager: WifiManager?,
|
||||
@Main mainExecutor: Executor,
|
||||
logger: ConnectivityPipelineLogger,
|
||||
) : WifiRepository {
|
||||
|
||||
// TODO(b/238425913): Actually implement the wifiModel flow.
|
||||
override val wifiModel: Flow<WifiModel?> = flowOf(WifiModel(ssid = "AB"))
|
||||
|
||||
override val wifiActivity: Flow<WifiActivityModel> =
|
||||
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(trafficStateToWifiActivityModel(state))
|
||||
}
|
||||
|
||||
wifiManager.registerTrafficStateCallback(mainExecutor, callback)
|
||||
trySend(ACTIVITY_DEFAULT)
|
||||
|
||||
awaitClose { wifiManager.unregisterTrafficStateCallback(callback) }
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
val ACTIVITY_DEFAULT = WifiActivityModel(hasActivityIn = false, hasActivityOut = false)
|
||||
|
||||
private fun trafficStateToWifiActivityModel(state: Int): WifiActivityModel {
|
||||
return WifiActivityModel(
|
||||
hasActivityIn = state == TrafficStateCallback.DATA_ACTIVITY_IN ||
|
||||
state == TrafficStateCallback.DATA_ACTIVITY_INOUT,
|
||||
hasActivityOut = state == TrafficStateCallback.DATA_ACTIVITY_OUT ||
|
||||
state == TrafficStateCallback.DATA_ACTIVITY_INOUT,
|
||||
)
|
||||
}
|
||||
|
||||
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"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
/*
|
||||
* 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.domain.interactor
|
||||
|
||||
import android.net.wifi.WifiManager
|
||||
import com.android.systemui.dagger.SysUISingleton
|
||||
import com.android.systemui.statusbar.pipeline.wifi.data.repository.WifiRepository
|
||||
import javax.inject.Inject
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.combine
|
||||
import kotlinx.coroutines.flow.map
|
||||
|
||||
/**
|
||||
* The business logic layer for the wifi icon.
|
||||
*
|
||||
* This interactor processes information from our data layer into information that the UI layer can
|
||||
* use.
|
||||
*/
|
||||
@SysUISingleton
|
||||
class WifiInteractor @Inject constructor(
|
||||
repository: WifiRepository,
|
||||
) {
|
||||
private val ssid: Flow<String?> = repository.wifiModel.map { info ->
|
||||
when {
|
||||
info == null -> null
|
||||
info.isPasspointAccessPoint || info.isOnlineSignUpForPasspointAccessPoint ->
|
||||
info.passpointProviderFriendlyName
|
||||
info.ssid != WifiManager.UNKNOWN_SSID -> info.ssid
|
||||
else -> null
|
||||
}
|
||||
}
|
||||
|
||||
val hasActivityIn: Flow<Boolean> = combine(repository.wifiActivity, ssid) { activity, ssid ->
|
||||
activity.hasActivityIn && ssid != null
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
/*
|
||||
* Copyright (C) 2022 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.systemui.statusbar.pipeline.wifi.shared
|
||||
|
||||
import android.content.Context
|
||||
import com.android.systemui.Dumpable
|
||||
import com.android.systemui.R
|
||||
import com.android.systemui.dagger.SysUISingleton
|
||||
import com.android.systemui.dump.DumpManager
|
||||
import com.android.systemui.statusbar.pipeline.shared.ConnectivityPipelineLogger.Companion.SB_LOGGING_TAG
|
||||
import java.io.PrintWriter
|
||||
import javax.inject.Inject
|
||||
|
||||
/**
|
||||
* An object storing constants that we use for calculating the wifi icon. Stored in a class for
|
||||
* logging purposes.
|
||||
*/
|
||||
@SysUISingleton
|
||||
class WifiConstants @Inject constructor(
|
||||
context: Context,
|
||||
dumpManager: DumpManager,
|
||||
) : Dumpable {
|
||||
init {
|
||||
dumpManager.registerDumpable("$SB_LOGGING_TAG:WifiConstants", this)
|
||||
}
|
||||
|
||||
/** True if we should show the activityIn/activityOut icons and false otherwise. */
|
||||
val shouldShowActivityConfig = context.resources.getBoolean(R.bool.config_showActivity)
|
||||
|
||||
override fun dump(pw: PrintWriter, args: Array<out String>) {
|
||||
pw.apply {
|
||||
println("shouldShowActivityConfig=$shouldShowActivityConfig")
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
/*
|
||||
* 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.ui.viewmodel
|
||||
|
||||
import com.android.systemui.statusbar.pipeline.shared.ConnectivityPipelineLogger
|
||||
import com.android.systemui.statusbar.pipeline.shared.ConnectivityPipelineLogger.Companion.logOutputChange
|
||||
import com.android.systemui.statusbar.pipeline.wifi.domain.interactor.WifiInteractor
|
||||
import com.android.systemui.statusbar.pipeline.wifi.shared.WifiConstants
|
||||
import javax.inject.Inject
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.flowOf
|
||||
|
||||
/**
|
||||
* Models the UI state for the status bar wifi icon.
|
||||
*
|
||||
* TODO(b/238425913): Hook this up to the real status bar wifi view using a view binder.
|
||||
*/
|
||||
class WifiViewModel @Inject constructor(
|
||||
private val constants: WifiConstants,
|
||||
private val logger: ConnectivityPipelineLogger,
|
||||
private val interactor: WifiInteractor,
|
||||
) {
|
||||
val isActivityInVisible: Flow<Boolean>
|
||||
get() =
|
||||
if (!constants.shouldShowActivityConfig) {
|
||||
flowOf(false)
|
||||
} else {
|
||||
interactor.hasActivityIn
|
||||
}
|
||||
.logOutputChange(logger, "activityInVisible")
|
||||
}
|
||||
@@ -20,7 +20,7 @@ import android.net.NetworkCapabilities
|
||||
import android.testing.AndroidTestingRunner
|
||||
import androidx.test.filters.SmallTest
|
||||
import com.android.systemui.SysuiTestCase
|
||||
import com.android.systemui.statusbar.pipeline.repository.NetworkCapabilityInfo
|
||||
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
|
||||
@@ -59,6 +59,7 @@ class ConnectivityInfoProcessorTest : SysuiTestCase() {
|
||||
context,
|
||||
scope,
|
||||
statusBarPipelineFlags,
|
||||
mock(),
|
||||
)
|
||||
|
||||
var mostRecentValue: ProcessedConnectivityInfo? = null
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.systemui.statusbar.pipeline
|
||||
package com.android.systemui.statusbar.pipeline.shared
|
||||
|
||||
import android.net.Network
|
||||
import android.net.NetworkCapabilities
|
||||
@@ -0,0 +1,40 @@
|
||||
/*
|
||||
* 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 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.repository.WifiRepositoryImpl.Companion.ACTIVITY_DEFAULT
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
|
||||
/** Fake implementation of [WifiRepository] exposing set methods for all the flows. */
|
||||
class FakeWifiRepository : WifiRepository {
|
||||
private val _wifiModel: MutableStateFlow<WifiModel?> = MutableStateFlow(null)
|
||||
override val wifiModel: Flow<WifiModel?> = _wifiModel
|
||||
|
||||
private val _wifiActivity = MutableStateFlow(ACTIVITY_DEFAULT)
|
||||
override val wifiActivity: Flow<WifiActivityModel> = _wifiActivity
|
||||
|
||||
fun setWifiModel(wifiModel: WifiModel?) {
|
||||
_wifiModel.value = wifiModel
|
||||
}
|
||||
|
||||
fun setWifiActivity(activity: WifiActivityModel) {
|
||||
_wifiActivity.value = activity
|
||||
}
|
||||
}
|
||||
@@ -14,7 +14,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.systemui.statusbar.pipeline.repository
|
||||
package com.android.systemui.statusbar.pipeline.wifi.data.repository
|
||||
|
||||
import android.net.ConnectivityManager
|
||||
import android.net.ConnectivityManager.NetworkCallback
|
||||
@@ -28,7 +28,7 @@ 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.ConnectivityPipelineLogger
|
||||
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
|
||||
@@ -0,0 +1,175 @@
|
||||
/*
|
||||
* 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.wifi.WifiManager
|
||||
import android.net.wifi.WifiManager.TrafficStateCallback
|
||||
import androidx.test.filters.SmallTest
|
||||
import com.android.systemui.SysuiTestCase
|
||||
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.repository.WifiRepositoryImpl.Companion.ACTIVITY_DEFAULT
|
||||
import com.android.systemui.util.concurrency.FakeExecutor
|
||||
import com.android.systemui.util.mockito.any
|
||||
import com.android.systemui.util.mockito.argumentCaptor
|
||||
import com.android.systemui.util.time.FakeSystemClock
|
||||
import com.google.common.truth.Truth.assertThat
|
||||
import java.util.concurrent.Executor
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
||||
import kotlinx.coroutines.flow.launchIn
|
||||
import kotlinx.coroutines.flow.onEach
|
||||
import kotlinx.coroutines.runBlocking
|
||||
import org.junit.Before
|
||||
import org.junit.Test
|
||||
import org.mockito.Mock
|
||||
import org.mockito.Mockito.verify
|
||||
import org.mockito.MockitoAnnotations
|
||||
|
||||
@OptIn(ExperimentalCoroutinesApi::class)
|
||||
@SmallTest
|
||||
class WifiRepositoryImplTest : SysuiTestCase() {
|
||||
|
||||
private lateinit var underTest: WifiRepositoryImpl
|
||||
|
||||
@Mock private lateinit var logger: ConnectivityPipelineLogger
|
||||
@Mock private lateinit var wifiManager: WifiManager
|
||||
private lateinit var executor: Executor
|
||||
|
||||
@Before
|
||||
fun setUp() {
|
||||
MockitoAnnotations.initMocks(this)
|
||||
executor = FakeExecutor(FakeSystemClock())
|
||||
}
|
||||
|
||||
@Test
|
||||
fun wifiActivity_nullWifiManager_receivesDefault() = runBlocking(IMMEDIATE) {
|
||||
underTest = WifiRepositoryImpl(
|
||||
wifiManager = null,
|
||||
executor,
|
||||
logger,
|
||||
)
|
||||
|
||||
var latest: WifiActivityModel? = null
|
||||
val job = underTest
|
||||
.wifiActivity
|
||||
.onEach { latest = it }
|
||||
.launchIn(this)
|
||||
|
||||
assertThat(latest).isEqualTo(ACTIVITY_DEFAULT)
|
||||
|
||||
job.cancel()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun wifiActivity_callbackGivesNone_activityFlowHasNone() = runBlocking(IMMEDIATE) {
|
||||
underTest = WifiRepositoryImpl(
|
||||
wifiManager,
|
||||
executor,
|
||||
logger,
|
||||
)
|
||||
|
||||
var latest: WifiActivityModel? = null
|
||||
val job = underTest
|
||||
.wifiActivity
|
||||
.onEach { latest = it }
|
||||
.launchIn(this)
|
||||
|
||||
getTrafficStateCallback().onStateChanged(TrafficStateCallback.DATA_ACTIVITY_NONE)
|
||||
|
||||
assertThat(latest).isEqualTo(
|
||||
WifiActivityModel(hasActivityIn = false, hasActivityOut = false)
|
||||
)
|
||||
|
||||
job.cancel()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun wifiActivity_callbackGivesIn_activityFlowHasIn() = runBlocking(IMMEDIATE) {
|
||||
underTest = WifiRepositoryImpl(
|
||||
wifiManager,
|
||||
executor,
|
||||
logger,
|
||||
)
|
||||
|
||||
var latest: WifiActivityModel? = null
|
||||
val job = underTest
|
||||
.wifiActivity
|
||||
.onEach { latest = it }
|
||||
.launchIn(this)
|
||||
|
||||
getTrafficStateCallback().onStateChanged(TrafficStateCallback.DATA_ACTIVITY_IN)
|
||||
|
||||
assertThat(latest).isEqualTo(
|
||||
WifiActivityModel(hasActivityIn = true, hasActivityOut = false)
|
||||
)
|
||||
|
||||
job.cancel()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun wifiActivity_callbackGivesOut_activityFlowHasOut() = runBlocking(IMMEDIATE) {
|
||||
underTest = WifiRepositoryImpl(
|
||||
wifiManager,
|
||||
executor,
|
||||
logger,
|
||||
)
|
||||
|
||||
var latest: WifiActivityModel? = null
|
||||
val job = underTest
|
||||
.wifiActivity
|
||||
.onEach { latest = it }
|
||||
.launchIn(this)
|
||||
|
||||
getTrafficStateCallback().onStateChanged(TrafficStateCallback.DATA_ACTIVITY_OUT)
|
||||
|
||||
assertThat(latest).isEqualTo(
|
||||
WifiActivityModel(hasActivityIn = false, hasActivityOut = true)
|
||||
)
|
||||
|
||||
job.cancel()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun wifiActivity_callbackGivesInout_activityFlowHasInAndOut() = runBlocking(IMMEDIATE) {
|
||||
underTest = WifiRepositoryImpl(
|
||||
wifiManager,
|
||||
executor,
|
||||
logger,
|
||||
)
|
||||
|
||||
var latest: WifiActivityModel? = null
|
||||
val job = underTest
|
||||
.wifiActivity
|
||||
.onEach { latest = it }
|
||||
.launchIn(this)
|
||||
|
||||
getTrafficStateCallback().onStateChanged(TrafficStateCallback.DATA_ACTIVITY_INOUT)
|
||||
|
||||
assertThat(latest).isEqualTo(WifiActivityModel(hasActivityIn = true, hasActivityOut = true))
|
||||
|
||||
job.cancel()
|
||||
}
|
||||
|
||||
private fun getTrafficStateCallback(): TrafficStateCallback {
|
||||
val callbackCaptor = argumentCaptor<TrafficStateCallback>()
|
||||
verify(wifiManager).registerTrafficStateCallback(any(), callbackCaptor.capture())
|
||||
return callbackCaptor.value!!
|
||||
}
|
||||
}
|
||||
|
||||
private val IMMEDIATE = Dispatchers.Main.immediate
|
||||
@@ -0,0 +1,163 @@
|
||||
/*
|
||||
* 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.domain.interactor
|
||||
|
||||
import androidx.test.filters.SmallTest
|
||||
import com.android.systemui.SysuiTestCase
|
||||
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.repository.FakeWifiRepository
|
||||
import com.google.common.truth.Truth.assertThat
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
||||
import kotlinx.coroutines.flow.launchIn
|
||||
import kotlinx.coroutines.flow.onEach
|
||||
import kotlinx.coroutines.runBlocking
|
||||
import kotlinx.coroutines.yield
|
||||
import org.junit.Before
|
||||
import org.junit.Test
|
||||
|
||||
@OptIn(ExperimentalCoroutinesApi::class)
|
||||
@SmallTest
|
||||
class WifiInteractorTest : SysuiTestCase() {
|
||||
|
||||
private lateinit var underTest: WifiInteractor
|
||||
|
||||
private lateinit var repository: FakeWifiRepository
|
||||
|
||||
@Before
|
||||
fun setUp() {
|
||||
repository = FakeWifiRepository()
|
||||
underTest = WifiInteractor(repository)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun hasActivityIn_noInOrOut_outputsFalse() = runBlocking(IMMEDIATE) {
|
||||
repository.setWifiModel(WifiModel(ssid = "AB"))
|
||||
repository.setWifiActivity(WifiActivityModel(hasActivityIn = false, hasActivityOut = false))
|
||||
|
||||
var latest: Boolean? = null
|
||||
val job = underTest
|
||||
.hasActivityIn
|
||||
.onEach { latest = it }
|
||||
.launchIn(this)
|
||||
|
||||
assertThat(latest).isFalse()
|
||||
|
||||
job.cancel()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun hasActivityIn_onlyOut_outputsFalse() = runBlocking(IMMEDIATE) {
|
||||
repository.setWifiModel(WifiModel(ssid = "AB"))
|
||||
repository.setWifiActivity(WifiActivityModel(hasActivityIn = false, hasActivityOut = true))
|
||||
|
||||
var latest: Boolean? = null
|
||||
val job = underTest
|
||||
.hasActivityIn
|
||||
.onEach { latest = it }
|
||||
.launchIn(this)
|
||||
|
||||
assertThat(latest).isFalse()
|
||||
|
||||
job.cancel()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun hasActivityIn_onlyIn_outputsTrue() = runBlocking(IMMEDIATE) {
|
||||
repository.setWifiModel(WifiModel(ssid = "AB"))
|
||||
repository.setWifiActivity(WifiActivityModel(hasActivityIn = true, hasActivityOut = false))
|
||||
|
||||
var latest: Boolean? = null
|
||||
val job = underTest
|
||||
.hasActivityIn
|
||||
.onEach { latest = it }
|
||||
.launchIn(this)
|
||||
|
||||
assertThat(latest).isTrue()
|
||||
|
||||
job.cancel()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun hasActivityIn_inAndOut_outputsTrue() = runBlocking(IMMEDIATE) {
|
||||
repository.setWifiModel(WifiModel(ssid = "AB"))
|
||||
repository.setWifiActivity(WifiActivityModel(hasActivityIn = true, hasActivityOut = true))
|
||||
|
||||
var latest: Boolean? = null
|
||||
val job = underTest
|
||||
.hasActivityIn
|
||||
.onEach { latest = it }
|
||||
.launchIn(this)
|
||||
|
||||
assertThat(latest).isTrue()
|
||||
|
||||
job.cancel()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun hasActivityIn_ssidNull_outputsFalse() = runBlocking(IMMEDIATE) {
|
||||
repository.setWifiModel(WifiModel(ssid = null))
|
||||
repository.setWifiActivity(WifiActivityModel(hasActivityIn = true, hasActivityOut = true))
|
||||
|
||||
var latest: Boolean? = null
|
||||
val job = underTest
|
||||
.hasActivityIn
|
||||
.onEach { latest = it }
|
||||
.launchIn(this)
|
||||
|
||||
assertThat(latest).isFalse()
|
||||
|
||||
job.cancel()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun hasActivityIn_multipleChanges_multipleOutputChanges() = runBlocking(IMMEDIATE) {
|
||||
repository.setWifiModel(WifiModel(ssid = "AB"))
|
||||
|
||||
var latest: Boolean? = null
|
||||
val job = underTest
|
||||
.hasActivityIn
|
||||
.onEach { latest = it }
|
||||
.launchIn(this)
|
||||
|
||||
// Conduct a series of changes and verify we catch each of them in succession
|
||||
repository.setWifiActivity(WifiActivityModel(hasActivityIn = true, hasActivityOut = false))
|
||||
yield()
|
||||
assertThat(latest).isTrue()
|
||||
|
||||
repository.setWifiActivity(WifiActivityModel(hasActivityIn = false, hasActivityOut = true))
|
||||
yield()
|
||||
assertThat(latest).isFalse()
|
||||
|
||||
repository.setWifiActivity(WifiActivityModel(hasActivityIn = true, hasActivityOut = true))
|
||||
yield()
|
||||
assertThat(latest).isTrue()
|
||||
|
||||
repository.setWifiActivity(WifiActivityModel(hasActivityIn = true, hasActivityOut = false))
|
||||
yield()
|
||||
assertThat(latest).isTrue()
|
||||
|
||||
repository.setWifiActivity(WifiActivityModel(hasActivityIn = false, hasActivityOut = false))
|
||||
yield()
|
||||
assertThat(latest).isFalse()
|
||||
|
||||
job.cancel()
|
||||
}
|
||||
}
|
||||
|
||||
private val IMMEDIATE = Dispatchers.Main.immediate
|
||||
@@ -0,0 +1,124 @@
|
||||
/*
|
||||
* 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.ui.viewmodel
|
||||
|
||||
import androidx.test.filters.SmallTest
|
||||
import com.android.systemui.SysuiTestCase
|
||||
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.WifiModel
|
||||
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.shared.WifiConstants
|
||||
import com.google.common.truth.Truth.assertThat
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
||||
import kotlinx.coroutines.flow.launchIn
|
||||
import kotlinx.coroutines.flow.onEach
|
||||
import kotlinx.coroutines.runBlocking
|
||||
import kotlinx.coroutines.yield
|
||||
import org.junit.Before
|
||||
import org.junit.Test
|
||||
import org.mockito.Mock
|
||||
import org.mockito.Mockito.`when` as whenever
|
||||
import org.mockito.MockitoAnnotations
|
||||
|
||||
@OptIn(ExperimentalCoroutinesApi::class)
|
||||
@SmallTest
|
||||
class WifiViewModelTest : SysuiTestCase() {
|
||||
|
||||
private lateinit var underTest: WifiViewModel
|
||||
|
||||
@Mock private lateinit var logger: ConnectivityPipelineLogger
|
||||
@Mock private lateinit var constants: WifiConstants
|
||||
private lateinit var repository: FakeWifiRepository
|
||||
private lateinit var interactor: WifiInteractor
|
||||
|
||||
@Before
|
||||
fun setUp() {
|
||||
MockitoAnnotations.initMocks(this)
|
||||
repository = FakeWifiRepository()
|
||||
interactor = WifiInteractor(repository)
|
||||
|
||||
underTest = WifiViewModel(
|
||||
constants,
|
||||
logger,
|
||||
interactor
|
||||
)
|
||||
|
||||
// Set up with a valid SSID
|
||||
repository.setWifiModel(WifiModel(ssid = "AB"))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun activityInVisible_showActivityConfigFalse_receivesFalse() = runBlocking(IMMEDIATE) {
|
||||
whenever(constants.shouldShowActivityConfig).thenReturn(false)
|
||||
|
||||
var latest: Boolean? = null
|
||||
val job = underTest
|
||||
.isActivityInVisible
|
||||
.onEach { latest = it }
|
||||
.launchIn(this)
|
||||
|
||||
// Verify that on launch, we receive a false.
|
||||
assertThat(latest).isFalse()
|
||||
|
||||
job.cancel()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun activityInVisible_showActivityConfigFalse_noUpdatesReceived() = runBlocking(IMMEDIATE) {
|
||||
whenever(constants.shouldShowActivityConfig).thenReturn(false)
|
||||
|
||||
var latest: Boolean? = null
|
||||
val job = underTest
|
||||
.isActivityInVisible
|
||||
.onEach { latest = it }
|
||||
.launchIn(this)
|
||||
|
||||
// Update the repo to have activityIn
|
||||
repository.setWifiActivity(WifiActivityModel(hasActivityIn = true, hasActivityOut = false))
|
||||
yield()
|
||||
|
||||
// Verify that we didn't update to activityIn=true (because our config is false)
|
||||
assertThat(latest).isFalse()
|
||||
|
||||
job.cancel()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun activityInVisible_showActivityConfigTrue_receivesUpdate() = runBlocking(IMMEDIATE) {
|
||||
whenever(constants.shouldShowActivityConfig).thenReturn(true)
|
||||
|
||||
var latest: Boolean? = null
|
||||
val job = underTest
|
||||
.isActivityInVisible
|
||||
.onEach { latest = it }
|
||||
.launchIn(this)
|
||||
|
||||
// Update the repo to have activityIn
|
||||
repository.setWifiActivity(WifiActivityModel(hasActivityIn = true, hasActivityOut = false))
|
||||
yield()
|
||||
|
||||
// Verify that we updated to activityIn=true
|
||||
assertThat(latest).isTrue()
|
||||
|
||||
job.cancel()
|
||||
}
|
||||
}
|
||||
|
||||
private val IMMEDIATE = Dispatchers.Main.immediate
|
||||
Reference in New Issue
Block a user