summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author Caitlin Shkuratov <caitlinshk@google.com> 2023-03-27 18:25:21 +0000
committer Caitlin Shkuratov <caitlinshk@google.com> 2023-04-11 18:18:09 +0000
commit6ccb71ecb59dfb459248a745c1701c9cb01520b1 (patch)
tree7773815359d34d6f91b7e8cffcbf5af7afdd6057
parent86e2b60c3b9104f03333c9d92f5b548658deb6d9 (diff)
[SB Refactor] Show space between wifi and RAT icon if needed.
Bug: 238425913 Test: with demo mode, display wifi pie next to RAT icon -> verify extra space Test: with demo mode, display wifi pie next to mobile triangle without RAT icon -> verify no extra space Test: atest MobileIconsViewModelTest WifiViewModelTest Change-Id: I9db7997b7f260fd24fe33e317d6056f221ba6b6a
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/pipeline/dagger/StatusBarPipelineModule.kt18
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/ui/viewmodel/MobileIconsViewModel.kt51
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/ui/binder/WifiViewBinder.kt8
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/ui/viewmodel/WifiViewModel.kt20
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/ui/viewmodel/WifiViewModelCommon.kt3
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/FakeMobileIconsInteractor.kt12
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/ui/viewmodel/MobileIconsViewModelTest.kt173
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/wifi/ui/view/ModernStatusBarWifiViewTest.kt3
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/wifi/ui/viewmodel/WifiViewModelIconParameterizedTest.kt5
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/wifi/ui/viewmodel/WifiViewModelTest.kt34
10 files changed, 299 insertions, 28 deletions
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/dagger/StatusBarPipelineModule.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/dagger/StatusBarPipelineModule.kt
index eaa145582ba3..b3d246164e87 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/dagger/StatusBarPipelineModule.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/dagger/StatusBarPipelineModule.kt
@@ -35,6 +35,7 @@ import com.android.systemui.statusbar.pipeline.mobile.data.repository.UserSetupR
import com.android.systemui.statusbar.pipeline.mobile.domain.interactor.MobileIconsInteractor
import com.android.systemui.statusbar.pipeline.mobile.domain.interactor.MobileIconsInteractorImpl
import com.android.systemui.statusbar.pipeline.mobile.ui.MobileUiAdapter
+import com.android.systemui.statusbar.pipeline.mobile.ui.viewmodel.MobileIconsViewModel
import com.android.systemui.statusbar.pipeline.mobile.util.MobileMappingsProxy
import com.android.systemui.statusbar.pipeline.mobile.util.MobileMappingsProxyImpl
import com.android.systemui.statusbar.pipeline.mobile.util.SubscriptionManagerProxy
@@ -53,6 +54,9 @@ import dagger.Module
import dagger.Provides
import dagger.multibindings.ClassKey
import dagger.multibindings.IntoMap
+import kotlinx.coroutines.flow.Flow
+import java.util.function.Supplier
+import javax.inject.Named
@Module
abstract class StatusBarPipelineModule {
@@ -115,6 +119,17 @@ abstract class StatusBarPipelineModule {
@Provides
@SysUISingleton
+ @Named(FIRST_MOBILE_SUB_SHOWING_NETWORK_TYPE_ICON)
+ fun provideFirstMobileSubShowingNetworkTypeIconProvider(
+ mobileIconsViewModel: MobileIconsViewModel,
+ ): Supplier<Flow<Boolean>> {
+ return Supplier<Flow<Boolean>> {
+ mobileIconsViewModel.firstMobileSubShowingNetworkTypeIcon
+ }
+ }
+
+ @Provides
+ @SysUISingleton
@WifiInputLog
fun provideWifiInputLogBuffer(factory: LogBufferFactory): LogBuffer {
return factory.create("WifiInputLog", 50)
@@ -168,5 +183,8 @@ abstract class StatusBarPipelineModule {
fun provideVerboseMobileViewLogBuffer(factory: LogBufferFactory): LogBuffer {
return factory.create("VerboseMobileViewLog", 100)
}
+
+ const val FIRST_MOBILE_SUB_SHOWING_NETWORK_TYPE_ICON =
+ "FirstMobileSubShowingNetworkTypeIcon"
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/ui/viewmodel/MobileIconsViewModel.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/ui/viewmodel/MobileIconsViewModel.kt
index 9af5e836659f..40b8c90fb9f5 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/ui/viewmodel/MobileIconsViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/ui/viewmodel/MobileIconsViewModel.kt
@@ -32,6 +32,9 @@ import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.flow.SharingStarted
import kotlinx.coroutines.flow.StateFlow
+import kotlinx.coroutines.flow.flatMapLatest
+import kotlinx.coroutines.flow.flowOf
+import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.mapLatest
import kotlinx.coroutines.flow.stateIn
import kotlinx.coroutines.launch
@@ -63,22 +66,36 @@ constructor(
}
.stateIn(scope, SharingStarted.WhileSubscribed(), listOf())
+ private val firstMobileSubViewModel: StateFlow<MobileIconViewModelCommon?> =
+ subscriptionIdsFlow
+ .map {
+ if (it.isEmpty()) {
+ null
+ } else {
+ // Mobile icons get reversed by [StatusBarIconController], so the last element
+ // in this list will show up visually first.
+ commonViewModelForSub(it.last())
+ }
+ }
+ .stateIn(scope, SharingStarted.WhileSubscribed(), null)
+
+ /**
+ * A flow that emits `true` if the mobile sub that's displayed first visually is showing its
+ * network type icon and `false` otherwise.
+ */
+ val firstMobileSubShowingNetworkTypeIcon: StateFlow<Boolean> =
+ firstMobileSubViewModel
+ .flatMapLatest { firstMobileSubViewModel ->
+ firstMobileSubViewModel?.networkTypeIcon?.map { it != null } ?: flowOf(false)
+ }
+ .stateIn(scope, SharingStarted.WhileSubscribed(), false)
+
init {
scope.launch { subscriptionIdsFlow.collect { removeInvalidModelsFromCache(it) } }
}
fun viewModelForSub(subId: Int, location: StatusBarLocation): LocationBasedMobileViewModel {
- val common =
- mobileIconSubIdCache[subId]
- ?: MobileIconViewModel(
- subId,
- interactor.createMobileConnectionInteractorForSubId(subId),
- airplaneModeInteractor,
- constants,
- scope,
- )
- .also { mobileIconSubIdCache[subId] = it }
-
+ val common = commonViewModelForSub(subId)
return LocationBasedMobileViewModel.viewModelForLocation(
common,
statusBarPipelineFlags,
@@ -87,6 +104,18 @@ constructor(
)
}
+ private fun commonViewModelForSub(subId: Int): MobileIconViewModelCommon {
+ return mobileIconSubIdCache[subId]
+ ?: MobileIconViewModel(
+ subId,
+ interactor.createMobileConnectionInteractorForSubId(subId),
+ airplaneModeInteractor,
+ constants,
+ scope,
+ )
+ .also { mobileIconSubIdCache[subId] = it }
+ }
+
private fun removeInvalidModelsFromCache(subIds: List<Int>) {
val subIdsToRemove = mobileIconSubIdCache.keys.filter { !subIds.contains(it) }
subIdsToRemove.forEach { mobileIconSubIdCache.remove(it) }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/ui/binder/WifiViewBinder.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/ui/binder/WifiViewBinder.kt
index 9e8c814ca2a9..e819c4fc96ac 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/ui/binder/WifiViewBinder.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/ui/binder/WifiViewBinder.kt
@@ -36,7 +36,6 @@ import com.android.systemui.statusbar.pipeline.wifi.ui.viewmodel.LocationBasedWi
import kotlinx.coroutines.InternalCoroutinesApi
import kotlinx.coroutines.awaitCancellation
import kotlinx.coroutines.flow.MutableStateFlow
-import kotlinx.coroutines.flow.collect
import kotlinx.coroutines.flow.distinctUntilChanged
import kotlinx.coroutines.launch
@@ -64,6 +63,7 @@ object WifiViewBinder {
val activityOutView = view.requireViewById<ImageView>(R.id.wifi_out)
val activityContainerView = view.requireViewById<View>(R.id.inout_container)
val airplaneSpacer = view.requireViewById<View>(R.id.wifi_airplane_spacer)
+ val signalSpacer = view.requireViewById<View>(R.id.wifi_signal_spacer)
view.isVisible = true
iconView.isVisible = true
@@ -133,6 +133,12 @@ object WifiViewBinder {
}
}
+ launch {
+ viewModel.isSignalSpacerVisible.distinctUntilChanged().collect { visible ->
+ signalSpacer.isVisible = visible
+ }
+ }
+
try {
awaitCancellation()
} finally {
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 c9a0786acc72..d9c214452ef1 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
@@ -30,8 +30,8 @@ import com.android.systemui.log.table.logDiffsForTable
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.airplane.ui.viewmodel.AirplaneModeViewModel
+import com.android.systemui.statusbar.pipeline.dagger.StatusBarPipelineModule.Companion.FIRST_MOBILE_SUB_SHOWING_NETWORK_TYPE_ICON
import com.android.systemui.statusbar.pipeline.dagger.WifiTableLog
import com.android.systemui.statusbar.pipeline.shared.ConnectivityConstants
import com.android.systemui.statusbar.pipeline.shared.data.model.DataActivityModel
@@ -39,7 +39,9 @@ import com.android.systemui.statusbar.pipeline.wifi.domain.interactor.WifiIntera
import com.android.systemui.statusbar.pipeline.wifi.shared.WifiConstants
import com.android.systemui.statusbar.pipeline.wifi.shared.model.WifiNetworkModel
import com.android.systemui.statusbar.pipeline.wifi.ui.model.WifiIcon
+import java.util.function.Supplier
import javax.inject.Inject
+import javax.inject.Named
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.SharingStarted
@@ -53,24 +55,24 @@ import kotlinx.coroutines.flow.stateIn
/**
* Models the UI state for the status bar wifi icon.
*
- * This class exposes three view models, one per status bar location: [home], [keyguard], and [qs].
- * In order to get the UI state for the wifi icon, you must use one of those view models (whichever
- * is correct for your location).
- *
- * Internally, this class maintains the current state of the wifi icon and notifies those three view
- * models of any changes.
+ * This is a singleton so that we don't have duplicate logs and should *not* be used directly to
+ * control views. Instead, use an instance of [LocationBasedWifiViewModel]. See
+ * [LocationBasedWifiViewModel.viewModelForLocation].
*/
@SysUISingleton
class WifiViewModel
@Inject
constructor(
airplaneModeViewModel: AirplaneModeViewModel,
+ // TODO(b/238425913): The wifi icon shouldn't need to consume mobile information. A
+ // container-level view model should do the work instead.
+ @Named(FIRST_MOBILE_SUB_SHOWING_NETWORK_TYPE_ICON)
+ shouldShowSignalSpacerProvider: Supplier<Flow<Boolean>>,
connectivityConstants: ConnectivityConstants,
private val context: Context,
@WifiTableLog wifiTableLogBuffer: TableLogBuffer,
interactor: WifiInteractor,
@Application private val scope: CoroutineScope,
- statusBarPipelineFlags: StatusBarPipelineFlags,
wifiConstants: WifiConstants,
) : WifiViewModelCommon {
/** Returns the icon to use based on the given network. */
@@ -183,6 +185,8 @@ constructor(
override val isAirplaneSpacerVisible: Flow<Boolean> =
airplaneModeViewModel.isAirplaneModeIconVisible
+ override val isSignalSpacerVisible: Flow<Boolean> = shouldShowSignalSpacerProvider.get()
+
companion object {
@StringRes
@VisibleForTesting
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/ui/viewmodel/WifiViewModelCommon.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/ui/viewmodel/WifiViewModelCommon.kt
index eccf02397a82..617e19200a0a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/ui/viewmodel/WifiViewModelCommon.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/ui/viewmodel/WifiViewModelCommon.kt
@@ -39,4 +39,7 @@ interface WifiViewModelCommon {
/** True if the airplane spacer view should be visible. */
val isAirplaneSpacerVisible: Flow<Boolean>
+
+ /** True if the spacer between the wifi icon and the RAT icon should be visible. */
+ val isSignalSpacerVisible: Flow<Boolean>
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/FakeMobileIconsInteractor.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/FakeMobileIconsInteractor.kt
index 3ced7b2c4e6e..b2bbcfd3d6ef 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/FakeMobileIconsInteractor.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/FakeMobileIconsInteractor.kt
@@ -49,6 +49,8 @@ class FakeMobileIconsInteractor(
FIVE_G_OVERRIDE_KEY to TelephonyIcons.NR_5G,
)
+ private val interactorCache: MutableMap<Int, FakeMobileIconInteractor> = mutableMapOf()
+
override val isDefaultConnectionFailed = MutableStateFlow(false)
override val filteredSubscriptions = MutableStateFlow<List<SubscriptionModel>>(listOf())
@@ -75,7 +77,15 @@ class FakeMobileIconsInteractor(
/** Always returns a new fake interactor */
override fun createMobileConnectionInteractorForSubId(subId: Int): MobileIconInteractor {
- return FakeMobileIconInteractor(tableLogBuffer)
+ return FakeMobileIconInteractor(tableLogBuffer).also { interactorCache[subId] = it }
+ }
+
+ /**
+ * Returns the most recently created interactor for the given subId, or null if an interactor
+ * has never been created for that sub.
+ */
+ fun getInteractorForSubId(subId: Int): FakeMobileIconInteractor? {
+ return interactorCache[subId]
}
companion object {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/ui/viewmodel/MobileIconsViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/ui/viewmodel/MobileIconsViewModelTest.kt
index 01bec879102d..f8e1aa94c387 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/ui/viewmodel/MobileIconsViewModelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/ui/viewmodel/MobileIconsViewModelTest.kt
@@ -17,6 +17,7 @@
package com.android.systemui.statusbar.pipeline.mobile.ui.viewmodel
import androidx.test.filters.SmallTest
+import com.android.settingslib.mobile.TelephonyIcons
import com.android.systemui.SysuiTestCase
import com.android.systemui.statusbar.phone.StatusBarLocation
import com.android.systemui.statusbar.pipeline.StatusBarPipelineFlags
@@ -24,6 +25,7 @@ import com.android.systemui.statusbar.pipeline.airplane.data.repository.FakeAirp
import com.android.systemui.statusbar.pipeline.airplane.domain.interactor.AirplaneModeInteractor
import com.android.systemui.statusbar.pipeline.mobile.data.model.SubscriptionModel
import com.android.systemui.statusbar.pipeline.mobile.domain.interactor.FakeMobileIconsInteractor
+import com.android.systemui.statusbar.pipeline.mobile.domain.model.NetworkTypeIconModel
import com.android.systemui.statusbar.pipeline.mobile.ui.MobileViewLogger
import com.android.systemui.statusbar.pipeline.mobile.ui.VerboseMobileViewLogger
import com.android.systemui.statusbar.pipeline.mobile.util.FakeMobileMappingsProxy
@@ -135,8 +137,179 @@ class MobileIconsViewModelTest : SysuiTestCase() {
assertThat(underTest.mobileIconSubIdCache).containsExactly(2, model2.commonImpl)
}
+ @Test
+ fun firstMobileSubShowingNetworkTypeIcon_noSubs_false() =
+ testScope.runTest {
+ var latest: Boolean? = null
+ val job =
+ underTest.firstMobileSubShowingNetworkTypeIcon.onEach { latest = it }.launchIn(this)
+
+ interactor.filteredSubscriptions.value = emptyList()
+
+ assertThat(latest).isFalse()
+
+ job.cancel()
+ }
+
+ @Test
+ fun firstMobileSubShowingNetworkTypeIcon_oneSub_notShowingRat_false() =
+ testScope.runTest {
+ var latest: Boolean? = null
+ val job =
+ underTest.firstMobileSubShowingNetworkTypeIcon.onEach { latest = it }.launchIn(this)
+
+ interactor.filteredSubscriptions.value = listOf(SUB_1)
+ // The unknown icon group doesn't show a RAT
+ interactor.getInteractorForSubId(1)!!.networkTypeIconGroup.value =
+ NetworkTypeIconModel.DefaultIcon(TelephonyIcons.UNKNOWN)
+
+ assertThat(latest).isFalse()
+
+ job.cancel()
+ }
+
+ @Test
+ fun firstMobileSubShowingNetworkTypeIcon_oneSub_showingRat_true() =
+ testScope.runTest {
+ var latest: Boolean? = null
+ val job =
+ underTest.firstMobileSubShowingNetworkTypeIcon.onEach { latest = it }.launchIn(this)
+
+ interactor.filteredSubscriptions.value = listOf(SUB_1)
+ // The 3G icon group will show a RAT
+ interactor.getInteractorForSubId(1)!!.networkTypeIconGroup.value =
+ NetworkTypeIconModel.DefaultIcon(TelephonyIcons.THREE_G)
+
+ assertThat(latest).isTrue()
+
+ job.cancel()
+ }
+
+ @Test
+ fun firstMobileSubShowingNetworkTypeIcon_updatesAsSubUpdates() =
+ testScope.runTest {
+ var latest: Boolean? = null
+ val job =
+ underTest.firstMobileSubShowingNetworkTypeIcon.onEach { latest = it }.launchIn(this)
+
+ interactor.filteredSubscriptions.value = listOf(SUB_1)
+ val sub1Interactor = interactor.getInteractorForSubId(1)!!
+
+ sub1Interactor.networkTypeIconGroup.value =
+ NetworkTypeIconModel.DefaultIcon(TelephonyIcons.THREE_G)
+ assertThat(latest).isTrue()
+
+ sub1Interactor.networkTypeIconGroup.value =
+ NetworkTypeIconModel.DefaultIcon(TelephonyIcons.UNKNOWN)
+ assertThat(latest).isFalse()
+
+ sub1Interactor.networkTypeIconGroup.value =
+ NetworkTypeIconModel.DefaultIcon(TelephonyIcons.LTE)
+ assertThat(latest).isTrue()
+
+ job.cancel()
+ }
+
+ @Test
+ fun firstMobileSubShowingNetworkTypeIcon_multipleSubs_lastSubNotShowingRat_false() =
+ testScope.runTest {
+ var latest: Boolean? = null
+ val job =
+ underTest.firstMobileSubShowingNetworkTypeIcon.onEach { latest = it }.launchIn(this)
+
+ interactor.filteredSubscriptions.value = listOf(SUB_1, SUB_2)
+ interactor.getInteractorForSubId(1)?.networkTypeIconGroup?.value =
+ NetworkTypeIconModel.DefaultIcon(TelephonyIcons.THREE_G)
+ interactor.getInteractorForSubId(2)!!.networkTypeIconGroup.value =
+ NetworkTypeIconModel.DefaultIcon(TelephonyIcons.UNKNOWN)
+
+ assertThat(latest).isFalse()
+
+ job.cancel()
+ }
+
+ @Test
+ fun firstMobileSubShowingNetworkTypeIcon_multipleSubs_lastSubShowingRat_true() =
+ testScope.runTest {
+ var latest: Boolean? = null
+ val job =
+ underTest.firstMobileSubShowingNetworkTypeIcon.onEach { latest = it }.launchIn(this)
+
+ interactor.filteredSubscriptions.value = listOf(SUB_1, SUB_2)
+ interactor.getInteractorForSubId(1)?.networkTypeIconGroup?.value =
+ NetworkTypeIconModel.DefaultIcon(TelephonyIcons.UNKNOWN)
+ interactor.getInteractorForSubId(2)!!.networkTypeIconGroup.value =
+ NetworkTypeIconModel.DefaultIcon(TelephonyIcons.THREE_G)
+
+ assertThat(latest).isTrue()
+ job.cancel()
+ }
+
+ @Test
+ fun firstMobileSubShowingNetworkTypeIcon_subListUpdates_valAlsoUpdates() =
+ testScope.runTest {
+ var latest: Boolean? = null
+ val job =
+ underTest.firstMobileSubShowingNetworkTypeIcon.onEach { latest = it }.launchIn(this)
+
+ interactor.filteredSubscriptions.value = listOf(SUB_1, SUB_2)
+ interactor.getInteractorForSubId(1)?.networkTypeIconGroup?.value =
+ NetworkTypeIconModel.DefaultIcon(TelephonyIcons.UNKNOWN)
+ interactor.getInteractorForSubId(2)!!.networkTypeIconGroup.value =
+ NetworkTypeIconModel.DefaultIcon(TelephonyIcons.THREE_G)
+
+ assertThat(latest).isTrue()
+
+ // WHEN the sub list gets new subscriptions where the last subscription is not showing
+ // the network type icon
+ interactor.filteredSubscriptions.value = listOf(SUB_1, SUB_2, SUB_3)
+ interactor.getInteractorForSubId(3)!!.networkTypeIconGroup.value =
+ NetworkTypeIconModel.DefaultIcon(TelephonyIcons.UNKNOWN)
+
+ // THEN the flow updates
+ assertThat(latest).isFalse()
+
+ job.cancel()
+ }
+
+ @Test
+ fun firstMobileSubShowingNetworkTypeIcon_subListReorders_valAlsoUpdates() =
+ testScope.runTest {
+ var latest: Boolean? = null
+ val job =
+ underTest.firstMobileSubShowingNetworkTypeIcon.onEach { latest = it }.launchIn(this)
+
+ interactor.filteredSubscriptions.value = listOf(SUB_1, SUB_2)
+ // Immediately switch the order so that we've created both interactors
+ interactor.filteredSubscriptions.value = listOf(SUB_2, SUB_1)
+ val sub1Interactor = interactor.getInteractorForSubId(1)!!
+ val sub2Interactor = interactor.getInteractorForSubId(2)!!
+
+ interactor.filteredSubscriptions.value = listOf(SUB_1, SUB_2)
+ sub1Interactor.networkTypeIconGroup.value =
+ NetworkTypeIconModel.DefaultIcon(TelephonyIcons.UNKNOWN)
+ sub2Interactor.networkTypeIconGroup.value =
+ NetworkTypeIconModel.DefaultIcon(TelephonyIcons.THREE_G)
+ assertThat(latest).isTrue()
+
+ // WHEN sub1 becomes last and sub1 has no network type icon
+ interactor.filteredSubscriptions.value = listOf(SUB_2, SUB_1)
+
+ // THEN the flow updates
+ assertThat(latest).isFalse()
+
+ // WHEN sub2 becomes last and sub2 has a network type icon
+ interactor.filteredSubscriptions.value = listOf(SUB_1, SUB_2)
+
+ // THEN the flow updates
+ assertThat(latest).isTrue()
+
+ job.cancel()
+ }
+
companion object {
private val SUB_1 = SubscriptionModel(subscriptionId = 1, isOpportunistic = false)
private val SUB_2 = SubscriptionModel(subscriptionId = 2, isOpportunistic = false)
+ private val SUB_3 = SubscriptionModel(subscriptionId = 3, isOpportunistic = false)
}
}
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 5c19108cc17e..0d51af2754f0 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
@@ -50,6 +50,7 @@ import com.android.systemui.util.mockito.whenever
import com.google.common.truth.Truth.assertThat
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.flow.MutableStateFlow
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
@@ -98,12 +99,12 @@ class ModernStatusBarWifiViewTest : SysuiTestCase() {
val viewModelCommon =
WifiViewModel(
airplaneModeViewModel,
+ shouldShowSignalSpacerProvider = { MutableStateFlow(false) },
connectivityConstants,
context,
tableLogBuffer,
interactor,
scope,
- statusBarPipelineFlags,
wifiConstants,
)
viewModel =
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/wifi/ui/viewmodel/WifiViewModelIconParameterizedTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/wifi/ui/viewmodel/WifiViewModelIconParameterizedTest.kt
index ffe990bf1cf6..e6724d86ec55 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/wifi/ui/viewmodel/WifiViewModelIconParameterizedTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/wifi/ui/viewmodel/WifiViewModelIconParameterizedTest.kt
@@ -27,7 +27,6 @@ import com.android.systemui.log.table.TableLogBuffer
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.airplane.data.repository.FakeAirplaneModeRepository
import com.android.systemui.statusbar.pipeline.airplane.domain.interactor.AirplaneModeInteractor
import com.android.systemui.statusbar.pipeline.airplane.ui.viewmodel.AirplaneModeViewModel
@@ -46,6 +45,7 @@ import com.google.common.truth.Truth.assertThat
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.cancel
+import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.runBlocking
import kotlinx.coroutines.yield
@@ -66,7 +66,6 @@ internal class WifiViewModelIconParameterizedTest(private val testCase: TestCase
private lateinit var underTest: WifiViewModel
- @Mock private lateinit var statusBarPipelineFlags: StatusBarPipelineFlags
@Mock private lateinit var tableLogBuffer: TableLogBuffer
@Mock private lateinit var connectivityConstants: ConnectivityConstants
@Mock private lateinit var wifiConstants: WifiConstants
@@ -121,12 +120,12 @@ internal class WifiViewModelIconParameterizedTest(private val testCase: TestCase
underTest =
WifiViewModel(
airplaneModeViewModel,
+ shouldShowSignalSpacerProvider = { MutableStateFlow(false) },
connectivityConstants,
context,
tableLogBuffer,
interactor,
scope,
- statusBarPipelineFlags,
wifiConstants,
)
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 802e360797a4..0e303b244094 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
@@ -39,8 +39,8 @@ import com.android.systemui.statusbar.pipeline.wifi.ui.viewmodel.LocationBasedWi
import com.google.common.truth.Truth.assertThat
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
-import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.cancel
+import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.onEach
import kotlinx.coroutines.runBlocking
@@ -53,7 +53,6 @@ import org.mockito.Mockito.`when` as whenever
import org.mockito.MockitoAnnotations
@Suppress("EXPERIMENTAL_IS_NOT_ENABLED")
-@OptIn(ExperimentalCoroutinesApi::class)
@SmallTest
class WifiViewModelTest : SysuiTestCase() {
@@ -68,6 +67,7 @@ class WifiViewModelTest : SysuiTestCase() {
private lateinit var wifiRepository: FakeWifiRepository
private lateinit var interactor: WifiInteractor
private lateinit var airplaneModeViewModel: AirplaneModeViewModel
+ private val shouldShowSignalSpacerProviderFlow = MutableStateFlow(false)
private lateinit var scope: CoroutineScope
@Before
@@ -473,6 +473,34 @@ class WifiViewModelTest : SysuiTestCase() {
job.cancel()
}
+ @Test
+ fun signalSpacer_firstSubNotShowingNetworkTypeIcon_outputsFalse() =
+ runBlocking(IMMEDIATE) {
+ var latest: Boolean? = null
+ val job = underTest.isSignalSpacerVisible.onEach { latest = it }.launchIn(this)
+
+ shouldShowSignalSpacerProviderFlow.value = false
+ yield()
+
+ assertThat(latest).isFalse()
+
+ job.cancel()
+ }
+
+ @Test
+ fun signalSpacer_firstSubIsShowingNetworkTypeIcon_outputsTrue() =
+ runBlocking(IMMEDIATE) {
+ var latest: Boolean? = null
+ val job = underTest.isSignalSpacerVisible.onEach { latest = it }.launchIn(this)
+
+ shouldShowSignalSpacerProviderFlow.value = true
+ yield()
+
+ assertThat(latest).isTrue()
+
+ job.cancel()
+ }
+
private fun createAndSetViewModel() {
// [WifiViewModel] creates its flows as soon as it's instantiated, and some of those flow
// creations rely on certain config values that we mock out in individual tests. This method
@@ -480,12 +508,12 @@ class WifiViewModelTest : SysuiTestCase() {
underTest =
WifiViewModel(
airplaneModeViewModel,
+ { shouldShowSignalSpacerProviderFlow },
connectivityConstants,
context,
tableLogBuffer,
interactor,
scope,
- statusBarPipelineFlags,
wifiConstants,
)
}