diff options
4 files changed, 133 insertions, 54 deletions
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/shared/WifiConstants.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/shared/WifiConstants.kt index a19d1bdd8e62..0eb4b0de9f6b 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/shared/WifiConstants.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/shared/WifiConstants.kt @@ -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") } } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/ui/viewmodel/WifiViewModel.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/ui/viewmodel/WifiViewModel.kt index 465f5097235e..47347a2666f9 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/ui/viewmodel/WifiViewModel.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/ui/viewmodel/WifiViewModel.kt @@ -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) diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/wifi/ui/view/ModernStatusBarWifiViewTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/wifi/ui/view/ModernStatusBarWifiViewTest.kt index a93b6b28e3b3..c577db8c4460 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/wifi/ui/view/ModernStatusBarWifiViewTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/wifi/ui/view/ModernStatusBarWifiViewTest.kt @@ -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 diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/wifi/ui/viewmodel/WifiViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/wifi/ui/viewmodel/WifiViewModelTest.kt index 9b6aef76d579..063072f7d763 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/wifi/ui/viewmodel/WifiViewModelTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/wifi/ui/viewmodel/WifiViewModelTest.kt @@ -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 |