Loading packages/SystemUI/Android.bp +3 −0 Original line number Diff line number Diff line Loading @@ -220,6 +220,7 @@ filegroup { "tests/src/**/systemui/statusbar/phone/StatusBarBoundsProviderTest.kt", "tests/src/**/systemui/statusbar/phone/StatusBarMoveFromCenterAnimationControllerTest.kt", "tests/src/**/systemui/statusbar/pipeline/airplane/ui/viewmodel/AirplaneModeViewModelImplTest.kt", "tests/src/**/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionsRepositoryKairosAdapterTest.kt", "tests/src/**/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionsRepositoryTest.kt", "tests/src/**/systemui/statusbar/pipeline/mobile/ui/view/ModernStatusBarMobileViewTest.kt", "tests/src/**/systemui/statusbar/pipeline/wifi/ui/view/ModernStatusBarWifiViewTest.kt", Loading Loading @@ -356,7 +357,9 @@ filegroup { "tests/src/**/systemui/qs/tiles/AlarmTileTest.kt", "tests/src/**/systemui/qs/tiles/BluetoothTileTest.kt", "tests/src/**/systemui/statusbar/pipeline/mobile/data/repository/prod/FullMobileConnectionRepositoryTest.kt", "tests/src/**/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionRepositoryKairosAdapterTest.kt", "tests/src/**/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionRepositoryTest.kt", "tests/src/**/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionKairosAdapterTelephonySmokeTests.kt", "tests/src/**/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionTelephonySmokeTests.kt", "tests/src/**/systemui/statusbar/pipeline/mobile/data/repository/MobileRepositorySwitcherTest.kt", "tests/src/**/systemui/statusbar/pipeline/mobile/data/model/SystemUiCarrierConfigTest.kt", Loading packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/CarrierMergedConnectionRepositoryKairosAdapterTest.kt 0 → 100644 +70 −0 Original line number Diff line number Diff line /* * Copyright (C) 2025 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.data.repository.prod import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.filters.SmallTest import com.android.systemui.activated import com.android.systemui.kairos.ExperimentalKairosApi import com.android.systemui.kairos.launchKairosNetwork import com.android.systemui.kairos.stateOf import com.android.systemui.statusbar.pipeline.mobile.data.model.SystemUiCarrierConfig import com.android.systemui.statusbar.pipeline.mobile.data.model.testCarrierConfig import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.Job import kotlinx.coroutines.launch import kotlinx.coroutines.test.runCurrent import org.junit.runner.RunWith import org.mockito.Mockito @OptIn(ExperimentalKairosApi::class, ExperimentalCoroutinesApi::class) @SmallTest @RunWith(AndroidJUnit4::class) class CarrierMergedConnectionRepositoryKairosAdapterTest : CarrierMergedConnectionRepositoryTestBase() { var job: Job? = null val kairosNetwork = testScope.backgroundScope.launchKairosNetwork() override fun recreateRepo(): MobileConnectionRepositoryKairosAdapter { lateinit var adapter: MobileConnectionRepositoryKairosAdapter job?.cancel() Mockito.clearInvocations(telephonyManager) job = testScope.backgroundScope.launch { kairosNetwork.activateSpec { val repo = activated { CarrierMergedConnectionRepositoryKairos( SUB_ID, logger, telephonyManager, wifiRepository, isInEcmMode = stateOf(false), ) } adapter = MobileConnectionRepositoryKairosAdapter( repo, SystemUiCarrierConfig(SUB_ID, testCarrierConfig()), ) Unit } } testScope.runCurrent() // ensure the lateinit is set return adapter } } packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/CarrierMergedConnectionRepositoryTest.kt +37 −49 Original line number Diff line number Diff line Loading @@ -25,6 +25,7 @@ import com.android.systemui.log.table.TableLogBuffer import com.android.systemui.statusbar.pipeline.mobile.data.model.DataConnectionState import com.android.systemui.statusbar.pipeline.mobile.data.model.NetworkNameModel import com.android.systemui.statusbar.pipeline.mobile.data.model.ResolvedNetworkType import com.android.systemui.statusbar.pipeline.mobile.data.repository.MobileConnectionRepository import com.android.systemui.statusbar.pipeline.shared.data.model.DataActivityModel import com.android.systemui.statusbar.pipeline.wifi.data.repository.FakeWifiRepository import com.android.systemui.statusbar.pipeline.wifi.shared.model.WifiNetworkModel Loading @@ -43,16 +44,30 @@ import org.mockito.MockitoAnnotations @SmallTest @RunWith(AndroidJUnit4::class) class CarrierMergedConnectionRepositoryTest : SysuiTestCase() { class CarrierMergedConnectionRepositoryTest : CarrierMergedConnectionRepositoryTestBase() { override fun recreateRepo() = CarrierMergedConnectionRepository( SUB_ID, logger, telephonyManager, testScope.backgroundScope.coroutineContext, testScope.backgroundScope, wifiRepository, ) } abstract class CarrierMergedConnectionRepositoryTestBase : SysuiTestCase() { protected lateinit var underTest: MobileConnectionRepository private lateinit var underTest: CarrierMergedConnectionRepository protected lateinit var wifiRepository: FakeWifiRepository @Mock protected lateinit var logger: TableLogBuffer @Mock protected lateinit var telephonyManager: TelephonyManager private lateinit var wifiRepository: FakeWifiRepository @Mock private lateinit var logger: TableLogBuffer @Mock private lateinit var telephonyManager: TelephonyManager protected val testDispatcher = UnconfinedTestDispatcher() protected val testScope = TestScope(testDispatcher) private val testDispatcher = UnconfinedTestDispatcher() private val testScope = TestScope(testDispatcher) abstract fun recreateRepo(): MobileConnectionRepository @Before fun setUp() { Loading @@ -62,15 +77,7 @@ class CarrierMergedConnectionRepositoryTest : SysuiTestCase() { wifiRepository = FakeWifiRepository() underTest = CarrierMergedConnectionRepository( SUB_ID, logger, telephonyManager, testScope.backgroundScope.coroutineContext, testScope.backgroundScope, wifiRepository, ) underTest = recreateRepo() } @Test Loading Loading @@ -121,10 +128,7 @@ class CarrierMergedConnectionRepositoryTest : SysuiTestCase() { wifiRepository.setIsWifiDefault(true) wifiRepository.setWifiNetwork( WifiNetworkModel.CarrierMerged.of( subscriptionId = SUB_ID, level = 3, ) WifiNetworkModel.CarrierMerged.of(subscriptionId = SUB_ID, level = 3) ) assertThat(latest).isEqualTo(3) Loading @@ -141,26 +145,17 @@ class CarrierMergedConnectionRepositoryTest : SysuiTestCase() { wifiRepository.setIsWifiEnabled(true) wifiRepository.setIsWifiDefault(true) wifiRepository.setWifiNetwork( WifiNetworkModel.CarrierMerged.of( subscriptionId = SUB_ID, level = 3, ) WifiNetworkModel.CarrierMerged.of(subscriptionId = SUB_ID, level = 3) ) wifiRepository.setWifiActivity( DataActivityModel( hasActivityIn = true, hasActivityOut = false, ) DataActivityModel(hasActivityIn = true, hasActivityOut = false) ) assertThat(latest!!.hasActivityIn).isTrue() assertThat(latest!!.hasActivityOut).isFalse() wifiRepository.setWifiActivity( DataActivityModel( hasActivityIn = false, hasActivityOut = true, ) DataActivityModel(hasActivityIn = false, hasActivityOut = true) ) assertThat(latest!!.hasActivityIn).isFalse() Loading @@ -178,10 +173,7 @@ class CarrierMergedConnectionRepositoryTest : SysuiTestCase() { val typeJob = underTest.resolvedNetworkType.onEach { latestType = it }.launchIn(this) wifiRepository.setWifiNetwork( WifiNetworkModel.CarrierMerged.of( subscriptionId = SUB_ID + 10, level = 3, ) WifiNetworkModel.CarrierMerged.of(subscriptionId = SUB_ID + 10, level = 3) ) assertThat(latestLevel).isNotEqualTo(3) Loading @@ -199,10 +191,7 @@ class CarrierMergedConnectionRepositoryTest : SysuiTestCase() { val job = underTest.primaryLevel.onEach { latest = it }.launchIn(this) wifiRepository.setWifiNetwork( WifiNetworkModel.CarrierMerged.of( subscriptionId = SUB_ID, level = 3, ) WifiNetworkModel.CarrierMerged.of(subscriptionId = SUB_ID, level = 3) ) wifiRepository.setIsWifiEnabled(false) Loading @@ -219,10 +208,7 @@ class CarrierMergedConnectionRepositoryTest : SysuiTestCase() { val job = underTest.primaryLevel.onEach { latest = it }.launchIn(this) wifiRepository.setWifiNetwork( WifiNetworkModel.CarrierMerged.of( subscriptionId = SUB_ID, level = 3, ) WifiNetworkModel.CarrierMerged.of(subscriptionId = SUB_ID, level = 3) ) wifiRepository.setIsWifiDefault(false) Loading Loading @@ -280,6 +266,7 @@ class CarrierMergedConnectionRepositoryTest : SysuiTestCase() { fun networkName_usesSimOperatorNameAsInitial() = testScope.runTest { whenever(telephonyManager.simOperatorName).thenReturn("Test SIM name") underTest = recreateRepo() var latest: NetworkNameModel? = null val job = underTest.networkName.onEach { latest = it }.launchIn(this) Loading @@ -293,6 +280,10 @@ class CarrierMergedConnectionRepositoryTest : SysuiTestCase() { fun networkName_updatesOnNetworkUpdate() = testScope.runTest { whenever(telephonyManager.simOperatorName).thenReturn("Test SIM name") underTest = recreateRepo() wifiRepository.setIsWifiEnabled(true) wifiRepository.setIsWifiDefault(true) var latest: NetworkNameModel? = null val job = underTest.networkName.onEach { latest = it }.launchIn(this) Loading @@ -301,10 +292,7 @@ class CarrierMergedConnectionRepositoryTest : SysuiTestCase() { whenever(telephonyManager.simOperatorName).thenReturn("New SIM name") wifiRepository.setWifiNetwork( WifiNetworkModel.CarrierMerged.of( subscriptionId = SUB_ID, level = 3, ) WifiNetworkModel.CarrierMerged.of(subscriptionId = SUB_ID, level = 3) ) assertThat(latest).isEqualTo(NetworkNameModel.SimDerived("New SIM name")) Loading @@ -320,7 +308,7 @@ class CarrierMergedConnectionRepositoryTest : SysuiTestCase() { assertThat(latest).isTrue() } private companion object { companion object { const val SUB_ID = 123 } } packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconInteractorKairosAdapterTest.kt 0 → 100644 +141 −0 Original line number Diff line number Diff line /* * Copyright (C) 2025 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.domain.interactor import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.filters.SmallTest import com.android.settingslib.SignalIcon import com.android.settingslib.mobile.MobileIconCarrierIdOverrides import com.android.systemui.activated import com.android.systemui.kairos.BuildScope import com.android.systemui.kairos.ExperimentalKairosApi import com.android.systemui.kairos.Incremental import com.android.systemui.kairos.State import com.android.systemui.kairos.asIncremental import com.android.systemui.kairos.buildSpec import com.android.systemui.kairos.combine import com.android.systemui.kairos.launchKairosNetwork import com.android.systemui.statusbar.pipeline.mobile.data.model.SubscriptionModel import com.android.systemui.statusbar.pipeline.mobile.domain.interactor.MobileIconsInteractorKairosAdapterTest.Companion.wrapRepo import com.android.systemui.util.mockito.mock import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.Job import kotlinx.coroutines.launch import kotlinx.coroutines.test.runCurrent import org.junit.runner.RunWith @OptIn(ExperimentalKairosApi::class, ExperimentalCoroutinesApi::class) @SmallTest @RunWith(AndroidJUnit4::class) class MobileIconInteractorKairosAdapterTest : MobileIconInteractorTestBase() { var job: Job? = null val kairosNetwork = testScope.backgroundScope.launchKairosNetwork() override fun createInteractor(overrides: MobileIconCarrierIdOverrides): MobileIconInteractor { lateinit var result: MobileIconInteractor job?.cancel() job = testScope.backgroundScope.launch { kairosNetwork.activateSpec { val wrapped = wrap(mobileIconsInteractor) result = MobileIconInteractorKairosAdapter( kairosImpl = activated { MobileIconInteractorKairosImpl( defaultSubscriptionHasDataEnabled = wrapped.activeDataConnectionHasDataEnabled, alwaysShowDataRatIcon = wrapped.alwaysShowDataRatIcon, alwaysUseCdmaLevel = wrapped.alwaysUseCdmaLevel, isSingleCarrier = wrapped.isSingleCarrier, mobileIsDefault = wrapped.mobileIsDefault, defaultMobileIconMapping = wrapped.defaultMobileIconMapping, defaultMobileIconGroup = wrapped.defaultMobileIconGroup, isDefaultConnectionFailed = wrapped.isDefaultConnectionFailed, isForceHidden = wrapped.isForceHidden, connectionRepository = wrapRepo(connectionRepository), context = context, carrierIdOverrides = overrides, ) } ) Unit } } testScope.runCurrent() // ensure the lateinit is set return result } /** Allows us to wrap a (likely fake) MobileIconsInteractor into a Kairos version. */ private fun BuildScope.wrap(interactor: MobileIconsInteractor): MobileIconsInteractorKairos { val filteredSubscriptions = interactor.filteredSubscriptions.toState(emptyList()) val icons = interactor.icons.toState() return InteractorWrapper( mobileIsDefault = interactor.mobileIsDefault.toState(), filteredSubscriptions = filteredSubscriptions, icons = combine(filteredSubscriptions, icons) { subs, icons -> subs.zip(icons).associate { (subModel, icon) -> subModel.subscriptionId to buildSpec { wrap(icon) } } } .asIncremental() .applyLatestSpecForKey(), isStackable = interactor.isStackable.toState(), activeDataConnectionHasDataEnabled = interactor.activeDataConnectionHasDataEnabled.toState(), activeDataIconInteractor = interactor.activeDataIconInteractor.toState().mapLatestBuild { it?.let { wrap(it) } }, alwaysShowDataRatIcon = interactor.alwaysShowDataRatIcon.toState(), alwaysUseCdmaLevel = interactor.alwaysUseCdmaLevel.toState(), isSingleCarrier = interactor.isSingleCarrier.toState(), defaultMobileIconMapping = interactor.defaultMobileIconMapping.toState(), defaultMobileIconGroup = interactor.defaultMobileIconGroup.toState(), isDefaultConnectionFailed = interactor.isDefaultConnectionFailed.toState(), isUserSetUp = interactor.isUserSetUp.toState(), isForceHidden = interactor.isForceHidden.toState(false), isDeviceInEmergencyCallsOnlyMode = interactor.isDeviceInEmergencyCallsOnlyMode.toState(false), ) } private fun BuildScope.wrap(interactor: MobileIconInteractor): MobileIconInteractorKairos = // unused in tests mock() private class InteractorWrapper( override val mobileIsDefault: State<Boolean>, override val filteredSubscriptions: State<List<SubscriptionModel>>, override val icons: Incremental<Int, MobileIconInteractorKairos>, override val isStackable: State<Boolean>, override val activeDataConnectionHasDataEnabled: State<Boolean>, override val activeDataIconInteractor: State<MobileIconInteractorKairos?>, override val alwaysShowDataRatIcon: State<Boolean>, override val alwaysUseCdmaLevel: State<Boolean>, override val isSingleCarrier: State<Boolean>, override val defaultMobileIconMapping: State<Map<String, SignalIcon.MobileIconGroup>>, override val defaultMobileIconGroup: State<SignalIcon.MobileIconGroup>, override val isDefaultConnectionFailed: State<Boolean>, override val isUserSetUp: State<Boolean>, override val isForceHidden: State<Boolean>, override val isDeviceInEmergencyCallsOnlyMode: State<Boolean>, ) : MobileIconsInteractorKairos } packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconInteractorTest.kt +30 −25 Original line number Diff line number Diff line Loading @@ -22,6 +22,7 @@ import android.telephony.CellSignalStrength import android.telephony.TelephonyManager.NETWORK_TYPE_UNKNOWN import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.filters.SmallTest import com.android.internal.telephony.flags.Flags import com.android.settingslib.mobile.MobileIconCarrierIdOverrides import com.android.settingslib.mobile.MobileIconCarrierIdOverridesImpl import com.android.settingslib.mobile.TelephonyIcons Loading Loading @@ -58,21 +59,40 @@ import org.mockito.ArgumentMatchers.anyString @SmallTest @RunWith(AndroidJUnit4::class) class MobileIconInteractorTest : SysuiTestCase() { private val kosmos = testKosmos() class MobileIconInteractorTest : MobileIconInteractorTestBase() { override fun createInteractor(overrides: MobileIconCarrierIdOverrides) = MobileIconInteractorImpl( testScope.backgroundScope, mobileIconsInteractor.activeDataConnectionHasDataEnabled, mobileIconsInteractor.alwaysShowDataRatIcon, mobileIconsInteractor.alwaysUseCdmaLevel, mobileIconsInteractor.isSingleCarrier, mobileIconsInteractor.mobileIsDefault, mobileIconsInteractor.defaultMobileIconMapping, mobileIconsInteractor.defaultMobileIconGroup, mobileIconsInteractor.isDefaultConnectionFailed, mobileIconsInteractor.isForceHidden, connectionRepository, context, overrides, ) } private lateinit var underTest: MobileIconInteractor private val mobileMappingsProxy = FakeMobileMappingsProxy() private val mobileIconsInteractor = FakeMobileIconsInteractor(mobileMappingsProxy, mock()) abstract class MobileIconInteractorTestBase : SysuiTestCase() { protected val kosmos = testKosmos() private val connectionRepository = protected lateinit var underTest: MobileIconInteractor protected val mobileMappingsProxy = FakeMobileMappingsProxy() protected val mobileIconsInteractor = FakeMobileIconsInteractor(mobileMappingsProxy, mock()) protected val connectionRepository = FakeMobileConnectionRepository( SUB_1_ID, logcatTableLogBuffer(kosmos, "MobileIconInteractorTest"), ) private val testDispatcher = UnconfinedTestDispatcher() private val testScope = TestScope(testDispatcher) protected val testDispatcher = UnconfinedTestDispatcher() protected val testScope = TestScope(testDispatcher) @Before fun setUp() { Loading Loading @@ -835,24 +855,9 @@ class MobileIconInteractorTest : SysuiTestCase() { assertThat(latest!!.level).isEqualTo(0) } private fun createInteractor( abstract fun createInteractor( overrides: MobileIconCarrierIdOverrides = MobileIconCarrierIdOverridesImpl() ) = MobileIconInteractorImpl( testScope.backgroundScope, mobileIconsInteractor.activeDataConnectionHasDataEnabled, mobileIconsInteractor.alwaysShowDataRatIcon, mobileIconsInteractor.alwaysUseCdmaLevel, mobileIconsInteractor.isSingleCarrier, mobileIconsInteractor.mobileIsDefault, mobileIconsInteractor.defaultMobileIconMapping, mobileIconsInteractor.defaultMobileIconGroup, mobileIconsInteractor.isDefaultConnectionFailed, mobileIconsInteractor.isForceHidden, connectionRepository, context, overrides, ) ): MobileIconInteractor companion object { private const val GSM_LEVEL = 1 Loading Loading
packages/SystemUI/Android.bp +3 −0 Original line number Diff line number Diff line Loading @@ -220,6 +220,7 @@ filegroup { "tests/src/**/systemui/statusbar/phone/StatusBarBoundsProviderTest.kt", "tests/src/**/systemui/statusbar/phone/StatusBarMoveFromCenterAnimationControllerTest.kt", "tests/src/**/systemui/statusbar/pipeline/airplane/ui/viewmodel/AirplaneModeViewModelImplTest.kt", "tests/src/**/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionsRepositoryKairosAdapterTest.kt", "tests/src/**/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionsRepositoryTest.kt", "tests/src/**/systemui/statusbar/pipeline/mobile/ui/view/ModernStatusBarMobileViewTest.kt", "tests/src/**/systemui/statusbar/pipeline/wifi/ui/view/ModernStatusBarWifiViewTest.kt", Loading Loading @@ -356,7 +357,9 @@ filegroup { "tests/src/**/systemui/qs/tiles/AlarmTileTest.kt", "tests/src/**/systemui/qs/tiles/BluetoothTileTest.kt", "tests/src/**/systemui/statusbar/pipeline/mobile/data/repository/prod/FullMobileConnectionRepositoryTest.kt", "tests/src/**/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionRepositoryKairosAdapterTest.kt", "tests/src/**/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionRepositoryTest.kt", "tests/src/**/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionKairosAdapterTelephonySmokeTests.kt", "tests/src/**/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionTelephonySmokeTests.kt", "tests/src/**/systemui/statusbar/pipeline/mobile/data/repository/MobileRepositorySwitcherTest.kt", "tests/src/**/systemui/statusbar/pipeline/mobile/data/model/SystemUiCarrierConfigTest.kt", Loading
packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/CarrierMergedConnectionRepositoryKairosAdapterTest.kt 0 → 100644 +70 −0 Original line number Diff line number Diff line /* * Copyright (C) 2025 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.data.repository.prod import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.filters.SmallTest import com.android.systemui.activated import com.android.systemui.kairos.ExperimentalKairosApi import com.android.systemui.kairos.launchKairosNetwork import com.android.systemui.kairos.stateOf import com.android.systemui.statusbar.pipeline.mobile.data.model.SystemUiCarrierConfig import com.android.systemui.statusbar.pipeline.mobile.data.model.testCarrierConfig import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.Job import kotlinx.coroutines.launch import kotlinx.coroutines.test.runCurrent import org.junit.runner.RunWith import org.mockito.Mockito @OptIn(ExperimentalKairosApi::class, ExperimentalCoroutinesApi::class) @SmallTest @RunWith(AndroidJUnit4::class) class CarrierMergedConnectionRepositoryKairosAdapterTest : CarrierMergedConnectionRepositoryTestBase() { var job: Job? = null val kairosNetwork = testScope.backgroundScope.launchKairosNetwork() override fun recreateRepo(): MobileConnectionRepositoryKairosAdapter { lateinit var adapter: MobileConnectionRepositoryKairosAdapter job?.cancel() Mockito.clearInvocations(telephonyManager) job = testScope.backgroundScope.launch { kairosNetwork.activateSpec { val repo = activated { CarrierMergedConnectionRepositoryKairos( SUB_ID, logger, telephonyManager, wifiRepository, isInEcmMode = stateOf(false), ) } adapter = MobileConnectionRepositoryKairosAdapter( repo, SystemUiCarrierConfig(SUB_ID, testCarrierConfig()), ) Unit } } testScope.runCurrent() // ensure the lateinit is set return adapter } }
packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/CarrierMergedConnectionRepositoryTest.kt +37 −49 Original line number Diff line number Diff line Loading @@ -25,6 +25,7 @@ import com.android.systemui.log.table.TableLogBuffer import com.android.systemui.statusbar.pipeline.mobile.data.model.DataConnectionState import com.android.systemui.statusbar.pipeline.mobile.data.model.NetworkNameModel import com.android.systemui.statusbar.pipeline.mobile.data.model.ResolvedNetworkType import com.android.systemui.statusbar.pipeline.mobile.data.repository.MobileConnectionRepository import com.android.systemui.statusbar.pipeline.shared.data.model.DataActivityModel import com.android.systemui.statusbar.pipeline.wifi.data.repository.FakeWifiRepository import com.android.systemui.statusbar.pipeline.wifi.shared.model.WifiNetworkModel Loading @@ -43,16 +44,30 @@ import org.mockito.MockitoAnnotations @SmallTest @RunWith(AndroidJUnit4::class) class CarrierMergedConnectionRepositoryTest : SysuiTestCase() { class CarrierMergedConnectionRepositoryTest : CarrierMergedConnectionRepositoryTestBase() { override fun recreateRepo() = CarrierMergedConnectionRepository( SUB_ID, logger, telephonyManager, testScope.backgroundScope.coroutineContext, testScope.backgroundScope, wifiRepository, ) } abstract class CarrierMergedConnectionRepositoryTestBase : SysuiTestCase() { protected lateinit var underTest: MobileConnectionRepository private lateinit var underTest: CarrierMergedConnectionRepository protected lateinit var wifiRepository: FakeWifiRepository @Mock protected lateinit var logger: TableLogBuffer @Mock protected lateinit var telephonyManager: TelephonyManager private lateinit var wifiRepository: FakeWifiRepository @Mock private lateinit var logger: TableLogBuffer @Mock private lateinit var telephonyManager: TelephonyManager protected val testDispatcher = UnconfinedTestDispatcher() protected val testScope = TestScope(testDispatcher) private val testDispatcher = UnconfinedTestDispatcher() private val testScope = TestScope(testDispatcher) abstract fun recreateRepo(): MobileConnectionRepository @Before fun setUp() { Loading @@ -62,15 +77,7 @@ class CarrierMergedConnectionRepositoryTest : SysuiTestCase() { wifiRepository = FakeWifiRepository() underTest = CarrierMergedConnectionRepository( SUB_ID, logger, telephonyManager, testScope.backgroundScope.coroutineContext, testScope.backgroundScope, wifiRepository, ) underTest = recreateRepo() } @Test Loading Loading @@ -121,10 +128,7 @@ class CarrierMergedConnectionRepositoryTest : SysuiTestCase() { wifiRepository.setIsWifiDefault(true) wifiRepository.setWifiNetwork( WifiNetworkModel.CarrierMerged.of( subscriptionId = SUB_ID, level = 3, ) WifiNetworkModel.CarrierMerged.of(subscriptionId = SUB_ID, level = 3) ) assertThat(latest).isEqualTo(3) Loading @@ -141,26 +145,17 @@ class CarrierMergedConnectionRepositoryTest : SysuiTestCase() { wifiRepository.setIsWifiEnabled(true) wifiRepository.setIsWifiDefault(true) wifiRepository.setWifiNetwork( WifiNetworkModel.CarrierMerged.of( subscriptionId = SUB_ID, level = 3, ) WifiNetworkModel.CarrierMerged.of(subscriptionId = SUB_ID, level = 3) ) wifiRepository.setWifiActivity( DataActivityModel( hasActivityIn = true, hasActivityOut = false, ) DataActivityModel(hasActivityIn = true, hasActivityOut = false) ) assertThat(latest!!.hasActivityIn).isTrue() assertThat(latest!!.hasActivityOut).isFalse() wifiRepository.setWifiActivity( DataActivityModel( hasActivityIn = false, hasActivityOut = true, ) DataActivityModel(hasActivityIn = false, hasActivityOut = true) ) assertThat(latest!!.hasActivityIn).isFalse() Loading @@ -178,10 +173,7 @@ class CarrierMergedConnectionRepositoryTest : SysuiTestCase() { val typeJob = underTest.resolvedNetworkType.onEach { latestType = it }.launchIn(this) wifiRepository.setWifiNetwork( WifiNetworkModel.CarrierMerged.of( subscriptionId = SUB_ID + 10, level = 3, ) WifiNetworkModel.CarrierMerged.of(subscriptionId = SUB_ID + 10, level = 3) ) assertThat(latestLevel).isNotEqualTo(3) Loading @@ -199,10 +191,7 @@ class CarrierMergedConnectionRepositoryTest : SysuiTestCase() { val job = underTest.primaryLevel.onEach { latest = it }.launchIn(this) wifiRepository.setWifiNetwork( WifiNetworkModel.CarrierMerged.of( subscriptionId = SUB_ID, level = 3, ) WifiNetworkModel.CarrierMerged.of(subscriptionId = SUB_ID, level = 3) ) wifiRepository.setIsWifiEnabled(false) Loading @@ -219,10 +208,7 @@ class CarrierMergedConnectionRepositoryTest : SysuiTestCase() { val job = underTest.primaryLevel.onEach { latest = it }.launchIn(this) wifiRepository.setWifiNetwork( WifiNetworkModel.CarrierMerged.of( subscriptionId = SUB_ID, level = 3, ) WifiNetworkModel.CarrierMerged.of(subscriptionId = SUB_ID, level = 3) ) wifiRepository.setIsWifiDefault(false) Loading Loading @@ -280,6 +266,7 @@ class CarrierMergedConnectionRepositoryTest : SysuiTestCase() { fun networkName_usesSimOperatorNameAsInitial() = testScope.runTest { whenever(telephonyManager.simOperatorName).thenReturn("Test SIM name") underTest = recreateRepo() var latest: NetworkNameModel? = null val job = underTest.networkName.onEach { latest = it }.launchIn(this) Loading @@ -293,6 +280,10 @@ class CarrierMergedConnectionRepositoryTest : SysuiTestCase() { fun networkName_updatesOnNetworkUpdate() = testScope.runTest { whenever(telephonyManager.simOperatorName).thenReturn("Test SIM name") underTest = recreateRepo() wifiRepository.setIsWifiEnabled(true) wifiRepository.setIsWifiDefault(true) var latest: NetworkNameModel? = null val job = underTest.networkName.onEach { latest = it }.launchIn(this) Loading @@ -301,10 +292,7 @@ class CarrierMergedConnectionRepositoryTest : SysuiTestCase() { whenever(telephonyManager.simOperatorName).thenReturn("New SIM name") wifiRepository.setWifiNetwork( WifiNetworkModel.CarrierMerged.of( subscriptionId = SUB_ID, level = 3, ) WifiNetworkModel.CarrierMerged.of(subscriptionId = SUB_ID, level = 3) ) assertThat(latest).isEqualTo(NetworkNameModel.SimDerived("New SIM name")) Loading @@ -320,7 +308,7 @@ class CarrierMergedConnectionRepositoryTest : SysuiTestCase() { assertThat(latest).isTrue() } private companion object { companion object { const val SUB_ID = 123 } }
packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconInteractorKairosAdapterTest.kt 0 → 100644 +141 −0 Original line number Diff line number Diff line /* * Copyright (C) 2025 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.domain.interactor import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.filters.SmallTest import com.android.settingslib.SignalIcon import com.android.settingslib.mobile.MobileIconCarrierIdOverrides import com.android.systemui.activated import com.android.systemui.kairos.BuildScope import com.android.systemui.kairos.ExperimentalKairosApi import com.android.systemui.kairos.Incremental import com.android.systemui.kairos.State import com.android.systemui.kairos.asIncremental import com.android.systemui.kairos.buildSpec import com.android.systemui.kairos.combine import com.android.systemui.kairos.launchKairosNetwork import com.android.systemui.statusbar.pipeline.mobile.data.model.SubscriptionModel import com.android.systemui.statusbar.pipeline.mobile.domain.interactor.MobileIconsInteractorKairosAdapterTest.Companion.wrapRepo import com.android.systemui.util.mockito.mock import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.Job import kotlinx.coroutines.launch import kotlinx.coroutines.test.runCurrent import org.junit.runner.RunWith @OptIn(ExperimentalKairosApi::class, ExperimentalCoroutinesApi::class) @SmallTest @RunWith(AndroidJUnit4::class) class MobileIconInteractorKairosAdapterTest : MobileIconInteractorTestBase() { var job: Job? = null val kairosNetwork = testScope.backgroundScope.launchKairosNetwork() override fun createInteractor(overrides: MobileIconCarrierIdOverrides): MobileIconInteractor { lateinit var result: MobileIconInteractor job?.cancel() job = testScope.backgroundScope.launch { kairosNetwork.activateSpec { val wrapped = wrap(mobileIconsInteractor) result = MobileIconInteractorKairosAdapter( kairosImpl = activated { MobileIconInteractorKairosImpl( defaultSubscriptionHasDataEnabled = wrapped.activeDataConnectionHasDataEnabled, alwaysShowDataRatIcon = wrapped.alwaysShowDataRatIcon, alwaysUseCdmaLevel = wrapped.alwaysUseCdmaLevel, isSingleCarrier = wrapped.isSingleCarrier, mobileIsDefault = wrapped.mobileIsDefault, defaultMobileIconMapping = wrapped.defaultMobileIconMapping, defaultMobileIconGroup = wrapped.defaultMobileIconGroup, isDefaultConnectionFailed = wrapped.isDefaultConnectionFailed, isForceHidden = wrapped.isForceHidden, connectionRepository = wrapRepo(connectionRepository), context = context, carrierIdOverrides = overrides, ) } ) Unit } } testScope.runCurrent() // ensure the lateinit is set return result } /** Allows us to wrap a (likely fake) MobileIconsInteractor into a Kairos version. */ private fun BuildScope.wrap(interactor: MobileIconsInteractor): MobileIconsInteractorKairos { val filteredSubscriptions = interactor.filteredSubscriptions.toState(emptyList()) val icons = interactor.icons.toState() return InteractorWrapper( mobileIsDefault = interactor.mobileIsDefault.toState(), filteredSubscriptions = filteredSubscriptions, icons = combine(filteredSubscriptions, icons) { subs, icons -> subs.zip(icons).associate { (subModel, icon) -> subModel.subscriptionId to buildSpec { wrap(icon) } } } .asIncremental() .applyLatestSpecForKey(), isStackable = interactor.isStackable.toState(), activeDataConnectionHasDataEnabled = interactor.activeDataConnectionHasDataEnabled.toState(), activeDataIconInteractor = interactor.activeDataIconInteractor.toState().mapLatestBuild { it?.let { wrap(it) } }, alwaysShowDataRatIcon = interactor.alwaysShowDataRatIcon.toState(), alwaysUseCdmaLevel = interactor.alwaysUseCdmaLevel.toState(), isSingleCarrier = interactor.isSingleCarrier.toState(), defaultMobileIconMapping = interactor.defaultMobileIconMapping.toState(), defaultMobileIconGroup = interactor.defaultMobileIconGroup.toState(), isDefaultConnectionFailed = interactor.isDefaultConnectionFailed.toState(), isUserSetUp = interactor.isUserSetUp.toState(), isForceHidden = interactor.isForceHidden.toState(false), isDeviceInEmergencyCallsOnlyMode = interactor.isDeviceInEmergencyCallsOnlyMode.toState(false), ) } private fun BuildScope.wrap(interactor: MobileIconInteractor): MobileIconInteractorKairos = // unused in tests mock() private class InteractorWrapper( override val mobileIsDefault: State<Boolean>, override val filteredSubscriptions: State<List<SubscriptionModel>>, override val icons: Incremental<Int, MobileIconInteractorKairos>, override val isStackable: State<Boolean>, override val activeDataConnectionHasDataEnabled: State<Boolean>, override val activeDataIconInteractor: State<MobileIconInteractorKairos?>, override val alwaysShowDataRatIcon: State<Boolean>, override val alwaysUseCdmaLevel: State<Boolean>, override val isSingleCarrier: State<Boolean>, override val defaultMobileIconMapping: State<Map<String, SignalIcon.MobileIconGroup>>, override val defaultMobileIconGroup: State<SignalIcon.MobileIconGroup>, override val isDefaultConnectionFailed: State<Boolean>, override val isUserSetUp: State<Boolean>, override val isForceHidden: State<Boolean>, override val isDeviceInEmergencyCallsOnlyMode: State<Boolean>, ) : MobileIconsInteractorKairos }
packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconInteractorTest.kt +30 −25 Original line number Diff line number Diff line Loading @@ -22,6 +22,7 @@ import android.telephony.CellSignalStrength import android.telephony.TelephonyManager.NETWORK_TYPE_UNKNOWN import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.filters.SmallTest import com.android.internal.telephony.flags.Flags import com.android.settingslib.mobile.MobileIconCarrierIdOverrides import com.android.settingslib.mobile.MobileIconCarrierIdOverridesImpl import com.android.settingslib.mobile.TelephonyIcons Loading Loading @@ -58,21 +59,40 @@ import org.mockito.ArgumentMatchers.anyString @SmallTest @RunWith(AndroidJUnit4::class) class MobileIconInteractorTest : SysuiTestCase() { private val kosmos = testKosmos() class MobileIconInteractorTest : MobileIconInteractorTestBase() { override fun createInteractor(overrides: MobileIconCarrierIdOverrides) = MobileIconInteractorImpl( testScope.backgroundScope, mobileIconsInteractor.activeDataConnectionHasDataEnabled, mobileIconsInteractor.alwaysShowDataRatIcon, mobileIconsInteractor.alwaysUseCdmaLevel, mobileIconsInteractor.isSingleCarrier, mobileIconsInteractor.mobileIsDefault, mobileIconsInteractor.defaultMobileIconMapping, mobileIconsInteractor.defaultMobileIconGroup, mobileIconsInteractor.isDefaultConnectionFailed, mobileIconsInteractor.isForceHidden, connectionRepository, context, overrides, ) } private lateinit var underTest: MobileIconInteractor private val mobileMappingsProxy = FakeMobileMappingsProxy() private val mobileIconsInteractor = FakeMobileIconsInteractor(mobileMappingsProxy, mock()) abstract class MobileIconInteractorTestBase : SysuiTestCase() { protected val kosmos = testKosmos() private val connectionRepository = protected lateinit var underTest: MobileIconInteractor protected val mobileMappingsProxy = FakeMobileMappingsProxy() protected val mobileIconsInteractor = FakeMobileIconsInteractor(mobileMappingsProxy, mock()) protected val connectionRepository = FakeMobileConnectionRepository( SUB_1_ID, logcatTableLogBuffer(kosmos, "MobileIconInteractorTest"), ) private val testDispatcher = UnconfinedTestDispatcher() private val testScope = TestScope(testDispatcher) protected val testDispatcher = UnconfinedTestDispatcher() protected val testScope = TestScope(testDispatcher) @Before fun setUp() { Loading Loading @@ -835,24 +855,9 @@ class MobileIconInteractorTest : SysuiTestCase() { assertThat(latest!!.level).isEqualTo(0) } private fun createInteractor( abstract fun createInteractor( overrides: MobileIconCarrierIdOverrides = MobileIconCarrierIdOverridesImpl() ) = MobileIconInteractorImpl( testScope.backgroundScope, mobileIconsInteractor.activeDataConnectionHasDataEnabled, mobileIconsInteractor.alwaysShowDataRatIcon, mobileIconsInteractor.alwaysUseCdmaLevel, mobileIconsInteractor.isSingleCarrier, mobileIconsInteractor.mobileIsDefault, mobileIconsInteractor.defaultMobileIconMapping, mobileIconsInteractor.defaultMobileIconGroup, mobileIconsInteractor.isDefaultConnectionFailed, mobileIconsInteractor.isForceHidden, connectionRepository, context, overrides, ) ): MobileIconInteractor companion object { private const val GSM_LEVEL = 1 Loading