Merge "[SB Refactor] Implement the wifi icon flow in the new pipeline." into tm-qpr-dev
This commit is contained in:
committed by
Android (Google) Code Review
commit
a9b3416a87
@@ -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;
|
||||
|
||||
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
|
||||
@@ -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")
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user