summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author Olivier St-Onge <ostonge@google.com> 2025-03-21 10:36:02 -0700
committer Android (Google) Code Review <android-gerrit@google.com> 2025-03-21 10:36:02 -0700
commit5af6802fdbbccdd034820e2d36be79a2dafaac75 (patch)
treeb0db26ad16811434e93c243dab863a50d765a488
parent15c634697e28a88c9c3af308f625a6275d6efce7 (diff)
parent1129650ee9cac7ecfe4e70638d7d3b184b46ecf6 (diff)
Merge changes I6e5eaa39,I6df2e609 into main
* changes: Collect the icon tint from the StateFlow Only show the stacked mobile icon when all individual mobile icons are visible
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconInteractorKairosAdapterTest.kt2
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/pipeline/mobile/ui/viewmodel/MobileIconsViewModelTest.kt43
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconsInteractor.kt25
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/ui/binder/StackedMobileIconBinder.kt7
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/ui/viewmodel/MobileIconsViewModel.kt14
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/ui/view/SingleBindableStatusBarComposeIconView.kt5
-rw-r--r--packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/FakeMobileIconsInteractor.kt3
7 files changed, 75 insertions, 24 deletions
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconInteractorKairosAdapterTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconInteractorKairosAdapterTest.kt
index e72d0c27e632..8aff622ee772 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconInteractorKairosAdapterTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconInteractorKairosAdapterTest.kt
@@ -97,7 +97,7 @@ class MobileIconInteractorKairosAdapterTest : MobileIconInteractorTestBase() {
}
.asIncremental()
.applyLatestSpecForKey(),
- isStackable = interactor.isStackable.toState(),
+ isStackable = interactor.isStackable.toState(false),
activeDataConnectionHasDataEnabled =
interactor.activeDataConnectionHasDataEnabled.toState(),
activeDataIconInteractor =
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/pipeline/mobile/ui/viewmodel/MobileIconsViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/pipeline/mobile/ui/viewmodel/MobileIconsViewModelTest.kt
index 3d37914b1a7d..7dbcb270190c 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/pipeline/mobile/ui/viewmodel/MobileIconsViewModelTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/pipeline/mobile/ui/viewmodel/MobileIconsViewModelTest.kt
@@ -60,7 +60,6 @@ class MobileIconsViewModelTest : SysuiTestCase() {
private val interactor = FakeMobileIconsInteractor(FakeMobileMappingsProxy(), mock())
private lateinit var airplaneModeInteractor: AirplaneModeInteractor
- @Mock private lateinit var constants: ConnectivityConstants
@Mock private lateinit var logger: MobileViewLogger
@Mock private lateinit var verboseLogger: VerboseMobileViewLogger
@@ -84,7 +83,10 @@ class MobileIconsViewModelTest : SysuiTestCase() {
verboseLogger,
interactor,
airplaneModeInteractor,
- constants,
+ object : ConnectivityConstants {
+ override val hasDataCapabilities = true
+ override val shouldShowActivityConfig = false
+ },
testScope.backgroundScope,
)
@@ -349,7 +351,42 @@ class MobileIconsViewModelTest : SysuiTestCase() {
// 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()
+ }
+
+ @Test
+ fun isStackable_apmEnabled_false() =
+ testScope.runTest {
+ var latest: Boolean? = null
+ val job = underTest.isStackable.onEach { latest = it }.launchIn(this)
+
+ // Set the interactor to true to test APM
+ interactor.isStackable.value = true
+
+ // Enable APM
+ airplaneModeInteractor.setIsAirplaneMode(true)
+
+ interactor.filteredSubscriptions.value = listOf(SUB_1, SUB_2)
+
+ assertThat(latest).isFalse()
+ job.cancel()
+ }
+
+ @Test
+ fun isStackable_apmDisabled_true() =
+ testScope.runTest {
+ var latest: Boolean? = null
+ val job = underTest.isStackable.onEach { latest = it }.launchIn(this)
+
+ // Set the interactor to true to test APM
+ interactor.isStackable.value = true
+
+ // Disable APM
+ airplaneModeInteractor.setIsAirplaneMode(false)
+
+ interactor.filteredSubscriptions.value = listOf(SUB_1, SUB_2)
+
assertThat(latest).isTrue()
job.cancel()
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconsInteractor.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconsInteractor.kt
index 10821dffd394..1f4ccd59b063 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconsInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconsInteractor.kt
@@ -84,7 +84,7 @@ interface MobileIconsInteractor {
val icons: StateFlow<List<MobileIconInteractor>>
/** Whether the mobile icons can be stacked vertically. */
- val isStackable: StateFlow<Boolean>
+ val isStackable: Flow<Boolean>
/**
* Observable for the subscriptionId of the current mobile data connection. Null if we don't
@@ -309,21 +309,20 @@ constructor(
override val isStackable =
if (NewStatusBarIcons.isEnabled && StatusBarRootModernization.isEnabled) {
- icons.flatMapLatest { icons ->
- combine(icons.map { it.signalLevelIcon }) { signalLevelIcons ->
- // These are only stackable if:
- // - They are cellular
- // - There's exactly two
- // - They have the same number of levels
- signalLevelIcons.filterIsInstance<SignalIconModel.Cellular>().let {
- it.size == 2 && it[0].numberOfLevels == it[1].numberOfLevels
- }
+ icons.flatMapLatest { icons ->
+ combine(icons.map { it.signalLevelIcon }) { signalLevelIcons ->
+ // These are only stackable if:
+ // - They are cellular
+ // - There's exactly two
+ // - They have the same number of levels
+ signalLevelIcons.filterIsInstance<SignalIconModel.Cellular>().let {
+ it.size == 2 && it[0].numberOfLevels == it[1].numberOfLevels
}
}
- } else {
- flowOf(false)
}
- .stateIn(scope, SharingStarted.WhileSubscribed(), false)
+ } else {
+ flowOf(false)
+ }
/**
* Copied from the old pipeline. We maintain a 2s period of time where we will keep the
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/ui/binder/StackedMobileIconBinder.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/ui/binder/StackedMobileIconBinder.kt
index 54cd8e3c46e4..72ff3b67c317 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/ui/binder/StackedMobileIconBinder.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/ui/binder/StackedMobileIconBinder.kt
@@ -18,9 +18,11 @@ package com.android.systemui.statusbar.pipeline.mobile.ui.binder
import androidx.compose.material3.LocalContentColor
import androidx.compose.runtime.CompositionLocalProvider
+import androidx.compose.runtime.getValue
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.platform.ViewCompositionStrategy
import androidx.lifecycle.Lifecycle
+import androidx.lifecycle.compose.collectAsStateWithLifecycle
import androidx.lifecycle.repeatOnLifecycle
import com.android.systemui.Flags
import com.android.systemui.kairos.ExperimentalKairosApi
@@ -48,7 +50,7 @@ object StackedMobileIconBinder {
return SingleBindableStatusBarComposeIconView.withDefaultBinding(
view = view,
shouldBeVisible = { mobileIconsViewModel.isStackable.value },
- ) { _, tint ->
+ ) { _, tintFlow ->
view.repeatWhenAttached {
repeatOnLifecycle(Lifecycle.State.STARTED) {
view.composeView.apply {
@@ -66,8 +68,9 @@ object StackedMobileIconBinder {
viewModelFactory.create()
}
}
+ val tint by tintFlow.collectAsStateWithLifecycle()
if (viewModel.isIconVisible) {
- CompositionLocalProvider(LocalContentColor provides Color(tint())) {
+ CompositionLocalProvider(LocalContentColor provides Color(tint)) {
StackedMobileIcon(viewModel)
}
}
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 494d95e7f177..997b185fdee5 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
@@ -36,6 +36,8 @@ import kotlinx.coroutines.Job
import kotlinx.coroutines.cancel
import kotlinx.coroutines.flow.SharingStarted
import kotlinx.coroutines.flow.StateFlow
+import kotlinx.coroutines.flow.collect
+import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.flow.flatMapLatest
import kotlinx.coroutines.flow.flowOf
import kotlinx.coroutines.flow.map
@@ -99,7 +101,17 @@ constructor(
}
.stateIn(scope, SharingStarted.WhileSubscribed(), false)
- val isStackable: StateFlow<Boolean> = interactor.isStackable
+ /** Whether all of [mobileSubViewModels] are visible or not. */
+ private val iconsAreAllVisible =
+ mobileSubViewModels.flatMapLatest { viewModels ->
+ combine(viewModels.map { it.isVisible }) { isVisibleArray -> isVisibleArray.all { it } }
+ }
+
+ val isStackable: StateFlow<Boolean> =
+ combine(iconsAreAllVisible, interactor.isStackable) { isVisible, isStackable ->
+ isVisible && isStackable
+ }
+ .stateIn(scope, SharingStarted.WhileSubscribed(), false)
init {
scope.launch { subscriptionIdsFlow.collect { invalidateCaches(it) } }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/ui/view/SingleBindableStatusBarComposeIconView.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/ui/view/SingleBindableStatusBarComposeIconView.kt
index 8076040564fb..9d1df8967fc0 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/ui/view/SingleBindableStatusBarComposeIconView.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/ui/view/SingleBindableStatusBarComposeIconView.kt
@@ -35,6 +35,7 @@ import com.android.systemui.statusbar.pipeline.shared.ui.binder.ModernStatusBarV
import com.android.systemui.statusbar.pipeline.shared.ui.binder.ModernStatusBarViewVisibilityHelper
import kotlinx.coroutines.awaitCancellation
import kotlinx.coroutines.flow.MutableStateFlow
+import kotlinx.coroutines.flow.StateFlow
/** Compose view that is bound to bindable_status_bar_compose_icon.xml */
class SingleBindableStatusBarComposeIconView(context: Context, attrs: AttributeSet?) :
@@ -78,7 +79,7 @@ class SingleBindableStatusBarComposeIconView(context: Context, attrs: AttributeS
fun withDefaultBinding(
view: SingleBindableStatusBarComposeIconView,
shouldBeVisible: () -> Boolean,
- block: suspend LifecycleOwner.(View, () -> Int) -> Unit,
+ block: suspend LifecycleOwner.(View, StateFlow<Int>) -> Unit,
): ModernStatusBarViewBinding {
@StatusBarIconView.VisibleState
val visibilityState: MutableStateFlow<Int> = MutableStateFlow(STATE_HIDDEN)
@@ -90,7 +91,7 @@ class SingleBindableStatusBarComposeIconView(context: Context, attrs: AttributeS
view.repeatWhenAttached {
// Child binding
- block(view) { iconTint.value }
+ block(view, iconTint)
lifecycleScope.launch {
repeatOnLifecycle(Lifecycle.State.STARTED) {
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/FakeMobileIconsInteractor.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/FakeMobileIconsInteractor.kt
index 8fa82cad5c32..72f9d550eb4d 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/FakeMobileIconsInteractor.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/FakeMobileIconsInteractor.kt
@@ -26,7 +26,6 @@ import com.android.systemui.log.table.TableLogBuffer
import com.android.systemui.statusbar.pipeline.mobile.data.model.SubscriptionModel
import com.android.systemui.statusbar.pipeline.mobile.util.MobileMappingsProxy
import kotlinx.coroutines.flow.MutableStateFlow
-import kotlinx.coroutines.flow.StateFlow
class FakeMobileIconsInteractor(
mobileMappings: MobileMappingsProxy,
@@ -76,7 +75,7 @@ class FakeMobileIconsInteractor(
override val icons: MutableStateFlow<List<MobileIconInteractor>> = MutableStateFlow(emptyList())
- override val isStackable: StateFlow<Boolean> = MutableStateFlow(false)
+ override val isStackable: MutableStateFlow<Boolean> = MutableStateFlow(false)
private val _defaultMobileIconMapping = MutableStateFlow(TEST_MAPPING)
override val defaultMobileIconMapping = _defaultMobileIconMapping