Merge "[SB Refactor] Implement the wifi icon flow in the new pipeline." into tm-qpr-dev am: a9b3416a87

Original change: https://googleplex-android-review.googlesource.com/c/platform/frameworks/base/+/19700880

Change-Id: I77913eb0cc04f28271c96618c96b7b4397195f06
Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
This commit is contained in:
Caitlin Shkuratov
2022-08-29 14:07:56 +00:00
committed by Automerger Merge Worker
10 changed files with 423 additions and 44 deletions

View File

@@ -31,7 +31,7 @@ public class WifiIcons {
com.android.internal.R.drawable.ic_wifi_signal_4
};
private static final int[] WIFI_NO_INTERNET_ICONS = {
public static final int[] WIFI_NO_INTERNET_ICONS = {
R.drawable.ic_no_internet_wifi_signal_0,
R.drawable.ic_no_internet_wifi_signal_1,
R.drawable.ic_no_internet_wifi_signal_2,
@@ -48,7 +48,7 @@ public class WifiIcons {
public static final int QS_WIFI_DISABLED = com.android.internal.R.drawable.ic_wifi_signal_0;
public static final int QS_WIFI_NO_NETWORK = com.android.internal.R.drawable.ic_wifi_signal_0;
static final int WIFI_NO_NETWORK = QS_WIFI_NO_NETWORK;
public static final int WIFI_NO_NETWORK = QS_WIFI_NO_NETWORK;
static final int WIFI_LEVEL_COUNT = WIFI_SIGNAL_STRENGTH[0].length;

View File

@@ -16,13 +16,23 @@
package com.android.systemui.statusbar.pipeline.wifi.data.model
import androidx.annotation.VisibleForTesting
/** Provides information about the current wifi network. */
sealed class WifiNetworkModel {
/** A model representing that we have no active wifi network. */
object Inactive : WifiNetworkModel()
/**
* A model representing that our wifi network is actually a carrier merged network, meaning it's
* treated as more of a mobile network.
*
* See [android.net.wifi.WifiInfo.isCarrierMerged] for more information.
*/
object CarrierMerged : WifiNetworkModel()
/** Provides information about an active wifi network. */
class Active(
data class Active(
/**
* The [android.net.Network.netId] we received from
* [android.net.ConnectivityManager.NetworkCallback] in association with this wifi network.
@@ -31,6 +41,19 @@ sealed class WifiNetworkModel {
*/
val networkId: Int,
/** See [android.net.NetworkCapabilities.NET_CAPABILITY_VALIDATED]. */
val isValidated: Boolean = false,
/**
* The wifi signal level, guaranteed to be 0 <= level <= 4.
*
* Null if we couldn't fetch the level for some reason.
*
* TODO(b/238425913): The level will only be null if we have a null WifiManager. Is there a
* way we can guarantee a non-null WifiManager?
*/
val level: Int? = null,
/** See [android.net.wifi.WifiInfo.ssid]. */
val ssid: String? = null,
@@ -42,5 +65,18 @@ sealed class WifiNetworkModel {
/** See [android.net.wifi.WifiInfo.passpointProviderFriendlyName]. */
val passpointProviderFriendlyName: String? = null,
) : WifiNetworkModel()
) : WifiNetworkModel() {
init {
require(level == null || level in MIN_VALID_LEVEL..MAX_VALID_LEVEL) {
"0 <= wifi level <= 4 required; level was $level"
}
}
companion object {
@VisibleForTesting
internal const val MIN_VALID_LEVEL = 0
@VisibleForTesting
internal const val MAX_VALID_LEVEL = 4
}
}
}

View File

@@ -21,6 +21,7 @@ import android.net.ConnectivityManager
import android.net.Network
import android.net.NetworkCapabilities
import android.net.NetworkCapabilities.NET_CAPABILITY_NOT_VPN
import android.net.NetworkCapabilities.NET_CAPABILITY_VALIDATED
import android.net.NetworkCapabilities.TRANSPORT_CELLULAR
import android.net.NetworkCapabilities.TRANSPORT_WIFI
import android.net.NetworkRequest
@@ -31,6 +32,7 @@ import android.util.Log
import com.android.settingslib.Utils
import com.android.systemui.common.coroutine.ConflatedCallbackFlow.conflatedCallbackFlow
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Application
import com.android.systemui.dagger.qualifiers.Main
import com.android.systemui.statusbar.pipeline.shared.ConnectivityPipelineLogger
import com.android.systemui.statusbar.pipeline.shared.ConnectivityPipelineLogger.Companion.SB_LOGGING_TAG
@@ -38,10 +40,13 @@ import com.android.systemui.statusbar.pipeline.wifi.data.model.WifiActivityModel
import com.android.systemui.statusbar.pipeline.wifi.data.model.WifiNetworkModel
import java.util.concurrent.Executor
import javax.inject.Inject
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.channels.awaitClose
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.SharingStarted
import kotlinx.coroutines.flow.flowOf
import kotlinx.coroutines.flow.shareIn
/**
* Provides data related to the wifi state.
@@ -63,10 +68,11 @@ interface WifiRepository {
@SysUISingleton
@SuppressLint("MissingPermission")
class WifiRepositoryImpl @Inject constructor(
connectivityManager: ConnectivityManager,
wifiManager: WifiManager?,
@Main mainExecutor: Executor,
logger: ConnectivityPipelineLogger,
connectivityManager: ConnectivityManager,
logger: ConnectivityPipelineLogger,
@Main mainExecutor: Executor,
@Application scope: CoroutineScope,
wifiManager: WifiManager?,
) : WifiRepository {
override val wifiNetwork: Flow<WifiNetworkModel> = conflatedCallbackFlow {
var currentWifi: WifiNetworkModel = WIFI_NETWORK_DEFAULT
@@ -80,7 +86,12 @@ class WifiRepositoryImpl @Inject constructor(
val wifiInfo = networkCapabilitiesToWifiInfo(networkCapabilities)
if (wifiInfo?.isPrimary == true) {
val wifiNetworkModel = wifiInfoToModel(wifiInfo, network.getNetId())
val wifiNetworkModel = createWifiNetworkModel(
wifiInfo,
network,
networkCapabilities,
wifiManager,
)
logger.logTransformation(
WIFI_NETWORK_CALLBACK_NAME,
oldValue = currentWifi,
@@ -112,6 +123,7 @@ class WifiRepositoryImpl @Inject constructor(
awaitClose { connectivityManager.unregisterNetworkCallback(callback) }
}
.shareIn(scope, started = SharingStarted.WhileSubscribed())
override val wifiActivity: Flow<WifiActivityModel> =
if (wifiManager == null) {
@@ -164,14 +176,25 @@ class WifiRepositoryImpl @Inject constructor(
}
}
private fun wifiInfoToModel(wifiInfo: WifiInfo, networkId: Int): WifiNetworkModel {
return WifiNetworkModel.Active(
networkId,
wifiInfo.ssid,
wifiInfo.isPasspointAp,
wifiInfo.isOsuAp,
wifiInfo.passpointProviderFriendlyName
)
private fun createWifiNetworkModel(
wifiInfo: WifiInfo,
network: Network,
networkCapabilities: NetworkCapabilities,
wifiManager: WifiManager?,
): WifiNetworkModel {
return if (wifiInfo.isCarrierMerged) {
WifiNetworkModel.CarrierMerged
} else {
WifiNetworkModel.Active(
network.getNetId(),
isValidated = networkCapabilities.hasCapability(NET_CAPABILITY_VALIDATED),
level = wifiManager?.calculateSignalLevel(wifiInfo.rssi),
wifiInfo.ssid,
wifiInfo.isPasspointAp,
wifiInfo.isOsuAp,
wifiInfo.passpointProviderFriendlyName
)
}
}
private fun prettyPrintActivity(activity: Int): String {

View File

@@ -33,11 +33,12 @@ import kotlinx.coroutines.flow.map
*/
@SysUISingleton
class WifiInteractor @Inject constructor(
repository: WifiRepository,
repository: WifiRepository,
) {
private val ssid: Flow<String?> = repository.wifiNetwork.map { info ->
when (info) {
is WifiNetworkModel.Inactive -> null
is WifiNetworkModel.CarrierMerged -> null
is WifiNetworkModel.Active -> when {
info.isPasspointAccessPoint || info.isOnlineSignUpForPasspointAccessPoint ->
info.passpointProviderFriendlyName
@@ -47,6 +48,10 @@ class WifiInteractor @Inject constructor(
}
}
/** Our current wifi network. See [WifiNetworkModel]. */
val wifiNetwork: Flow<WifiNetworkModel> = repository.wifiNetwork
/** True if our wifi network has activity in (download), and false otherwise. */
val hasActivityIn: Flow<Boolean> = combine(repository.wifiActivity, ssid) { activity, ssid ->
activity.hasActivityIn && ssid != null
}

View File

@@ -25,10 +25,10 @@ import androidx.lifecycle.Lifecycle
import androidx.lifecycle.repeatOnLifecycle
import com.android.systemui.R
import com.android.systemui.lifecycle.repeatWhenAttached
import com.android.systemui.statusbar.connectivity.WifiIcons.WIFI_FULL_ICONS
import com.android.systemui.statusbar.pipeline.wifi.ui.viewmodel.WifiViewModel
import kotlinx.coroutines.InternalCoroutinesApi
import kotlinx.coroutines.flow.collect
import kotlinx.coroutines.flow.distinctUntilChanged
import kotlinx.coroutines.launch
/**
@@ -50,10 +50,21 @@ object WifiViewBinder {
view.isVisible = true
iconView.isVisible = true
iconView.setImageDrawable(view.context.getDrawable(WIFI_FULL_ICONS[2]))
view.repeatWhenAttached {
repeatOnLifecycle(Lifecycle.State.STARTED) {
launch {
viewModel.wifiIconResId.distinctUntilChanged().collect { iconResId ->
iconView.setImageDrawable(
if (iconResId != null && iconResId > 0) {
iconView.context.getDrawable(iconResId)
} else {
null
}
)
}
}
launch {
viewModel.tint.collect { tint ->
iconView.imageTintList = ColorStateList.valueOf(tint)

View File

@@ -17,20 +17,24 @@
package com.android.systemui.statusbar.pipeline.wifi.ui.viewmodel
import android.graphics.Color
import androidx.annotation.DrawableRes
import com.android.systemui.statusbar.connectivity.WifiIcons.WIFI_FULL_ICONS
import com.android.systemui.statusbar.connectivity.WifiIcons.WIFI_NO_INTERNET_ICONS
import com.android.systemui.statusbar.connectivity.WifiIcons.WIFI_NO_NETWORK
import com.android.systemui.statusbar.pipeline.StatusBarPipelineFlags
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.data.model.WifiNetworkModel
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.emptyFlow
import kotlinx.coroutines.flow.flowOf
import kotlinx.coroutines.flow.map
/**
* 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(
statusBarPipelineFlags: StatusBarPipelineFlags,
@@ -38,6 +42,23 @@ class WifiViewModel @Inject constructor(
private val logger: ConnectivityPipelineLogger,
private val interactor: WifiInteractor,
) {
/**
* The drawable resource ID to use for the wifi icon. Null if we shouldn't display any icon.
*/
@DrawableRes
val wifiIconResId: Flow<Int?> = interactor.wifiNetwork.map {
when (it) {
is WifiNetworkModel.CarrierMerged -> null
is WifiNetworkModel.Inactive -> WIFI_NO_NETWORK
is WifiNetworkModel.Active ->
when {
it.level == null -> null
it.isValidated -> WIFI_FULL_ICONS[it.level]
else -> WIFI_NO_INTERNET_ICONS[it.level]
}
}
}
val isActivityInVisible: Flow<Boolean>
get() =
if (!constants.shouldShowActivityConfig) {

View File

@@ -0,0 +1,54 @@
/*
* 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
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.statusbar.pipeline.wifi.data.model.WifiNetworkModel.Active.Companion.MAX_VALID_LEVEL
import com.android.systemui.statusbar.pipeline.wifi.data.model.WifiNetworkModel.Active.Companion.MIN_VALID_LEVEL
import org.junit.Test
@SmallTest
class WifiNetworkModelTest : SysuiTestCase() {
@Test
fun active_levelsInValidRange_noException() {
(MIN_VALID_LEVEL..MAX_VALID_LEVEL).forEach { level ->
WifiNetworkModel.Active(NETWORK_ID, level = level)
// No assert, just need no crash
}
}
@Test
fun active_levelNull_noException() {
WifiNetworkModel.Active(NETWORK_ID, level = null)
// No assert, just need no crash
}
@Test(expected = IllegalArgumentException::class)
fun active_levelNegative_exceptionThrown() {
WifiNetworkModel.Active(NETWORK_ID, level = MIN_VALID_LEVEL - 1)
}
@Test(expected = IllegalArgumentException::class)
fun active_levelTooHigh_exceptionThrown() {
WifiNetworkModel.Active(NETWORK_ID, level = MAX_VALID_LEVEL + 1)
}
companion object {
private const val NETWORK_ID = 2
}
}

View File

@@ -19,6 +19,7 @@ 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.NET_CAPABILITY_VALIDATED
import android.net.NetworkCapabilities.TRANSPORT_CELLULAR
import android.net.NetworkCapabilities.TRANSPORT_WIFI
import android.net.vcn.VcnTransportInfo
@@ -39,11 +40,14 @@ import com.android.systemui.util.mockito.mock
import com.android.systemui.util.time.FakeSystemClock
import com.google.common.truth.Truth.assertThat
import java.util.concurrent.Executor
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.cancel
import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.onEach
import kotlinx.coroutines.runBlocking
import org.junit.After
import org.junit.Before
import org.junit.Test
import org.mockito.Mock
@@ -61,20 +65,28 @@ class WifiRepositoryImplTest : SysuiTestCase() {
@Mock private lateinit var connectivityManager: ConnectivityManager
@Mock private lateinit var wifiManager: WifiManager
private lateinit var executor: Executor
private lateinit var scope: CoroutineScope
@Before
fun setUp() {
MockitoAnnotations.initMocks(this)
executor = FakeExecutor(FakeSystemClock())
scope = CoroutineScope(IMMEDIATE)
underTest = WifiRepositoryImpl(
connectivityManager,
wifiManager,
executor,
logger,
executor,
scope,
wifiManager,
)
}
@After
fun tearDown() {
scope.cancel()
}
@Test
fun wifiNetwork_initiallyGetsDefault() = runBlocking(IMMEDIATE) {
var latest: WifiNetworkModel? = null
@@ -114,6 +126,61 @@ class WifiRepositoryImplTest : SysuiTestCase() {
job.cancel()
}
@Test
fun wifiNetwork_isCarrierMerged_flowHasCarrierMerged() = 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)
whenever(this.isCarrierMerged).thenReturn(true)
}
getNetworkCallback().onCapabilitiesChanged(NETWORK, createWifiNetworkCapabilities(wifiInfo))
assertThat(latest is WifiNetworkModel.CarrierMerged).isTrue()
job.cancel()
}
@Test
fun wifiNetwork_notValidated_networkNotValidated() = runBlocking(IMMEDIATE) {
var latest: WifiNetworkModel? = null
val job = underTest
.wifiNetwork
.onEach { latest = it }
.launchIn(this)
getNetworkCallback().onCapabilitiesChanged(
NETWORK, createWifiNetworkCapabilities(PRIMARY_WIFI_INFO, isValidated = false)
)
assertThat((latest as WifiNetworkModel.Active).isValidated).isFalse()
job.cancel()
}
@Test
fun wifiNetwork_validated_networkValidated() = runBlocking(IMMEDIATE) {
var latest: WifiNetworkModel? = null
val job = underTest
.wifiNetwork
.onEach { latest = it }
.launchIn(this)
getNetworkCallback().onCapabilitiesChanged(
NETWORK, createWifiNetworkCapabilities(PRIMARY_WIFI_INFO, isValidated = true)
)
assertThat((latest as WifiNetworkModel.Active).isValidated).isTrue()
job.cancel()
}
@Test
fun wifiNetwork_nonPrimaryWifiNetworkAdded_flowHasNoNetwork() = runBlocking(IMMEDIATE) {
var latest: WifiNetworkModel? = null
@@ -282,13 +349,14 @@ class WifiRepositoryImplTest : SysuiTestCase() {
.launchIn(this)
val wifiInfo = mock<WifiInfo>().apply {
whenever(this.ssid).thenReturn(SSID)
whenever(this.isPrimary).thenReturn(true)
}
whenever(this.ssid).thenReturn(SSID)
whenever(this.isPrimary).thenReturn(true)
}
// Start with the original network
getNetworkCallback()
.onCapabilitiesChanged(NETWORK, createWifiNetworkCapabilities(wifiInfo))
getNetworkCallback().onCapabilitiesChanged(
NETWORK, createWifiNetworkCapabilities(wifiInfo, isValidated = true)
)
// WHEN we keep the same network ID but change the SSID
val newSsid = "CD"
@@ -297,14 +365,16 @@ class WifiRepositoryImplTest : SysuiTestCase() {
whenever(this.isPrimary).thenReturn(true)
}
getNetworkCallback()
.onCapabilitiesChanged(NETWORK, createWifiNetworkCapabilities(newWifiInfo))
getNetworkCallback().onCapabilitiesChanged(
NETWORK, createWifiNetworkCapabilities(newWifiInfo, isValidated = false)
)
// 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)
assertThat(latestActive.isValidated).isFalse()
job.cancel()
}
@@ -406,10 +476,11 @@ class WifiRepositoryImplTest : SysuiTestCase() {
@Test
fun wifiActivity_nullWifiManager_receivesDefault() = runBlocking(IMMEDIATE) {
underTest = WifiRepositoryImpl(
connectivityManager,
wifiManager = null,
executor,
logger,
connectivityManager,
logger,
executor,
scope,
wifiManager = null,
)
var latest: WifiActivityModel? = null
@@ -501,11 +572,16 @@ class WifiRepositoryImplTest : SysuiTestCase() {
return callbackCaptor.value!!
}
private fun createWifiNetworkCapabilities(wifiInfo: WifiInfo) =
mock<NetworkCapabilities>().apply {
whenever(this.hasTransport(TRANSPORT_WIFI)).thenReturn(true)
whenever(this.transportInfo).thenReturn(wifiInfo)
private fun createWifiNetworkCapabilities(
wifiInfo: WifiInfo,
isValidated: Boolean = true,
): NetworkCapabilities {
return mock<NetworkCapabilities>().also {
whenever(it.hasTransport(TRANSPORT_WIFI)).thenReturn(true)
whenever(it.transportInfo).thenReturn(wifiInfo)
whenever(it.hasCapability(NET_CAPABILITY_VALIDATED)).thenReturn(isValidated)
}
}
private companion object {
const val NETWORK_ID = 45

View File

@@ -125,6 +125,38 @@ class WifiInteractorTest : SysuiTestCase() {
job.cancel()
}
@Test
fun hasActivityIn_inactiveNetwork_outputsFalse() = runBlocking(IMMEDIATE) {
repository.setWifiNetwork(WifiNetworkModel.Inactive)
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_carrierMergedNetwork_outputsFalse() = runBlocking(IMMEDIATE) {
repository.setWifiNetwork(WifiNetworkModel.CarrierMerged)
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.setWifiNetwork(VALID_WIFI_NETWORK_MODEL)
@@ -159,6 +191,28 @@ class WifiInteractorTest : SysuiTestCase() {
job.cancel()
}
@Test
fun wifiNetwork_matchesRepoWifiNetwork() = runBlocking(IMMEDIATE) {
val wifiNetwork = WifiNetworkModel.Active(
networkId = 45,
isValidated = true,
level = 3,
ssid = "AB",
passpointProviderFriendlyName = "friendly"
)
repository.setWifiNetwork(wifiNetwork)
var latest: WifiNetworkModel? = null
val job = underTest
.wifiNetwork
.onEach { latest = it }
.launchIn(this)
assertThat(latest).isEqualTo(wifiNetwork)
job.cancel()
}
companion object {
val VALID_WIFI_NETWORK_MODEL = WifiNetworkModel.Active(networkId = 1, ssid = "AB")
}

View File

@@ -18,6 +18,9 @@ package com.android.systemui.statusbar.pipeline.wifi.ui.viewmodel
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.statusbar.connectivity.WifiIcons.WIFI_FULL_ICONS
import com.android.systemui.statusbar.connectivity.WifiIcons.WIFI_NO_INTERNET_ICONS
import com.android.systemui.statusbar.connectivity.WifiIcons.WIFI_NO_NETWORK
import com.android.systemui.statusbar.pipeline.StatusBarPipelineFlags
import com.android.systemui.statusbar.pipeline.shared.ConnectivityPipelineLogger
import com.android.systemui.statusbar.pipeline.wifi.data.model.WifiActivityModel
@@ -62,14 +65,103 @@ class WifiViewModelTest : SysuiTestCase() {
logger,
interactor
)
// Set up with a valid SSID
repository.setWifiNetwork(WifiNetworkModel.Active(networkId = 1, ssid = "AB"))
}
@Test
fun activityInVisible_showActivityConfigFalse_receivesFalse() = runBlocking(IMMEDIATE) {
fun wifiIconResId_inactiveNetwork_outputsNoNetworkIcon() = runBlocking(IMMEDIATE) {
repository.setWifiNetwork(WifiNetworkModel.Inactive)
var latest: Int? = null
val job = underTest
.wifiIconResId
.onEach { latest = it }
.launchIn(this)
assertThat(latest).isEqualTo(WIFI_NO_NETWORK)
job.cancel()
}
@Test
fun wifiIconResId_carrierMergedNetwork_outputsNull() = runBlocking(IMMEDIATE) {
repository.setWifiNetwork(WifiNetworkModel.CarrierMerged)
var latest: Int? = null
val job = underTest
.wifiIconResId
.onEach { latest = it }
.launchIn(this)
assertThat(latest).isNull()
job.cancel()
}
@Test
fun wifiIconResId_isActiveNullLevel_outputsNull() = runBlocking(IMMEDIATE) {
repository.setWifiNetwork(WifiNetworkModel.Active(NETWORK_ID, level = null))
var latest: Int? = null
val job = underTest
.wifiIconResId
.onEach { latest = it }
.launchIn(this)
assertThat(latest).isNull()
job.cancel()
}
@Test
fun wifiIconResId_isActiveAndValidated_level1_outputsFull1Icon() = runBlocking(IMMEDIATE) {
val level = 1
repository.setWifiNetwork(
WifiNetworkModel.Active(
NETWORK_ID,
isValidated = true,
level = level
)
)
var latest: Int? = null
val job = underTest
.wifiIconResId
.onEach { latest = it }
.launchIn(this)
assertThat(latest).isEqualTo(WIFI_FULL_ICONS[level])
job.cancel()
}
@Test
fun wifiIconResId_isActiveAndNotValidated_level4_outputsEmpty4Icon() = runBlocking(IMMEDIATE) {
val level = 4
repository.setWifiNetwork(
WifiNetworkModel.Active(
NETWORK_ID,
isValidated = false,
level = level
)
)
var latest: Int? = null
val job = underTest
.wifiIconResId
.onEach { latest = it }
.launchIn(this)
assertThat(latest).isEqualTo(WIFI_NO_INTERNET_ICONS[level])
job.cancel()
}
@Test
fun activityInVisible_showActivityConfigFalse_outputsFalse() = runBlocking(IMMEDIATE) {
whenever(constants.shouldShowActivityConfig).thenReturn(false)
repository.setWifiNetwork(ACTIVE_VALID_WIFI_NETWORK)
var latest: Boolean? = null
val job = underTest
@@ -86,6 +178,7 @@ class WifiViewModelTest : SysuiTestCase() {
@Test
fun activityInVisible_showActivityConfigFalse_noUpdatesReceived() = runBlocking(IMMEDIATE) {
whenever(constants.shouldShowActivityConfig).thenReturn(false)
repository.setWifiNetwork(ACTIVE_VALID_WIFI_NETWORK)
var latest: Boolean? = null
val job = underTest
@@ -104,8 +197,9 @@ class WifiViewModelTest : SysuiTestCase() {
}
@Test
fun activityInVisible_showActivityConfigTrue_receivesUpdate() = runBlocking(IMMEDIATE) {
fun activityInVisible_showActivityConfigTrue_outputsUpdate() = runBlocking(IMMEDIATE) {
whenever(constants.shouldShowActivityConfig).thenReturn(true)
repository.setWifiNetwork(ACTIVE_VALID_WIFI_NETWORK)
var latest: Boolean? = null
val job = underTest
@@ -122,6 +216,11 @@ class WifiViewModelTest : SysuiTestCase() {
job.cancel()
}
companion object {
private const val NETWORK_ID = 2
private val ACTIVE_VALID_WIFI_NETWORK = WifiNetworkModel.Active(NETWORK_ID, ssid = "AB")
}
}
private val IMMEDIATE = Dispatchers.Main.immediate