[SB Refactor] Only show wifi icon if (1) the network is active and

validated; or (2) we're configured to always show it when enabled.

This matches part of the logic in
WifiSignalController#notifyListenersForNonCarrierWifi.wifiVisible.

Test: manual: With alwaysShow config off, verify that the wifi icon only
appears when we're fully connected to a network
Test: manual: With alwaysShow config on, verify that the wifi icon
always appears (unless wifi is disabled)
Test: statusbar.pipeline tests
Bug: 238425913

Change-Id: I723cfc0435265699f98b5b1adeb4cb9bbfaf2929
This commit is contained in:
Caitlin Shkuratov
2022-09-27 17:28:50 +00:00
parent 022a29820b
commit 2dc080cbf7
4 changed files with 133 additions and 54 deletions

View File

@@ -41,9 +41,14 @@ class WifiConstants @Inject constructor(
/** True if we should show the activityIn/activityOut icons and false otherwise. */
val shouldShowActivityConfig = context.resources.getBoolean(R.bool.config_showActivity)
/** True if we should always show the wifi icon when wifi is enabled and false otherwise. */
val alwaysShowIconIfEnabled =
context.resources.getBoolean(R.bool.config_showWifiIndicatorWhenEnabled)
override fun dump(pw: PrintWriter, args: Array<out String>) {
pw.apply {
println("shouldShowActivityConfig=$shouldShowActivityConfig")
println("alwaysShowIconIfEnabled=$alwaysShowIconIfEnabled")
}
}
}

View File

@@ -72,68 +72,70 @@ constructor(
@Application private val scope: CoroutineScope,
statusBarPipelineFlags: StatusBarPipelineFlags,
) {
/** The drawable resource ID to use for the wifi icon. Null if we shouldn't display any icon. */
/**
* Returns the drawable resource ID to use for the wifi icon based on the given network.
* Null if we can't compute the icon.
*/
@DrawableRes
private val iconResId: 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]
}
private fun WifiNetworkModel.iconResId(): Int? {
return when (this) {
is WifiNetworkModel.CarrierMerged -> null
is WifiNetworkModel.Inactive -> WIFI_NO_NETWORK
is WifiNetworkModel.Active ->
when {
this.level == null -> null
this.isValidated -> WIFI_FULL_ICONS[this.level]
else -> WIFI_NO_INTERNET_ICONS[this.level]
}
}
.stateIn(scope, started = SharingStarted.WhileSubscribed(), initialValue = null)
}
}
/** The content description for the wifi icon. */
private val contentDescription: Flow<ContentDescription?> =
interactor.wifiNetwork
.map {
when (it) {
is WifiNetworkModel.CarrierMerged -> null
is WifiNetworkModel.Inactive ->
ContentDescription.Loaded(
"${context.getString(WIFI_NO_CONNECTION)}," +
context.getString(NO_INTERNET)
)
is WifiNetworkModel.Active ->
when (it.level) {
null -> null
else -> {
val levelDesc =
context.getString(WIFI_CONNECTION_STRENGTH[it.level])
when {
it.isValidated -> ContentDescription.Loaded(levelDesc)
else ->
ContentDescription.Loaded(
"$levelDesc,${context.getString(NO_INTERNET)}"
)
}
}
/**
* Returns the content description for the wifi icon based on the given network.
* Null if we can't compute the content description.
*/
private fun WifiNetworkModel.contentDescription(): ContentDescription? {
return when (this) {
is WifiNetworkModel.CarrierMerged -> null
is WifiNetworkModel.Inactive ->
ContentDescription.Loaded(
"${context.getString(WIFI_NO_CONNECTION)},${context.getString(NO_INTERNET)}"
)
is WifiNetworkModel.Active ->
when (this.level) {
null -> null
else -> {
val levelDesc = context.getString(WIFI_CONNECTION_STRENGTH[this.level])
when {
this.isValidated -> ContentDescription.Loaded(levelDesc)
else ->
ContentDescription.Loaded(
"$levelDesc,${context.getString(NO_INTERNET)}"
)
}
}
}
}
.stateIn(scope, started = SharingStarted.WhileSubscribed(), initialValue = null)
}
}
/** The wifi icon that should be displayed. Null if we shouldn't display any icon. */
private val wifiIcon: StateFlow<Icon?> =
combine(
interactor.isEnabled,
interactor.isForceHidden,
iconResId,
contentDescription,
) { isEnabled, isForceHidden, iconResId, contentDescription ->
when {
!isEnabled ||
isForceHidden ||
iconResId == null ||
iconResId <= 0 -> null
else -> Icon.Resource(iconResId, contentDescription)
interactor.wifiNetwork,
) { isEnabled, isForceHidden, wifiNetwork ->
if (!isEnabled || isForceHidden || wifiNetwork is WifiNetworkModel.CarrierMerged) {
return@combine null
}
val iconResId = wifiNetwork.iconResId() ?: return@combine null
val icon = Icon.Resource(iconResId, wifiNetwork.contentDescription())
return@combine when {
constants.alwaysShowIconIfEnabled -> icon
wifiNetwork is WifiNetworkModel.Active && wifiNetwork.isValidated -> icon
else -> null
}
}
.stateIn(scope, started = SharingStarted.WhileSubscribed(), initialValue = null)

View File

@@ -32,6 +32,7 @@ import com.android.systemui.statusbar.phone.StatusBarLocation
import com.android.systemui.statusbar.pipeline.StatusBarPipelineFlags
import com.android.systemui.statusbar.pipeline.shared.ConnectivityPipelineLogger
import com.android.systemui.statusbar.pipeline.shared.data.repository.FakeConnectivityRepository
import com.android.systemui.statusbar.pipeline.wifi.data.model.WifiNetworkModel
import com.android.systemui.statusbar.pipeline.wifi.data.repository.FakeWifiRepository
import com.android.systemui.statusbar.pipeline.wifi.domain.interactor.WifiInteractor
import com.android.systemui.statusbar.pipeline.wifi.shared.WifiConstants
@@ -182,6 +183,9 @@ class ModernStatusBarWifiViewTest : SysuiTestCase() {
@Test
fun isIconVisible_notEnabled_outputsFalse() {
wifiRepository.setIsWifiEnabled(false)
wifiRepository.setWifiNetwork(
WifiNetworkModel.Active(NETWORK_ID, isValidated = true, level = 2)
)
val view = ModernStatusBarWifiView.constructAndBind(
context, SLOT_NAME, viewModel, StatusBarLocation.HOME
@@ -198,6 +202,9 @@ class ModernStatusBarWifiViewTest : SysuiTestCase() {
@Test
fun isIconVisible_enabled_outputsTrue() {
wifiRepository.setIsWifiEnabled(true)
wifiRepository.setWifiNetwork(
WifiNetworkModel.Active(NETWORK_ID, isValidated = true, level = 2)
)
val view = ModernStatusBarWifiView.constructAndBind(
context, SLOT_NAME, viewModel, StatusBarLocation.HOME
@@ -221,3 +228,4 @@ class ModernStatusBarWifiViewTest : SysuiTestCase() {
}
private const val SLOT_NAME = "TestSlotName"
private const val NETWORK_ID = 200

View File

@@ -51,6 +51,7 @@ import org.mockito.Mock
import org.mockito.Mockito.`when` as whenever
import org.mockito.MockitoAnnotations
@Suppress("EXPERIMENTAL_IS_NOT_ENABLED")
@OptIn(ExperimentalCoroutinesApi::class)
@SmallTest
class WifiViewModelTest : SysuiTestCase() {
@@ -137,7 +138,9 @@ class WifiViewModelTest : SysuiTestCase() {
.onEach { latest = it }
.launchIn(this)
wifiRepository.setWifiNetwork(WifiNetworkModel.Active(NETWORK_ID, level = 2))
wifiRepository.setWifiNetwork(
WifiNetworkModel.Active(NETWORK_ID, isValidated = true, level = 2)
)
yield()
assertThat(latest).isInstanceOf(Icon.Resource::class.java)
@@ -146,7 +149,31 @@ class WifiViewModelTest : SysuiTestCase() {
}
@Test
fun wifiIcon_inactiveNetwork_outputsNoNetworkIcon() = runBlocking(IMMEDIATE) {
fun wifiIcon_inactiveNetwork_alwaysShowFalse_outputsNull() = runBlocking(IMMEDIATE) {
whenever(constants.alwaysShowIconIfEnabled).thenReturn(false)
createAndSetViewModel()
// Start as non-null so we can verify we got the update
var latest: Icon? = Icon.Resource(0, null)
val job = underTest
.home
.wifiIcon
.onEach { latest = it }
.launchIn(this)
wifiRepository.setWifiNetwork(WifiNetworkModel.Inactive)
yield()
assertThat(latest).isNull()
job.cancel()
}
@Test
fun wifiIcon_inactiveNetwork_alwaysShowTrue_outputsNoNetworkIcon() = runBlocking(IMMEDIATE) {
whenever(constants.alwaysShowIconIfEnabled).thenReturn(true)
createAndSetViewModel()
var latest: Icon? = null
val job = underTest
.home
@@ -170,6 +197,10 @@ class WifiViewModelTest : SysuiTestCase() {
@Test
fun wifiIcon_carrierMergedNetwork_outputsNull() = runBlocking(IMMEDIATE) {
// Even when we should always show the icon
whenever(constants.alwaysShowIconIfEnabled).thenReturn(true)
createAndSetViewModel()
var latest: Icon? = Icon.Resource(0, null)
val job = underTest
.home
@@ -177,9 +208,11 @@ class WifiViewModelTest : SysuiTestCase() {
.onEach { latest = it }
.launchIn(this)
// WHEN we have a carrier merged network
wifiRepository.setWifiNetwork(WifiNetworkModel.CarrierMerged)
yield()
// THEN we override the alwaysShow boolean and still don't show the icon
assertThat(latest).isNull()
job.cancel()
@@ -187,6 +220,10 @@ class WifiViewModelTest : SysuiTestCase() {
@Test
fun wifiIcon_isActiveNullLevel_outputsNull() = runBlocking(IMMEDIATE) {
// Even when we should always show the icon
whenever(constants.alwaysShowIconIfEnabled).thenReturn(true)
createAndSetViewModel()
var latest: Icon? = Icon.Resource(0, null)
val job = underTest
.home
@@ -194,9 +231,11 @@ class WifiViewModelTest : SysuiTestCase() {
.onEach { latest = it }
.launchIn(this)
// WHEN we have a null level
wifiRepository.setWifiNetwork(WifiNetworkModel.Active(NETWORK_ID, level = null))
yield()
// THEN we override the alwaysShow boolean and still don't show the icon
assertThat(latest).isNull()
job.cancel()
@@ -233,7 +272,32 @@ class WifiViewModelTest : SysuiTestCase() {
}
@Test
fun wifiIcon_isActiveAndNotValidated_level4_outputsEmpty4Icon() = runBlocking(IMMEDIATE) {
fun wifiIcon_isActiveAndNotValidated_alwaysShowFalse_outputsNull() = runBlocking(IMMEDIATE) {
whenever(constants.alwaysShowIconIfEnabled).thenReturn(false)
createAndSetViewModel()
var latest: Icon? = Icon.Resource(0, null)
val job = underTest
.home
.wifiIcon
.onEach { latest = it }
.launchIn(this)
wifiRepository.setWifiNetwork(
WifiNetworkModel.Active(NETWORK_ID, isValidated = false, level = 4,)
)
yield()
assertThat(latest).isNull()
job.cancel()
}
@Test
fun wifiIcon_isActiveAndNotValidated_alwaysShowTrue_outputsIcon() = runBlocking(IMMEDIATE) {
whenever(constants.alwaysShowIconIfEnabled).thenReturn(true)
createAndSetViewModel()
var latest: Icon? = null
val job = underTest
.home