[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:
@@ -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")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user