diff options
7 files changed, 209 insertions, 19 deletions
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconInteractor.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconInteractor.kt index b36ba3845fe9..d42e30c9b1b9 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconInteractor.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconInteractor.kt @@ -110,6 +110,9 @@ interface MobileIconInteractor { /** See [MobileIconsInteractor.isForceHidden]. */ val isForceHidden: Flow<Boolean> + + /** True when in carrier network change mode */ + val carrierNetworkChangeActive: StateFlow<Boolean> } /** Interactor for a single mobile connection. This connection _should_ have one subscription ID */ @@ -135,6 +138,9 @@ class MobileIconInteractorImpl( override val isDataEnabled: StateFlow<Boolean> = connectionRepository.dataEnabled + override val carrierNetworkChangeActive: StateFlow<Boolean> = + connectionRepository.carrierNetworkChangeActive + // True if there exists _any_ icon override for this carrierId. Note that overrides can include // any or none of the icon groups defined in MobileMappings, so we still need to check on a // per-network-type basis whether or not the given icon group is overridden diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/ui/binder/MobileIconBinder.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/ui/binder/MobileIconBinder.kt index 5b7d45b55c5c..a2a247a279fb 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/ui/binder/MobileIconBinder.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/ui/binder/MobileIconBinder.kt @@ -109,12 +109,7 @@ object MobileIconBinder { viewModel.subscriptionId, icon, ) - mobileDrawable.level = - SignalDrawable.getState( - icon.level, - icon.numberOfLevels, - icon.showExclamationMark, - ) + mobileDrawable.level = icon.toSignalDrawableState() } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/ui/model/SignalIconModel.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/ui/model/SignalIconModel.kt index be2e41a2a581..6de3f85027ae 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/ui/model/SignalIconModel.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/ui/model/SignalIconModel.kt @@ -16,6 +16,7 @@ package com.android.systemui.statusbar.pipeline.mobile.ui.model +import com.android.settingslib.graph.SignalDrawable import com.android.systemui.log.table.Diffable import com.android.systemui.log.table.TableRowLogger @@ -24,6 +25,7 @@ data class SignalIconModel( val level: Int, val numberOfLevels: Int, val showExclamationMark: Boolean, + val carrierNetworkChange: Boolean, ) : Diffable<SignalIconModel> { // TODO(b/267767715): Can we implement [logDiffs] and [logFull] generically for data classes? override fun logDiffs(prevVal: SignalIconModel, row: TableRowLogger) { @@ -36,17 +38,30 @@ data class SignalIconModel( if (prevVal.showExclamationMark != showExclamationMark) { row.logChange(COL_SHOW_EXCLAMATION, showExclamationMark) } + if (prevVal.carrierNetworkChange != carrierNetworkChange) { + row.logChange(COL_CARRIER_NETWORK_CHANGE, carrierNetworkChange) + } } override fun logFull(row: TableRowLogger) { row.logChange(COL_LEVEL, level) row.logChange(COL_NUM_LEVELS, numberOfLevels) row.logChange(COL_SHOW_EXCLAMATION, showExclamationMark) + row.logChange(COL_CARRIER_NETWORK_CHANGE, carrierNetworkChange) } + /** Convert this model to an [Int] consumable by [SignalDrawable]. */ + fun toSignalDrawableState(): Int = + if (carrierNetworkChange) { + SignalDrawable.getCarrierChangeState(numberOfLevels) + } else { + SignalDrawable.getState(level, numberOfLevels, showExclamationMark) + } + companion object { private const val COL_LEVEL = "level" private const val COL_NUM_LEVELS = "numLevels" private const val COL_SHOW_EXCLAMATION = "showExclamation" + private const val COL_CARRIER_NETWORK_CHANGE = "carrierNetworkChange" } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/ui/viewmodel/MobileIconViewModel.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/ui/viewmodel/MobileIconViewModel.kt index 54730ed82564..35f4f9aa4622 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/ui/viewmodel/MobileIconViewModel.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/ui/viewmodel/MobileIconViewModel.kt @@ -122,13 +122,20 @@ constructor( level = shownLevel.value, numberOfLevels = iconInteractor.numberOfLevels.value, showExclamationMark = showExclamationMark.value, + carrierNetworkChange = iconInteractor.carrierNetworkChangeActive.value, ) combine( shownLevel, iconInteractor.numberOfLevels, showExclamationMark, - ) { shownLevel, numberOfLevels, showExclamationMark -> - SignalIconModel(shownLevel, numberOfLevels, showExclamationMark) + iconInteractor.carrierNetworkChangeActive, + ) { shownLevel, numberOfLevels, showExclamationMark, carrierNetworkChange -> + SignalIconModel( + shownLevel, + numberOfLevels, + showExclamationMark, + carrierNetworkChange, + ) } .distinctUntilChanged() .logDiffsForTable( @@ -152,8 +159,10 @@ constructor( iconInteractor.isDataEnabled, iconInteractor.alwaysShowDataRatIcon, iconInteractor.mobileIsDefault, - ) { dataConnected, dataEnabled, alwaysShow, mobileIsDefault -> - alwaysShow || (dataEnabled && dataConnected && mobileIsDefault) + iconInteractor.carrierNetworkChangeActive, + ) { dataConnected, dataEnabled, alwaysShow, mobileIsDefault, carrierNetworkChange -> + alwaysShow || + (!carrierNetworkChange && (dataEnabled && dataConnected && mobileIsDefault)) } .distinctUntilChanged() .logDiffsForTable( diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/FakeMobileIconInteractor.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/FakeMobileIconInteractor.kt index f054422e6524..c4e419366759 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/FakeMobileIconInteractor.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/FakeMobileIconInteractor.kt @@ -40,6 +40,8 @@ class FakeMobileIconInteractor( ) ) + override val carrierNetworkChangeActive = MutableStateFlow(false) + override val mobileIsDefault = MutableStateFlow(true) override val networkTypeIconGroup = diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/ui/model/SignalIconModelParameterizedTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/ui/model/SignalIconModelParameterizedTest.kt new file mode 100644 index 000000000000..01c388a523e6 --- /dev/null +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/ui/model/SignalIconModelParameterizedTest.kt @@ -0,0 +1,117 @@ +/* + * Copyright (C) 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.statusbar.pipeline.mobile.ui.model + +import androidx.test.filters.SmallTest +import com.android.settingslib.graph.SignalDrawable +import com.android.systemui.SysuiTestCase +import com.google.common.truth.Truth.assertThat +import org.junit.Test +import org.junit.runner.RunWith +import org.junit.runners.Parameterized +import org.junit.runners.Parameterized.Parameters + +@SmallTest +@RunWith(Parameterized::class) +internal class SignalIconModelParameterizedTest(private val testCase: TestCase) : SysuiTestCase() { + @Test + fun drawableFromModel_level0_numLevels4_noExclamation_notCarrierNetworkChange() { + val model = + SignalIconModel( + level = 0, + numberOfLevels = 4, + showExclamationMark = false, + carrierNetworkChange = false + ) + + val expected = + SignalDrawable.getState(/* level = */ 0, /* numLevels = */ 4, /* cutOut = */ false) + + assertThat(model.toSignalDrawableState()).isEqualTo(expected) + } + + @Test + fun runTest() { + val model = testCase.toSignalIconModel() + assertThat(model.toSignalDrawableState()).isEqualTo(testCase.expected) + } + + internal data class TestCase( + val level: Int, + val numberOfLevels: Int, + val showExclamation: Boolean, + val carrierNetworkChange: Boolean, + val expected: Int, + ) { + fun toSignalIconModel() = + SignalIconModel( + level = level, + numberOfLevels = numberOfLevels, + showExclamationMark = showExclamation, + carrierNetworkChange = carrierNetworkChange, + ) + + override fun toString(): String = + "INPUT(level=$level," + + "numberOfLevels=$numberOfLevels," + + "showExclamation=$showExclamation," + + "carrierNetworkChange=$carrierNetworkChange)" + } + + companion object { + @Parameters(name = "{0}") @JvmStatic fun data() = testData() + + private fun testData(): Collection<TestCase> = + listOf( + TestCase( + level = 0, + numberOfLevels = 4, + showExclamation = false, + carrierNetworkChange = false, + expected = SignalDrawable.getState(0, 4, false) + ), + TestCase( + level = 0, + numberOfLevels = 4, + showExclamation = false, + carrierNetworkChange = true, + expected = SignalDrawable.getCarrierChangeState(4) + ), + TestCase( + level = 2, + numberOfLevels = 5, + showExclamation = false, + carrierNetworkChange = false, + expected = SignalDrawable.getState(2, 5, false) + ), + TestCase( + level = 2, + numberOfLevels = 5, + showExclamation = true, + carrierNetworkChange = false, + expected = SignalDrawable.getState(2, 5, true) + ), + TestCase( + level = 2, + numberOfLevels = 5, + showExclamation = true, + carrierNetworkChange = true, + expected = SignalDrawable.getCarrierChangeState(5) + ), + ) + } +} diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/ui/viewmodel/MobileIconViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/ui/viewmodel/MobileIconViewModelTest.kt index 2b7bc780f7c7..b5ab29d6217e 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/ui/viewmodel/MobileIconViewModelTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/ui/viewmodel/MobileIconViewModelTest.kt @@ -273,6 +273,27 @@ class MobileIconViewModelTest : SysuiTestCase() { } @Test + fun icon_usesCarrierNetworkState_whenInCarrierNetworkChangeMode() = + testScope.runTest { + var latest: SignalIconModel? = null + val job = underTest.icon.onEach { latest = it }.launchIn(this) + + interactor.carrierNetworkChangeActive.value = true + interactor.level.value = 1 + + assertThat(latest!!.level).isEqualTo(1) + assertThat(latest!!.carrierNetworkChange).isTrue() + + // SignalIconModel respects the current level + interactor.level.value = 2 + + assertThat(latest!!.level).isEqualTo(2) + assertThat(latest!!.carrierNetworkChange).isTrue() + + job.cancel() + } + + @Test fun contentDescription_notInService_usesNoPhone() = testScope.runTest { var latest: ContentDescription? = null @@ -338,6 +359,20 @@ class MobileIconViewModelTest : SysuiTestCase() { } @Test + fun networkType_null_whenCarrierNetworkChangeActive() = + testScope.runTest { + interactor.networkTypeIconGroup.value = NetworkTypeIconModel.DefaultIcon(THREE_G) + interactor.carrierNetworkChangeActive.value = true + interactor.mobileIsDefault.value = true + var latest: Icon? = null + val job = underTest.networkTypeIcon.onEach { latest = it }.launchIn(this) + + assertThat(latest).isNull() + + job.cancel() + } + + @Test fun networkTypeIcon_notNull_whenEnabled() = testScope.runTest { val expected = @@ -617,13 +652,14 @@ class MobileIconViewModelTest : SysuiTestCase() { } private fun createAndSetViewModel() { - underTest = MobileIconViewModel( - SUB_1_ID, - interactor, - airplaneModeInteractor, - constants, - testScope.backgroundScope, - ) + underTest = + MobileIconViewModel( + SUB_1_ID, + interactor, + airplaneModeInteractor, + constants, + testScope.backgroundScope, + ) } companion object { @@ -632,10 +668,20 @@ class MobileIconViewModelTest : SysuiTestCase() { /** Convenience constructor for these tests */ fun defaultSignal(level: Int = 1): SignalIconModel { - return SignalIconModel(level, NUM_LEVELS, showExclamationMark = false) + return SignalIconModel( + level, + NUM_LEVELS, + showExclamationMark = false, + carrierNetworkChange = false, + ) } fun emptySignal(): SignalIconModel = - SignalIconModel(level = 0, numberOfLevels = NUM_LEVELS, showExclamationMark = true) + SignalIconModel( + level = 0, + numberOfLevels = NUM_LEVELS, + showExclamationMark = true, + carrierNetworkChange = false, + ) } } |